1c1cb2cd8Shaad /*
2c1cb2cd8Shaad * CDDL HEADER START
3c1cb2cd8Shaad *
4c1cb2cd8Shaad * The contents of this file are subject to the terms of the
5c1cb2cd8Shaad * Common Development and Distribution License (the "License").
6c1cb2cd8Shaad * You may not use this file except in compliance with the License.
7c1cb2cd8Shaad *
8c1cb2cd8Shaad * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c1cb2cd8Shaad * or http://www.opensolaris.org/os/licensing.
10c1cb2cd8Shaad * See the License for the specific language governing permissions
11c1cb2cd8Shaad * and limitations under the License.
12c1cb2cd8Shaad *
13c1cb2cd8Shaad * When distributing Covered Code, include this CDDL HEADER in each
14c1cb2cd8Shaad * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c1cb2cd8Shaad * If applicable, add the following below this CDDL HEADER, with the
16c1cb2cd8Shaad * fields enclosed by brackets "[]" replaced with your own identifying
17c1cb2cd8Shaad * information: Portions Copyright [yyyy] [name of copyright owner]
18c1cb2cd8Shaad *
19c1cb2cd8Shaad * CDDL HEADER END
20c1cb2cd8Shaad */
21*ba2539a9Schs
22c1cb2cd8Shaad /*
23*ba2539a9Schs * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24*ba2539a9Schs * Copyright (c) 2013, Joyent, Inc. All rights reserved.
25*ba2539a9Schs * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
26*ba2539a9Schs * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
27c1cb2cd8Shaad */
28c1cb2cd8Shaad
29c1cb2cd8Shaad /*
30c1cb2cd8Shaad * Internal utility routines for the ZFS library.
31c1cb2cd8Shaad */
32c1cb2cd8Shaad
33*ba2539a9Schs #include <sys/param.h>
34*ba2539a9Schs #include <sys/linker.h>
35*ba2539a9Schs #include <sys/module.h>
36*ba2539a9Schs #include <sys/stat.h>
37*ba2539a9Schs
38c1cb2cd8Shaad #include <errno.h>
39c1cb2cd8Shaad #include <fcntl.h>
40c1cb2cd8Shaad #include <libintl.h>
41c1cb2cd8Shaad #include <stdarg.h>
42c1cb2cd8Shaad #include <stdio.h>
43c1cb2cd8Shaad #include <stdlib.h>
44c1cb2cd8Shaad #include <strings.h>
45c1cb2cd8Shaad #include <unistd.h>
46c1cb2cd8Shaad #include <ctype.h>
47c1cb2cd8Shaad #include <math.h>
48c1cb2cd8Shaad #include <sys/mnttab.h>
49c1cb2cd8Shaad #include <sys/mntent.h>
50c1cb2cd8Shaad #include <sys/types.h>
51f337b6c7Sdsl #include <sys/ioctl.h>
52c1cb2cd8Shaad
53*ba2539a9Schs #ifdef __NetBSD__
54*ba2539a9Schs #include <sys/statvfs.h>
55*ba2539a9Schs #endif
56*ba2539a9Schs
57c1cb2cd8Shaad #include <libzfs.h>
58*ba2539a9Schs #include <libzfs_core.h>
59c1cb2cd8Shaad
60c1cb2cd8Shaad #include "libzfs_impl.h"
61c1cb2cd8Shaad #include "zfs_prop.h"
62*ba2539a9Schs #include "zfeature_common.h"
63*ba2539a9Schs
64c1cb2cd8Shaad
65c1cb2cd8Shaad int
libzfs_errno(libzfs_handle_t * hdl)66c1cb2cd8Shaad libzfs_errno(libzfs_handle_t *hdl)
67c1cb2cd8Shaad {
68c1cb2cd8Shaad return (hdl->libzfs_error);
69c1cb2cd8Shaad }
70c1cb2cd8Shaad
71c1cb2cd8Shaad const char *
libzfs_error_action(libzfs_handle_t * hdl)72c1cb2cd8Shaad libzfs_error_action(libzfs_handle_t *hdl)
73c1cb2cd8Shaad {
74c1cb2cd8Shaad return (hdl->libzfs_action);
75c1cb2cd8Shaad }
76c1cb2cd8Shaad
77c1cb2cd8Shaad const char *
libzfs_error_description(libzfs_handle_t * hdl)78c1cb2cd8Shaad libzfs_error_description(libzfs_handle_t *hdl)
79c1cb2cd8Shaad {
80c1cb2cd8Shaad if (hdl->libzfs_desc[0] != '\0')
81c1cb2cd8Shaad return (hdl->libzfs_desc);
82c1cb2cd8Shaad
83c1cb2cd8Shaad switch (hdl->libzfs_error) {
84c1cb2cd8Shaad case EZFS_NOMEM:
85c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "out of memory"));
86c1cb2cd8Shaad case EZFS_BADPROP:
87c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid property value"));
88c1cb2cd8Shaad case EZFS_PROPREADONLY:
89*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "read-only property"));
90c1cb2cd8Shaad case EZFS_PROPTYPE:
91c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "property doesn't apply to "
92c1cb2cd8Shaad "datasets of this type"));
93c1cb2cd8Shaad case EZFS_PROPNONINHERIT:
94c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));
95c1cb2cd8Shaad case EZFS_PROPSPACE:
96c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));
97c1cb2cd8Shaad case EZFS_BADTYPE:
98c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "operation not applicable to "
99c1cb2cd8Shaad "datasets of this type"));
100c1cb2cd8Shaad case EZFS_BUSY:
101c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "pool or dataset is busy"));
102c1cb2cd8Shaad case EZFS_EXISTS:
103c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "pool or dataset exists"));
104c1cb2cd8Shaad case EZFS_NOENT:
105c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "no such pool or dataset"));
106c1cb2cd8Shaad case EZFS_BADSTREAM:
107c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid backup stream"));
108c1cb2cd8Shaad case EZFS_DSREADONLY:
109*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "dataset is read-only"));
110c1cb2cd8Shaad case EZFS_VOLTOOBIG:
111c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
112c1cb2cd8Shaad "this system"));
113c1cb2cd8Shaad case EZFS_INVALIDNAME:
114c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid name"));
115c1cb2cd8Shaad case EZFS_BADRESTORE:
116c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "unable to restore to "
117c1cb2cd8Shaad "destination"));
118c1cb2cd8Shaad case EZFS_BADBACKUP:
119c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "backup failed"));
120c1cb2cd8Shaad case EZFS_BADTARGET:
121c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid target vdev"));
122c1cb2cd8Shaad case EZFS_NODEVICE:
123c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "no such device in pool"));
124c1cb2cd8Shaad case EZFS_BADDEV:
125c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid device"));
126c1cb2cd8Shaad case EZFS_NOREPLICAS:
127c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "no valid replicas"));
128c1cb2cd8Shaad case EZFS_RESILVERING:
129c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "currently resilvering"));
130c1cb2cd8Shaad case EZFS_BADVERSION:
131*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "unsupported version or "
132*ba2539a9Schs "feature"));
133c1cb2cd8Shaad case EZFS_POOLUNAVAIL:
134c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "pool is unavailable"));
135c1cb2cd8Shaad case EZFS_DEVOVERFLOW:
136c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "too many devices in one vdev"));
137c1cb2cd8Shaad case EZFS_BADPATH:
138c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "must be an absolute path"));
139c1cb2cd8Shaad case EZFS_CROSSTARGET:
140c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "operation crosses datasets or "
141c1cb2cd8Shaad "pools"));
142c1cb2cd8Shaad case EZFS_ZONED:
143c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "dataset in use by local zone"));
144c1cb2cd8Shaad case EZFS_MOUNTFAILED:
145c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "mount failed"));
146c1cb2cd8Shaad case EZFS_UMOUNTFAILED:
147c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "umount failed"));
148c1cb2cd8Shaad case EZFS_UNSHARENFSFAILED:
149c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
150c1cb2cd8Shaad case EZFS_SHARENFSFAILED:
151c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
152c1cb2cd8Shaad case EZFS_UNSHARESMBFAILED:
153c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "smb remove share failed"));
154c1cb2cd8Shaad case EZFS_SHARESMBFAILED:
155c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "smb add share failed"));
156c1cb2cd8Shaad case EZFS_PERM:
157c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "permission denied"));
158c1cb2cd8Shaad case EZFS_NOSPC:
159c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "out of space"));
160*ba2539a9Schs case EZFS_FAULT:
161*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "bad address"));
162c1cb2cd8Shaad case EZFS_IO:
163c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "I/O error"));
164c1cb2cd8Shaad case EZFS_INTR:
165c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "signal received"));
166c1cb2cd8Shaad case EZFS_ISSPARE:
167c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "device is reserved as a hot "
168c1cb2cd8Shaad "spare"));
169c1cb2cd8Shaad case EZFS_INVALCONFIG:
170c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid vdev configuration"));
171c1cb2cd8Shaad case EZFS_RECURSIVE:
172c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));
173c1cb2cd8Shaad case EZFS_NOHISTORY:
174c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "no history available"));
175c1cb2cd8Shaad case EZFS_POOLPROPS:
176c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "failed to retrieve "
177c1cb2cd8Shaad "pool properties"));
178c1cb2cd8Shaad case EZFS_POOL_NOTSUP:
179c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "operation not supported "
180c1cb2cd8Shaad "on this type of pool"));
181c1cb2cd8Shaad case EZFS_POOL_INVALARG:
182c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid argument for "
183c1cb2cd8Shaad "this pool operation"));
184c1cb2cd8Shaad case EZFS_NAMETOOLONG:
185c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "dataset name is too long"));
186c1cb2cd8Shaad case EZFS_OPENFAILED:
187c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "open failed"));
188c1cb2cd8Shaad case EZFS_NOCAP:
189c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN,
190c1cb2cd8Shaad "disk capacity information could not be retrieved"));
191c1cb2cd8Shaad case EZFS_LABELFAILED:
192c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "write of label failed"));
193c1cb2cd8Shaad case EZFS_BADWHO:
194c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid user/group"));
195c1cb2cd8Shaad case EZFS_BADPERM:
196c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid permission"));
197c1cb2cd8Shaad case EZFS_BADPERMSET:
198c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid permission set name"));
199c1cb2cd8Shaad case EZFS_NODELEGATION:
200c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "delegated administration is "
201c1cb2cd8Shaad "disabled on pool"));
202c1cb2cd8Shaad case EZFS_BADCACHE:
203c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "invalid or missing cache file"));
204c1cb2cd8Shaad case EZFS_ISL2CACHE:
205c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "device is in use as a cache"));
206c1cb2cd8Shaad case EZFS_VDEVNOTSUP:
207c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "vdev specification is not "
208c1cb2cd8Shaad "supported"));
209c1cb2cd8Shaad case EZFS_NOTSUP:
210c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "operation not supported "
211c1cb2cd8Shaad "on this dataset"));
212c1cb2cd8Shaad case EZFS_ACTIVE_SPARE:
213c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "pool has active shared spare "
214c1cb2cd8Shaad "device"));
215a252d550Shaad case EZFS_UNPLAYED_LOGS:
216a252d550Shaad return (dgettext(TEXT_DOMAIN, "log device has unplayed intent "
217a252d550Shaad "logs"));
218a252d550Shaad case EZFS_REFTAG_RELE:
219a252d550Shaad return (dgettext(TEXT_DOMAIN, "no such tag on this dataset"));
220a252d550Shaad case EZFS_REFTAG_HOLD:
221a252d550Shaad return (dgettext(TEXT_DOMAIN, "tag already exists on this "
222a252d550Shaad "dataset"));
223a252d550Shaad case EZFS_TAGTOOLONG:
224a252d550Shaad return (dgettext(TEXT_DOMAIN, "tag too long"));
225a252d550Shaad case EZFS_PIPEFAILED:
226a252d550Shaad return (dgettext(TEXT_DOMAIN, "pipe create failed"));
227a252d550Shaad case EZFS_THREADCREATEFAILED:
228a252d550Shaad return (dgettext(TEXT_DOMAIN, "thread create failed"));
229a252d550Shaad case EZFS_POSTSPLIT_ONLINE:
230a252d550Shaad return (dgettext(TEXT_DOMAIN, "disk was split from this pool "
231a252d550Shaad "into a new one"));
232*ba2539a9Schs case EZFS_SCRUBBING:
233*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "currently scrubbing; "
234*ba2539a9Schs "use 'zpool scrub -s' to cancel current scrub"));
235*ba2539a9Schs case EZFS_NO_SCRUB:
236*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "there is no active scrub"));
237*ba2539a9Schs case EZFS_DIFF:
238*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "unable to generate diffs"));
239*ba2539a9Schs case EZFS_DIFFDATA:
240*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "invalid diff data"));
241*ba2539a9Schs case EZFS_POOLREADONLY:
242*ba2539a9Schs return (dgettext(TEXT_DOMAIN, "pool is read-only"));
243c1cb2cd8Shaad case EZFS_UNKNOWN:
244c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "unknown error"));
245c1cb2cd8Shaad default:
246c1cb2cd8Shaad assert(hdl->libzfs_error == 0);
247c1cb2cd8Shaad return (dgettext(TEXT_DOMAIN, "no error"));
248c1cb2cd8Shaad }
249c1cb2cd8Shaad }
250c1cb2cd8Shaad
251c1cb2cd8Shaad /*PRINTFLIKE2*/
252c1cb2cd8Shaad void
zfs_error_aux(libzfs_handle_t * hdl,const char * fmt,...)253c1cb2cd8Shaad zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...)
254c1cb2cd8Shaad {
255c1cb2cd8Shaad va_list ap;
256c1cb2cd8Shaad
257c1cb2cd8Shaad va_start(ap, fmt);
258c1cb2cd8Shaad
259c1cb2cd8Shaad (void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc),
260c1cb2cd8Shaad fmt, ap);
261c1cb2cd8Shaad hdl->libzfs_desc_active = 1;
262c1cb2cd8Shaad
263c1cb2cd8Shaad va_end(ap);
264c1cb2cd8Shaad }
265c1cb2cd8Shaad
266c1cb2cd8Shaad static void
zfs_verror(libzfs_handle_t * hdl,int error,const char * fmt,va_list ap)267c1cb2cd8Shaad zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap)
268c1cb2cd8Shaad {
269c1cb2cd8Shaad (void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action),
270c1cb2cd8Shaad fmt, ap);
271c1cb2cd8Shaad hdl->libzfs_error = error;
272c1cb2cd8Shaad
273c1cb2cd8Shaad if (hdl->libzfs_desc_active)
274c1cb2cd8Shaad hdl->libzfs_desc_active = 0;
275c1cb2cd8Shaad else
276c1cb2cd8Shaad hdl->libzfs_desc[0] = '\0';
277c1cb2cd8Shaad
278c1cb2cd8Shaad if (hdl->libzfs_printerr) {
279c1cb2cd8Shaad if (error == EZFS_UNKNOWN) {
280c1cb2cd8Shaad (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal "
281c1cb2cd8Shaad "error: %s\n"), libzfs_error_description(hdl));
282c1cb2cd8Shaad abort();
283c1cb2cd8Shaad }
284c1cb2cd8Shaad
285c1cb2cd8Shaad (void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action,
286c1cb2cd8Shaad libzfs_error_description(hdl));
287c1cb2cd8Shaad if (error == EZFS_NOMEM)
288c1cb2cd8Shaad exit(1);
289c1cb2cd8Shaad }
290c1cb2cd8Shaad }
291c1cb2cd8Shaad
292c1cb2cd8Shaad int
zfs_error(libzfs_handle_t * hdl,int error,const char * msg)293c1cb2cd8Shaad zfs_error(libzfs_handle_t *hdl, int error, const char *msg)
294c1cb2cd8Shaad {
295c1cb2cd8Shaad return (zfs_error_fmt(hdl, error, "%s", msg));
296c1cb2cd8Shaad }
297c1cb2cd8Shaad
298c1cb2cd8Shaad /*PRINTFLIKE3*/
299c1cb2cd8Shaad int
zfs_error_fmt(libzfs_handle_t * hdl,int error,const char * fmt,...)300c1cb2cd8Shaad zfs_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
301c1cb2cd8Shaad {
302c1cb2cd8Shaad va_list ap;
303c1cb2cd8Shaad
304c1cb2cd8Shaad va_start(ap, fmt);
305c1cb2cd8Shaad
306c1cb2cd8Shaad zfs_verror(hdl, error, fmt, ap);
307c1cb2cd8Shaad
308c1cb2cd8Shaad va_end(ap);
309c1cb2cd8Shaad
310c1cb2cd8Shaad return (-1);
311c1cb2cd8Shaad }
312c1cb2cd8Shaad
313c1cb2cd8Shaad static int
zfs_common_error(libzfs_handle_t * hdl,int error,const char * fmt,va_list ap)314c1cb2cd8Shaad zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
315c1cb2cd8Shaad va_list ap)
316c1cb2cd8Shaad {
317c1cb2cd8Shaad switch (error) {
318c1cb2cd8Shaad case EPERM:
319c1cb2cd8Shaad case EACCES:
320c1cb2cd8Shaad zfs_verror(hdl, EZFS_PERM, fmt, ap);
321c1cb2cd8Shaad return (-1);
322c1cb2cd8Shaad
323c1cb2cd8Shaad case ECANCELED:
324c1cb2cd8Shaad zfs_verror(hdl, EZFS_NODELEGATION, fmt, ap);
325c1cb2cd8Shaad return (-1);
326c1cb2cd8Shaad
327c1cb2cd8Shaad case EIO:
328c1cb2cd8Shaad zfs_verror(hdl, EZFS_IO, fmt, ap);
329c1cb2cd8Shaad return (-1);
330c1cb2cd8Shaad
331*ba2539a9Schs case EFAULT:
332*ba2539a9Schs zfs_verror(hdl, EZFS_FAULT, fmt, ap);
333*ba2539a9Schs return (-1);
334*ba2539a9Schs
335c1cb2cd8Shaad case EINTR:
336c1cb2cd8Shaad zfs_verror(hdl, EZFS_INTR, fmt, ap);
337c1cb2cd8Shaad return (-1);
338c1cb2cd8Shaad }
339c1cb2cd8Shaad
340c1cb2cd8Shaad return (0);
341c1cb2cd8Shaad }
342c1cb2cd8Shaad
343c1cb2cd8Shaad int
zfs_standard_error(libzfs_handle_t * hdl,int error,const char * msg)344c1cb2cd8Shaad zfs_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
345c1cb2cd8Shaad {
346c1cb2cd8Shaad return (zfs_standard_error_fmt(hdl, error, "%s", msg));
347c1cb2cd8Shaad }
348c1cb2cd8Shaad
349c1cb2cd8Shaad /*PRINTFLIKE3*/
350c1cb2cd8Shaad int
zfs_standard_error_fmt(libzfs_handle_t * hdl,int error,const char * fmt,...)351c1cb2cd8Shaad zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
352c1cb2cd8Shaad {
353c1cb2cd8Shaad va_list ap;
354c1cb2cd8Shaad
355c1cb2cd8Shaad va_start(ap, fmt);
356c1cb2cd8Shaad
357c1cb2cd8Shaad if (zfs_common_error(hdl, error, fmt, ap) != 0) {
358c1cb2cd8Shaad va_end(ap);
359c1cb2cd8Shaad return (-1);
360c1cb2cd8Shaad }
361c1cb2cd8Shaad
362c1cb2cd8Shaad switch (error) {
363c1cb2cd8Shaad case ENXIO:
364c1cb2cd8Shaad case ENODEV:
365*ba2539a9Schs case EPIPE:
366c1cb2cd8Shaad zfs_verror(hdl, EZFS_IO, fmt, ap);
367c1cb2cd8Shaad break;
368c1cb2cd8Shaad
369c1cb2cd8Shaad case ENOENT:
370c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
371c1cb2cd8Shaad "dataset does not exist"));
372c1cb2cd8Shaad zfs_verror(hdl, EZFS_NOENT, fmt, ap);
373c1cb2cd8Shaad break;
374c1cb2cd8Shaad
375c1cb2cd8Shaad case ENOSPC:
376c1cb2cd8Shaad case EDQUOT:
377c1cb2cd8Shaad zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
378*ba2539a9Schs va_end(ap);
379c1cb2cd8Shaad return (-1);
380c1cb2cd8Shaad
381c1cb2cd8Shaad case EEXIST:
382c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
383c1cb2cd8Shaad "dataset already exists"));
384c1cb2cd8Shaad zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
385c1cb2cd8Shaad break;
386c1cb2cd8Shaad
387c1cb2cd8Shaad case EBUSY:
388c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
389c1cb2cd8Shaad "dataset is busy"));
390c1cb2cd8Shaad zfs_verror(hdl, EZFS_BUSY, fmt, ap);
391c1cb2cd8Shaad break;
392c1cb2cd8Shaad case EROFS:
393*ba2539a9Schs zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
394c1cb2cd8Shaad break;
395c1cb2cd8Shaad case ENAMETOOLONG:
396c1cb2cd8Shaad zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
397c1cb2cd8Shaad break;
398c1cb2cd8Shaad case ENOTSUP:
399c1cb2cd8Shaad zfs_verror(hdl, EZFS_BADVERSION, fmt, ap);
400c1cb2cd8Shaad break;
401a252d550Shaad case EAGAIN:
402a252d550Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
403a252d550Shaad "pool I/O is currently suspended"));
404a252d550Shaad zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
405a252d550Shaad break;
406c1cb2cd8Shaad default:
407a252d550Shaad zfs_error_aux(hdl, strerror(error));
408c1cb2cd8Shaad zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
409c1cb2cd8Shaad break;
410c1cb2cd8Shaad }
411c1cb2cd8Shaad
412c1cb2cd8Shaad va_end(ap);
413c1cb2cd8Shaad return (-1);
414c1cb2cd8Shaad }
415c1cb2cd8Shaad
416c1cb2cd8Shaad int
zpool_standard_error(libzfs_handle_t * hdl,int error,const char * msg)417c1cb2cd8Shaad zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
418c1cb2cd8Shaad {
419c1cb2cd8Shaad return (zpool_standard_error_fmt(hdl, error, "%s", msg));
420c1cb2cd8Shaad }
421c1cb2cd8Shaad
422c1cb2cd8Shaad /*PRINTFLIKE3*/
423c1cb2cd8Shaad int
zpool_standard_error_fmt(libzfs_handle_t * hdl,int error,const char * fmt,...)424c1cb2cd8Shaad zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
425c1cb2cd8Shaad {
426c1cb2cd8Shaad va_list ap;
427c1cb2cd8Shaad
428c1cb2cd8Shaad va_start(ap, fmt);
429c1cb2cd8Shaad
430c1cb2cd8Shaad if (zfs_common_error(hdl, error, fmt, ap) != 0) {
431c1cb2cd8Shaad va_end(ap);
432c1cb2cd8Shaad return (-1);
433c1cb2cd8Shaad }
434c1cb2cd8Shaad
435c1cb2cd8Shaad switch (error) {
436c1cb2cd8Shaad case ENODEV:
437c1cb2cd8Shaad zfs_verror(hdl, EZFS_NODEVICE, fmt, ap);
438c1cb2cd8Shaad break;
439c1cb2cd8Shaad
440c1cb2cd8Shaad case ENOENT:
441c1cb2cd8Shaad zfs_error_aux(hdl,
442c1cb2cd8Shaad dgettext(TEXT_DOMAIN, "no such pool or dataset"));
443c1cb2cd8Shaad zfs_verror(hdl, EZFS_NOENT, fmt, ap);
444c1cb2cd8Shaad break;
445c1cb2cd8Shaad
446c1cb2cd8Shaad case EEXIST:
447c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
448c1cb2cd8Shaad "pool already exists"));
449c1cb2cd8Shaad zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
450c1cb2cd8Shaad break;
451c1cb2cd8Shaad
452c1cb2cd8Shaad case EBUSY:
453c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
454c1cb2cd8Shaad zfs_verror(hdl, EZFS_BUSY, fmt, ap);
455c1cb2cd8Shaad break;
456c1cb2cd8Shaad
457c1cb2cd8Shaad case ENXIO:
458c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
459c1cb2cd8Shaad "one or more devices is currently unavailable"));
460c1cb2cd8Shaad zfs_verror(hdl, EZFS_BADDEV, fmt, ap);
461c1cb2cd8Shaad break;
462c1cb2cd8Shaad
463c1cb2cd8Shaad case ENAMETOOLONG:
464c1cb2cd8Shaad zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap);
465c1cb2cd8Shaad break;
466c1cb2cd8Shaad
467c1cb2cd8Shaad case ENOTSUP:
468c1cb2cd8Shaad zfs_verror(hdl, EZFS_POOL_NOTSUP, fmt, ap);
469c1cb2cd8Shaad break;
470c1cb2cd8Shaad
471c1cb2cd8Shaad case EINVAL:
472c1cb2cd8Shaad zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap);
473c1cb2cd8Shaad break;
474c1cb2cd8Shaad
475c1cb2cd8Shaad case ENOSPC:
476c1cb2cd8Shaad case EDQUOT:
477c1cb2cd8Shaad zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
478*ba2539a9Schs va_end(ap);
479c1cb2cd8Shaad return (-1);
480*ba2539a9Schs
481a252d550Shaad case EAGAIN:
482a252d550Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
483a252d550Shaad "pool I/O is currently suspended"));
484a252d550Shaad zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
485a252d550Shaad break;
486c1cb2cd8Shaad
487*ba2539a9Schs case EROFS:
488*ba2539a9Schs zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
489*ba2539a9Schs break;
490*ba2539a9Schs
491c1cb2cd8Shaad default:
492c1cb2cd8Shaad zfs_error_aux(hdl, strerror(error));
493c1cb2cd8Shaad zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
494c1cb2cd8Shaad }
495c1cb2cd8Shaad
496c1cb2cd8Shaad va_end(ap);
497c1cb2cd8Shaad return (-1);
498c1cb2cd8Shaad }
499c1cb2cd8Shaad
500c1cb2cd8Shaad /*
501c1cb2cd8Shaad * Display an out of memory error message and abort the current program.
502c1cb2cd8Shaad */
503c1cb2cd8Shaad int
no_memory(libzfs_handle_t * hdl)504c1cb2cd8Shaad no_memory(libzfs_handle_t *hdl)
505c1cb2cd8Shaad {
506c1cb2cd8Shaad return (zfs_error(hdl, EZFS_NOMEM, "internal error"));
507c1cb2cd8Shaad }
508c1cb2cd8Shaad
509c1cb2cd8Shaad /*
510c1cb2cd8Shaad * A safe form of malloc() which will die if the allocation fails.
511c1cb2cd8Shaad */
512c1cb2cd8Shaad void *
zfs_alloc(libzfs_handle_t * hdl,size_t size)513c1cb2cd8Shaad zfs_alloc(libzfs_handle_t *hdl, size_t size)
514c1cb2cd8Shaad {
515c1cb2cd8Shaad void *data;
516c1cb2cd8Shaad
517c1cb2cd8Shaad if ((data = calloc(1, size)) == NULL)
518c1cb2cd8Shaad (void) no_memory(hdl);
519c1cb2cd8Shaad
520c1cb2cd8Shaad return (data);
521c1cb2cd8Shaad }
522c1cb2cd8Shaad
523c1cb2cd8Shaad /*
524*ba2539a9Schs * A safe form of asprintf() which will die if the allocation fails.
525*ba2539a9Schs */
526*ba2539a9Schs /*PRINTFLIKE2*/
527*ba2539a9Schs char *
zfs_asprintf(libzfs_handle_t * hdl,const char * fmt,...)528*ba2539a9Schs zfs_asprintf(libzfs_handle_t *hdl, const char *fmt, ...)
529*ba2539a9Schs {
530*ba2539a9Schs va_list ap;
531*ba2539a9Schs char *ret;
532*ba2539a9Schs int err;
533*ba2539a9Schs
534*ba2539a9Schs va_start(ap, fmt);
535*ba2539a9Schs
536*ba2539a9Schs err = vasprintf(&ret, fmt, ap);
537*ba2539a9Schs
538*ba2539a9Schs va_end(ap);
539*ba2539a9Schs
540*ba2539a9Schs if (err < 0)
541*ba2539a9Schs (void) no_memory(hdl);
542*ba2539a9Schs
543*ba2539a9Schs return (ret);
544*ba2539a9Schs }
545*ba2539a9Schs
546*ba2539a9Schs /*
547c1cb2cd8Shaad * A safe form of realloc(), which also zeroes newly allocated space.
548c1cb2cd8Shaad */
549c1cb2cd8Shaad void *
zfs_realloc(libzfs_handle_t * hdl,void * ptr,size_t oldsize,size_t newsize)550c1cb2cd8Shaad zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize)
551c1cb2cd8Shaad {
552c1cb2cd8Shaad void *ret;
553c1cb2cd8Shaad
554c1cb2cd8Shaad if ((ret = realloc(ptr, newsize)) == NULL) {
555c1cb2cd8Shaad (void) no_memory(hdl);
556c1cb2cd8Shaad return (NULL);
557c1cb2cd8Shaad }
558c1cb2cd8Shaad
559c1cb2cd8Shaad bzero((char *)ret + oldsize, (newsize - oldsize));
560c1cb2cd8Shaad return (ret);
561c1cb2cd8Shaad }
562c1cb2cd8Shaad
563c1cb2cd8Shaad /*
564c1cb2cd8Shaad * A safe form of strdup() which will die if the allocation fails.
565c1cb2cd8Shaad */
566c1cb2cd8Shaad char *
zfs_strdup(libzfs_handle_t * hdl,const char * str)567c1cb2cd8Shaad zfs_strdup(libzfs_handle_t *hdl, const char *str)
568c1cb2cd8Shaad {
569c1cb2cd8Shaad char *ret;
570c1cb2cd8Shaad
571c1cb2cd8Shaad if ((ret = strdup(str)) == NULL)
572c1cb2cd8Shaad (void) no_memory(hdl);
573c1cb2cd8Shaad
574c1cb2cd8Shaad return (ret);
575c1cb2cd8Shaad }
576c1cb2cd8Shaad
577c1cb2cd8Shaad /*
578c1cb2cd8Shaad * Convert a number to an appropriately human-readable output.
579c1cb2cd8Shaad */
580c1cb2cd8Shaad void
zfs_nicenum(uint64_t num,char * buf,size_t buflen)581c1cb2cd8Shaad zfs_nicenum(uint64_t num, char *buf, size_t buflen)
582c1cb2cd8Shaad {
583c1cb2cd8Shaad uint64_t n = num;
584c1cb2cd8Shaad int index = 0;
585c1cb2cd8Shaad char u;
586c1cb2cd8Shaad
587c1cb2cd8Shaad while (n >= 1024) {
588c1cb2cd8Shaad n /= 1024;
589c1cb2cd8Shaad index++;
590c1cb2cd8Shaad }
591c1cb2cd8Shaad
592c1cb2cd8Shaad u = " KMGTPE"[index];
593c1cb2cd8Shaad
594c1cb2cd8Shaad if (index == 0) {
595c1cb2cd8Shaad (void) snprintf(buf, buflen, "%llu", n);
596c1cb2cd8Shaad } else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
597c1cb2cd8Shaad /*
598c1cb2cd8Shaad * If this is an even multiple of the base, always display
599c1cb2cd8Shaad * without any decimal precision.
600c1cb2cd8Shaad */
601c1cb2cd8Shaad (void) snprintf(buf, buflen, "%llu%c", n, u);
602c1cb2cd8Shaad } else {
603c1cb2cd8Shaad /*
604c1cb2cd8Shaad * We want to choose a precision that reflects the best choice
605c1cb2cd8Shaad * for fitting in 5 characters. This can get rather tricky when
606c1cb2cd8Shaad * we have numbers that are very close to an order of magnitude.
607c1cb2cd8Shaad * For example, when displaying 10239 (which is really 9.999K),
608c1cb2cd8Shaad * we want only a single place of precision for 10.0K. We could
609c1cb2cd8Shaad * develop some complex heuristics for this, but it's much
610c1cb2cd8Shaad * easier just to try each combination in turn.
611c1cb2cd8Shaad */
612c1cb2cd8Shaad int i;
613c1cb2cd8Shaad for (i = 2; i >= 0; i--) {
614c1cb2cd8Shaad if (snprintf(buf, buflen, "%.*f%c", i,
615c1cb2cd8Shaad (double)num / (1ULL << 10 * index), u) <= 5)
616c1cb2cd8Shaad break;
617c1cb2cd8Shaad }
618c1cb2cd8Shaad }
619c1cb2cd8Shaad }
620c1cb2cd8Shaad
621c1cb2cd8Shaad void
libzfs_print_on_error(libzfs_handle_t * hdl,boolean_t printerr)622c1cb2cd8Shaad libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)
623c1cb2cd8Shaad {
624c1cb2cd8Shaad hdl->libzfs_printerr = printerr;
625c1cb2cd8Shaad }
626c1cb2cd8Shaad
627*ba2539a9Schs static int
libzfs_load(void)628*ba2539a9Schs libzfs_load(void)
629*ba2539a9Schs {
630*ba2539a9Schs #ifdef __FreeBSD__
631*ba2539a9Schs if (modfind("zfs") < 0) {
632*ba2539a9Schs /* Not present in kernel, try loading it. */
633*ba2539a9Schs if (kldload("zfs") < 0 || modfind("zfs") < 0) {
634*ba2539a9Schs if (errno != EEXIST)
635*ba2539a9Schs return (-1);
636*ba2539a9Schs }
637*ba2539a9Schs }
638*ba2539a9Schs #endif
639*ba2539a9Schs #ifdef __NetBSD__
640*ba2539a9Schs modctl_load_t cmdargs;
641*ba2539a9Schs
642*ba2539a9Schs cmdargs.ml_filename = "zfs";
643*ba2539a9Schs cmdargs.ml_flags = MODCTL_NO_PROP;
644*ba2539a9Schs cmdargs.ml_props = NULL;
645*ba2539a9Schs cmdargs.ml_propslen = 0;
646*ba2539a9Schs
647*ba2539a9Schs if (modctl(MODCTL_LOAD, &cmdargs) < 0 && errno != EEXIST)
648*ba2539a9Schs return (-1);
649*ba2539a9Schs #endif
650*ba2539a9Schs return (0);
651*ba2539a9Schs }
652*ba2539a9Schs
653c1cb2cd8Shaad libzfs_handle_t *
libzfs_init(void)654c1cb2cd8Shaad libzfs_init(void)
655c1cb2cd8Shaad {
656c1cb2cd8Shaad libzfs_handle_t *hdl;
657c1cb2cd8Shaad
658*ba2539a9Schs if ((hdl = calloc(1, sizeof (libzfs_handle_t))) == NULL) {
659*ba2539a9Schs return (NULL);
660*ba2539a9Schs }
661*ba2539a9Schs
662*ba2539a9Schs if (libzfs_load() < 0) {
663*ba2539a9Schs free(hdl);
664c1cb2cd8Shaad return (NULL);
665c1cb2cd8Shaad }
666c1cb2cd8Shaad
667c1cb2cd8Shaad if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
668c1cb2cd8Shaad free(hdl);
669c1cb2cd8Shaad return (NULL);
670c1cb2cd8Shaad }
671c1cb2cd8Shaad
672c1cb2cd8Shaad if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
673c1cb2cd8Shaad (void) close(hdl->libzfs_fd);
674c1cb2cd8Shaad free(hdl);
675c1cb2cd8Shaad return (NULL);
676c1cb2cd8Shaad }
677c1cb2cd8Shaad
678*ba2539a9Schs hdl->libzfs_sharetab = fopen(ZFS_EXPORTS_PATH, "r");
679*ba2539a9Schs
680*ba2539a9Schs if (libzfs_core_init() != 0) {
681*ba2539a9Schs (void) close(hdl->libzfs_fd);
682*ba2539a9Schs (void) fclose(hdl->libzfs_mnttab);
683*ba2539a9Schs (void) fclose(hdl->libzfs_sharetab);
684*ba2539a9Schs free(hdl);
685*ba2539a9Schs return (NULL);
686*ba2539a9Schs }
687c1cb2cd8Shaad
688c1cb2cd8Shaad zfs_prop_init();
689c1cb2cd8Shaad zpool_prop_init();
690*ba2539a9Schs zpool_feature_init();
691a252d550Shaad libzfs_mnttab_init(hdl);
692c1cb2cd8Shaad
693c1cb2cd8Shaad return (hdl);
694c1cb2cd8Shaad }
695c1cb2cd8Shaad
696c1cb2cd8Shaad void
libzfs_fini(libzfs_handle_t * hdl)697c1cb2cd8Shaad libzfs_fini(libzfs_handle_t *hdl)
698c1cb2cd8Shaad {
699c1cb2cd8Shaad (void) close(hdl->libzfs_fd);
700c1cb2cd8Shaad if (hdl->libzfs_mnttab)
701c1cb2cd8Shaad (void) fclose(hdl->libzfs_mnttab);
702c1cb2cd8Shaad if (hdl->libzfs_sharetab)
703c1cb2cd8Shaad (void) fclose(hdl->libzfs_sharetab);
704c1cb2cd8Shaad zfs_uninit_libshare(hdl);
705c1cb2cd8Shaad zpool_free_handles(hdl);
706*ba2539a9Schs #ifdef illumos
707a252d550Shaad libzfs_fru_clear(hdl, B_TRUE);
7088f7b707fShaad #endif
709c1cb2cd8Shaad namespace_clear(hdl);
710a252d550Shaad libzfs_mnttab_fini(hdl);
711*ba2539a9Schs libzfs_core_fini();
712c1cb2cd8Shaad free(hdl);
713c1cb2cd8Shaad }
714c1cb2cd8Shaad
715c1cb2cd8Shaad libzfs_handle_t *
zpool_get_handle(zpool_handle_t * zhp)716c1cb2cd8Shaad zpool_get_handle(zpool_handle_t *zhp)
717c1cb2cd8Shaad {
718c1cb2cd8Shaad return (zhp->zpool_hdl);
719c1cb2cd8Shaad }
720c1cb2cd8Shaad
721c1cb2cd8Shaad libzfs_handle_t *
zfs_get_handle(zfs_handle_t * zhp)722c1cb2cd8Shaad zfs_get_handle(zfs_handle_t *zhp)
723c1cb2cd8Shaad {
724c1cb2cd8Shaad return (zhp->zfs_hdl);
725c1cb2cd8Shaad }
726c1cb2cd8Shaad
727c1cb2cd8Shaad zpool_handle_t *
zfs_get_pool_handle(const zfs_handle_t * zhp)728c1cb2cd8Shaad zfs_get_pool_handle(const zfs_handle_t *zhp)
729c1cb2cd8Shaad {
730c1cb2cd8Shaad return (zhp->zpool_hdl);
731c1cb2cd8Shaad }
732c1cb2cd8Shaad
733c1cb2cd8Shaad /*
734c1cb2cd8Shaad * Given a name, determine whether or not it's a valid path
735c1cb2cd8Shaad * (starts with '/' or "./"). If so, walk the mnttab trying
736c1cb2cd8Shaad * to match the device number. If not, treat the path as an
737c1cb2cd8Shaad * fs/vol/snap name.
738c1cb2cd8Shaad */
739c1cb2cd8Shaad zfs_handle_t *
zfs_path_to_zhandle(libzfs_handle_t * hdl,char * path,zfs_type_t argtype)740c1cb2cd8Shaad zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
741c1cb2cd8Shaad {
742*ba2539a9Schs struct stat64 statbuf;
743*ba2539a9Schs struct extmnttab entry;
744c1cb2cd8Shaad int ret;
745c1cb2cd8Shaad
746c1cb2cd8Shaad if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {
747c1cb2cd8Shaad /*
748c1cb2cd8Shaad * It's not a valid path, assume it's a name of type 'argtype'.
749c1cb2cd8Shaad */
750c1cb2cd8Shaad return (zfs_open(hdl, path, argtype));
751c1cb2cd8Shaad }
752c1cb2cd8Shaad
753*ba2539a9Schs if (stat64(path, &statbuf) != 0) {
754c1cb2cd8Shaad (void) fprintf(stderr, "%s: %s\n", path, strerror(errno));
755c1cb2cd8Shaad return (NULL);
756c1cb2cd8Shaad }
757c1cb2cd8Shaad
758*ba2539a9Schs #ifdef illumos
759*ba2539a9Schs rewind(hdl->libzfs_mnttab);
760*ba2539a9Schs while ((ret = getextmntent(hdl->libzfs_mnttab, &entry, 0)) == 0) {
761*ba2539a9Schs if (makedevice(entry.mnt_major, entry.mnt_minor) ==
762*ba2539a9Schs statbuf.st_dev) {
763*ba2539a9Schs break;
764*ba2539a9Schs }
765*ba2539a9Schs }
766*ba2539a9Schs #endif /* illumos */
767*ba2539a9Schs #ifdef __FreeBSD__
768*ba2539a9Schs {
769*ba2539a9Schs struct statfs sfs;
770*ba2539a9Schs
771*ba2539a9Schs ret = statfs(path, &sfs);
772*ba2539a9Schs if (ret == 0)
773*ba2539a9Schs statfs2mnttab(&sfs, &entry);
774*ba2539a9Schs else {
775*ba2539a9Schs (void) fprintf(stderr, "%s: %s\n", path,
776*ba2539a9Schs strerror(errno));
777*ba2539a9Schs }
778*ba2539a9Schs }
779*ba2539a9Schs #endif /* __FreeBSD__ */
780*ba2539a9Schs #ifdef __NetBSD__
781*ba2539a9Schs {
782*ba2539a9Schs struct statvfs sfs;
783*ba2539a9Schs
784*ba2539a9Schs ret = statvfs(path, &sfs);
785*ba2539a9Schs if (ret == 0)
786*ba2539a9Schs statvfs2mnttab(&sfs, &entry);
787*ba2539a9Schs else {
788*ba2539a9Schs (void) fprintf(stderr, "%s: %s\n", path,
789*ba2539a9Schs strerror(errno));
790*ba2539a9Schs }
791*ba2539a9Schs }
792*ba2539a9Schs #endif /* __NetBSD__ */
793*ba2539a9Schs if (ret != 0) {
794*ba2539a9Schs return (NULL);
795*ba2539a9Schs }
796*ba2539a9Schs
797*ba2539a9Schs if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
798c1cb2cd8Shaad (void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
799c1cb2cd8Shaad path);
800c1cb2cd8Shaad return (NULL);
801c1cb2cd8Shaad }
802c1cb2cd8Shaad
803*ba2539a9Schs return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM));
804c1cb2cd8Shaad }
805c1cb2cd8Shaad
806c1cb2cd8Shaad /*
807c1cb2cd8Shaad * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from
808c1cb2cd8Shaad * an ioctl().
809c1cb2cd8Shaad */
810c1cb2cd8Shaad int
zcmd_alloc_dst_nvlist(libzfs_handle_t * hdl,zfs_cmd_t * zc,size_t len)811c1cb2cd8Shaad zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
812c1cb2cd8Shaad {
813c1cb2cd8Shaad if (len == 0)
814*ba2539a9Schs len = 16 * 1024;
815c1cb2cd8Shaad zc->zc_nvlist_dst_size = len;
816*ba2539a9Schs zc->zc_nvlist_dst =
817*ba2539a9Schs (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
818*ba2539a9Schs if (zc->zc_nvlist_dst == 0)
819c1cb2cd8Shaad return (-1);
820c1cb2cd8Shaad
821c1cb2cd8Shaad return (0);
822c1cb2cd8Shaad }
823c1cb2cd8Shaad
824c1cb2cd8Shaad /*
825c1cb2cd8Shaad * Called when an ioctl() which returns an nvlist fails with ENOMEM. This will
826c1cb2cd8Shaad * expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was
827c1cb2cd8Shaad * filled in by the kernel to indicate the actual required size.
828c1cb2cd8Shaad */
829c1cb2cd8Shaad int
zcmd_expand_dst_nvlist(libzfs_handle_t * hdl,zfs_cmd_t * zc)830c1cb2cd8Shaad zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
831c1cb2cd8Shaad {
832c1cb2cd8Shaad free((void *)(uintptr_t)zc->zc_nvlist_dst);
833*ba2539a9Schs zc->zc_nvlist_dst =
834*ba2539a9Schs (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
835*ba2539a9Schs if (zc->zc_nvlist_dst == 0)
836c1cb2cd8Shaad return (-1);
837c1cb2cd8Shaad
838c1cb2cd8Shaad return (0);
839c1cb2cd8Shaad }
840c1cb2cd8Shaad
841c1cb2cd8Shaad /*
842c1cb2cd8Shaad * Called to free the src and dst nvlists stored in the command structure.
843c1cb2cd8Shaad */
844c1cb2cd8Shaad void
zcmd_free_nvlists(zfs_cmd_t * zc)845c1cb2cd8Shaad zcmd_free_nvlists(zfs_cmd_t *zc)
846c1cb2cd8Shaad {
847c1cb2cd8Shaad free((void *)(uintptr_t)zc->zc_nvlist_conf);
848c1cb2cd8Shaad free((void *)(uintptr_t)zc->zc_nvlist_src);
849c1cb2cd8Shaad free((void *)(uintptr_t)zc->zc_nvlist_dst);
850*ba2539a9Schs zc->zc_nvlist_conf = NULL;
851*ba2539a9Schs zc->zc_nvlist_src = NULL;
852*ba2539a9Schs zc->zc_nvlist_dst = NULL;
853c1cb2cd8Shaad }
854c1cb2cd8Shaad
855c1cb2cd8Shaad static int
zcmd_write_nvlist_com(libzfs_handle_t * hdl,uint64_t * outnv,uint64_t * outlen,nvlist_t * nvl)856c1cb2cd8Shaad zcmd_write_nvlist_com(libzfs_handle_t *hdl, uint64_t *outnv, uint64_t *outlen,
857c1cb2cd8Shaad nvlist_t *nvl)
858c1cb2cd8Shaad {
859c1cb2cd8Shaad char *packed;
860c1cb2cd8Shaad size_t len;
861c1cb2cd8Shaad
862c1cb2cd8Shaad verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0);
863c1cb2cd8Shaad
864c1cb2cd8Shaad if ((packed = zfs_alloc(hdl, len)) == NULL)
865c1cb2cd8Shaad return (-1);
866c1cb2cd8Shaad
867c1cb2cd8Shaad verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
868c1cb2cd8Shaad
869c1cb2cd8Shaad *outnv = (uint64_t)(uintptr_t)packed;
870c1cb2cd8Shaad *outlen = len;
871c1cb2cd8Shaad
872c1cb2cd8Shaad return (0);
873c1cb2cd8Shaad }
874c1cb2cd8Shaad
875c1cb2cd8Shaad int
zcmd_write_conf_nvlist(libzfs_handle_t * hdl,zfs_cmd_t * zc,nvlist_t * nvl)876c1cb2cd8Shaad zcmd_write_conf_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)
877c1cb2cd8Shaad {
878c1cb2cd8Shaad return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_conf,
879c1cb2cd8Shaad &zc->zc_nvlist_conf_size, nvl));
880c1cb2cd8Shaad }
881c1cb2cd8Shaad
882c1cb2cd8Shaad int
zcmd_write_src_nvlist(libzfs_handle_t * hdl,zfs_cmd_t * zc,nvlist_t * nvl)883c1cb2cd8Shaad zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)
884c1cb2cd8Shaad {
885c1cb2cd8Shaad return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_src,
886c1cb2cd8Shaad &zc->zc_nvlist_src_size, nvl));
887c1cb2cd8Shaad }
888c1cb2cd8Shaad
889c1cb2cd8Shaad /*
890c1cb2cd8Shaad * Unpacks an nvlist from the ZFS ioctl command structure.
891c1cb2cd8Shaad */
892c1cb2cd8Shaad int
zcmd_read_dst_nvlist(libzfs_handle_t * hdl,zfs_cmd_t * zc,nvlist_t ** nvlp)893c1cb2cd8Shaad zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
894c1cb2cd8Shaad {
895c1cb2cd8Shaad if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst,
896c1cb2cd8Shaad zc->zc_nvlist_dst_size, nvlp, 0) != 0)
897c1cb2cd8Shaad return (no_memory(hdl));
898c1cb2cd8Shaad
899c1cb2cd8Shaad return (0);
900c1cb2cd8Shaad }
901c1cb2cd8Shaad
902c1cb2cd8Shaad int
zfs_ioctl(libzfs_handle_t * hdl,int request,zfs_cmd_t * zc)903c1cb2cd8Shaad zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
904c1cb2cd8Shaad {
905*ba2539a9Schs return (ioctl(hdl->libzfs_fd, request, zc));
906c1cb2cd8Shaad }
907c1cb2cd8Shaad
908c1cb2cd8Shaad /*
909c1cb2cd8Shaad * ================================================================
910c1cb2cd8Shaad * API shared by zfs and zpool property management
911c1cb2cd8Shaad * ================================================================
912c1cb2cd8Shaad */
913c1cb2cd8Shaad
914c1cb2cd8Shaad static void
zprop_print_headers(zprop_get_cbdata_t * cbp,zfs_type_t type)915c1cb2cd8Shaad zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
916c1cb2cd8Shaad {
917c1cb2cd8Shaad zprop_list_t *pl = cbp->cb_proplist;
918c1cb2cd8Shaad int i;
919c1cb2cd8Shaad char *title;
920c1cb2cd8Shaad size_t len;
921c1cb2cd8Shaad
922c1cb2cd8Shaad cbp->cb_first = B_FALSE;
923c1cb2cd8Shaad if (cbp->cb_scripted)
924c1cb2cd8Shaad return;
925c1cb2cd8Shaad
926c1cb2cd8Shaad /*
927c1cb2cd8Shaad * Start with the length of the column headers.
928c1cb2cd8Shaad */
929c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN, "NAME"));
930c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,
931c1cb2cd8Shaad "PROPERTY"));
932c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
933c1cb2cd8Shaad "VALUE"));
934a252d550Shaad cbp->cb_colwidths[GET_COL_RECVD] = strlen(dgettext(TEXT_DOMAIN,
935a252d550Shaad "RECEIVED"));
936c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
937c1cb2cd8Shaad "SOURCE"));
938c1cb2cd8Shaad
939a252d550Shaad /* first property is always NAME */
940a252d550Shaad assert(cbp->cb_proplist->pl_prop ==
941a252d550Shaad ((type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME : ZFS_PROP_NAME));
942a252d550Shaad
943c1cb2cd8Shaad /*
944c1cb2cd8Shaad * Go through and calculate the widths for each column. For the
945c1cb2cd8Shaad * 'source' column, we kludge it up by taking the worst-case scenario of
946c1cb2cd8Shaad * inheriting from the longest name. This is acceptable because in the
947c1cb2cd8Shaad * majority of cases 'SOURCE' is the last column displayed, and we don't
948c1cb2cd8Shaad * use the width anyway. Note that the 'VALUE' column can be oversized,
949a252d550Shaad * if the name of the property is much longer than any values we find.
950c1cb2cd8Shaad */
951c1cb2cd8Shaad for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
952c1cb2cd8Shaad /*
953c1cb2cd8Shaad * 'PROPERTY' column
954c1cb2cd8Shaad */
955c1cb2cd8Shaad if (pl->pl_prop != ZPROP_INVAL) {
956c1cb2cd8Shaad const char *propname = (type == ZFS_TYPE_POOL) ?
957c1cb2cd8Shaad zpool_prop_to_name(pl->pl_prop) :
958c1cb2cd8Shaad zfs_prop_to_name(pl->pl_prop);
959c1cb2cd8Shaad
960c1cb2cd8Shaad len = strlen(propname);
961c1cb2cd8Shaad if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
962c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_PROPERTY] = len;
963c1cb2cd8Shaad } else {
964c1cb2cd8Shaad len = strlen(pl->pl_user_prop);
965c1cb2cd8Shaad if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
966c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_PROPERTY] = len;
967c1cb2cd8Shaad }
968c1cb2cd8Shaad
969c1cb2cd8Shaad /*
970a252d550Shaad * 'VALUE' column. The first property is always the 'name'
971a252d550Shaad * property that was tacked on either by /sbin/zfs's
972a252d550Shaad * zfs_do_get() or when calling zprop_expand_list(), so we
973a252d550Shaad * ignore its width. If the user specified the name property
974a252d550Shaad * to display, then it will be later in the list in any case.
975c1cb2cd8Shaad */
976a252d550Shaad if (pl != cbp->cb_proplist &&
977c1cb2cd8Shaad pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
978c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
979c1cb2cd8Shaad
980a252d550Shaad /* 'RECEIVED' column. */
981a252d550Shaad if (pl != cbp->cb_proplist &&
982a252d550Shaad pl->pl_recvd_width > cbp->cb_colwidths[GET_COL_RECVD])
983a252d550Shaad cbp->cb_colwidths[GET_COL_RECVD] = pl->pl_recvd_width;
984a252d550Shaad
985c1cb2cd8Shaad /*
986c1cb2cd8Shaad * 'NAME' and 'SOURCE' columns
987c1cb2cd8Shaad */
988c1cb2cd8Shaad if (pl->pl_prop == (type == ZFS_TYPE_POOL ? ZPOOL_PROP_NAME :
989c1cb2cd8Shaad ZFS_PROP_NAME) &&
990c1cb2cd8Shaad pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
991c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
992c1cb2cd8Shaad cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width +
993c1cb2cd8Shaad strlen(dgettext(TEXT_DOMAIN, "inherited from"));
994c1cb2cd8Shaad }
995c1cb2cd8Shaad }
996c1cb2cd8Shaad
997c1cb2cd8Shaad /*
998c1cb2cd8Shaad * Now go through and print the headers.
999c1cb2cd8Shaad */
1000a252d550Shaad for (i = 0; i < ZFS_GET_NCOLS; i++) {
1001c1cb2cd8Shaad switch (cbp->cb_columns[i]) {
1002c1cb2cd8Shaad case GET_COL_NAME:
1003c1cb2cd8Shaad title = dgettext(TEXT_DOMAIN, "NAME");
1004c1cb2cd8Shaad break;
1005c1cb2cd8Shaad case GET_COL_PROPERTY:
1006c1cb2cd8Shaad title = dgettext(TEXT_DOMAIN, "PROPERTY");
1007c1cb2cd8Shaad break;
1008c1cb2cd8Shaad case GET_COL_VALUE:
1009c1cb2cd8Shaad title = dgettext(TEXT_DOMAIN, "VALUE");
1010c1cb2cd8Shaad break;
1011a252d550Shaad case GET_COL_RECVD:
1012a252d550Shaad title = dgettext(TEXT_DOMAIN, "RECEIVED");
1013a252d550Shaad break;
1014c1cb2cd8Shaad case GET_COL_SOURCE:
1015c1cb2cd8Shaad title = dgettext(TEXT_DOMAIN, "SOURCE");
1016c1cb2cd8Shaad break;
1017c1cb2cd8Shaad default:
1018c1cb2cd8Shaad title = NULL;
1019c1cb2cd8Shaad }
1020c1cb2cd8Shaad
1021c1cb2cd8Shaad if (title != NULL) {
1022a252d550Shaad if (i == (ZFS_GET_NCOLS - 1) ||
1023a252d550Shaad cbp->cb_columns[i + 1] == GET_COL_NONE)
1024c1cb2cd8Shaad (void) printf("%s", title);
1025c1cb2cd8Shaad else
1026c1cb2cd8Shaad (void) printf("%-*s ",
1027c1cb2cd8Shaad cbp->cb_colwidths[cbp->cb_columns[i]],
1028c1cb2cd8Shaad title);
1029c1cb2cd8Shaad }
1030c1cb2cd8Shaad }
1031c1cb2cd8Shaad (void) printf("\n");
1032c1cb2cd8Shaad }
1033c1cb2cd8Shaad
1034c1cb2cd8Shaad /*
1035c1cb2cd8Shaad * Display a single line of output, according to the settings in the callback
1036c1cb2cd8Shaad * structure.
1037c1cb2cd8Shaad */
1038c1cb2cd8Shaad void
zprop_print_one_property(const char * name,zprop_get_cbdata_t * cbp,const char * propname,const char * value,zprop_source_t sourcetype,const char * source,const char * recvd_value)1039c1cb2cd8Shaad zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
1040c1cb2cd8Shaad const char *propname, const char *value, zprop_source_t sourcetype,
1041a252d550Shaad const char *source, const char *recvd_value)
1042c1cb2cd8Shaad {
1043c1cb2cd8Shaad int i;
1044*ba2539a9Schs const char *str = NULL;
1045c1cb2cd8Shaad char buf[128];
1046c1cb2cd8Shaad
1047c1cb2cd8Shaad /*
1048c1cb2cd8Shaad * Ignore those source types that the user has chosen to ignore.
1049c1cb2cd8Shaad */
1050c1cb2cd8Shaad if ((sourcetype & cbp->cb_sources) == 0)
1051c1cb2cd8Shaad return;
1052c1cb2cd8Shaad
1053c1cb2cd8Shaad if (cbp->cb_first)
1054c1cb2cd8Shaad zprop_print_headers(cbp, cbp->cb_type);
1055c1cb2cd8Shaad
1056a252d550Shaad for (i = 0; i < ZFS_GET_NCOLS; i++) {
1057c1cb2cd8Shaad switch (cbp->cb_columns[i]) {
1058c1cb2cd8Shaad case GET_COL_NAME:
1059c1cb2cd8Shaad str = name;
1060c1cb2cd8Shaad break;
1061c1cb2cd8Shaad
1062c1cb2cd8Shaad case GET_COL_PROPERTY:
1063c1cb2cd8Shaad str = propname;
1064c1cb2cd8Shaad break;
1065c1cb2cd8Shaad
1066c1cb2cd8Shaad case GET_COL_VALUE:
1067c1cb2cd8Shaad str = value;
1068c1cb2cd8Shaad break;
1069c1cb2cd8Shaad
1070c1cb2cd8Shaad case GET_COL_SOURCE:
1071c1cb2cd8Shaad switch (sourcetype) {
1072c1cb2cd8Shaad case ZPROP_SRC_NONE:
1073c1cb2cd8Shaad str = "-";
1074c1cb2cd8Shaad break;
1075c1cb2cd8Shaad
1076c1cb2cd8Shaad case ZPROP_SRC_DEFAULT:
1077c1cb2cd8Shaad str = "default";
1078c1cb2cd8Shaad break;
1079c1cb2cd8Shaad
1080c1cb2cd8Shaad case ZPROP_SRC_LOCAL:
1081c1cb2cd8Shaad str = "local";
1082c1cb2cd8Shaad break;
1083c1cb2cd8Shaad
1084c1cb2cd8Shaad case ZPROP_SRC_TEMPORARY:
1085c1cb2cd8Shaad str = "temporary";
1086c1cb2cd8Shaad break;
1087c1cb2cd8Shaad
1088c1cb2cd8Shaad case ZPROP_SRC_INHERITED:
1089c1cb2cd8Shaad (void) snprintf(buf, sizeof (buf),
1090c1cb2cd8Shaad "inherited from %s", source);
1091c1cb2cd8Shaad str = buf;
1092c1cb2cd8Shaad break;
1093a252d550Shaad case ZPROP_SRC_RECEIVED:
1094a252d550Shaad str = "received";
1095a252d550Shaad break;
1096*ba2539a9Schs
1097*ba2539a9Schs default:
1098*ba2539a9Schs str = NULL;
1099*ba2539a9Schs assert(!"unhandled zprop_source_t");
1100c1cb2cd8Shaad }
1101c1cb2cd8Shaad break;
1102c1cb2cd8Shaad
1103a252d550Shaad case GET_COL_RECVD:
1104a252d550Shaad str = (recvd_value == NULL ? "-" : recvd_value);
1105a252d550Shaad break;
1106a252d550Shaad
1107c1cb2cd8Shaad default:
1108c1cb2cd8Shaad continue;
1109c1cb2cd8Shaad }
1110c1cb2cd8Shaad
1111a252d550Shaad if (cbp->cb_columns[i + 1] == GET_COL_NONE)
1112c1cb2cd8Shaad (void) printf("%s", str);
1113c1cb2cd8Shaad else if (cbp->cb_scripted)
1114c1cb2cd8Shaad (void) printf("%s\t", str);
1115c1cb2cd8Shaad else
1116c1cb2cd8Shaad (void) printf("%-*s ",
1117c1cb2cd8Shaad cbp->cb_colwidths[cbp->cb_columns[i]],
1118c1cb2cd8Shaad str);
1119c1cb2cd8Shaad }
1120c1cb2cd8Shaad
1121c1cb2cd8Shaad (void) printf("\n");
1122c1cb2cd8Shaad }
1123c1cb2cd8Shaad
1124c1cb2cd8Shaad /*
1125c1cb2cd8Shaad * Given a numeric suffix, convert the value into a number of bits that the
1126c1cb2cd8Shaad * resulting value must be shifted.
1127c1cb2cd8Shaad */
1128c1cb2cd8Shaad static int
str2shift(libzfs_handle_t * hdl,const char * buf)1129c1cb2cd8Shaad str2shift(libzfs_handle_t *hdl, const char *buf)
1130c1cb2cd8Shaad {
1131c1cb2cd8Shaad const char *ends = "BKMGTPEZ";
1132c1cb2cd8Shaad int i;
1133c1cb2cd8Shaad
1134c1cb2cd8Shaad if (buf[0] == '\0')
1135c1cb2cd8Shaad return (0);
1136c1cb2cd8Shaad for (i = 0; i < strlen(ends); i++) {
1137c1cb2cd8Shaad if (toupper(buf[0]) == ends[i])
1138c1cb2cd8Shaad break;
1139c1cb2cd8Shaad }
1140c1cb2cd8Shaad if (i == strlen(ends)) {
1141c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1142c1cb2cd8Shaad "invalid numeric suffix '%s'"), buf);
1143c1cb2cd8Shaad return (-1);
1144c1cb2cd8Shaad }
1145c1cb2cd8Shaad
1146c1cb2cd8Shaad /*
1147c1cb2cd8Shaad * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't
1148c1cb2cd8Shaad * allow 'BB' - that's just weird.
1149c1cb2cd8Shaad */
1150c1cb2cd8Shaad if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
1151c1cb2cd8Shaad toupper(buf[0]) != 'B'))
1152c1cb2cd8Shaad return (10*i);
1153c1cb2cd8Shaad
1154c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1155c1cb2cd8Shaad "invalid numeric suffix '%s'"), buf);
1156c1cb2cd8Shaad return (-1);
1157c1cb2cd8Shaad }
1158c1cb2cd8Shaad
1159c1cb2cd8Shaad /*
1160c1cb2cd8Shaad * Convert a string of the form '100G' into a real number. Used when setting
1161c1cb2cd8Shaad * properties or creating a volume. 'buf' is used to place an extended error
1162c1cb2cd8Shaad * message for the caller to use.
1163c1cb2cd8Shaad */
1164c1cb2cd8Shaad int
zfs_nicestrtonum(libzfs_handle_t * hdl,const char * value,uint64_t * num)1165c1cb2cd8Shaad zfs_nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
1166c1cb2cd8Shaad {
1167c1cb2cd8Shaad char *end;
1168c1cb2cd8Shaad int shift;
1169c1cb2cd8Shaad
1170c1cb2cd8Shaad *num = 0;
1171c1cb2cd8Shaad
1172c1cb2cd8Shaad /* Check to see if this looks like a number. */
1173c1cb2cd8Shaad if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
1174c1cb2cd8Shaad if (hdl)
1175c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1176c1cb2cd8Shaad "bad numeric value '%s'"), value);
1177c1cb2cd8Shaad return (-1);
1178c1cb2cd8Shaad }
1179c1cb2cd8Shaad
1180a252d550Shaad /* Rely on strtoull() to process the numeric portion. */
1181c1cb2cd8Shaad errno = 0;
1182a252d550Shaad *num = strtoull(value, &end, 10);
1183c1cb2cd8Shaad
1184c1cb2cd8Shaad /*
1185c1cb2cd8Shaad * Check for ERANGE, which indicates that the value is too large to fit
1186c1cb2cd8Shaad * in a 64-bit value.
1187c1cb2cd8Shaad */
1188c1cb2cd8Shaad if (errno == ERANGE) {
1189c1cb2cd8Shaad if (hdl)
1190c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1191c1cb2cd8Shaad "numeric value is too large"));
1192c1cb2cd8Shaad return (-1);
1193c1cb2cd8Shaad }
1194c1cb2cd8Shaad
1195c1cb2cd8Shaad /*
1196c1cb2cd8Shaad * If we have a decimal value, then do the computation with floating
1197c1cb2cd8Shaad * point arithmetic. Otherwise, use standard arithmetic.
1198c1cb2cd8Shaad */
1199c1cb2cd8Shaad if (*end == '.') {
1200c1cb2cd8Shaad double fval = strtod(value, &end);
1201c1cb2cd8Shaad
1202c1cb2cd8Shaad if ((shift = str2shift(hdl, end)) == -1)
1203c1cb2cd8Shaad return (-1);
1204c1cb2cd8Shaad
1205c1cb2cd8Shaad fval *= pow(2, shift);
1206c1cb2cd8Shaad
1207c1cb2cd8Shaad if (fval > UINT64_MAX) {
1208c1cb2cd8Shaad if (hdl)
1209c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1210c1cb2cd8Shaad "numeric value is too large"));
1211c1cb2cd8Shaad return (-1);
1212c1cb2cd8Shaad }
1213c1cb2cd8Shaad
1214c1cb2cd8Shaad *num = (uint64_t)fval;
1215c1cb2cd8Shaad } else {
1216c1cb2cd8Shaad if ((shift = str2shift(hdl, end)) == -1)
1217c1cb2cd8Shaad return (-1);
1218c1cb2cd8Shaad
1219c1cb2cd8Shaad /* Check for overflow */
1220c1cb2cd8Shaad if (shift >= 64 || (*num << shift) >> shift != *num) {
1221c1cb2cd8Shaad if (hdl)
1222c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1223c1cb2cd8Shaad "numeric value is too large"));
1224c1cb2cd8Shaad return (-1);
1225c1cb2cd8Shaad }
1226c1cb2cd8Shaad
1227c1cb2cd8Shaad *num <<= shift;
1228c1cb2cd8Shaad }
1229c1cb2cd8Shaad
1230c1cb2cd8Shaad return (0);
1231c1cb2cd8Shaad }
1232c1cb2cd8Shaad
1233c1cb2cd8Shaad /*
1234c1cb2cd8Shaad * Given a propname=value nvpair to set, parse any numeric properties
1235c1cb2cd8Shaad * (index, boolean, etc) if they are specified as strings and add the
1236c1cb2cd8Shaad * resulting nvpair to the returned nvlist.
1237c1cb2cd8Shaad *
1238c1cb2cd8Shaad * At the DSL layer, all properties are either 64-bit numbers or strings.
1239c1cb2cd8Shaad * We want the user to be able to ignore this fact and specify properties
1240c1cb2cd8Shaad * as native values (numbers, for example) or as strings (to simplify
1241c1cb2cd8Shaad * command line utilities). This also handles converting index types
1242c1cb2cd8Shaad * (compression, checksum, etc) from strings to their on-disk index.
1243c1cb2cd8Shaad */
1244c1cb2cd8Shaad int
zprop_parse_value(libzfs_handle_t * hdl,nvpair_t * elem,int prop,zfs_type_t type,nvlist_t * ret,char ** svalp,uint64_t * ivalp,const char * errbuf)1245c1cb2cd8Shaad zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,
1246c1cb2cd8Shaad zfs_type_t type, nvlist_t *ret, char **svalp, uint64_t *ivalp,
1247c1cb2cd8Shaad const char *errbuf)
1248c1cb2cd8Shaad {
1249c1cb2cd8Shaad data_type_t datatype = nvpair_type(elem);
1250c1cb2cd8Shaad zprop_type_t proptype;
1251c1cb2cd8Shaad const char *propname;
1252c1cb2cd8Shaad char *value;
1253c1cb2cd8Shaad boolean_t isnone = B_FALSE;
1254c1cb2cd8Shaad
1255c1cb2cd8Shaad if (type == ZFS_TYPE_POOL) {
1256c1cb2cd8Shaad proptype = zpool_prop_get_type(prop);
1257c1cb2cd8Shaad propname = zpool_prop_to_name(prop);
1258c1cb2cd8Shaad } else {
1259c1cb2cd8Shaad proptype = zfs_prop_get_type(prop);
1260c1cb2cd8Shaad propname = zfs_prop_to_name(prop);
1261c1cb2cd8Shaad }
1262c1cb2cd8Shaad
1263c1cb2cd8Shaad /*
1264c1cb2cd8Shaad * Convert any properties to the internal DSL value types.
1265c1cb2cd8Shaad */
1266c1cb2cd8Shaad *svalp = NULL;
1267c1cb2cd8Shaad *ivalp = 0;
1268c1cb2cd8Shaad
1269c1cb2cd8Shaad switch (proptype) {
1270c1cb2cd8Shaad case PROP_TYPE_STRING:
1271c1cb2cd8Shaad if (datatype != DATA_TYPE_STRING) {
1272c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1273c1cb2cd8Shaad "'%s' must be a string"), nvpair_name(elem));
1274c1cb2cd8Shaad goto error;
1275c1cb2cd8Shaad }
1276c1cb2cd8Shaad (void) nvpair_value_string(elem, svalp);
1277c1cb2cd8Shaad if (strlen(*svalp) >= ZFS_MAXPROPLEN) {
1278c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1279c1cb2cd8Shaad "'%s' is too long"), nvpair_name(elem));
1280c1cb2cd8Shaad goto error;
1281c1cb2cd8Shaad }
1282c1cb2cd8Shaad break;
1283c1cb2cd8Shaad
1284c1cb2cd8Shaad case PROP_TYPE_NUMBER:
1285c1cb2cd8Shaad if (datatype == DATA_TYPE_STRING) {
1286c1cb2cd8Shaad (void) nvpair_value_string(elem, &value);
1287c1cb2cd8Shaad if (strcmp(value, "none") == 0) {
1288c1cb2cd8Shaad isnone = B_TRUE;
1289c1cb2cd8Shaad } else if (zfs_nicestrtonum(hdl, value, ivalp)
1290c1cb2cd8Shaad != 0) {
1291c1cb2cd8Shaad goto error;
1292c1cb2cd8Shaad }
1293c1cb2cd8Shaad } else if (datatype == DATA_TYPE_UINT64) {
1294c1cb2cd8Shaad (void) nvpair_value_uint64(elem, ivalp);
1295c1cb2cd8Shaad } else {
1296c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1297c1cb2cd8Shaad "'%s' must be a number"), nvpair_name(elem));
1298c1cb2cd8Shaad goto error;
1299c1cb2cd8Shaad }
1300c1cb2cd8Shaad
1301c1cb2cd8Shaad /*
1302c1cb2cd8Shaad * Quota special: force 'none' and don't allow 0.
1303c1cb2cd8Shaad */
1304c1cb2cd8Shaad if ((type & ZFS_TYPE_DATASET) && *ivalp == 0 && !isnone &&
1305c1cb2cd8Shaad (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_REFQUOTA)) {
1306c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1307c1cb2cd8Shaad "use 'none' to disable quota/refquota"));
1308c1cb2cd8Shaad goto error;
1309c1cb2cd8Shaad }
1310*ba2539a9Schs
1311*ba2539a9Schs /*
1312*ba2539a9Schs * Special handling for "*_limit=none". In this case it's not
1313*ba2539a9Schs * 0 but UINT64_MAX.
1314*ba2539a9Schs */
1315*ba2539a9Schs if ((type & ZFS_TYPE_DATASET) && isnone &&
1316*ba2539a9Schs (prop == ZFS_PROP_FILESYSTEM_LIMIT ||
1317*ba2539a9Schs prop == ZFS_PROP_SNAPSHOT_LIMIT)) {
1318*ba2539a9Schs *ivalp = UINT64_MAX;
1319*ba2539a9Schs }
1320c1cb2cd8Shaad break;
1321c1cb2cd8Shaad
1322c1cb2cd8Shaad case PROP_TYPE_INDEX:
1323c1cb2cd8Shaad if (datatype != DATA_TYPE_STRING) {
1324c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1325c1cb2cd8Shaad "'%s' must be a string"), nvpair_name(elem));
1326c1cb2cd8Shaad goto error;
1327c1cb2cd8Shaad }
1328c1cb2cd8Shaad
1329c1cb2cd8Shaad (void) nvpair_value_string(elem, &value);
1330c1cb2cd8Shaad
1331c1cb2cd8Shaad if (zprop_string_to_index(prop, value, ivalp, type) != 0) {
1332c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1333c1cb2cd8Shaad "'%s' must be one of '%s'"), propname,
1334c1cb2cd8Shaad zprop_values(prop, type));
1335c1cb2cd8Shaad goto error;
1336c1cb2cd8Shaad }
1337c1cb2cd8Shaad break;
1338c1cb2cd8Shaad
1339c1cb2cd8Shaad default:
1340c1cb2cd8Shaad abort();
1341c1cb2cd8Shaad }
1342c1cb2cd8Shaad
1343c1cb2cd8Shaad /*
1344c1cb2cd8Shaad * Add the result to our return set of properties.
1345c1cb2cd8Shaad */
1346c1cb2cd8Shaad if (*svalp != NULL) {
1347c1cb2cd8Shaad if (nvlist_add_string(ret, propname, *svalp) != 0) {
1348c1cb2cd8Shaad (void) no_memory(hdl);
1349c1cb2cd8Shaad return (-1);
1350c1cb2cd8Shaad }
1351c1cb2cd8Shaad } else {
1352c1cb2cd8Shaad if (nvlist_add_uint64(ret, propname, *ivalp) != 0) {
1353c1cb2cd8Shaad (void) no_memory(hdl);
1354c1cb2cd8Shaad return (-1);
1355c1cb2cd8Shaad }
1356c1cb2cd8Shaad }
1357c1cb2cd8Shaad
1358c1cb2cd8Shaad return (0);
1359c1cb2cd8Shaad error:
1360c1cb2cd8Shaad (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1361c1cb2cd8Shaad return (-1);
1362c1cb2cd8Shaad }
1363c1cb2cd8Shaad
1364c1cb2cd8Shaad static int
addlist(libzfs_handle_t * hdl,char * propname,zprop_list_t ** listp,zfs_type_t type)1365c1cb2cd8Shaad addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp,
1366c1cb2cd8Shaad zfs_type_t type)
1367c1cb2cd8Shaad {
1368c1cb2cd8Shaad int prop;
1369c1cb2cd8Shaad zprop_list_t *entry;
1370c1cb2cd8Shaad
1371c1cb2cd8Shaad prop = zprop_name_to_prop(propname, type);
1372c1cb2cd8Shaad
1373c1cb2cd8Shaad if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type))
1374c1cb2cd8Shaad prop = ZPROP_INVAL;
1375c1cb2cd8Shaad
1376c1cb2cd8Shaad /*
1377c1cb2cd8Shaad * When no property table entry can be found, return failure if
1378c1cb2cd8Shaad * this is a pool property or if this isn't a user-defined
1379c1cb2cd8Shaad * dataset property,
1380c1cb2cd8Shaad */
1381*ba2539a9Schs if (prop == ZPROP_INVAL && ((type == ZFS_TYPE_POOL &&
1382*ba2539a9Schs !zpool_prop_feature(propname) &&
1383*ba2539a9Schs !zpool_prop_unsupported(propname)) ||
1384*ba2539a9Schs (type == ZFS_TYPE_DATASET && !zfs_prop_user(propname) &&
1385*ba2539a9Schs !zfs_prop_userquota(propname) && !zfs_prop_written(propname)))) {
1386c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1387c1cb2cd8Shaad "invalid property '%s'"), propname);
1388c1cb2cd8Shaad return (zfs_error(hdl, EZFS_BADPROP,
1389c1cb2cd8Shaad dgettext(TEXT_DOMAIN, "bad property list")));
1390c1cb2cd8Shaad }
1391c1cb2cd8Shaad
1392c1cb2cd8Shaad if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
1393c1cb2cd8Shaad return (-1);
1394c1cb2cd8Shaad
1395c1cb2cd8Shaad entry->pl_prop = prop;
1396c1cb2cd8Shaad if (prop == ZPROP_INVAL) {
1397*ba2539a9Schs if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) ==
1398*ba2539a9Schs NULL) {
1399c1cb2cd8Shaad free(entry);
1400c1cb2cd8Shaad return (-1);
1401c1cb2cd8Shaad }
1402c1cb2cd8Shaad entry->pl_width = strlen(propname);
1403c1cb2cd8Shaad } else {
1404c1cb2cd8Shaad entry->pl_width = zprop_width(prop, &entry->pl_fixed,
1405c1cb2cd8Shaad type);
1406c1cb2cd8Shaad }
1407c1cb2cd8Shaad
1408c1cb2cd8Shaad *listp = entry;
1409c1cb2cd8Shaad
1410c1cb2cd8Shaad return (0);
1411c1cb2cd8Shaad }
1412c1cb2cd8Shaad
1413c1cb2cd8Shaad /*
1414c1cb2cd8Shaad * Given a comma-separated list of properties, construct a property list
1415c1cb2cd8Shaad * containing both user-defined and native properties. This function will
1416c1cb2cd8Shaad * return a NULL list if 'all' is specified, which can later be expanded
1417c1cb2cd8Shaad * by zprop_expand_list().
1418c1cb2cd8Shaad */
1419c1cb2cd8Shaad int
zprop_get_list(libzfs_handle_t * hdl,char * props,zprop_list_t ** listp,zfs_type_t type)1420c1cb2cd8Shaad zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp,
1421c1cb2cd8Shaad zfs_type_t type)
1422c1cb2cd8Shaad {
1423c1cb2cd8Shaad *listp = NULL;
1424c1cb2cd8Shaad
1425c1cb2cd8Shaad /*
1426c1cb2cd8Shaad * If 'all' is specified, return a NULL list.
1427c1cb2cd8Shaad */
1428c1cb2cd8Shaad if (strcmp(props, "all") == 0)
1429c1cb2cd8Shaad return (0);
1430c1cb2cd8Shaad
1431c1cb2cd8Shaad /*
1432c1cb2cd8Shaad * If no props were specified, return an error.
1433c1cb2cd8Shaad */
1434c1cb2cd8Shaad if (props[0] == '\0') {
1435c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1436c1cb2cd8Shaad "no properties specified"));
1437c1cb2cd8Shaad return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
1438c1cb2cd8Shaad "bad property list")));
1439c1cb2cd8Shaad }
1440c1cb2cd8Shaad
1441c1cb2cd8Shaad /*
1442c1cb2cd8Shaad * It would be nice to use getsubopt() here, but the inclusion of column
1443c1cb2cd8Shaad * aliases makes this more effort than it's worth.
1444c1cb2cd8Shaad */
1445c1cb2cd8Shaad while (*props != '\0') {
1446c1cb2cd8Shaad size_t len;
1447c1cb2cd8Shaad char *p;
1448c1cb2cd8Shaad char c;
1449c1cb2cd8Shaad
1450c1cb2cd8Shaad if ((p = strchr(props, ',')) == NULL) {
1451c1cb2cd8Shaad len = strlen(props);
1452c1cb2cd8Shaad p = props + len;
1453c1cb2cd8Shaad } else {
1454c1cb2cd8Shaad len = p - props;
1455c1cb2cd8Shaad }
1456c1cb2cd8Shaad
1457c1cb2cd8Shaad /*
1458c1cb2cd8Shaad * Check for empty options.
1459c1cb2cd8Shaad */
1460c1cb2cd8Shaad if (len == 0) {
1461c1cb2cd8Shaad zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1462c1cb2cd8Shaad "empty property name"));
1463c1cb2cd8Shaad return (zfs_error(hdl, EZFS_BADPROP,
1464c1cb2cd8Shaad dgettext(TEXT_DOMAIN, "bad property list")));
1465c1cb2cd8Shaad }
1466c1cb2cd8Shaad
1467c1cb2cd8Shaad /*
1468c1cb2cd8Shaad * Check all regular property names.
1469c1cb2cd8Shaad */
1470c1cb2cd8Shaad c = props[len];
1471c1cb2cd8Shaad props[len] = '\0';
1472c1cb2cd8Shaad
1473c1cb2cd8Shaad if (strcmp(props, "space") == 0) {
1474c1cb2cd8Shaad static char *spaceprops[] = {
1475c1cb2cd8Shaad "name", "avail", "used", "usedbysnapshots",
1476c1cb2cd8Shaad "usedbydataset", "usedbyrefreservation",
1477c1cb2cd8Shaad "usedbychildren", NULL
1478c1cb2cd8Shaad };
1479c1cb2cd8Shaad int i;
1480c1cb2cd8Shaad
1481c1cb2cd8Shaad for (i = 0; spaceprops[i]; i++) {
1482c1cb2cd8Shaad if (addlist(hdl, spaceprops[i], listp, type))
1483c1cb2cd8Shaad return (-1);
1484c1cb2cd8Shaad listp = &(*listp)->pl_next;
1485c1cb2cd8Shaad }
1486c1cb2cd8Shaad } else {
1487c1cb2cd8Shaad if (addlist(hdl, props, listp, type))
1488c1cb2cd8Shaad return (-1);
1489c1cb2cd8Shaad listp = &(*listp)->pl_next;
1490c1cb2cd8Shaad }
1491c1cb2cd8Shaad
1492c1cb2cd8Shaad props = p;
1493c1cb2cd8Shaad if (c == ',')
1494c1cb2cd8Shaad props++;
1495c1cb2cd8Shaad }
1496c1cb2cd8Shaad
1497c1cb2cd8Shaad return (0);
1498c1cb2cd8Shaad }
1499c1cb2cd8Shaad
1500c1cb2cd8Shaad void
zprop_free_list(zprop_list_t * pl)1501c1cb2cd8Shaad zprop_free_list(zprop_list_t *pl)
1502c1cb2cd8Shaad {
1503c1cb2cd8Shaad zprop_list_t *next;
1504c1cb2cd8Shaad
1505c1cb2cd8Shaad while (pl != NULL) {
1506c1cb2cd8Shaad next = pl->pl_next;
1507c1cb2cd8Shaad free(pl->pl_user_prop);
1508c1cb2cd8Shaad free(pl);
1509c1cb2cd8Shaad pl = next;
1510c1cb2cd8Shaad }
1511c1cb2cd8Shaad }
1512c1cb2cd8Shaad
1513c1cb2cd8Shaad typedef struct expand_data {
1514c1cb2cd8Shaad zprop_list_t **last;
1515c1cb2cd8Shaad libzfs_handle_t *hdl;
1516c1cb2cd8Shaad zfs_type_t type;
1517c1cb2cd8Shaad } expand_data_t;
1518c1cb2cd8Shaad
1519c1cb2cd8Shaad int
zprop_expand_list_cb(int prop,void * cb)1520c1cb2cd8Shaad zprop_expand_list_cb(int prop, void *cb)
1521c1cb2cd8Shaad {
1522c1cb2cd8Shaad zprop_list_t *entry;
1523c1cb2cd8Shaad expand_data_t *edp = cb;
1524c1cb2cd8Shaad
1525c1cb2cd8Shaad if ((entry = zfs_alloc(edp->hdl, sizeof (zprop_list_t))) == NULL)
1526c1cb2cd8Shaad return (ZPROP_INVAL);
1527c1cb2cd8Shaad
1528c1cb2cd8Shaad entry->pl_prop = prop;
1529c1cb2cd8Shaad entry->pl_width = zprop_width(prop, &entry->pl_fixed, edp->type);
1530c1cb2cd8Shaad entry->pl_all = B_TRUE;
1531c1cb2cd8Shaad
1532c1cb2cd8Shaad *(edp->last) = entry;
1533c1cb2cd8Shaad edp->last = &entry->pl_next;
1534c1cb2cd8Shaad
1535c1cb2cd8Shaad return (ZPROP_CONT);
1536c1cb2cd8Shaad }
1537c1cb2cd8Shaad
1538c1cb2cd8Shaad int
zprop_expand_list(libzfs_handle_t * hdl,zprop_list_t ** plp,zfs_type_t type)1539c1cb2cd8Shaad zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, zfs_type_t type)
1540c1cb2cd8Shaad {
1541c1cb2cd8Shaad zprop_list_t *entry;
1542c1cb2cd8Shaad zprop_list_t **last;
1543c1cb2cd8Shaad expand_data_t exp;
1544c1cb2cd8Shaad
1545c1cb2cd8Shaad if (*plp == NULL) {
1546c1cb2cd8Shaad /*
1547c1cb2cd8Shaad * If this is the very first time we've been called for an 'all'
1548c1cb2cd8Shaad * specification, expand the list to include all native
1549c1cb2cd8Shaad * properties.
1550c1cb2cd8Shaad */
1551c1cb2cd8Shaad last = plp;
1552c1cb2cd8Shaad
1553c1cb2cd8Shaad exp.last = last;
1554c1cb2cd8Shaad exp.hdl = hdl;
1555c1cb2cd8Shaad exp.type = type;
1556c1cb2cd8Shaad
1557c1cb2cd8Shaad if (zprop_iter_common(zprop_expand_list_cb, &exp, B_FALSE,
1558c1cb2cd8Shaad B_FALSE, type) == ZPROP_INVAL)
1559c1cb2cd8Shaad return (-1);
1560c1cb2cd8Shaad
1561c1cb2cd8Shaad /*
1562c1cb2cd8Shaad * Add 'name' to the beginning of the list, which is handled
1563c1cb2cd8Shaad * specially.
1564c1cb2cd8Shaad */
1565c1cb2cd8Shaad if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
1566c1cb2cd8Shaad return (-1);
1567c1cb2cd8Shaad
1568c1cb2cd8Shaad entry->pl_prop = (type == ZFS_TYPE_POOL) ? ZPOOL_PROP_NAME :
1569c1cb2cd8Shaad ZFS_PROP_NAME;
1570c1cb2cd8Shaad entry->pl_width = zprop_width(entry->pl_prop,
1571c1cb2cd8Shaad &entry->pl_fixed, type);
1572c1cb2cd8Shaad entry->pl_all = B_TRUE;
1573c1cb2cd8Shaad entry->pl_next = *plp;
1574c1cb2cd8Shaad *plp = entry;
1575c1cb2cd8Shaad }
1576c1cb2cd8Shaad return (0);
1577c1cb2cd8Shaad }
1578c1cb2cd8Shaad
1579c1cb2cd8Shaad int
zprop_iter(zprop_func func,void * cb,boolean_t show_all,boolean_t ordered,zfs_type_t type)1580c1cb2cd8Shaad zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered,
1581c1cb2cd8Shaad zfs_type_t type)
1582c1cb2cd8Shaad {
1583c1cb2cd8Shaad return (zprop_iter_common(func, cb, show_all, ordered, type));
1584c1cb2cd8Shaad }
1585