aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/opensolaris/lib
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib/opensolaris/lib')
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/drti.c1
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c1
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c1
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c11
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c1286
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h196
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c59
-rw-r--r--cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c406
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h391
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h35
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h181
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c135
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c570
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c128
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c122
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c718
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c277
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c70
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c205
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c56
-rw-r--r--cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c300
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h894
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c736
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c121
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h44
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c469
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c5284
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c834
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c452
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h228
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c1929
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c546
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c1734
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c4669
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c3924
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c511
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c1661
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c1234
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h114
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c189
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h47
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/kernel.c1238
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h838
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/taskq.c353
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/util.c196
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/zfs.d36
46 files changed, 11 insertions, 33419 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
index 836eeccb8274..a66661fd9ab8 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
@@ -24,6 +24,7 @@
* Use is subject to license terms.
*/
+#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <dlfcn.h>
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index 05f2785e6600..8f32890057f0 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -31,6 +31,7 @@
#include <assert.h>
#include <elf.h>
+#include <sys/types.h>
#include <fcntl.h>
#include <gelf.h>
#include <limits.h>
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
index 0a3a10a76954..97da0c3a5ac2 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
@@ -77,7 +77,6 @@
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <arpa/nameser.h>
#include <dt_module.h>
#include <dt_printf.h>
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
index f7b4684b01d0..57a7db4ad0fd 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
@@ -44,12 +44,19 @@
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <arpa/nameser.h>
-
+#include <sys/byteorder.h>
#include <dt_printf.h>
#include <dt_string.h>
#include <dt_impl.h>
+#ifndef NS_IN6ADDRSZ
+#define NS_IN6ADDRSZ 16
+#endif
+
+#ifndef NS_INADDRSZ
+#define NS_INADDRSZ 4
+#endif
+
/*ARGSUSED*/
static int
pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
deleted file mode 100644
index c6fbfe97a9af..000000000000
--- a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
+++ /dev/null
@@ -1,1286 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
- */
-
-#include <solaris.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <string.h>
-#include <libintl.h>
-#include <stdarg.h>
-#include "libnvpair.h"
-
-/*
- * libnvpair - A tools library for manipulating <name, value> pairs.
- *
- * This library provides routines packing an unpacking nv pairs
- * for transporting data across process boundaries, transporting
- * between kernel and userland, and possibly saving onto disk files.
- */
-
-/*
- * Print control structure.
- */
-
-#define DEFINEOP(opname, vtype) \
- struct { \
- int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
- const char *, vtype); \
- void *arg; \
- } opname
-
-#define DEFINEARROP(opname, vtype) \
- struct { \
- int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
- const char *, vtype, uint_t); \
- void *arg; \
- } opname
-
-struct nvlist_printops {
- DEFINEOP(print_boolean, int);
- DEFINEOP(print_boolean_value, boolean_t);
- DEFINEOP(print_byte, uchar_t);
- DEFINEOP(print_int8, int8_t);
- DEFINEOP(print_uint8, uint8_t);
- DEFINEOP(print_int16, int16_t);
- DEFINEOP(print_uint16, uint16_t);
- DEFINEOP(print_int32, int32_t);
- DEFINEOP(print_uint32, uint32_t);
- DEFINEOP(print_int64, int64_t);
- DEFINEOP(print_uint64, uint64_t);
- DEFINEOP(print_double, double);
- DEFINEOP(print_string, char *);
- DEFINEOP(print_hrtime, hrtime_t);
- DEFINEOP(print_nvlist, nvlist_t *);
- DEFINEARROP(print_boolean_array, boolean_t *);
- DEFINEARROP(print_byte_array, uchar_t *);
- DEFINEARROP(print_int8_array, int8_t *);
- DEFINEARROP(print_uint8_array, uint8_t *);
- DEFINEARROP(print_int16_array, int16_t *);
- DEFINEARROP(print_uint16_array, uint16_t *);
- DEFINEARROP(print_int32_array, int32_t *);
- DEFINEARROP(print_uint32_array, uint32_t *);
- DEFINEARROP(print_int64_array, int64_t *);
- DEFINEARROP(print_uint64_array, uint64_t *);
- DEFINEARROP(print_string_array, char **);
- DEFINEARROP(print_nvlist_array, nvlist_t **);
-};
-
-struct nvlist_prtctl {
- FILE *nvprt_fp; /* output destination */
- enum nvlist_indent_mode nvprt_indent_mode; /* see above */
- int nvprt_indent; /* absolute indent, or tab depth */
- int nvprt_indentinc; /* indent or tab increment */
- const char *nvprt_nmfmt; /* member name format, max one %s */
- const char *nvprt_eomfmt; /* after member format, e.g. "\n" */
- const char *nvprt_btwnarrfmt; /* between array members */
- int nvprt_btwnarrfmt_nl; /* nvprt_eoamfmt includes newline? */
- struct nvlist_printops *nvprt_dfltops;
- struct nvlist_printops *nvprt_custops;
-};
-
-#define DFLTPRTOP(pctl, type) \
- ((pctl)->nvprt_dfltops->print_##type.op)
-
-#define DFLTPRTOPARG(pctl, type) \
- ((pctl)->nvprt_dfltops->print_##type.arg)
-
-#define CUSTPRTOP(pctl, type) \
- ((pctl)->nvprt_custops->print_##type.op)
-
-#define CUSTPRTOPARG(pctl, type) \
- ((pctl)->nvprt_custops->print_##type.arg)
-
-#define RENDER(pctl, type, nvl, name, val) \
- { \
- int done = 0; \
- if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
- done = CUSTPRTOP(pctl, type)(pctl, \
- CUSTPRTOPARG(pctl, type), nvl, name, val); \
- } \
- if (!done) { \
- (void) DFLTPRTOP(pctl, type)(pctl, \
- DFLTPRTOPARG(pctl, type), nvl, name, val); \
- } \
- (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
- }
-
-#define ARENDER(pctl, type, nvl, name, arrp, count) \
- { \
- int done = 0; \
- if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
- done = CUSTPRTOP(pctl, type)(pctl, \
- CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \
- } \
- if (!done) { \
- (void) DFLTPRTOP(pctl, type)(pctl, \
- DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \
- } \
- (void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
- }
-
-static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t);
-
-/*
- * ======================================================================
- * | |
- * | Indentation |
- * | |
- * ======================================================================
- */
-
-static void
-indent(nvlist_prtctl_t pctl, int onemore)
-{
- int depth;
-
- switch (pctl->nvprt_indent_mode) {
- case NVLIST_INDENT_ABS:
- (void) fprintf(pctl->nvprt_fp, "%*s",
- pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, "");
- break;
-
- case NVLIST_INDENT_TABBED:
- depth = pctl->nvprt_indent + onemore;
- while (depth-- > 0)
- (void) fprintf(pctl->nvprt_fp, "\t");
- }
-}
-
-/*
- * ======================================================================
- * | |
- * | Default nvlist member rendering functions. |
- * | |
- * ======================================================================
- */
-
-/*
- * Generate functions to print single-valued nvlist members.
- *
- * type_and_variant - suffix to form function name
- * vtype - C type for the member value
- * ptype - C type to cast value to for printing
- * vfmt - format string for pair value, e.g "%d" or "0x%llx"
- */
-
-#define NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \
-static int \
-nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
- nvlist_t *nvl, const char *name, vtype value) \
-{ \
- FILE *fp = pctl->nvprt_fp; \
- NOTE(ARGUNUSED(private)) \
- NOTE(ARGUNUSED(nvl)) \
- indent(pctl, 1); \
- (void) fprintf(fp, pctl->nvprt_nmfmt, name); \
- (void) fprintf(fp, vfmt, (ptype)value); \
- return (1); \
-}
-
-NVLIST_PRTFUNC(boolean, int, int, "%d")
-NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d")
-NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x")
-NVLIST_PRTFUNC(int8, int8_t, int, "%d")
-NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x")
-NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d")
-NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x")
-NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")
-NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
-NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
-NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
-NVLIST_PRTFUNC(double, double, double, "0x%f")
-NVLIST_PRTFUNC(string, char *, char *, "%s")
-NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
-
-/*
- * Generate functions to print array-valued nvlist members.
- */
-
-#define NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \
-static int \
-nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
- nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \
-{ \
- FILE *fp = pctl->nvprt_fp; \
- uint_t i; \
- NOTE(ARGUNUSED(private)) \
- NOTE(ARGUNUSED(nvl)) \
- for (i = 0; i < count; i++) { \
- if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \
- indent(pctl, 1); \
- (void) fprintf(fp, pctl->nvprt_nmfmt, name); \
- if (pctl->nvprt_btwnarrfmt_nl) \
- (void) fprintf(fp, "[%d]: ", i); \
- } \
- if (i != 0) \
- (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
- (void) fprintf(fp, vfmt, (ptype)valuep[i]); \
- } \
- return (1); \
-}
-
-NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d")
-NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x")
-NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d")
-NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x")
-NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d")
-NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x")
-NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d")
-NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x")
-NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld")
-NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx")
-NVLIST_ARRPRTFUNC(string_array, char *, char *, "%s")
-
-/*ARGSUSED*/
-static int
-nvprint_nvlist(nvlist_prtctl_t pctl, void *private,
- nvlist_t *nvl, const char *name, nvlist_t *value)
-{
- FILE *fp = pctl->nvprt_fp;
-
- indent(pctl, 1);
- (void) fprintf(fp, "%s = (embedded nvlist)\n", name);
-
- pctl->nvprt_indent += pctl->nvprt_indentinc;
- nvlist_print_with_indent(value, pctl);
- pctl->nvprt_indent -= pctl->nvprt_indentinc;
-
- indent(pctl, 1);
- (void) fprintf(fp, "(end %s)\n", name);
-
- return (1);
-}
-
-/*ARGSUSED*/
-static int
-nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private,
- nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count)
-{
- FILE *fp = pctl->nvprt_fp;
- uint_t i;
-
- indent(pctl, 1);
- (void) fprintf(fp, "%s = (array of embedded nvlists)\n", name);
-
- for (i = 0; i < count; i++) {
- indent(pctl, 1);
- (void) fprintf(fp, "(start %s[%d])\n", name, i);
-
- pctl->nvprt_indent += pctl->nvprt_indentinc;
- nvlist_print_with_indent(valuep[i], pctl);
- pctl->nvprt_indent -= pctl->nvprt_indentinc;
-
- indent(pctl, 1);
- (void) fprintf(fp, "(end %s[%d])\n", name, i);
- }
-
- return (1);
-}
-
-/*
- * ======================================================================
- * | |
- * | Interfaces that allow control over formatting. |
- * | |
- * ======================================================================
- */
-
-void
-nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp)
-{
- pctl->nvprt_fp = fp;
-}
-
-FILE *
-nvlist_prtctl_getdest(nvlist_prtctl_t pctl)
-{
- return (pctl->nvprt_fp);
-}
-
-
-void
-nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode,
- int start, int inc)
-{
- if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED)
- mode = NVLIST_INDENT_TABBED;
-
- if (start < 0)
- start = 0;
-
- if (inc < 0)
- inc = 1;
-
- pctl->nvprt_indent_mode = mode;
- pctl->nvprt_indent = start;
- pctl->nvprt_indentinc = inc;
-}
-
-void
-nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore)
-{
- indent(pctl, onemore);
-}
-
-
-void
-nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which,
- const char *fmt)
-{
- switch (which) {
- case NVLIST_FMT_MEMBER_NAME:
- if (fmt == NULL)
- fmt = "%s = ";
- pctl->nvprt_nmfmt = fmt;
- break;
-
- case NVLIST_FMT_MEMBER_POSTAMBLE:
- if (fmt == NULL)
- fmt = "\n";
- pctl->nvprt_eomfmt = fmt;
- break;
-
- case NVLIST_FMT_BTWN_ARRAY:
- if (fmt == NULL) {
- pctl->nvprt_btwnarrfmt = " ";
- pctl->nvprt_btwnarrfmt_nl = 0;
- } else {
- pctl->nvprt_btwnarrfmt = fmt;
- pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL);
- }
- break;
-
- default:
- break;
- }
-}
-
-
-void
-nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...)
-{
- FILE *fp = pctl->nvprt_fp;
- va_list ap;
- char *name;
-
- va_start(ap, which);
-
- switch (which) {
- case NVLIST_FMT_MEMBER_NAME:
- name = va_arg(ap, char *);
- (void) fprintf(fp, pctl->nvprt_nmfmt, name);
- break;
-
- case NVLIST_FMT_MEMBER_POSTAMBLE:
- (void) fprintf(fp, pctl->nvprt_eomfmt);
- break;
-
- case NVLIST_FMT_BTWN_ARRAY:
- (void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
- break;
-
- default:
- break;
- }
-
- va_end(ap);
-}
-
-/*
- * ======================================================================
- * | |
- * | Interfaces to allow appointment of replacement rendering functions.|
- * | |
- * ======================================================================
- */
-
-#define NVLIST_PRINTCTL_REPLACE(type, vtype) \
-void \
-nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
- int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \
- void *private) \
-{ \
- CUSTPRTOP(pctl, type) = func; \
- CUSTPRTOPARG(pctl, type) = private; \
-}
-
-NVLIST_PRINTCTL_REPLACE(boolean, int)
-NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t)
-NVLIST_PRINTCTL_REPLACE(byte, uchar_t)
-NVLIST_PRINTCTL_REPLACE(int8, int8_t)
-NVLIST_PRINTCTL_REPLACE(uint8, uint8_t)
-NVLIST_PRINTCTL_REPLACE(int16, int16_t)
-NVLIST_PRINTCTL_REPLACE(uint16, uint16_t)
-NVLIST_PRINTCTL_REPLACE(int32, int32_t)
-NVLIST_PRINTCTL_REPLACE(uint32, uint32_t)
-NVLIST_PRINTCTL_REPLACE(int64, int64_t)
-NVLIST_PRINTCTL_REPLACE(uint64, uint64_t)
-NVLIST_PRINTCTL_REPLACE(double, double)
-NVLIST_PRINTCTL_REPLACE(string, char *)
-NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t)
-NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *)
-
-#define NVLIST_PRINTCTL_AREPLACE(type, vtype) \
-void \
-nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
- int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \
- uint_t), void *private) \
-{ \
- CUSTPRTOP(pctl, type) = func; \
- CUSTPRTOPARG(pctl, type) = private; \
-}
-
-NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *)
-NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *)
-NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *)
-NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *)
-NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *)
-NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *)
-NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *)
-NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *)
-NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *)
-NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *)
-NVLIST_PRINTCTL_AREPLACE(string_array, char **)
-NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **)
-
-/*
- * ======================================================================
- * | |
- * | Interfaces to manage nvlist_prtctl_t cookies. |
- * | |
- * ======================================================================
- */
-
-
-static const struct nvlist_printops defprtops = {
- { nvprint_boolean, NULL },
- { nvprint_boolean_value, NULL },
- { nvprint_byte, NULL },
- { nvprint_int8, NULL },
- { nvprint_uint8, NULL },
- { nvprint_int16, NULL },
- { nvprint_uint16, NULL },
- { nvprint_int32, NULL },
- { nvprint_uint32, NULL },
- { nvprint_int64, NULL },
- { nvprint_uint64, NULL },
- { nvprint_double, NULL },
- { nvprint_string, NULL },
- { nvprint_hrtime, NULL },
- { nvprint_nvlist, NULL },
- { nvaprint_boolean_array, NULL },
- { nvaprint_byte_array, NULL },
- { nvaprint_int8_array, NULL },
- { nvaprint_uint8_array, NULL },
- { nvaprint_int16_array, NULL },
- { nvaprint_uint16_array, NULL },
- { nvaprint_int32_array, NULL },
- { nvaprint_uint32_array, NULL },
- { nvaprint_int64_array, NULL },
- { nvaprint_uint64_array, NULL },
- { nvaprint_string_array, NULL },
- { nvaprint_nvlist_array, NULL },
-};
-
-static void
-prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl,
- struct nvlist_printops *ops)
-{
- pctl->nvprt_fp = fp;
- pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED;
- pctl->nvprt_indent = 0;
- pctl->nvprt_indentinc = 1;
- pctl->nvprt_nmfmt = "%s = ";
- pctl->nvprt_eomfmt = "\n";
- pctl->nvprt_btwnarrfmt = " ";
- pctl->nvprt_btwnarrfmt_nl = 0;
-
- pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops;
- pctl->nvprt_custops = ops;
-}
-
-nvlist_prtctl_t
-nvlist_prtctl_alloc(void)
-{
- struct nvlist_prtctl *pctl;
- struct nvlist_printops *ops;
-
- if ((pctl = malloc(sizeof (*pctl))) == NULL)
- return (NULL);
-
- if ((ops = calloc(1, sizeof (*ops))) == NULL) {
- free(pctl);
- return (NULL);
- }
-
- prtctl_defaults(stdout, pctl, ops);
-
- return (pctl);
-}
-
-void
-nvlist_prtctl_free(nvlist_prtctl_t pctl)
-{
- if (pctl != NULL) {
- free(pctl->nvprt_custops);
- free(pctl);
- }
-}
-
-/*
- * ======================================================================
- * | |
- * | Top-level print request interfaces. |
- * | |
- * ======================================================================
- */
-
-/*
- * nvlist_print - Prints elements in an event buffer
- */
-static void
-nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl)
-{
- FILE *fp = pctl->nvprt_fp;
- char *name;
- uint_t nelem;
- nvpair_t *nvp;
-
- if (nvl == NULL)
- return;
-
- indent(pctl, 0);
- (void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
-
- nvp = nvlist_next_nvpair(nvl, NULL);
-
- while (nvp) {
- data_type_t type = nvpair_type(nvp);
-
- name = nvpair_name(nvp);
- nelem = 0;
-
- switch (type) {
- case DATA_TYPE_BOOLEAN: {
- RENDER(pctl, boolean, nvl, name, 1);
- break;
- }
- case DATA_TYPE_BOOLEAN_VALUE: {
- boolean_t val;
- (void) nvpair_value_boolean_value(nvp, &val);
- RENDER(pctl, boolean_value, nvl, name, val);
- break;
- }
- case DATA_TYPE_BYTE: {
- uchar_t val;
- (void) nvpair_value_byte(nvp, &val);
- RENDER(pctl, byte, nvl, name, val);
- break;
- }
- case DATA_TYPE_INT8: {
- int8_t val;
- (void) nvpair_value_int8(nvp, &val);
- RENDER(pctl, int8, nvl, name, val);
- break;
- }
- case DATA_TYPE_UINT8: {
- uint8_t val;
- (void) nvpair_value_uint8(nvp, &val);
- RENDER(pctl, uint8, nvl, name, val);
- break;
- }
- case DATA_TYPE_INT16: {
- int16_t val;
- (void) nvpair_value_int16(nvp, &val);
- RENDER(pctl, int16, nvl, name, val);
- break;
- }
- case DATA_TYPE_UINT16: {
- uint16_t val;
- (void) nvpair_value_uint16(nvp, &val);
- RENDER(pctl, uint16, nvl, name, val);
- break;
- }
- case DATA_TYPE_INT32: {
- int32_t val;
- (void) nvpair_value_int32(nvp, &val);
- RENDER(pctl, int32, nvl, name, val);
- break;
- }
- case DATA_TYPE_UINT32: {
- uint32_t val;
- (void) nvpair_value_uint32(nvp, &val);
- RENDER(pctl, uint32, nvl, name, val);
- break;
- }
- case DATA_TYPE_INT64: {
- int64_t val;
- (void) nvpair_value_int64(nvp, &val);
- RENDER(pctl, int64, nvl, name, val);
- break;
- }
- case DATA_TYPE_UINT64: {
- uint64_t val;
- (void) nvpair_value_uint64(nvp, &val);
- RENDER(pctl, uint64, nvl, name, val);
- break;
- }
- case DATA_TYPE_DOUBLE: {
- double val;
- (void) nvpair_value_double(nvp, &val);
- RENDER(pctl, double, nvl, name, val);
- break;
- }
- case DATA_TYPE_STRING: {
- char *val;
- (void) nvpair_value_string(nvp, &val);
- RENDER(pctl, string, nvl, name, val);
- break;
- }
- case DATA_TYPE_BOOLEAN_ARRAY: {
- boolean_t *val;
- (void) nvpair_value_boolean_array(nvp, &val, &nelem);
- ARENDER(pctl, boolean_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_BYTE_ARRAY: {
- uchar_t *val;
- (void) nvpair_value_byte_array(nvp, &val, &nelem);
- ARENDER(pctl, byte_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_INT8_ARRAY: {
- int8_t *val;
- (void) nvpair_value_int8_array(nvp, &val, &nelem);
- ARENDER(pctl, int8_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_UINT8_ARRAY: {
- uint8_t *val;
- (void) nvpair_value_uint8_array(nvp, &val, &nelem);
- ARENDER(pctl, uint8_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_INT16_ARRAY: {
- int16_t *val;
- (void) nvpair_value_int16_array(nvp, &val, &nelem);
- ARENDER(pctl, int16_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_UINT16_ARRAY: {
- uint16_t *val;
- (void) nvpair_value_uint16_array(nvp, &val, &nelem);
- ARENDER(pctl, uint16_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_INT32_ARRAY: {
- int32_t *val;
- (void) nvpair_value_int32_array(nvp, &val, &nelem);
- ARENDER(pctl, int32_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_UINT32_ARRAY: {
- uint32_t *val;
- (void) nvpair_value_uint32_array(nvp, &val, &nelem);
- ARENDER(pctl, uint32_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_INT64_ARRAY: {
- int64_t *val;
- (void) nvpair_value_int64_array(nvp, &val, &nelem);
- ARENDER(pctl, int64_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_UINT64_ARRAY: {
- uint64_t *val;
- (void) nvpair_value_uint64_array(nvp, &val, &nelem);
- ARENDER(pctl, uint64_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_STRING_ARRAY: {
- char **val;
- (void) nvpair_value_string_array(nvp, &val, &nelem);
- ARENDER(pctl, string_array, nvl, name, val, nelem);
- break;
- }
- case DATA_TYPE_HRTIME: {
- hrtime_t val;
- (void) nvpair_value_hrtime(nvp, &val);
- RENDER(pctl, hrtime, nvl, name, val);
- break;
- }
- case DATA_TYPE_NVLIST: {
- nvlist_t *val;
- (void) nvpair_value_nvlist(nvp, &val);
- RENDER(pctl, nvlist, nvl, name, val);
- break;
- }
- case DATA_TYPE_NVLIST_ARRAY: {
- nvlist_t **val;
- (void) nvpair_value_nvlist_array(nvp, &val, &nelem);
- ARENDER(pctl, nvlist_array, nvl, name, val, nelem);
- break;
- }
- default:
- (void) fprintf(fp, " unknown data type (%d)", type);
- break;
- }
- nvp = nvlist_next_nvpair(nvl, nvp);
- }
-}
-
-void
-nvlist_print(FILE *fp, nvlist_t *nvl)
-{
- struct nvlist_prtctl pc;
-
- prtctl_defaults(fp, &pc, NULL);
- nvlist_print_with_indent(nvl, &pc);
-}
-
-void
-nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl)
-{
- nvlist_print_with_indent(nvl, pctl);
-}
-
-#define NVP(elem, type, vtype, ptype, format) { \
- vtype value; \
-\
- (void) nvpair_value_##type(elem, &value); \
- (void) printf("%*s%s: " format "\n", indent, "", \
- nvpair_name(elem), (ptype)value); \
-}
-
-#define NVPA(elem, type, vtype, ptype, format) { \
- uint_t i, count; \
- vtype *value; \
-\
- (void) nvpair_value_##type(elem, &value, &count); \
- for (i = 0; i < count; i++) { \
- (void) printf("%*s%s[%d]: " format "\n", indent, "", \
- nvpair_name(elem), i, (ptype)value[i]); \
- } \
-}
-
-/*
- * Similar to nvlist_print() but handles arrays slightly differently.
- */
-void
-dump_nvlist(nvlist_t *list, int indent)
-{
- nvpair_t *elem = NULL;
- boolean_t bool_value;
- boolean_t *bool_array_value;
- nvlist_t *nvlist_value;
- nvlist_t **nvlist_array_value;
- uint_t i, count;
-
- if (list == NULL) {
- return;
- }
-
- while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
- switch (nvpair_type(elem)) {
- case DATA_TYPE_BOOLEAN:
- (void) printf("%*s%s\n", indent, "", nvpair_name(elem));
- break;
-
- case DATA_TYPE_BOOLEAN_VALUE:
- (void) nvpair_value_boolean_value(elem, &bool_value);
- (void) printf("%*s%s: %s\n", indent, "",
- nvpair_name(elem), bool_value ? "true" : "false");
- break;
-
- case DATA_TYPE_BYTE:
- NVP(elem, byte, uchar_t, int, "%u");
- break;
-
- case DATA_TYPE_INT8:
- NVP(elem, int8, int8_t, int, "%d");
- break;
-
- case DATA_TYPE_UINT8:
- NVP(elem, uint8, uint8_t, int, "%u");
- break;
-
- case DATA_TYPE_INT16:
- NVP(elem, int16, int16_t, int, "%d");
- break;
-
- case DATA_TYPE_UINT16:
- NVP(elem, uint16, uint16_t, int, "%u");
- break;
-
- case DATA_TYPE_INT32:
- NVP(elem, int32, int32_t, long, "%ld");
- break;
-
- case DATA_TYPE_UINT32:
- NVP(elem, uint32, uint32_t, ulong_t, "%lu");
- break;
-
- case DATA_TYPE_INT64:
- NVP(elem, int64, int64_t, longlong_t, "%lld");
- break;
-
- case DATA_TYPE_UINT64:
- NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
- break;
-
- case DATA_TYPE_STRING:
- NVP(elem, string, char *, char *, "'%s'");
- break;
-
- case DATA_TYPE_BOOLEAN_ARRAY:
- (void) nvpair_value_boolean_array(elem,
- &bool_array_value, &count);
- for (i = 0; i < count; i++) {
- (void) printf("%*s%s[%d]: %s\n", indent, "",
- nvpair_name(elem), i,
- bool_array_value[i] ? "true" : "false");
- }
- break;
-
- case DATA_TYPE_BYTE_ARRAY:
- NVPA(elem, byte_array, uchar_t, int, "%u");
- break;
-
- case DATA_TYPE_INT8_ARRAY:
- NVPA(elem, int8_array, int8_t, int, "%d");
- break;
-
- case DATA_TYPE_UINT8_ARRAY:
- NVPA(elem, uint8_array, uint8_t, int, "%u");
- break;
-
- case DATA_TYPE_INT16_ARRAY:
- NVPA(elem, int16_array, int16_t, int, "%d");
- break;
-
- case DATA_TYPE_UINT16_ARRAY:
- NVPA(elem, uint16_array, uint16_t, int, "%u");
- break;
-
- case DATA_TYPE_INT32_ARRAY:
- NVPA(elem, int32_array, int32_t, long, "%ld");
- break;
-
- case DATA_TYPE_UINT32_ARRAY:
- NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
- break;
-
- case DATA_TYPE_INT64_ARRAY:
- NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
- break;
-
- case DATA_TYPE_UINT64_ARRAY:
- NVPA(elem, uint64_array, uint64_t, u_longlong_t,
- "%llu");
- break;
-
- case DATA_TYPE_STRING_ARRAY:
- NVPA(elem, string_array, char *, char *, "'%s'");
- break;
-
- case DATA_TYPE_NVLIST:
- (void) nvpair_value_nvlist(elem, &nvlist_value);
- (void) printf("%*s%s:\n", indent, "",
- nvpair_name(elem));
- dump_nvlist(nvlist_value, indent + 4);
- break;
-
- case DATA_TYPE_NVLIST_ARRAY:
- (void) nvpair_value_nvlist_array(elem,
- &nvlist_array_value, &count);
- for (i = 0; i < count; i++) {
- (void) printf("%*s%s[%u]:\n", indent, "",
- nvpair_name(elem), i);
- dump_nvlist(nvlist_array_value[i], indent + 4);
- }
- break;
-
- default:
- (void) printf(dgettext(TEXT_DOMAIN, "bad config type "
- "%d for %s\n"), nvpair_type(elem),
- nvpair_name(elem));
- }
- }
-}
-
-/*
- * ======================================================================
- * | |
- * | Misc private interface. |
- * | |
- * ======================================================================
- */
-
-/*
- * Determine if string 'value' matches 'nvp' value. The 'value' string is
- * converted, depending on the type of 'nvp', prior to match. For numeric
- * types, a radix independent sscanf conversion of 'value' is used. If 'nvp'
- * is an array type, 'ai' is the index into the array against which we are
- * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass
- * in a regex_t compilation of value in 'value_regex' to trigger regular
- * expression string match instead of simple strcmp().
- *
- * Return 1 on match, 0 on no-match, and -1 on error. If the error is
- * related to value syntax error and 'ep' is non-NULL, *ep will point into
- * the 'value' string at the location where the error exists.
- *
- * NOTE: It may be possible to move the non-regex_t version of this into
- * common code used by library/kernel/boot.
- */
-int
-nvpair_value_match_regex(nvpair_t *nvp, int ai,
- char *value, regex_t *value_regex, char **ep)
-{
- char *evalue;
- uint_t a_len;
- int sr;
-
- if (ep)
- *ep = NULL;
-
- if ((nvp == NULL) || (value == NULL))
- return (-1); /* error fail match - invalid args */
-
- /* make sure array and index combination make sense */
- if ((nvpair_type_is_array(nvp) && (ai < 0)) ||
- (!nvpair_type_is_array(nvp) && (ai >= 0)))
- return (-1); /* error fail match - bad index */
-
- /* non-string values should be single 'chunk' */
- if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&
- (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {
- value += strspn(value, " \t");
- evalue = value + strcspn(value, " \t");
- if (*evalue) {
- if (ep)
- *ep = evalue;
- return (-1); /* error fail match - syntax */
- }
- }
-
- sr = EOF;
- switch (nvpair_type(nvp)) {
- case DATA_TYPE_STRING: {
- char *val;
-
- /* check string value for match */
- if (nvpair_value_string(nvp, &val) == 0) {
- if (value_regex) {
- if (regexec(value_regex, val,
- (size_t)0, NULL, 0) == 0)
- return (1); /* match */
- } else {
- if (strcmp(value, val) == 0)
- return (1); /* match */
- }
- }
- break;
- }
- case DATA_TYPE_STRING_ARRAY: {
- char **val_array;
-
- /* check indexed string value of array for match */
- if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len)) {
- if (value_regex) {
- if (regexec(value_regex, val_array[ai],
- (size_t)0, NULL, 0) == 0)
- return (1);
- } else {
- if (strcmp(value, val_array[ai]) == 0)
- return (1);
- }
- }
- break;
- }
- case DATA_TYPE_BYTE: {
- uchar_t val, val_arg;
-
- /* scanf uchar_t from value and check for match */
- sr = sscanf(value, "%c", &val_arg);
- if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_BYTE_ARRAY: {
- uchar_t *val_array, val_arg;
-
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%c", &val_arg);
- if ((sr == 1) &&
- (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT8: {
- int8_t val, val_arg;
-
- /* scanf int8_t from value and check for match */
- sr = sscanf(value, "%"SCNi8, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int8(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT8_ARRAY: {
- int8_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi8, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT8: {
- uint8_t val, val_arg;
-
- /* scanf uint8_t from value and check for match */
- sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint8(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT8_ARRAY: {
- uint8_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT16: {
- int16_t val, val_arg;
-
- /* scanf int16_t from value and check for match */
- sr = sscanf(value, "%"SCNi16, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int16(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT16_ARRAY: {
- int16_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi16, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT16: {
- uint16_t val, val_arg;
-
- /* scanf uint16_t from value and check for match */
- sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint16(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT16_ARRAY: {
- uint16_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT32: {
- int32_t val, val_arg;
-
- /* scanf int32_t from value and check for match */
- sr = sscanf(value, "%"SCNi32, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int32(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT32_ARRAY: {
- int32_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi32, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT32: {
- uint32_t val, val_arg;
-
- /* scanf uint32_t from value and check for match */
- sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint32(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT32_ARRAY: {
- uint32_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT64: {
- int64_t val, val_arg;
-
- /* scanf int64_t from value and check for match */
- sr = sscanf(value, "%"SCNi64, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int64(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_INT64_ARRAY: {
- int64_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi64, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT64: {
- uint64_t val_arg, val;
-
- /* scanf uint64_t from value and check for match */
- sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint64(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_UINT64_ARRAY: {
- uint64_t *val_array, val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
- if ((sr == 1) &&
- (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_BOOLEAN_VALUE: {
- int32_t val_arg;
- boolean_t val;
-
- /* scanf boolean_t from value and check for match */
- sr = sscanf(value, "%"SCNi32, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_boolean_value(nvp, &val) == 0) &&
- (val == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_BOOLEAN_ARRAY: {
- boolean_t *val_array;
- int32_t val_arg;
-
- /* check indexed value of array for match */
- sr = sscanf(value, "%"SCNi32, &val_arg);
- if ((sr == 1) &&
- (nvpair_value_boolean_array(nvp,
- &val_array, &a_len) == 0) &&
- (ai < a_len) &&
- (val_array[ai] == val_arg))
- return (1);
- break;
- }
- case DATA_TYPE_HRTIME:
- case DATA_TYPE_NVLIST:
- case DATA_TYPE_NVLIST_ARRAY:
- case DATA_TYPE_BOOLEAN:
- case DATA_TYPE_DOUBLE:
- case DATA_TYPE_UNKNOWN:
- default:
- /*
- * unknown/unsupported data type
- */
- return (-1); /* error fail match */
- }
-
- /*
- * check to see if sscanf failed conversion, return approximate
- * pointer to problem
- */
- if (sr != 1) {
- if (ep)
- *ep = value;
- return (-1); /* error fail match - syntax */
- }
-
- return (0); /* fail match */
-}
-
-int
-nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep)
-{
- return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));
-}
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h b/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h
deleted file mode 100644
index b05669e506ba..000000000000
--- a/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
- */
-
-#ifndef _LIBNVPAIR_H
-#define _LIBNVPAIR_H
-
-#include <sys/nvpair.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <regex.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * All interfaces described in this file are private to Solaris, and
- * are subject to change at any time and without notice. The public
- * nvlist/nvpair interfaces, as documented in manpage sections 3NVPAIR,
- * are all imported from <sys/nvpair.h> included above.
- */
-
-extern int nvpair_value_match(nvpair_t *, int, char *, char **);
-extern int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *,
- char **);
-
-extern void nvlist_print(FILE *, nvlist_t *);
-extern int nvlist_print_json(FILE *, nvlist_t *);
-extern void dump_nvlist(nvlist_t *, int);
-
-/*
- * Private nvlist printing interface that allows the caller some control
- * over output rendering (as opposed to nvlist_print and dump_nvlist).
- *
- * Obtain an opaque nvlist_prtctl_t cookie using nvlist_prtctl_alloc
- * (NULL on failure); on return the cookie is set up for default formatting
- * and rendering. Quote the cookie in subsequent customisation functions and
- * then pass the cookie to nvlist_prt to render the nvlist. Finally,
- * use nvlist_prtctl_free to release the cookie.
- *
- * For all nvlist_lookup_xxx and nvlist_lookup_xxx_array functions
- * we have a corresponding brace of functions that appoint replacement
- * rendering functions:
- *
- * extern void nvlist_prtctl_xxx(nvlist_prtctl_t,
- * void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
- * xxxtype value))
- *
- * and
- *
- * extern void nvlist_prtctl_xxx_array(nvlist_prtctl_t,
- * void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
- * xxxtype value, uint_t count))
- *
- * where xxxtype is the C datatype corresponding to xxx, eg int8_t for "int8"
- * and char * for "string". The function that is appointed to render the
- * specified datatype receives as arguments the cookie, the nvlist
- * member name, the value of that member (or a pointer for array function),
- * and (for array rendering functions) a count of the number of elements.
- */
-
-typedef struct nvlist_prtctl *nvlist_prtctl_t; /* opaque */
-
-enum nvlist_indent_mode {
- NVLIST_INDENT_ABS, /* Absolute indentation */
- NVLIST_INDENT_TABBED /* Indent with tabstops */
-};
-
-extern nvlist_prtctl_t nvlist_prtctl_alloc(void);
-extern void nvlist_prtctl_free(nvlist_prtctl_t);
-extern void nvlist_prt(nvlist_t *, nvlist_prtctl_t);
-
-/* Output stream */
-extern void nvlist_prtctl_setdest(nvlist_prtctl_t, FILE *);
-extern FILE *nvlist_prtctl_getdest(nvlist_prtctl_t);
-
-/* Indentation mode, start indent, indent increment; default tabbed/0/1 */
-extern void nvlist_prtctl_setindent(nvlist_prtctl_t, enum nvlist_indent_mode,
- int, int);
-extern void nvlist_prtctl_doindent(nvlist_prtctl_t, int);
-
-enum nvlist_prtctl_fmt {
- NVLIST_FMT_MEMBER_NAME, /* name fmt; default "%s = " */
- NVLIST_FMT_MEMBER_POSTAMBLE, /* after nvlist member; default "\n" */
- NVLIST_FMT_BTWN_ARRAY /* between array members; default " " */
-};
-
-extern void nvlist_prtctl_setfmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt,
- const char *);
-extern void nvlist_prtctl_dofmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt, ...);
-
-/*
- * Function prototypes for interfaces that appoint a new rendering function
- * for single-valued nvlist members.
- *
- * A replacement function receives arguments as follows:
- *
- * nvlist_prtctl_t Print control structure; do not change preferences
- * for this object from a print callback function.
- *
- * void * The function-private cookie argument registered
- * when the replacement function was appointed.
- *
- * nvlist_t * The full nvlist that is being processed. The
- * rendering function is called to render a single
- * member (name and value passed as below) but it may
- * want to reference or incorporate other aspects of
- * the full nvlist.
- *
- * const char * Member name to render
- *
- * valtype Value of the member to render
- *
- * The function must return non-zero if it has rendered output for this
- * member, or 0 if it wants to default to standard rendering for this
- * one member.
- */
-
-#define NVLIST_PRINTCTL_SVDECL(funcname, valtype) \
- extern void funcname(nvlist_prtctl_t, \
- int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, valtype), \
- void *)
-
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean, int);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean_value, boolean_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_byte, uchar_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int8, int8_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint8, uint8_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int16, int16_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint16, uint16_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int32, int32_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint32, uint32_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int64, int64_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint64, uint64_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_double, double);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_string, char *);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_hrtime, hrtime_t);
-NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_nvlist, nvlist_t *);
-
-#undef NVLIST_PRINTCTL_SVDECL /* was just for "clarity" above */
-
-/*
- * Function prototypes for interfaces that appoint a new rendering function
- * for array-valued nvlist members.
- *
- * One additional argument is taken: uint_t for the number of array elements
- *
- * Return values as above.
- */
-#define NVLIST_PRINTCTL_AVDECL(funcname, vtype) \
- extern void funcname(nvlist_prtctl_t, \
- int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, uint_t), \
- void *)
-
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_boolean_array, boolean_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_byte_array, uchar_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int8_array, int8_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint8_array, uint8_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int16_array, int16_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint16_array, uint16_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int32_array, int32_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint32_array, uint32_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int64_array, int64_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint64_array, uint64_t *);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_string_array, char **);
-NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_nvlist_array, nvlist_t **);
-
-#undef NVLIST_PRINTCTL_AVDECL /* was just for "clarity" above */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBNVPAIR_H */
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c b/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c
deleted file mode 100644
index 1aefc1004daf..000000000000
--- a/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <sys/nvpair.h>
-#include <stdlib.h>
-
-/*ARGSUSED*/
-static void *
-nv_alloc_sys(nv_alloc_t *nva, size_t size)
-{
- return (malloc(size));
-}
-
-/*ARGSUSED*/
-static void
-nv_free_sys(nv_alloc_t *nva, void *buf, size_t size)
-{
- free(buf);
-}
-
-const nv_alloc_ops_t system_ops_def = {
- NULL, /* nv_ao_init() */
- NULL, /* nv_ao_fini() */
- nv_alloc_sys, /* nv_ao_alloc() */
- nv_free_sys, /* nv_ao_free() */
- NULL /* nv_ao_reset() */
-};
-
-nv_alloc_t nv_alloc_nosleep_def = {
- &system_ops_def,
- NULL
-};
-
-nv_alloc_t *nv_alloc_nosleep = &nv_alloc_nosleep_def;
diff --git a/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c b/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c
deleted file mode 100644
index b687a2f5761a..000000000000
--- a/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * This file and its contents are supplied under the terms of the
- * Common Development and Distribution License ("CDDL"), version 1.0.
- * You may only use this file in accordance with the terms of version
- * 1.0 of the CDDL.
- *
- * A full copy of the text of the CDDL should have accompanied this
- * source. A copy of the CDDL is also available via the Internet at
- * http://www.illumos.org/license/CDDL.
- */
-/*
- * Copyright (c) 2014, Joyent, Inc.
- * Copyright (c) 2017 by Delphix. All rights reserved.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <wchar.h>
-#include <sys/debug.h>
-
-#include "libnvpair.h"
-
-#define FPRINTF(fp, ...) \
- do { \
- if (fprintf(fp, __VA_ARGS__) < 0) \
- return (-1); \
- } while (0)
-
-/*
- * When formatting a string for JSON output we must escape certain characters,
- * as described in RFC4627. This applies to both member names and
- * DATA_TYPE_STRING values.
- *
- * This function will only operate correctly if the following conditions are
- * met:
- *
- * 1. The input String is encoded in the current locale.
- *
- * 2. The current locale includes the Basic Multilingual Plane (plane 0)
- * as defined in the Unicode standard.
- *
- * The output will be entirely 7-bit ASCII (as a subset of UTF-8) with all
- * representable Unicode characters included in their escaped numeric form.
- */
-static int
-nvlist_print_json_string(FILE *fp, const char *input)
-{
- mbstate_t mbr;
- wchar_t c;
- size_t sz;
-
- bzero(&mbr, sizeof (mbr));
-
- FPRINTF(fp, "\"");
- while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {
- switch (c) {
- case '"':
- FPRINTF(fp, "\\\"");
- break;
- case '\n':
- FPRINTF(fp, "\\n");
- break;
- case '\r':
- FPRINTF(fp, "\\r");
- break;
- case '\\':
- FPRINTF(fp, "\\\\");
- break;
- case '\f':
- FPRINTF(fp, "\\f");
- break;
- case '\t':
- FPRINTF(fp, "\\t");
- break;
- case '\b':
- FPRINTF(fp, "\\b");
- break;
- default:
- if ((c >= 0x00 && c <= 0x1f) ||
- (c > 0x7f && c <= 0xffff)) {
- /*
- * Render both Control Characters and Unicode
- * characters in the Basic Multilingual Plane
- * as JSON-escaped multibyte characters.
- */
- FPRINTF(fp, "\\u%04x", (int)(0xffff & c));
- } else if (c >= 0x20 && c <= 0x7f) {
- /*
- * Render other 7-bit ASCII characters directly
- * and drop other, unrepresentable characters.
- */
- FPRINTF(fp, "%c", (int)(0xff & c));
- }
- break;
- }
- input += sz;
- }
-
- if (sz == (size_t)-1 || sz == (size_t)-2) {
- /*
- * We last read an invalid multibyte character sequence,
- * so return an error.
- */
- return (-1);
- }
-
- FPRINTF(fp, "\"");
- return (0);
-}
-
-/*
- * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
- * This routine does not output any new-lines or additional whitespace other
- * than that contained in strings, nor does it call fflush(3C).
- */
-int
-nvlist_print_json(FILE *fp, nvlist_t *nvl)
-{
- nvpair_t *curr;
- boolean_t first = B_TRUE;
-
- FPRINTF(fp, "{");
-
- for (curr = nvlist_next_nvpair(nvl, NULL); curr;
- curr = nvlist_next_nvpair(nvl, curr)) {
- data_type_t type = nvpair_type(curr);
-
- if (!first)
- FPRINTF(fp, ",");
- else
- first = B_FALSE;
-
- if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1)
- return (-1);
- FPRINTF(fp, ":");
-
- switch (type) {
- case DATA_TYPE_STRING: {
- char *string = fnvpair_value_string(curr);
- if (nvlist_print_json_string(fp, string) == -1)
- return (-1);
- break;
- }
-
- case DATA_TYPE_BOOLEAN: {
- FPRINTF(fp, "true");
- break;
- }
-
- case DATA_TYPE_BOOLEAN_VALUE: {
- FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) ==
- B_TRUE ? "true" : "false");
- break;
- }
-
- case DATA_TYPE_BYTE: {
- FPRINTF(fp, "%hhu", fnvpair_value_byte(curr));
- break;
- }
-
- case DATA_TYPE_INT8: {
- FPRINTF(fp, "%hhd", fnvpair_value_int8(curr));
- break;
- }
-
- case DATA_TYPE_UINT8: {
- FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr));
- break;
- }
-
- case DATA_TYPE_INT16: {
- FPRINTF(fp, "%hd", fnvpair_value_int16(curr));
- break;
- }
-
- case DATA_TYPE_UINT16: {
- FPRINTF(fp, "%hu", fnvpair_value_uint16(curr));
- break;
- }
-
- case DATA_TYPE_INT32: {
- FPRINTF(fp, "%d", fnvpair_value_int32(curr));
- break;
- }
-
- case DATA_TYPE_UINT32: {
- FPRINTF(fp, "%u", fnvpair_value_uint32(curr));
- break;
- }
-
- case DATA_TYPE_INT64: {
- FPRINTF(fp, "%lld",
- (long long)fnvpair_value_int64(curr));
- break;
- }
-
- case DATA_TYPE_UINT64: {
- FPRINTF(fp, "%llu",
- (unsigned long long)fnvpair_value_uint64(curr));
- break;
- }
-
- case DATA_TYPE_HRTIME: {
- hrtime_t val;
- VERIFY0(nvpair_value_hrtime(curr, &val));
- FPRINTF(fp, "%llu", (unsigned long long)val);
- break;
- }
-
- case DATA_TYPE_DOUBLE: {
- double val;
- VERIFY0(nvpair_value_double(curr, &val));
- FPRINTF(fp, "%f", val);
- break;
- }
-
- case DATA_TYPE_NVLIST: {
- if (nvlist_print_json(fp,
- fnvpair_value_nvlist(curr)) == -1)
- return (-1);
- break;
- }
-
- case DATA_TYPE_STRING_ARRAY: {
- char **val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_string_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- if (nvlist_print_json_string(fp, val[i]) == -1)
- return (-1);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_NVLIST_ARRAY: {
- nvlist_t **val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- if (nvlist_print_json(fp, val[i]) == -1)
- return (-1);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_BOOLEAN_ARRAY: {
- boolean_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, val[i] == B_TRUE ?
- "true" : "false");
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_BYTE_ARRAY: {
- uchar_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hhu", val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_UINT8_ARRAY: {
- uint8_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hhu", val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_INT8_ARRAY: {
- int8_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hhd", val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_UINT16_ARRAY: {
- uint16_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hu", val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_INT16_ARRAY: {
- int16_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hd", val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_UINT32_ARRAY: {
- uint32_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%u", val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_INT32_ARRAY: {
- int32_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%d", val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_UINT64_ARRAY: {
- uint64_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%llu",
- (unsigned long long)val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_INT64_ARRAY: {
- int64_t *val;
- uint_t valsz, i;
- VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%lld", (long long)val[i]);
- }
- FPRINTF(fp, "]");
- break;
- }
-
- case DATA_TYPE_UNKNOWN:
- case DATA_TYPE_DONTCARE:
- return (-1);
- }
-
- }
-
- FPRINTF(fp, "}");
- return (0);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h
deleted file mode 100644
index 7a5f8a8570c6..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#ifndef _LIBUUTIL_H
-#define _LIBUUTIL_H
-
-#include <solaris.h>
-#include <sys/types.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Standard flags codes.
- */
-#define UU_DEFAULT 0
-
-/*
- * Standard error codes.
- */
-#define UU_ERROR_NONE 0 /* no error */
-#define UU_ERROR_INVALID_ARGUMENT 1 /* invalid argument */
-#define UU_ERROR_UNKNOWN_FLAG 2 /* passed flag invalid */
-#define UU_ERROR_NO_MEMORY 3 /* out of memory */
-#define UU_ERROR_CALLBACK_FAILED 4 /* callback-initiated error */
-#define UU_ERROR_NOT_SUPPORTED 5 /* operation not supported */
-#define UU_ERROR_EMPTY 6 /* no value provided */
-#define UU_ERROR_UNDERFLOW 7 /* value is too small */
-#define UU_ERROR_OVERFLOW 8 /* value is too value */
-#define UU_ERROR_INVALID_CHAR 9 /* value contains unexpected char */
-#define UU_ERROR_INVALID_DIGIT 10 /* value contains digit not in base */
-
-#define UU_ERROR_SYSTEM 99 /* underlying system error */
-#define UU_ERROR_UNKNOWN 100 /* error status not known */
-
-/*
- * Standard program exit codes.
- */
-#define UU_EXIT_OK (*(uu_exit_ok()))
-#define UU_EXIT_FATAL (*(uu_exit_fatal()))
-#define UU_EXIT_USAGE (*(uu_exit_usage()))
-
-/*
- * Exit status profiles.
- */
-#define UU_PROFILE_DEFAULT 0
-#define UU_PROFILE_LAUNCHER 1
-
-/*
- * Error reporting functions.
- */
-uint32_t uu_error(void);
-const char *uu_strerror(uint32_t);
-
-/*
- * Program notification functions.
- */
-extern void uu_alt_exit(int);
-extern const char *uu_setpname(char *);
-extern const char *uu_getpname(void);
-/*PRINTFLIKE1*/
-extern void uu_warn(const char *, ...);
-extern void uu_vwarn(const char *, va_list);
-/*PRINTFLIKE1*/
-extern void uu_die(const char *, ...) __NORETURN;
-extern void uu_vdie(const char *, va_list) __NORETURN;
-/*PRINTFLIKE2*/
-extern void uu_xdie(int, const char *, ...) __NORETURN;
-extern void uu_vxdie(int, const char *, va_list) __NORETURN;
-
-/*
- * Exit status functions (not to be used directly)
- */
-extern int *uu_exit_ok(void);
-extern int *uu_exit_fatal(void);
-extern int *uu_exit_usage(void);
-
-/*
- * string->number conversions
- */
-extern int uu_strtoint(const char *, void *, size_t, int, int64_t, int64_t);
-extern int uu_strtouint(const char *, void *, size_t, int, uint64_t, uint64_t);
-
-/*
- * Debug print facility functions.
- */
-typedef struct uu_dprintf uu_dprintf_t;
-
-typedef enum {
- UU_DPRINTF_SILENT,
- UU_DPRINTF_FATAL,
- UU_DPRINTF_WARNING,
- UU_DPRINTF_NOTICE,
- UU_DPRINTF_INFO,
- UU_DPRINTF_DEBUG
-} uu_dprintf_severity_t;
-
-extern uu_dprintf_t *uu_dprintf_create(const char *, uu_dprintf_severity_t,
- uint_t);
-/*PRINTFLIKE3*/
-extern void uu_dprintf(uu_dprintf_t *, uu_dprintf_severity_t,
- const char *, ...);
-extern void uu_dprintf_destroy(uu_dprintf_t *);
-extern const char *uu_dprintf_getname(uu_dprintf_t *);
-
-/*
- * Identifier test flags and function.
- */
-#define UU_NAME_DOMAIN 0x1 /* allow SUNW, or com.sun, prefix */
-#define UU_NAME_PATH 0x2 /* allow '/'-delimited paths */
-
-int uu_check_name(const char *, uint_t);
-
-/*
- * File creation functions.
- */
-extern int uu_open_tmp(const char *dir, uint_t uflags);
-
-/*
- * Convenience functions.
- */
-#define UU_NELEM(a) (sizeof (a) / sizeof ((a)[0]))
-
-/*PRINTFLIKE1*/
-extern char *uu_msprintf(const char *format, ...);
-extern void *uu_zalloc(size_t);
-extern char *uu_strdup(const char *);
-extern void uu_free(void *);
-
-extern boolean_t uu_strcaseeq(const char *a, const char *b);
-extern boolean_t uu_streq(const char *a, const char *b);
-extern char *uu_strndup(const char *s, size_t n);
-extern boolean_t uu_strbw(const char *a, const char *b);
-extern void *uu_memdup(const void *buf, size_t sz);
-extern void uu_dump(FILE *out, const char *prefix, const void *buf, size_t len);
-
-/*
- * Comparison function type definition.
- * Developers should be careful in their use of the _private argument. If you
- * break interface guarantees, you get undefined behavior.
- */
-typedef int uu_compare_fn_t(const void *__left, const void *__right,
- void *__private);
-
-/*
- * Walk variant flags.
- * A data structure need not provide support for all variants and
- * combinations. Refer to the appropriate documentation.
- */
-#define UU_WALK_ROBUST 0x00000001 /* walk can survive removes */
-#define UU_WALK_REVERSE 0x00000002 /* reverse walk order */
-
-#define UU_WALK_PREORDER 0x00000010 /* walk tree in pre-order */
-#define UU_WALK_POSTORDER 0x00000020 /* walk tree in post-order */
-
-/*
- * Walk callback function return codes.
- */
-#define UU_WALK_ERROR -1
-#define UU_WALK_NEXT 0
-#define UU_WALK_DONE 1
-
-/*
- * Walk callback function type definition.
- */
-typedef int uu_walk_fn_t(void *_elem, void *_private);
-
-/*
- * lists: opaque structures
- */
-typedef struct uu_list_pool uu_list_pool_t;
-typedef struct uu_list uu_list_t;
-
-typedef struct uu_list_node {
- uintptr_t uln_opaque[2];
-} uu_list_node_t;
-
-typedef struct uu_list_walk uu_list_walk_t;
-
-typedef uintptr_t uu_list_index_t;
-
-/*
- * lists: interface
- *
- * basic usage:
- * typedef struct foo {
- * ...
- * uu_list_node_t foo_node;
- * ...
- * } foo_t;
- *
- * static int
- * foo_compare(void *l_arg, void *r_arg, void *private)
- * {
- * foo_t *l = l_arg;
- * foo_t *r = r_arg;
- *
- * if (... l greater than r ...)
- * return (1);
- * if (... l less than r ...)
- * return (-1);
- * return (0);
- * }
- *
- * ...
- * // at initialization time
- * foo_pool = uu_list_pool_create("foo_pool",
- * sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
- * debugging? 0 : UU_AVL_POOL_DEBUG);
- * ...
- */
-uu_list_pool_t *uu_list_pool_create(const char *, size_t, size_t,
- uu_compare_fn_t *, uint32_t);
-#define UU_LIST_POOL_DEBUG 0x00000001
-
-void uu_list_pool_destroy(uu_list_pool_t *);
-
-/*
- * usage:
- *
- * foo_t *a;
- * a = malloc(sizeof(*a));
- * uu_list_node_init(a, &a->foo_list, pool);
- * ...
- * uu_list_node_fini(a, &a->foo_list, pool);
- * free(a);
- */
-void uu_list_node_init(void *, uu_list_node_t *, uu_list_pool_t *);
-void uu_list_node_fini(void *, uu_list_node_t *, uu_list_pool_t *);
-
-uu_list_t *uu_list_create(uu_list_pool_t *, void *_parent, uint32_t);
-#define UU_LIST_DEBUG 0x00000001
-#define UU_LIST_SORTED 0x00000002 /* list is sorted */
-
-void uu_list_destroy(uu_list_t *); /* list must be empty */
-
-size_t uu_list_numnodes(uu_list_t *);
-
-void *uu_list_first(uu_list_t *);
-void *uu_list_last(uu_list_t *);
-
-void *uu_list_next(uu_list_t *, void *);
-void *uu_list_prev(uu_list_t *, void *);
-
-int uu_list_walk(uu_list_t *, uu_walk_fn_t *, void *, uint32_t);
-
-uu_list_walk_t *uu_list_walk_start(uu_list_t *, uint32_t);
-void *uu_list_walk_next(uu_list_walk_t *);
-void uu_list_walk_end(uu_list_walk_t *);
-
-void *uu_list_find(uu_list_t *, void *, void *, uu_list_index_t *);
-void uu_list_insert(uu_list_t *, void *, uu_list_index_t);
-
-void *uu_list_nearest_next(uu_list_t *, uu_list_index_t);
-void *uu_list_nearest_prev(uu_list_t *, uu_list_index_t);
-
-void *uu_list_teardown(uu_list_t *, void **);
-
-void uu_list_remove(uu_list_t *, void *);
-
-/*
- * lists: interfaces for non-sorted lists only
- */
-int uu_list_insert_before(uu_list_t *, void *_target, void *_elem);
-int uu_list_insert_after(uu_list_t *, void *_target, void *_elem);
-
-/*
- * avl trees: opaque structures
- */
-typedef struct uu_avl_pool uu_avl_pool_t;
-typedef struct uu_avl uu_avl_t;
-
-typedef struct uu_avl_node {
-#ifdef _LP64
- uintptr_t uan_opaque[3];
-#else
- uintptr_t uan_opaque[4];
-#endif
-} uu_avl_node_t;
-
-typedef struct uu_avl_walk uu_avl_walk_t;
-
-typedef uintptr_t uu_avl_index_t;
-
-/*
- * avl trees: interface
- *
- * basic usage:
- * typedef struct foo {
- * ...
- * uu_avl_node_t foo_node;
- * ...
- * } foo_t;
- *
- * static int
- * foo_compare(void *l_arg, void *r_arg, void *private)
- * {
- * foo_t *l = l_arg;
- * foo_t *r = r_arg;
- *
- * if (... l greater than r ...)
- * return (1);
- * if (... l less than r ...)
- * return (-1);
- * return (0);
- * }
- *
- * ...
- * // at initialization time
- * foo_pool = uu_avl_pool_create("foo_pool",
- * sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
- * debugging? 0 : UU_AVL_POOL_DEBUG);
- * ...
- */
-uu_avl_pool_t *uu_avl_pool_create(const char *, size_t, size_t,
- uu_compare_fn_t *, uint32_t);
-#define UU_AVL_POOL_DEBUG 0x00000001
-
-void uu_avl_pool_destroy(uu_avl_pool_t *);
-
-/*
- * usage:
- *
- * foo_t *a;
- * a = malloc(sizeof(*a));
- * uu_avl_node_init(a, &a->foo_avl, pool);
- * ...
- * uu_avl_node_fini(a, &a->foo_avl, pool);
- * free(a);
- */
-void uu_avl_node_init(void *, uu_avl_node_t *, uu_avl_pool_t *);
-void uu_avl_node_fini(void *, uu_avl_node_t *, uu_avl_pool_t *);
-
-uu_avl_t *uu_avl_create(uu_avl_pool_t *, void *_parent, uint32_t);
-#define UU_AVL_DEBUG 0x00000001
-
-void uu_avl_destroy(uu_avl_t *); /* list must be empty */
-
-size_t uu_avl_numnodes(uu_avl_t *);
-
-void *uu_avl_first(uu_avl_t *);
-void *uu_avl_last(uu_avl_t *);
-
-void *uu_avl_next(uu_avl_t *, void *);
-void *uu_avl_prev(uu_avl_t *, void *);
-
-int uu_avl_walk(uu_avl_t *, uu_walk_fn_t *, void *, uint32_t);
-
-uu_avl_walk_t *uu_avl_walk_start(uu_avl_t *, uint32_t);
-void *uu_avl_walk_next(uu_avl_walk_t *);
-void uu_avl_walk_end(uu_avl_walk_t *);
-
-void *uu_avl_find(uu_avl_t *, void *, void *, uu_avl_index_t *);
-void uu_avl_insert(uu_avl_t *, void *, uu_avl_index_t);
-
-void *uu_avl_nearest_next(uu_avl_t *, uu_avl_index_t);
-void *uu_avl_nearest_prev(uu_avl_t *, uu_avl_index_t);
-
-void *uu_avl_teardown(uu_avl_t *, void **);
-
-void uu_avl_remove(uu_avl_t *, void *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBUUTIL_H */
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h
deleted file mode 100644
index 9ebaaedfd237..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _LIBUUTIL_COMMON_H
-#define _LIBUUTIL_COMMON_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <libuutil.h>
-#include <libuutil_impl.h>
-
-#endif /* _LIBUUTIL_COMMON_H */
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h b/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h
deleted file mode 100644
index 9466e5974581..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _LIBUUTIL_IMPL_H
-#define _LIBUUTIL_IMPL_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <libuutil.h>
-#include <pthread.h>
-
-#include <sys/avl_impl.h>
-#include <sys/byteorder.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void uu_set_error(uint_t);
-#pragma rarely_called(uu_set_error)
-
-/*PRINTFLIKE1*/
-void uu_panic(const char *format, ...);
-#pragma rarely_called(uu_panic)
-
-struct uu_dprintf {
- char *uud_name;
- uu_dprintf_severity_t uud_severity;
- uint_t uud_flags;
-};
-
-/*
- * For debugging purposes, libuutil keeps around linked lists of all uu_lists
- * and uu_avls, along with pointers to their parents. These can cause false
- * negatives when looking for memory leaks, so we encode the pointers by
- * storing them with swapped endianness; this is not perfect, but it's about
- * the best we can do without wasting a lot of space.
- */
-#ifdef _LP64
-#define UU_PTR_ENCODE(ptr) BSWAP_64((uintptr_t)(void *)(ptr))
-#else
-#define UU_PTR_ENCODE(ptr) BSWAP_32((uintptr_t)(void *)(ptr))
-#endif
-
-#define UU_PTR_DECODE(ptr) ((void *)UU_PTR_ENCODE(ptr))
-
-/*
- * uu_list structures
- */
-typedef struct uu_list_node_impl {
- struct uu_list_node_impl *uln_next;
- struct uu_list_node_impl *uln_prev;
-} uu_list_node_impl_t;
-
-struct uu_list_walk {
- uu_list_walk_t *ulw_next;
- uu_list_walk_t *ulw_prev;
-
- uu_list_t *ulw_list;
- int8_t ulw_dir;
- uint8_t ulw_robust;
- uu_list_node_impl_t *ulw_next_result;
-};
-
-struct uu_list {
- uintptr_t ul_next_enc;
- uintptr_t ul_prev_enc;
-
- uu_list_pool_t *ul_pool;
- uintptr_t ul_parent_enc; /* encoded parent pointer */
- size_t ul_offset;
- size_t ul_numnodes;
- uint8_t ul_debug;
- uint8_t ul_sorted;
- uint8_t ul_index; /* mark for uu_list_index_ts */
-
- uu_list_node_impl_t ul_null_node;
- uu_list_walk_t ul_null_walk; /* for robust walkers */
-};
-
-#define UU_LIST_PTR(ptr) ((uu_list_t *)UU_PTR_DECODE(ptr))
-
-#define UU_LIST_POOL_MAXNAME 64
-
-struct uu_list_pool {
- uu_list_pool_t *ulp_next;
- uu_list_pool_t *ulp_prev;
-
- char ulp_name[UU_LIST_POOL_MAXNAME];
- size_t ulp_nodeoffset;
- size_t ulp_objsize;
- uu_compare_fn_t *ulp_cmp;
- uint8_t ulp_debug;
- uint8_t ulp_last_index;
- pthread_mutex_t ulp_lock; /* protects null_list */
- uu_list_t ulp_null_list;
-};
-
-/*
- * uu_avl structures
- */
-typedef struct avl_node uu_avl_node_impl_t;
-
-struct uu_avl_walk {
- uu_avl_walk_t *uaw_next;
- uu_avl_walk_t *uaw_prev;
-
- uu_avl_t *uaw_avl;
- void *uaw_next_result;
- int8_t uaw_dir;
- uint8_t uaw_robust;
-};
-
-struct uu_avl {
- uintptr_t ua_next_enc;
- uintptr_t ua_prev_enc;
-
- uu_avl_pool_t *ua_pool;
- uintptr_t ua_parent_enc;
- uint8_t ua_debug;
- uint8_t ua_index; /* mark for uu_avl_index_ts */
-
- struct avl_tree ua_tree;
- uu_avl_walk_t ua_null_walk;
-};
-
-#define UU_AVL_PTR(x) ((uu_avl_t *)UU_PTR_DECODE(x))
-
-#define UU_AVL_POOL_MAXNAME 64
-
-struct uu_avl_pool {
- uu_avl_pool_t *uap_next;
- uu_avl_pool_t *uap_prev;
-
- char uap_name[UU_AVL_POOL_MAXNAME];
- size_t uap_nodeoffset;
- size_t uap_objsize;
- uu_compare_fn_t *uap_cmp;
- uint8_t uap_debug;
- uint8_t uap_last_index;
- pthread_mutex_t uap_lock; /* protects null_avl */
- uu_avl_t uap_null_avl;
-};
-
-/*
- * atfork() handlers
- */
-void uu_avl_lockup(void);
-void uu_avl_release(void);
-
-void uu_list_lockup(void);
-void uu_list_release(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBUUTIL_IMPL_H */
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c
deleted file mode 100644
index 2bef759d525e..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include "libuutil_common.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-void *
-uu_zalloc(size_t n)
-{
- void *p = malloc(n);
-
- if (p == NULL) {
- uu_set_error(UU_ERROR_SYSTEM);
- return (NULL);
- }
-
- (void) memset(p, 0, n);
-
- return (p);
-}
-
-void
-uu_free(void *p)
-{
- free(p);
-}
-
-char *
-uu_strdup(const char *str)
-{
- char *buf = NULL;
-
- if (str != NULL) {
- size_t sz;
-
- sz = strlen(str) + 1;
- buf = uu_zalloc(sz);
- if (buf != NULL)
- (void) memcpy(buf, str, sz);
- }
- return (buf);
-}
-
-/*
- * Duplicate up to n bytes of a string. Kind of sort of like
- * strdup(strlcpy(s, n)).
- */
-char *
-uu_strndup(const char *s, size_t n)
-{
- size_t len;
- char *p;
-
- len = strnlen(s, n);
- p = uu_zalloc(len + 1);
- if (p == NULL)
- return (NULL);
-
- if (len > 0)
- (void) memcpy(p, s, len);
- p[len] = '\0';
-
- return (p);
-}
-
-/*
- * Duplicate a block of memory. Combines malloc with memcpy, much as
- * strdup combines malloc, strlen, and strcpy.
- */
-void *
-uu_memdup(const void *buf, size_t sz)
-{
- void *p;
-
- p = uu_zalloc(sz);
- if (p == NULL)
- return (NULL);
- (void) memcpy(p, buf, sz);
- return (p);
-}
-
-char *
-uu_msprintf(const char *format, ...)
-{
- va_list args;
- char attic[1];
- uint_t M, m;
- char *b;
-
- va_start(args, format);
- M = vsnprintf(attic, 1, format, args);
- va_end(args);
-
- for (;;) {
- m = M;
- if ((b = uu_zalloc(m + 1)) == NULL)
- return (NULL);
-
- va_start(args, format);
- M = vsnprintf(b, m + 1, format, args);
- va_end(args);
-
- if (M == m)
- break; /* sizes match */
-
- uu_free(b);
- }
-
- return (b);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
deleted file mode 100644
index 5e78ececeec9..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libuutil_common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/avl.h>
-
-static uu_avl_pool_t uu_null_apool = { &uu_null_apool, &uu_null_apool };
-static pthread_mutex_t uu_apool_list_lock = PTHREAD_MUTEX_INITIALIZER;
-
-/*
- * The index mark change on every insert and delete, to catch stale
- * references.
- *
- * We leave the low bit alone, since the avl code uses it.
- */
-#define INDEX_MAX (sizeof (uintptr_t) - 2)
-#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 2 : ((m) + 2) & INDEX_MAX)
-
-#define INDEX_DECODE(i) ((i) & ~INDEX_MAX)
-#define INDEX_ENCODE(p, n) (((n) & ~INDEX_MAX) | (p)->ua_index)
-#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ua_index)
-#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
-
-/*
- * When an element is inactive (not in a tree), we keep a marked pointer to
- * its containing pool in its first word, and a NULL pointer in its second.
- *
- * On insert, we use these to verify that it comes from the correct pool.
- */
-#define NODE_ARRAY(p, n) ((uintptr_t *)((uintptr_t)(n) + \
- (pp)->uap_nodeoffset))
-
-#define POOL_TO_MARKER(pp) (((uintptr_t)(pp) | 1))
-
-#define DEAD_MARKER 0xc4
-
-uu_avl_pool_t *
-uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset,
- uu_compare_fn_t *compare_func, uint32_t flags)
-{
- uu_avl_pool_t *pp, *next, *prev;
-
- if (name == NULL ||
- uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
- nodeoffset + sizeof (uu_avl_node_t) > objsize ||
- compare_func == NULL) {
- uu_set_error(UU_ERROR_INVALID_ARGUMENT);
- return (NULL);
- }
-
- if (flags & ~UU_AVL_POOL_DEBUG) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (NULL);
- }
-
- pp = uu_zalloc(sizeof (uu_avl_pool_t));
- if (pp == NULL) {
- uu_set_error(UU_ERROR_NO_MEMORY);
- return (NULL);
- }
-
- (void) strlcpy(pp->uap_name, name, sizeof (pp->uap_name));
- pp->uap_nodeoffset = nodeoffset;
- pp->uap_objsize = objsize;
- pp->uap_cmp = compare_func;
- if (flags & UU_AVL_POOL_DEBUG)
- pp->uap_debug = 1;
- pp->uap_last_index = 0;
-
- (void) pthread_mutex_init(&pp->uap_lock, NULL);
-
- pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
- pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
-
- (void) pthread_mutex_lock(&uu_apool_list_lock);
- pp->uap_next = next = &uu_null_apool;
- pp->uap_prev = prev = next->uap_prev;
- next->uap_prev = pp;
- prev->uap_next = pp;
- (void) pthread_mutex_unlock(&uu_apool_list_lock);
-
- return (pp);
-}
-
-void
-uu_avl_pool_destroy(uu_avl_pool_t *pp)
-{
- if (pp->uap_debug) {
- if (pp->uap_null_avl.ua_next_enc !=
- UU_PTR_ENCODE(&pp->uap_null_avl) ||
- pp->uap_null_avl.ua_prev_enc !=
- UU_PTR_ENCODE(&pp->uap_null_avl)) {
- uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has "
- "outstanding avls, or is corrupt.\n",
- (int)sizeof (pp->uap_name), pp->uap_name,
- (void *)pp);
- }
- }
- (void) pthread_mutex_lock(&uu_apool_list_lock);
- pp->uap_next->uap_prev = pp->uap_prev;
- pp->uap_prev->uap_next = pp->uap_next;
- (void) pthread_mutex_unlock(&uu_apool_list_lock);
- (void) pthread_mutex_destroy(&pp->uap_lock);
- pp->uap_prev = NULL;
- pp->uap_next = NULL;
- uu_free(pp);
-}
-
-void
-uu_avl_node_init(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
-{
- uintptr_t *na = (uintptr_t *)np;
-
- if (pp->uap_debug) {
- uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
- if (offset + sizeof (*np) > pp->uap_objsize) {
- uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
- "offset %ld doesn't fit in object (size %ld)\n",
- base, (void *)np, (void *)pp, pp->uap_name,
- (long)offset, (long)pp->uap_objsize);
- }
- if (offset != pp->uap_nodeoffset) {
- uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
- "offset %ld doesn't match pool's offset (%ld)\n",
- base, (void *)np, (void *)pp, pp->uap_name,
- (long)offset, (long)pp->uap_objsize);
- }
- }
-
- na[0] = POOL_TO_MARKER(pp);
- na[1] = 0;
-}
-
-void
-uu_avl_node_fini(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
-{
- uintptr_t *na = (uintptr_t *)np;
-
- if (pp->uap_debug) {
- if (na[0] == DEAD_MARKER && na[1] == DEAD_MARKER) {
- uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
- "node already finied\n",
- base, (void *)np, (void *)pp, pp->uap_name);
- }
- if (na[0] != POOL_TO_MARKER(pp) || na[1] != 0) {
- uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
- "node corrupt, in tree, or in different pool\n",
- base, (void *)np, (void *)pp, pp->uap_name);
- }
- }
-
- na[0] = DEAD_MARKER;
- na[1] = DEAD_MARKER;
- na[2] = DEAD_MARKER;
-}
-
-struct uu_avl_node_compare_info {
- uu_compare_fn_t *ac_compare;
- void *ac_private;
- void *ac_right;
- void *ac_found;
-};
-
-static int
-uu_avl_node_compare(const void *l, const void *r)
-{
- struct uu_avl_node_compare_info *info =
- (struct uu_avl_node_compare_info *)l;
-
- int res = info->ac_compare(r, info->ac_right, info->ac_private);
-
- if (res == 0) {
- if (info->ac_found == NULL)
- info->ac_found = (void *)r;
- return (-1);
- }
- if (res < 0)
- return (1);
- return (-1);
-}
-
-uu_avl_t *
-uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
-{
- uu_avl_t *ap, *next, *prev;
-
- if (flags & ~UU_AVL_DEBUG) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (NULL);
- }
-
- ap = uu_zalloc(sizeof (*ap));
- if (ap == NULL) {
- uu_set_error(UU_ERROR_NO_MEMORY);
- return (NULL);
- }
-
- ap->ua_pool = pp;
- ap->ua_parent_enc = UU_PTR_ENCODE(parent);
- ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG);
- ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index));
-
- avl_create(&ap->ua_tree, &uu_avl_node_compare, pp->uap_objsize,
- pp->uap_nodeoffset);
-
- ap->ua_null_walk.uaw_next = &ap->ua_null_walk;
- ap->ua_null_walk.uaw_prev = &ap->ua_null_walk;
-
- (void) pthread_mutex_lock(&pp->uap_lock);
- next = &pp->uap_null_avl;
- prev = UU_PTR_DECODE(next->ua_prev_enc);
- ap->ua_next_enc = UU_PTR_ENCODE(next);
- ap->ua_prev_enc = UU_PTR_ENCODE(prev);
- next->ua_prev_enc = UU_PTR_ENCODE(ap);
- prev->ua_next_enc = UU_PTR_ENCODE(ap);
- (void) pthread_mutex_unlock(&pp->uap_lock);
-
- return (ap);
-}
-
-void
-uu_avl_destroy(uu_avl_t *ap)
-{
- uu_avl_pool_t *pp = ap->ua_pool;
-
- if (ap->ua_debug) {
- if (avl_numnodes(&ap->ua_tree) != 0) {
- uu_panic("uu_avl_destroy(%p): tree not empty\n",
- (void *)ap);
- }
- if (ap->ua_null_walk.uaw_next != &ap->ua_null_walk ||
- ap->ua_null_walk.uaw_prev != &ap->ua_null_walk) {
- uu_panic("uu_avl_destroy(%p): outstanding walkers\n",
- (void *)ap);
- }
- }
- (void) pthread_mutex_lock(&pp->uap_lock);
- UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc;
- UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc;
- (void) pthread_mutex_unlock(&pp->uap_lock);
- ap->ua_prev_enc = UU_PTR_ENCODE(NULL);
- ap->ua_next_enc = UU_PTR_ENCODE(NULL);
-
- ap->ua_pool = NULL;
- avl_destroy(&ap->ua_tree);
-
- uu_free(ap);
-}
-
-size_t
-uu_avl_numnodes(uu_avl_t *ap)
-{
- return (avl_numnodes(&ap->ua_tree));
-}
-
-void *
-uu_avl_first(uu_avl_t *ap)
-{
- return (avl_first(&ap->ua_tree));
-}
-
-void *
-uu_avl_last(uu_avl_t *ap)
-{
- return (avl_last(&ap->ua_tree));
-}
-
-void *
-uu_avl_next(uu_avl_t *ap, void *node)
-{
- return (AVL_NEXT(&ap->ua_tree, node));
-}
-
-void *
-uu_avl_prev(uu_avl_t *ap, void *node)
-{
- return (AVL_PREV(&ap->ua_tree, node));
-}
-
-static void
-_avl_walk_init(uu_avl_walk_t *wp, uu_avl_t *ap, uint32_t flags)
-{
- uu_avl_walk_t *next, *prev;
-
- int robust = (flags & UU_WALK_ROBUST);
- int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
-
- (void) memset(wp, 0, sizeof (*wp));
- wp->uaw_avl = ap;
- wp->uaw_robust = robust;
- wp->uaw_dir = direction;
-
- if (direction > 0)
- wp->uaw_next_result = avl_first(&ap->ua_tree);
- else
- wp->uaw_next_result = avl_last(&ap->ua_tree);
-
- if (ap->ua_debug || robust) {
- wp->uaw_next = next = &ap->ua_null_walk;
- wp->uaw_prev = prev = next->uaw_prev;
- next->uaw_prev = wp;
- prev->uaw_next = wp;
- }
-}
-
-static void *
-_avl_walk_advance(uu_avl_walk_t *wp, uu_avl_t *ap)
-{
- void *np = wp->uaw_next_result;
-
- avl_tree_t *t = &ap->ua_tree;
-
- if (np == NULL)
- return (NULL);
-
- wp->uaw_next_result = (wp->uaw_dir > 0)? AVL_NEXT(t, np) :
- AVL_PREV(t, np);
-
- return (np);
-}
-
-static void
-_avl_walk_fini(uu_avl_walk_t *wp)
-{
- if (wp->uaw_next != NULL) {
- wp->uaw_next->uaw_prev = wp->uaw_prev;
- wp->uaw_prev->uaw_next = wp->uaw_next;
- wp->uaw_next = NULL;
- wp->uaw_prev = NULL;
- }
- wp->uaw_avl = NULL;
- wp->uaw_next_result = NULL;
-}
-
-uu_avl_walk_t *
-uu_avl_walk_start(uu_avl_t *ap, uint32_t flags)
-{
- uu_avl_walk_t *wp;
-
- if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (NULL);
- }
-
- wp = uu_zalloc(sizeof (*wp));
- if (wp == NULL) {
- uu_set_error(UU_ERROR_NO_MEMORY);
- return (NULL);
- }
-
- _avl_walk_init(wp, ap, flags);
- return (wp);
-}
-
-void *
-uu_avl_walk_next(uu_avl_walk_t *wp)
-{
- return (_avl_walk_advance(wp, wp->uaw_avl));
-}
-
-void
-uu_avl_walk_end(uu_avl_walk_t *wp)
-{
- _avl_walk_fini(wp);
- uu_free(wp);
-}
-
-int
-uu_avl_walk(uu_avl_t *ap, uu_walk_fn_t *func, void *private, uint32_t flags)
-{
- void *e;
- uu_avl_walk_t my_walk;
-
- int status = UU_WALK_NEXT;
-
- if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (-1);
- }
-
- _avl_walk_init(&my_walk, ap, flags);
- while (status == UU_WALK_NEXT &&
- (e = _avl_walk_advance(&my_walk, ap)) != NULL)
- status = (*func)(e, private);
- _avl_walk_fini(&my_walk);
-
- if (status >= 0)
- return (0);
- uu_set_error(UU_ERROR_CALLBACK_FAILED);
- return (-1);
-}
-
-void
-uu_avl_remove(uu_avl_t *ap, void *elem)
-{
- uu_avl_walk_t *wp;
- uu_avl_pool_t *pp = ap->ua_pool;
- uintptr_t *na = NODE_ARRAY(pp, elem);
-
- if (ap->ua_debug) {
- /*
- * invalidate outstanding uu_avl_index_ts.
- */
- ap->ua_index = INDEX_NEXT(ap->ua_index);
- }
-
- /*
- * Robust walkers most be advanced, if we are removing the node
- * they are currently using. In debug mode, non-robust walkers
- * are also on the walker list.
- */
- for (wp = ap->ua_null_walk.uaw_next; wp != &ap->ua_null_walk;
- wp = wp->uaw_next) {
- if (wp->uaw_robust) {
- if (elem == wp->uaw_next_result)
- (void) _avl_walk_advance(wp, ap);
- } else if (wp->uaw_next_result != NULL) {
- uu_panic("uu_avl_remove(%p, %p): active non-robust "
- "walker\n", (void *)ap, elem);
- }
- }
-
- avl_remove(&ap->ua_tree, elem);
-
- na[0] = POOL_TO_MARKER(pp);
- na[1] = 0;
-}
-
-void *
-uu_avl_teardown(uu_avl_t *ap, void **cookie)
-{
- void *elem = avl_destroy_nodes(&ap->ua_tree, cookie);
-
- if (elem != NULL) {
- uu_avl_pool_t *pp = ap->ua_pool;
- uintptr_t *na = NODE_ARRAY(pp, elem);
-
- na[0] = POOL_TO_MARKER(pp);
- na[1] = 0;
- }
- return (elem);
-}
-
-void *
-uu_avl_find(uu_avl_t *ap, void *elem, void *private, uu_avl_index_t *out)
-{
- struct uu_avl_node_compare_info info;
- void *result;
-
- info.ac_compare = ap->ua_pool->uap_cmp;
- info.ac_private = private;
- info.ac_right = elem;
- info.ac_found = NULL;
-
- result = avl_find(&ap->ua_tree, &info, out);
- if (out != NULL)
- *out = INDEX_ENCODE(ap, *out);
-
- if (ap->ua_debug && result != NULL)
- uu_panic("uu_avl_find: internal error: avl_find succeeded\n");
-
- return (info.ac_found);
-}
-
-void
-uu_avl_insert(uu_avl_t *ap, void *elem, uu_avl_index_t idx)
-{
- if (ap->ua_debug) {
- uu_avl_pool_t *pp = ap->ua_pool;
- uintptr_t *na = NODE_ARRAY(pp, elem);
-
- if (na[1] != 0)
- uu_panic("uu_avl_insert(%p, %p, %p): node already "
- "in tree, or corrupt\n",
- (void *)ap, elem, (void *)idx);
- if (na[0] == 0)
- uu_panic("uu_avl_insert(%p, %p, %p): node not "
- "initialized\n",
- (void *)ap, elem, (void *)idx);
- if (na[0] != POOL_TO_MARKER(pp))
- uu_panic("uu_avl_insert(%p, %p, %p): node from "
- "other pool, or corrupt\n",
- (void *)ap, elem, (void *)idx);
-
- if (!INDEX_VALID(ap, idx))
- uu_panic("uu_avl_insert(%p, %p, %p): %s\n",
- (void *)ap, elem, (void *)idx,
- INDEX_CHECK(idx)? "outdated index" :
- "invalid index");
-
- /*
- * invalidate outstanding uu_avl_index_ts.
- */
- ap->ua_index = INDEX_NEXT(ap->ua_index);
- }
- avl_insert(&ap->ua_tree, elem, INDEX_DECODE(idx));
-}
-
-void *
-uu_avl_nearest_next(uu_avl_t *ap, uu_avl_index_t idx)
-{
- if (ap->ua_debug && !INDEX_VALID(ap, idx))
- uu_panic("uu_avl_nearest_next(%p, %p): %s\n",
- (void *)ap, (void *)idx, INDEX_CHECK(idx)?
- "outdated index" : "invalid index");
- return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_AFTER));
-}
-
-void *
-uu_avl_nearest_prev(uu_avl_t *ap, uu_avl_index_t idx)
-{
- if (ap->ua_debug && !INDEX_VALID(ap, idx))
- uu_panic("uu_avl_nearest_prev(%p, %p): %s\n",
- (void *)ap, (void *)idx, INDEX_CHECK(idx)?
- "outdated index" : "invalid index");
- return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_BEFORE));
-}
-
-/*
- * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
- */
-void
-uu_avl_lockup(void)
-{
- uu_avl_pool_t *pp;
-
- (void) pthread_mutex_lock(&uu_apool_list_lock);
- for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
- pp = pp->uap_next)
- (void) pthread_mutex_lock(&pp->uap_lock);
-}
-
-void
-uu_avl_release(void)
-{
- uu_avl_pool_t *pp;
-
- for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
- pp = pp->uap_next)
- (void) pthread_mutex_unlock(&pp->uap_lock);
- (void) pthread_mutex_unlock(&uu_apool_list_lock);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c
deleted file mode 100644
index 528c3e7f6d25..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libuutil_common.h"
-
-#include <errno.h>
-#include <libintl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define FACILITY_FMT "%s (%s): "
-
-#if !defined(TEXT_DOMAIN)
-#define TEXT_DOMAIN "SYS_TEST"
-#endif
-
-static const char *
-strseverity(uu_dprintf_severity_t severity)
-{
- switch (severity) {
- case UU_DPRINTF_SILENT:
- return (dgettext(TEXT_DOMAIN, "silent"));
- case UU_DPRINTF_FATAL:
- return (dgettext(TEXT_DOMAIN, "FATAL"));
- case UU_DPRINTF_WARNING:
- return (dgettext(TEXT_DOMAIN, "WARNING"));
- case UU_DPRINTF_NOTICE:
- return (dgettext(TEXT_DOMAIN, "note"));
- case UU_DPRINTF_INFO:
- return (dgettext(TEXT_DOMAIN, "info"));
- case UU_DPRINTF_DEBUG:
- return (dgettext(TEXT_DOMAIN, "debug"));
- default:
- return (dgettext(TEXT_DOMAIN, "unspecified"));
- }
-}
-
-uu_dprintf_t *
-uu_dprintf_create(const char *name, uu_dprintf_severity_t severity,
- uint_t flags)
-{
- uu_dprintf_t *D;
-
- if (uu_check_name(name, UU_NAME_DOMAIN) == -1) {
- uu_set_error(UU_ERROR_INVALID_ARGUMENT);
- return (NULL);
- }
-
- if ((D = uu_zalloc(sizeof (uu_dprintf_t))) == NULL)
- return (NULL);
-
- if (name != NULL) {
- D->uud_name = strdup(name);
- if (D->uud_name == NULL) {
- uu_free(D);
- return (NULL);
- }
- } else {
- D->uud_name = NULL;
- }
-
- D->uud_severity = severity;
- D->uud_flags = flags;
-
- return (D);
-}
-
-/*PRINTFLIKE3*/
-void
-uu_dprintf(uu_dprintf_t *D, uu_dprintf_severity_t severity,
- const char *format, ...)
-{
- va_list alist;
-
- /* XXX Assert that severity is not UU_DPRINTF_SILENT. */
-
- if (severity > D->uud_severity)
- return;
-
- (void) fprintf(stderr, FACILITY_FMT, D->uud_name,
- strseverity(severity));
-
- va_start(alist, format);
- (void) vfprintf(stderr, format, alist);
- va_end(alist);
-}
-
-void
-uu_dprintf_destroy(uu_dprintf_t *D)
-{
- if (D->uud_name)
- free(D->uud_name);
-
- uu_free(D);
-}
-
-const char *
-uu_dprintf_getname(uu_dprintf_t *D)
-{
- return (D->uud_name);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c
deleted file mode 100644
index 9a643845f8c2..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libuutil_common.h"
-
-#include <string.h>
-
-/*
- * We require names of the form:
- * [provider,]identifier[/[provider,]identifier]...
- *
- * Where provider is either a stock symbol (SUNW) or a java-style reversed
- * domain name (com.sun).
- *
- * Both providers and identifiers must start with a letter, and may
- * only contain alphanumerics, dashes, and underlines. Providers
- * may also contain periods.
- *
- * Note that we do _not_ use the macros in <ctype.h>, since they are affected
- * by the current locale settings.
- */
-
-#define IS_ALPHA(c) \
- (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
-
-#define IS_DIGIT(c) \
- ((c) >= '0' && (c) <= '9')
-
-static int
-is_valid_ident(const char *s, const char *e, int allowdot)
-{
- char c;
-
- if (s >= e)
- return (0); /* name is empty */
-
- c = *s++;
- if (!IS_ALPHA(c))
- return (0); /* does not start with letter */
-
- while (s < e && (c = *s++) != 0) {
- if (IS_ALPHA(c) || IS_DIGIT(c) || c == '-' || c == '_' ||
- (allowdot && c == '.'))
- continue;
- return (0); /* invalid character */
- }
- return (1);
-}
-
-static int
-is_valid_component(const char *b, const char *e, uint_t flags)
-{
- char *sp;
-
- if (flags & UU_NAME_DOMAIN) {
- sp = strchr(b, ',');
- if (sp != NULL && sp < e) {
- if (!is_valid_ident(b, sp, 1))
- return (0);
- b = sp + 1;
- }
- }
-
- return (is_valid_ident(b, e, 0));
-}
-
-int
-uu_check_name(const char *name, uint_t flags)
-{
- const char *end = name + strlen(name);
- const char *p;
-
- if (flags & ~(UU_NAME_DOMAIN | UU_NAME_PATH)) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (-1);
- }
-
- if (!(flags & UU_NAME_PATH)) {
- if (!is_valid_component(name, end, flags))
- goto bad;
- return (0);
- }
-
- while ((p = strchr(name, '/')) != NULL) {
- if (!is_valid_component(name, p - 1, flags))
- goto bad;
- name = p + 1;
- }
- if (!is_valid_component(name, end, flags))
- goto bad;
-
- return (0);
-
-bad:
- uu_set_error(UU_ERROR_INVALID_ARGUMENT);
- return (-1);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c
deleted file mode 100644
index 35c7ba800103..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c
+++ /dev/null
@@ -1,718 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libuutil_common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/time.h>
-
-#define ELEM_TO_NODE(lp, e) \
- ((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
-
-#define NODE_TO_ELEM(lp, n) \
- ((void *)((uintptr_t)(n) - (lp)->ul_offset))
-
-/*
- * uu_list_index_ts define a location for insertion. They are simply a
- * pointer to the object after the insertion point. We store a mark
- * in the low-bits of the index, to help prevent mistakes.
- *
- * When debugging, the index mark changes on every insert and delete, to
- * catch stale references.
- */
-#define INDEX_MAX (sizeof (uintptr_t) - 1)
-#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
-
-#define INDEX_TO_NODE(i) ((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
-#define NODE_TO_INDEX(p, n) (((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
-#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ul_index)
-#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
-
-#define POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
-
-static uu_list_pool_t uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
-static pthread_mutex_t uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
-
-uu_list_pool_t *
-uu_list_pool_create(const char *name, size_t objsize,
- size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
-{
- uu_list_pool_t *pp, *next, *prev;
-
- if (name == NULL ||
- uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
- nodeoffset + sizeof (uu_list_node_t) > objsize) {
- uu_set_error(UU_ERROR_INVALID_ARGUMENT);
- return (NULL);
- }
-
- if (flags & ~UU_LIST_POOL_DEBUG) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (NULL);
- }
-
- pp = uu_zalloc(sizeof (uu_list_pool_t));
- if (pp == NULL) {
- uu_set_error(UU_ERROR_NO_MEMORY);
- return (NULL);
- }
-
- (void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
- pp->ulp_nodeoffset = nodeoffset;
- pp->ulp_objsize = objsize;
- pp->ulp_cmp = compare_func;
- if (flags & UU_LIST_POOL_DEBUG)
- pp->ulp_debug = 1;
- pp->ulp_last_index = 0;
-
- (void) pthread_mutex_init(&pp->ulp_lock, NULL);
-
- pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
- pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
-
- (void) pthread_mutex_lock(&uu_lpool_list_lock);
- pp->ulp_next = next = &uu_null_lpool;
- pp->ulp_prev = prev = next->ulp_prev;
- next->ulp_prev = pp;
- prev->ulp_next = pp;
- (void) pthread_mutex_unlock(&uu_lpool_list_lock);
-
- return (pp);
-}
-
-void
-uu_list_pool_destroy(uu_list_pool_t *pp)
-{
- if (pp->ulp_debug) {
- if (pp->ulp_null_list.ul_next_enc !=
- UU_PTR_ENCODE(&pp->ulp_null_list) ||
- pp->ulp_null_list.ul_prev_enc !=
- UU_PTR_ENCODE(&pp->ulp_null_list)) {
- uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
- "outstanding lists, or is corrupt.\n",
- (int)sizeof (pp->ulp_name), pp->ulp_name,
- (void *)pp);
- }
- }
- (void) pthread_mutex_lock(&uu_lpool_list_lock);
- pp->ulp_next->ulp_prev = pp->ulp_prev;
- pp->ulp_prev->ulp_next = pp->ulp_next;
- (void) pthread_mutex_unlock(&uu_lpool_list_lock);
- pp->ulp_prev = NULL;
- pp->ulp_next = NULL;
- uu_free(pp);
-}
-
-void
-uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
-{
- uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
-
- if (pp->ulp_debug) {
- uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
- if (offset + sizeof (*np) > pp->ulp_objsize) {
- uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
- "offset %ld doesn't fit in object (size %ld)\n",
- base, (void *)np, (void *)pp, pp->ulp_name,
- (long)offset, (long)pp->ulp_objsize);
- }
- if (offset != pp->ulp_nodeoffset) {
- uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
- "offset %ld doesn't match pool's offset (%ld)\n",
- base, (void *)np, (void *)pp, pp->ulp_name,
- (long)offset, (long)pp->ulp_objsize);
- }
- }
- np->uln_next = POOL_TO_MARKER(pp);
- np->uln_prev = NULL;
-}
-
-void
-uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
-{
- uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
-
- if (pp->ulp_debug) {
- if (np->uln_next == NULL &&
- np->uln_prev == NULL) {
- uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
- "node already finied\n",
- base, (void *)np_arg, (void *)pp, pp->ulp_name);
- }
- if (np->uln_next != POOL_TO_MARKER(pp) ||
- np->uln_prev != NULL) {
- uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
- "node corrupt or on list\n",
- base, (void *)np_arg, (void *)pp, pp->ulp_name);
- }
- }
- np->uln_next = NULL;
- np->uln_prev = NULL;
-}
-
-uu_list_t *
-uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
-{
- uu_list_t *lp, *next, *prev;
-
- if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (NULL);
- }
-
- if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
- if (pp->ulp_debug)
- uu_panic("uu_list_create(%p, ...): requested "
- "UU_LIST_SORTED, but pool has no comparison func\n",
- (void *)pp);
- uu_set_error(UU_ERROR_NOT_SUPPORTED);
- return (NULL);
- }
-
- lp = uu_zalloc(sizeof (*lp));
- if (lp == NULL) {
- uu_set_error(UU_ERROR_NO_MEMORY);
- return (NULL);
- }
-
- lp->ul_pool = pp;
- lp->ul_parent_enc = UU_PTR_ENCODE(parent);
- lp->ul_offset = pp->ulp_nodeoffset;
- lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
- lp->ul_sorted = (flags & UU_LIST_SORTED);
- lp->ul_numnodes = 0;
- lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
-
- lp->ul_null_node.uln_next = &lp->ul_null_node;
- lp->ul_null_node.uln_prev = &lp->ul_null_node;
-
- lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
- lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
-
- (void) pthread_mutex_lock(&pp->ulp_lock);
- next = &pp->ulp_null_list;
- prev = UU_PTR_DECODE(next->ul_prev_enc);
- lp->ul_next_enc = UU_PTR_ENCODE(next);
- lp->ul_prev_enc = UU_PTR_ENCODE(prev);
- next->ul_prev_enc = UU_PTR_ENCODE(lp);
- prev->ul_next_enc = UU_PTR_ENCODE(lp);
- (void) pthread_mutex_unlock(&pp->ulp_lock);
-
- return (lp);
-}
-
-void
-uu_list_destroy(uu_list_t *lp)
-{
- uu_list_pool_t *pp = lp->ul_pool;
-
- if (lp->ul_debug) {
- if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
- lp->ul_null_node.uln_prev != &lp->ul_null_node) {
- uu_panic("uu_list_destroy(%p): list not empty\n",
- (void *)lp);
- }
- if (lp->ul_numnodes != 0) {
- uu_panic("uu_list_destroy(%p): numnodes is nonzero, "
- "but list is empty\n", (void *)lp);
- }
- if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
- lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
- uu_panic("uu_list_destroy(%p): outstanding walkers\n",
- (void *)lp);
- }
- }
-
- (void) pthread_mutex_lock(&pp->ulp_lock);
- UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
- UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
- (void) pthread_mutex_unlock(&pp->ulp_lock);
- lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
- lp->ul_next_enc = UU_PTR_ENCODE(NULL);
- lp->ul_pool = NULL;
- uu_free(lp);
-}
-
-static void
-list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
- uu_list_node_impl_t *next)
-{
- if (lp->ul_debug) {
- if (next->uln_prev != prev || prev->uln_next != next)
- uu_panic("insert(%p): internal error: %p and %p not "
- "neighbors\n", (void *)lp, (void *)next,
- (void *)prev);
-
- if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
- np->uln_prev != NULL) {
- uu_panic("insert(%p): elem %p node %p corrupt, "
- "not initialized, or already in a list.\n",
- (void *)lp, NODE_TO_ELEM(lp, np), (void *)np);
- }
- /*
- * invalidate outstanding uu_list_index_ts.
- */
- lp->ul_index = INDEX_NEXT(lp->ul_index);
- }
- np->uln_next = next;
- np->uln_prev = prev;
- next->uln_prev = np;
- prev->uln_next = np;
-
- lp->ul_numnodes++;
-}
-
-void
-uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
-{
- uu_list_node_impl_t *np;
-
- np = INDEX_TO_NODE(idx);
- if (np == NULL)
- np = &lp->ul_null_node;
-
- if (lp->ul_debug) {
- if (!INDEX_VALID(lp, idx))
- uu_panic("uu_list_insert(%p, %p, %p): %s\n",
- (void *)lp, elem, (void *)idx,
- INDEX_CHECK(idx)? "outdated index" :
- "invalid index");
- if (np->uln_prev == NULL)
- uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
- "index\n", (void *)lp, elem, (void *)idx);
- }
-
- list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
-}
-
-void *
-uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
-{
- int sorted = lp->ul_sorted;
- uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
- uu_list_node_impl_t *np;
-
- if (func == NULL) {
- if (out != NULL)
- *out = 0;
- uu_set_error(UU_ERROR_NOT_SUPPORTED);
- return (NULL);
- }
- for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
- np = np->uln_next) {
- void *ep = NODE_TO_ELEM(lp, np);
- int cmp = func(ep, elem, private);
- if (cmp == 0) {
- if (out != NULL)
- *out = NODE_TO_INDEX(lp, np);
- return (ep);
- }
- if (sorted && cmp > 0) {
- if (out != NULL)
- *out = NODE_TO_INDEX(lp, np);
- return (NULL);
- }
- }
- if (out != NULL)
- *out = NODE_TO_INDEX(lp, 0);
- return (NULL);
-}
-
-void *
-uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
-{
- uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
-
- if (np == NULL)
- np = &lp->ul_null_node;
-
- if (lp->ul_debug) {
- if (!INDEX_VALID(lp, idx))
- uu_panic("uu_list_nearest_next(%p, %p): %s\n",
- (void *)lp, (void *)idx,
- INDEX_CHECK(idx)? "outdated index" :
- "invalid index");
- if (np->uln_prev == NULL)
- uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
- "index\n", (void *)lp, (void *)idx);
- }
-
- if (np == &lp->ul_null_node)
- return (NULL);
- else
- return (NODE_TO_ELEM(lp, np));
-}
-
-void *
-uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
-{
- uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
-
- if (np == NULL)
- np = &lp->ul_null_node;
-
- if (lp->ul_debug) {
- if (!INDEX_VALID(lp, idx))
- uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
- (void *)lp, (void *)idx, INDEX_CHECK(idx)?
- "outdated index" : "invalid index");
- if (np->uln_prev == NULL)
- uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
- "index\n", (void *)lp, (void *)idx);
- }
-
- if ((np = np->uln_prev) == &lp->ul_null_node)
- return (NULL);
- else
- return (NODE_TO_ELEM(lp, np));
-}
-
-static void
-list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
-{
- uu_list_walk_t *next, *prev;
-
- int robust = (flags & UU_WALK_ROBUST);
- int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
-
- (void) memset(wp, 0, sizeof (*wp));
- wp->ulw_list = lp;
- wp->ulw_robust = robust;
- wp->ulw_dir = direction;
- if (direction > 0)
- wp->ulw_next_result = lp->ul_null_node.uln_next;
- else
- wp->ulw_next_result = lp->ul_null_node.uln_prev;
-
- if (lp->ul_debug || robust) {
- /*
- * Add this walker to the list's list of walkers so
- * uu_list_remove() can advance us if somebody tries to
- * remove ulw_next_result.
- */
- wp->ulw_next = next = &lp->ul_null_walk;
- wp->ulw_prev = prev = next->ulw_prev;
- next->ulw_prev = wp;
- prev->ulw_next = wp;
- }
-}
-
-static uu_list_node_impl_t *
-list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
-{
- uu_list_node_impl_t *np = wp->ulw_next_result;
- uu_list_node_impl_t *next;
-
- if (np == &lp->ul_null_node)
- return (NULL);
-
- next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
-
- wp->ulw_next_result = next;
- return (np);
-}
-
-static void
-list_walk_fini(uu_list_walk_t *wp)
-{
- /* GLXXX debugging? */
- if (wp->ulw_next != NULL) {
- wp->ulw_next->ulw_prev = wp->ulw_prev;
- wp->ulw_prev->ulw_next = wp->ulw_next;
- wp->ulw_next = NULL;
- wp->ulw_prev = NULL;
- }
- wp->ulw_list = NULL;
- wp->ulw_next_result = NULL;
-}
-
-uu_list_walk_t *
-uu_list_walk_start(uu_list_t *lp, uint32_t flags)
-{
- uu_list_walk_t *wp;
-
- if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (NULL);
- }
-
- wp = uu_zalloc(sizeof (*wp));
- if (wp == NULL) {
- uu_set_error(UU_ERROR_NO_MEMORY);
- return (NULL);
- }
-
- list_walk_init(wp, lp, flags);
- return (wp);
-}
-
-void *
-uu_list_walk_next(uu_list_walk_t *wp)
-{
- uu_list_t *lp = wp->ulw_list;
- uu_list_node_impl_t *np = list_walk_advance(wp, lp);
-
- if (np == NULL)
- return (NULL);
-
- return (NODE_TO_ELEM(lp, np));
-}
-
-void
-uu_list_walk_end(uu_list_walk_t *wp)
-{
- list_walk_fini(wp);
- uu_free(wp);
-}
-
-int
-uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
-{
- uu_list_node_impl_t *np;
-
- int status = UU_WALK_NEXT;
-
- int robust = (flags & UU_WALK_ROBUST);
- int reverse = (flags & UU_WALK_REVERSE);
-
- if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
- uu_set_error(UU_ERROR_UNKNOWN_FLAG);
- return (-1);
- }
-
- if (lp->ul_debug || robust) {
- uu_list_walk_t my_walk;
- void *e;
-
- list_walk_init(&my_walk, lp, flags);
- while (status == UU_WALK_NEXT &&
- (e = uu_list_walk_next(&my_walk)) != NULL)
- status = (*func)(e, private);
- list_walk_fini(&my_walk);
- } else {
- if (!reverse) {
- for (np = lp->ul_null_node.uln_next;
- status == UU_WALK_NEXT && np != &lp->ul_null_node;
- np = np->uln_next) {
- status = (*func)(NODE_TO_ELEM(lp, np), private);
- }
- } else {
- for (np = lp->ul_null_node.uln_prev;
- status == UU_WALK_NEXT && np != &lp->ul_null_node;
- np = np->uln_prev) {
- status = (*func)(NODE_TO_ELEM(lp, np), private);
- }
- }
- }
- if (status >= 0)
- return (0);
- uu_set_error(UU_ERROR_CALLBACK_FAILED);
- return (-1);
-}
-
-void
-uu_list_remove(uu_list_t *lp, void *elem)
-{
- uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
- uu_list_walk_t *wp;
-
- if (lp->ul_debug) {
- if (np->uln_prev == NULL)
- uu_panic("uu_list_remove(%p, %p): elem not on list\n",
- (void *)lp, elem);
- /*
- * invalidate outstanding uu_list_index_ts.
- */
- lp->ul_index = INDEX_NEXT(lp->ul_index);
- }
-
- /*
- * robust walkers must be advanced. In debug mode, non-robust
- * walkers are also on the list. If there are any, it's an error.
- */
- for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
- wp = wp->ulw_next) {
- if (wp->ulw_robust) {
- if (np == wp->ulw_next_result)
- (void) list_walk_advance(wp, lp);
- } else if (wp->ulw_next_result != NULL) {
- uu_panic("uu_list_remove(%p, %p): active non-robust "
- "walker\n", (void *)lp, elem);
- }
- }
-
- np->uln_next->uln_prev = np->uln_prev;
- np->uln_prev->uln_next = np->uln_next;
-
- lp->ul_numnodes--;
-
- np->uln_next = POOL_TO_MARKER(lp->ul_pool);
- np->uln_prev = NULL;
-}
-
-void *
-uu_list_teardown(uu_list_t *lp, void **cookie)
-{
- void *ep;
-
- /*
- * XXX: disable list modification until list is empty
- */
- if (lp->ul_debug && *cookie != NULL)
- uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n",
- (void *)lp, (void *)cookie);
-
- ep = uu_list_first(lp);
- if (ep)
- uu_list_remove(lp, ep);
- return (ep);
-}
-
-int
-uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
-{
- uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
-
- if (target == NULL)
- np = &lp->ul_null_node;
-
- if (lp->ul_debug) {
- if (np->uln_prev == NULL)
- uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
- "not currently on a list\n",
- (void *)lp, target, elem, target);
- }
- if (lp->ul_sorted) {
- if (lp->ul_debug)
- uu_panic("uu_list_insert_before(%p, ...): list is "
- "UU_LIST_SORTED\n", (void *)lp);
- uu_set_error(UU_ERROR_NOT_SUPPORTED);
- return (-1);
- }
-
- list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
- return (0);
-}
-
-int
-uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
-{
- uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
-
- if (target == NULL)
- np = &lp->ul_null_node;
-
- if (lp->ul_debug) {
- if (np->uln_prev == NULL)
- uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
- "not currently on a list\n",
- (void *)lp, target, elem, target);
- }
- if (lp->ul_sorted) {
- if (lp->ul_debug)
- uu_panic("uu_list_insert_after(%p, ...): list is "
- "UU_LIST_SORTED\n", (void *)lp);
- uu_set_error(UU_ERROR_NOT_SUPPORTED);
- return (-1);
- }
-
- list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
- return (0);
-}
-
-size_t
-uu_list_numnodes(uu_list_t *lp)
-{
- return (lp->ul_numnodes);
-}
-
-void *
-uu_list_first(uu_list_t *lp)
-{
- uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
- if (n == &lp->ul_null_node)
- return (NULL);
- return (NODE_TO_ELEM(lp, n));
-}
-
-void *
-uu_list_last(uu_list_t *lp)
-{
- uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
- if (n == &lp->ul_null_node)
- return (NULL);
- return (NODE_TO_ELEM(lp, n));
-}
-
-void *
-uu_list_next(uu_list_t *lp, void *elem)
-{
- uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
-
- n = n->uln_next;
- if (n == &lp->ul_null_node)
- return (NULL);
- return (NODE_TO_ELEM(lp, n));
-}
-
-void *
-uu_list_prev(uu_list_t *lp, void *elem)
-{
- uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
-
- n = n->uln_prev;
- if (n == &lp->ul_null_node)
- return (NULL);
- return (NODE_TO_ELEM(lp, n));
-}
-
-/*
- * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
- */
-void
-uu_list_lockup(void)
-{
- uu_list_pool_t *pp;
-
- (void) pthread_mutex_lock(&uu_lpool_list_lock);
- for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
- pp = pp->ulp_next)
- (void) pthread_mutex_lock(&pp->ulp_lock);
-}
-
-void
-uu_list_release(void)
-{
- uu_list_pool_t *pp;
-
- for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
- pp = pp->ulp_next)
- (void) pthread_mutex_unlock(&pp->ulp_lock);
- (void) pthread_mutex_unlock(&uu_lpool_list_lock);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c
deleted file mode 100644
index b673834e4dcf..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include "libuutil_common.h"
-
-#define HAVE_ASSFAIL 1
-
-#include <assert.h>
-#include <errno.h>
-#include <libintl.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/debug.h>
-#include <thread.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#if !defined(TEXT_DOMAIN)
-#define TEXT_DOMAIN "SYS_TEST"
-#endif
-
-/*
- * All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
- * is here to enable the building of a native version of
- * libuutil.so when the build machine has not yet been upgraded
- * to a version of libc that provides pthread_key_create_once_np().
- * It should all be deleted when solaris_nevada ships.
- * The code is not MT-safe in a relaxed memory model.
- */
-
-#if defined(PTHREAD_ONCE_KEY_NP)
-static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP;
-#else /* PTHREAD_ONCE_KEY_NP */
-static pthread_key_t uu_error_key = 0;
-static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif /* PTHREAD_ONCE_KEY_NP */
-
-static int uu_error_key_setup = 0;
-
-static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
-/* LINTED static unused */
-static const char *uu_panic_format;
-/* LINTED static unused */
-static va_list uu_panic_args;
-static pthread_t uu_panic_thread;
-
-static uint32_t _uu_main_error;
-
-void
-uu_set_error(uint_t code)
-{
-
-#if defined(PTHREAD_ONCE_KEY_NP)
- if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
- uu_error_key_setup = -1;
- else
- uu_error_key_setup = 1;
-#else /* PTHREAD_ONCE_KEY_NP */
- if (uu_error_key_setup == 0) {
- (void) pthread_mutex_lock(&uu_key_lock);
- if (uu_error_key_setup == 0) {
- if (pthread_key_create(&uu_error_key, NULL) != 0)
- uu_error_key_setup = -1;
- else
- uu_error_key_setup = 1;
- }
- (void) pthread_mutex_unlock(&uu_key_lock);
- }
-#endif /* PTHREAD_ONCE_KEY_NP */
- if (uu_error_key_setup > 0)
- (void) pthread_setspecific(uu_error_key,
- (void *)(uintptr_t)code);
-}
-
-uint32_t
-uu_error(void)
-{
-
- if (uu_error_key_setup < 0) /* can't happen? */
- return (UU_ERROR_UNKNOWN);
-
- /*
- * Because UU_ERROR_NONE == 0, if uu_set_error() was
- * never called, then this will return UU_ERROR_NONE:
- */
- return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
-}
-
-const char *
-uu_strerror(uint32_t code)
-{
- const char *str;
-
- switch (code) {
- case UU_ERROR_NONE:
- str = dgettext(TEXT_DOMAIN, "No error");
- break;
-
- case UU_ERROR_INVALID_ARGUMENT:
- str = dgettext(TEXT_DOMAIN, "Invalid argument");
- break;
-
- case UU_ERROR_UNKNOWN_FLAG:
- str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
- break;
-
- case UU_ERROR_NO_MEMORY:
- str = dgettext(TEXT_DOMAIN, "Out of memory");
- break;
-
- case UU_ERROR_CALLBACK_FAILED:
- str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
- break;
-
- case UU_ERROR_NOT_SUPPORTED:
- str = dgettext(TEXT_DOMAIN, "Operation not supported");
- break;
-
- case UU_ERROR_EMPTY:
- str = dgettext(TEXT_DOMAIN, "No value provided");
- break;
-
- case UU_ERROR_UNDERFLOW:
- str = dgettext(TEXT_DOMAIN, "Value too small");
- break;
-
- case UU_ERROR_OVERFLOW:
- str = dgettext(TEXT_DOMAIN, "Value too large");
- break;
-
- case UU_ERROR_INVALID_CHAR:
- str = dgettext(TEXT_DOMAIN,
- "Value contains unexpected character");
- break;
-
- case UU_ERROR_INVALID_DIGIT:
- str = dgettext(TEXT_DOMAIN,
- "Value contains digit not in base");
- break;
-
- case UU_ERROR_SYSTEM:
- str = dgettext(TEXT_DOMAIN, "Underlying system error");
- break;
-
- case UU_ERROR_UNKNOWN:
- str = dgettext(TEXT_DOMAIN, "Error status not known");
- break;
-
- default:
- errno = ESRCH;
- str = NULL;
- break;
- }
- return (str);
-}
-
-void
-uu_panic(const char *format, ...)
-{
- va_list args;
-
- va_start(args, format);
-
- (void) pthread_mutex_lock(&uu_panic_lock);
- if (uu_panic_thread == 0) {
- uu_panic_thread = pthread_self();
- uu_panic_format = format;
- va_copy(uu_panic_args, args);
- }
- (void) pthread_mutex_unlock(&uu_panic_lock);
-
- (void) vfprintf(stderr, format, args);
-
- if (uu_panic_thread == pthread_self())
- abort();
- else
- for (;;)
- (void) pause();
-}
-
-int
-assfail(const char *astring, const char *file, int line)
-{
- __assert(astring, file, line);
- /*NOTREACHED*/
- return (0);
-}
-
-static void
-uu_lockup(void)
-{
- (void) pthread_mutex_lock(&uu_panic_lock);
-#if !defined(PTHREAD_ONCE_KEY_NP)
- (void) pthread_mutex_lock(&uu_key_lock);
-#endif
- uu_avl_lockup();
- uu_list_lockup();
-}
-
-static void
-uu_release(void)
-{
- (void) pthread_mutex_unlock(&uu_panic_lock);
-#if !defined(PTHREAD_ONCE_KEY_NP)
- (void) pthread_mutex_unlock(&uu_key_lock);
-#endif
- uu_avl_release();
- uu_list_release();
-}
-
-static void
-uu_release_child(void)
-{
- uu_panic_format = NULL;
- uu_panic_thread = 0;
-
- uu_release();
-}
-
-#pragma init(uu_init)
-static void
-uu_init(void)
-{
- (void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
-}
-
-/*
- * Dump a block of memory in hex+ascii, for debugging
- */
-void
-uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
-{
- const unsigned char *p = buf;
- int i;
-
- for (i = 0; i < len; i += 16) {
- int j;
-
- (void) fprintf(out, "%s", prefix);
- for (j = 0; j < 16 && i + j < len; j++) {
- (void) fprintf(out, "%2.2x ", p[i + j]);
- }
- for (; j < 16; j++) {
- (void) fprintf(out, " ");
- }
- for (j = 0; j < 16 && i + j < len; j++) {
- (void) fprintf(out, "%c",
- isprint(p[i + j]) ? p[i + j] : '.');
- }
- (void) fprintf(out, "\n");
- }
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c
deleted file mode 100644
index 7256662e38f6..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libuutil_common.h"
-
-#include <sys/time.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#ifdef _LP64
-#define TMPPATHFMT "%s/uu%ld"
-#else /* _LP64 */
-#define TMPPATHFMT "%s/uu%lld"
-#endif /* _LP64 */
-
-/*ARGSUSED*/
-int
-uu_open_tmp(const char *dir, uint_t uflags)
-{
- int f;
- char *fname = uu_zalloc(PATH_MAX);
-
- if (fname == NULL)
- return (-1);
-
- for (;;) {
- (void) snprintf(fname, PATH_MAX, "%s/uu%lld", dir, gethrtime());
-
- f = open(fname, O_CREAT | O_EXCL | O_RDWR, 0600);
-
- if (f >= 0 || errno != EEXIST)
- break;
- }
-
- if (f >= 0)
- (void) unlink(fname);
-
- uu_free(fname);
-
- return (f);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c
deleted file mode 100644
index 20626ace6b2f..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libuutil_common.h"
-
-#include <libintl.h>
-#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <errno.h>
-#include <wchar.h>
-#include <unistd.h>
-
-static const char PNAME_FMT[] = "%s: ";
-static const char ERRNO_FMT[] = ": %s\n";
-
-static const char *pname;
-
-static void
-uu_die_internal(int status, const char *format, va_list alist) __NORETURN;
-
-int uu_exit_ok_value = EXIT_SUCCESS;
-int uu_exit_fatal_value = EXIT_FAILURE;
-int uu_exit_usage_value = 2;
-
-int *
-uu_exit_ok(void)
-{
- return (&uu_exit_ok_value);
-}
-
-int *
-uu_exit_fatal(void)
-{
- return (&uu_exit_fatal_value);
-}
-
-int *
-uu_exit_usage(void)
-{
- return (&uu_exit_usage_value);
-}
-
-void
-uu_alt_exit(int profile)
-{
- switch (profile) {
- case UU_PROFILE_DEFAULT:
- uu_exit_ok_value = EXIT_SUCCESS;
- uu_exit_fatal_value = EXIT_FAILURE;
- uu_exit_usage_value = 2;
- break;
- case UU_PROFILE_LAUNCHER:
- uu_exit_ok_value = EXIT_SUCCESS;
- uu_exit_fatal_value = 124;
- uu_exit_usage_value = 125;
- break;
- }
-}
-
-static void
-uu_warn_internal(int err, const char *format, va_list alist)
-{
- if (pname != NULL)
- (void) fprintf(stderr, PNAME_FMT, pname);
-
- (void) vfprintf(stderr, format, alist);
-
- if (strrchr(format, '\n') == NULL)
- (void) fprintf(stderr, ERRNO_FMT, strerror(err));
-}
-
-void
-uu_vwarn(const char *format, va_list alist)
-{
- uu_warn_internal(errno, format, alist);
-}
-
-/*PRINTFLIKE1*/
-void
-uu_warn(const char *format, ...)
-{
- va_list alist;
- va_start(alist, format);
- uu_warn_internal(errno, format, alist);
- va_end(alist);
-}
-
-static void
-uu_die_internal(int status, const char *format, va_list alist)
-{
- uu_warn_internal(errno, format, alist);
-#ifdef DEBUG
- {
- char *cp;
-
- if (!issetugid()) {
- cp = getenv("UU_DIE_ABORTS");
- if (cp != NULL && *cp != '\0')
- abort();
- }
- }
-#endif
- exit(status);
-}
-
-void
-uu_vdie(const char *format, va_list alist)
-{
- uu_die_internal(UU_EXIT_FATAL, format, alist);
-}
-
-/*PRINTFLIKE1*/
-void
-uu_die(const char *format, ...)
-{
- va_list alist;
- va_start(alist, format);
- uu_die_internal(UU_EXIT_FATAL, format, alist);
- va_end(alist);
-}
-
-void
-uu_vxdie(int status, const char *format, va_list alist)
-{
- uu_die_internal(status, format, alist);
-}
-
-/*PRINTFLIKE2*/
-void
-uu_xdie(int status, const char *format, ...)
-{
- va_list alist;
- va_start(alist, format);
- uu_die_internal(status, format, alist);
- va_end(alist);
-}
-
-const char *
-uu_setpname(char *arg0)
-{
- /*
- * Having a NULL argv[0], while uncommon, is possible. It
- * makes more sense to handle this event in uu_setpname rather
- * than in each of its consumers.
- */
- if (arg0 == NULL) {
- pname = "unknown_command";
- return (pname);
- }
-
- /*
- * Guard against '/' at end of command invocation.
- */
- for (;;) {
- char *p = strrchr(arg0, '/');
- if (p == NULL) {
- pname = arg0;
- break;
- } else {
- if (*(p + 1) == '\0') {
- *p = '\0';
- continue;
- }
-
- pname = p + 1;
- break;
- }
- }
-
- return (pname);
-}
-
-const char *
-uu_getpname(void)
-{
- return (pname);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c
deleted file mode 100644
index 66afba05e849..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * String helper functions
- */
-
-#include <string.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <ctype.h>
-#include "libuutil.h"
-
-/* Return true if strings are equal */
-boolean_t
-uu_streq(const char *a, const char *b)
-{
- return (strcmp(a, b) == 0);
-}
-
-/* Return true if strings are equal, case-insensitively */
-boolean_t
-uu_strcaseeq(const char *a, const char *b)
-{
- return (strcasecmp(a, b) == 0);
-}
-
-/* Return true if string a Begins With string b */
-boolean_t
-uu_strbw(const char *a, const char *b)
-{
- return (strncmp(a, b, strlen(b)) == 0);
-}
diff --git a/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c b/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c
deleted file mode 100644
index 8fd1148365cb..000000000000
--- a/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include "libuutil_common.h"
-
-#include <limits.h>
-#include <ctype.h>
-
-#define MAX_BASE 36
-
-#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9')
-
-#define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \
- ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A')
-
-static int
-strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign)
-{
- const unsigned char *s = (const unsigned char *)s_arg;
-
- uint64_t val = 0;
- uint64_t multmax;
-
- unsigned c, i;
-
- int neg = 0;
-
- int bad_digit = 0;
- int bad_char = 0;
- int overflow = 0;
-
- if (s == NULL || base == 1 || base > MAX_BASE) {
- uu_set_error(UU_ERROR_INVALID_ARGUMENT);
- return (-1);
- }
-
- while ((c = *s) != 0 && isspace(c))
- s++;
-
- switch (c) {
- case '-':
- if (!sign)
- overflow = 1; /* becomes underflow below */
- neg = 1;
- /*FALLTHRU*/
- case '+':
- c = *++s;
- break;
- default:
- break;
- }
-
- if (c == '\0') {
- uu_set_error(UU_ERROR_EMPTY);
- return (-1);
- }
-
- if (base == 0) {
- if (c != '0')
- base = 10;
- else if (s[1] == 'x' || s[1] == 'X')
- base = 16;
- else
- base = 8;
- }
-
- if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X'))
- c = *(s += 2);
-
- if ((val = CTOI(c)) >= base) {
- if (IS_DIGIT(c))
- bad_digit = 1;
- else
- bad_char = 1;
- val = 0;
- }
-
- multmax = (uint64_t)UINT64_MAX / (uint64_t)base;
-
- for (c = *++s; c != '\0'; c = *++s) {
- if ((i = CTOI(c)) >= base) {
- if (isspace(c))
- break;
- if (IS_DIGIT(c))
- bad_digit = 1;
- else
- bad_char = 1;
- i = 0;
- }
-
- if (val > multmax)
- overflow = 1;
-
- val *= base;
- if ((uint64_t)UINT64_MAX - val < (uint64_t)i)
- overflow = 1;
-
- val += i;
- }
-
- while ((c = *s) != 0) {
- if (!isspace(c))
- bad_char = 1;
- s++;
- }
-
- if (sign) {
- if (neg) {
- if (val > -(uint64_t)INT64_MIN)
- overflow = 1;
- } else {
- if (val > INT64_MAX)
- overflow = 1;
- }
- }
-
- if (neg)
- val = -val;
-
- if (bad_char | bad_digit | overflow) {
- if (bad_char)
- uu_set_error(UU_ERROR_INVALID_CHAR);
- else if (bad_digit)
- uu_set_error(UU_ERROR_INVALID_DIGIT);
- else if (overflow) {
- if (neg)
- uu_set_error(UU_ERROR_UNDERFLOW);
- else
- uu_set_error(UU_ERROR_OVERFLOW);
- }
- return (-1);
- }
-
- *out = val;
- return (0);
-}
-
-int
-uu_strtoint(const char *s, void *v, size_t sz, int base,
- int64_t min, int64_t max)
-{
- uint64_t val_u;
- int64_t val;
-
- if (min > max)
- goto bad_argument;
-
- switch (sz) {
- case 1:
- if (max > INT8_MAX || min < INT8_MIN)
- goto bad_argument;
- break;
- case 2:
- if (max > INT16_MAX || min < INT16_MIN)
- goto bad_argument;
- break;
- case 4:
- if (max > INT32_MAX || min < INT32_MIN)
- goto bad_argument;
- break;
- case 8:
- if (max > INT64_MAX || min < INT64_MIN)
- goto bad_argument;
- break;
- default:
- goto bad_argument;
- }
-
- if (min == 0 && max == 0) {
- min = -(1ULL << (8 * sz - 1));
- max = (1ULL << (8 * sz - 1)) - 1;
- }
-
- if (strtoint(s, &val_u, base, 1) == -1)
- return (-1);
-
- val = (int64_t)val_u;
-
- if (val < min) {
- uu_set_error(UU_ERROR_UNDERFLOW);
- return (-1);
- } else if (val > max) {
- uu_set_error(UU_ERROR_OVERFLOW);
- return (-1);
- }
-
- switch (sz) {
- case 1:
- *(int8_t *)v = val;
- return (0);
- case 2:
- *(int16_t *)v = val;
- return (0);
- case 4:
- *(int32_t *)v = val;
- return (0);
- case 8:
- *(int64_t *)v = val;
- return (0);
- default:
- break; /* fall through to bad_argument */
- }
-
-bad_argument:
- uu_set_error(UU_ERROR_INVALID_ARGUMENT);
- return (-1);
-}
-
-int
-uu_strtouint(const char *s, void *v, size_t sz, int base,
- uint64_t min, uint64_t max)
-{
- uint64_t val;
-
- if (min > max)
- goto bad_argument;
-
- switch (sz) {
- case 1:
- if (max > UINT8_MAX)
- goto bad_argument;
- break;
- case 2:
- if (max > UINT16_MAX)
- goto bad_argument;
- break;
- case 4:
- if (max > UINT32_MAX)
- goto bad_argument;
- break;
- case 8:
- if (max > UINT64_MAX)
- goto bad_argument;
- break;
- default:
- goto bad_argument;
- }
-
- if (min == 0 && max == 0) {
- /* we have to be careful, since << can overflow */
- max = (1ULL << (8 * sz - 1)) * 2 - 1;
- }
-
- if (strtoint(s, &val, base, 0) == -1)
- return (-1);
-
- if (val < min) {
- uu_set_error(UU_ERROR_UNDERFLOW);
- return (-1);
- } else if (val > max) {
- uu_set_error(UU_ERROR_OVERFLOW);
- return (-1);
- }
-
- switch (sz) {
- case 1:
- *(uint8_t *)v = val;
- return (0);
- case 2:
- *(uint16_t *)v = val;
- return (0);
- case 4:
- *(uint32_t *)v = val;
- return (0);
- case 8:
- *(uint64_t *)v = val;
- return (0);
- default:
- break; /* shouldn't happen, fall through */
- }
-
-bad_argument:
- uu_set_error(UU_ERROR_INVALID_ARGUMENT);
- return (-1);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
deleted file mode 100644
index 1899e318d53e..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
+++ /dev/null
@@ -1,894 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
- * Copyright 2019 Joyent, Inc.
- * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
- * Copyright (c) 2013 Steven Hartland. All rights reserved.
- * Copyright (c) 2014 Integros [integros.com]
- * Copyright 2016 Nexenta Systems, Inc.
- * Copyright (c) 2019 Datto Inc.
- */
-
-#ifndef _LIBZFS_H
-#define _LIBZFS_H
-
-#include <assert.h>
-#include <libnvpair.h>
-#include <sys/mnttab.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/varargs.h>
-#include <sys/fs/zfs.h>
-#include <sys/avl.h>
-#include <sys/zfs_ioctl.h>
-#include <libzfs_core.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Miscellaneous ZFS constants
- */
-#define ZFS_MAXPROPLEN MAXPATHLEN
-#define ZPOOL_MAXPROPLEN MAXPATHLEN
-
-/*
- * libzfs errors
- */
-typedef enum zfs_error {
- EZFS_SUCCESS = 0, /* no error -- success */
- EZFS_NOMEM = 2000, /* out of memory */
- EZFS_BADPROP, /* invalid property value */
- EZFS_PROPREADONLY, /* cannot set readonly property */
- EZFS_PROPTYPE, /* property does not apply to dataset type */
- EZFS_PROPNONINHERIT, /* property is not inheritable */
- EZFS_PROPSPACE, /* bad quota or reservation */
- EZFS_BADTYPE, /* dataset is not of appropriate type */
- EZFS_BUSY, /* pool or dataset is busy */
- EZFS_EXISTS, /* pool or dataset already exists */
- EZFS_NOENT, /* no such pool or dataset */
- EZFS_BADSTREAM, /* bad backup stream */
- EZFS_DSREADONLY, /* dataset is readonly */
- EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */
- EZFS_INVALIDNAME, /* invalid dataset name */
- EZFS_BADRESTORE, /* unable to restore to destination */
- EZFS_BADBACKUP, /* backup failed */
- EZFS_BADTARGET, /* bad attach/detach/replace target */
- EZFS_NODEVICE, /* no such device in pool */
- EZFS_BADDEV, /* invalid device to add */
- EZFS_NOREPLICAS, /* no valid replicas */
- EZFS_RESILVERING, /* currently resilvering */
- EZFS_BADVERSION, /* unsupported version */
- EZFS_POOLUNAVAIL, /* pool is currently unavailable */
- EZFS_DEVOVERFLOW, /* too many devices in one vdev */
- EZFS_BADPATH, /* must be an absolute path */
- EZFS_CROSSTARGET, /* rename or clone across pool or dataset */
- EZFS_ZONED, /* used improperly in local zone */
- EZFS_MOUNTFAILED, /* failed to mount dataset */
- EZFS_UMOUNTFAILED, /* failed to unmount dataset */
- EZFS_UNSHARENFSFAILED, /* unshare(1M) failed */
- EZFS_SHARENFSFAILED, /* share(1M) failed */
- EZFS_PERM, /* permission denied */
- EZFS_NOSPC, /* out of space */
- EZFS_FAULT, /* bad address */
- EZFS_IO, /* I/O error */
- EZFS_INTR, /* signal received */
- EZFS_ISSPARE, /* device is a hot spare */
- EZFS_INVALCONFIG, /* invalid vdev configuration */
- EZFS_RECURSIVE, /* recursive dependency */
- EZFS_NOHISTORY, /* no history object */
- EZFS_POOLPROPS, /* couldn't retrieve pool props */
- EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */
- EZFS_POOL_INVALARG, /* invalid argument for this pool operation */
- EZFS_NAMETOOLONG, /* dataset name is too long */
- EZFS_OPENFAILED, /* open of device failed */
- EZFS_NOCAP, /* couldn't get capacity */
- EZFS_LABELFAILED, /* write of label failed */
- EZFS_BADWHO, /* invalid permission who */
- EZFS_BADPERM, /* invalid permission */
- EZFS_BADPERMSET, /* invalid permission set name */
- EZFS_NODELEGATION, /* delegated administration is disabled */
- EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */
- EZFS_SHARESMBFAILED, /* failed to share over smb */
- EZFS_BADCACHE, /* bad cache file */
- EZFS_ISL2CACHE, /* device is for the level 2 ARC */
- EZFS_VDEVNOTSUP, /* unsupported vdev type */
- EZFS_NOTSUP, /* ops not supported on this dataset */
- EZFS_ACTIVE_SPARE, /* pool has active shared spare devices */
- EZFS_UNPLAYED_LOGS, /* log device has unplayed logs */
- EZFS_REFTAG_RELE, /* snapshot release: tag not found */
- EZFS_REFTAG_HOLD, /* snapshot hold: tag already exists */
- EZFS_TAGTOOLONG, /* snapshot hold/rele: tag too long */
- EZFS_PIPEFAILED, /* pipe create failed */
- EZFS_THREADCREATEFAILED, /* thread create failed */
- EZFS_POSTSPLIT_ONLINE, /* onlining a disk after splitting it */
- EZFS_SCRUBBING, /* currently scrubbing */
- EZFS_NO_SCRUB, /* no active scrub */
- EZFS_DIFF, /* general failure of zfs diff */
- EZFS_DIFFDATA, /* bad zfs diff data */
- EZFS_POOLREADONLY, /* pool is in read-only mode */
- EZFS_SCRUB_PAUSED, /* scrub currently paused */
- EZFS_ACTIVE_POOL, /* pool is imported on a different system */
- EZFS_NO_PENDING, /* cannot cancel, no operation is pending */
- EZFS_CHECKPOINT_EXISTS, /* checkpoint exists */
- EZFS_DISCARDING_CHECKPOINT, /* currently discarding a checkpoint */
- EZFS_NO_CHECKPOINT, /* pool has no checkpoint */
- EZFS_DEVRM_IN_PROGRESS, /* a device is currently being removed */
- EZFS_VDEV_TOO_BIG, /* a device is too big to be used */
- EZFS_TOOMANY, /* argument list too long */
- EZFS_INITIALIZING, /* currently initializing */
- EZFS_NO_INITIALIZE, /* no active initialize */
- EZFS_WRONG_PARENT, /* invalid parent dataset (e.g ZVOL) */
- EZFS_IOC_NOTSUPPORTED, /* operation not supported by zfs module */
- EZFS_UNKNOWN
-} zfs_error_t;
-
-/*
- * UEFI boot support parameters. When creating whole disk boot pool,
- * zpool create should allow to create EFI System partition for UEFI boot
- * program. In case of BIOS, the EFI System partition is not used
- * even if it does exist.
- */
-typedef enum zpool_boot_label {
- ZPOOL_NO_BOOT_LABEL = 0,
- ZPOOL_CREATE_BOOT_LABEL,
- ZPOOL_COPY_BOOT_LABEL
-} zpool_boot_label_t;
-
-/*
- * The following data structures are all part
- * of the zfs_allow_t data structure which is
- * used for printing 'allow' permissions.
- * It is a linked list of zfs_allow_t's which
- * then contain avl tree's for user/group/sets/...
- * and each one of the entries in those trees have
- * avl tree's for the permissions they belong to and
- * whether they are local,descendent or local+descendent
- * permissions. The AVL trees are used primarily for
- * sorting purposes, but also so that we can quickly find
- * a given user and or permission.
- */
-typedef struct zfs_perm_node {
- avl_node_t z_node;
- char z_pname[MAXPATHLEN];
-} zfs_perm_node_t;
-
-typedef struct zfs_allow_node {
- avl_node_t z_node;
- char z_key[MAXPATHLEN]; /* name, such as joe */
- avl_tree_t z_localdescend; /* local+descendent perms */
- avl_tree_t z_local; /* local permissions */
- avl_tree_t z_descend; /* descendent permissions */
-} zfs_allow_node_t;
-
-typedef struct zfs_allow {
- struct zfs_allow *z_next;
- char z_setpoint[MAXPATHLEN];
- avl_tree_t z_sets;
- avl_tree_t z_crperms;
- avl_tree_t z_user;
- avl_tree_t z_group;
- avl_tree_t z_everyone;
-} zfs_allow_t;
-
-/*
- * Basic handle types
- */
-typedef struct zfs_handle zfs_handle_t;
-typedef struct zpool_handle zpool_handle_t;
-typedef struct libzfs_handle libzfs_handle_t;
-
-/*
- * Library initialization
- */
-extern libzfs_handle_t *libzfs_init(void);
-extern void libzfs_fini(libzfs_handle_t *);
-
-extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
-extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
-
-extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
-
-extern void zfs_save_arguments(int argc, char **, char *, int);
-extern int zpool_log_history(libzfs_handle_t *, const char *);
-
-extern int libzfs_errno(libzfs_handle_t *);
-extern const char *libzfs_error_action(libzfs_handle_t *);
-extern const char *libzfs_error_description(libzfs_handle_t *);
-extern int zfs_standard_error(libzfs_handle_t *, int, const char *);
-extern void libzfs_mnttab_init(libzfs_handle_t *);
-extern void libzfs_mnttab_fini(libzfs_handle_t *);
-extern void libzfs_mnttab_cache(libzfs_handle_t *, boolean_t);
-extern int libzfs_mnttab_find(libzfs_handle_t *, const char *,
- struct mnttab *);
-extern void libzfs_mnttab_add(libzfs_handle_t *, const char *,
- const char *, const char *);
-extern void libzfs_mnttab_remove(libzfs_handle_t *, const char *);
-
-/*
- * Basic handle functions
- */
-extern zpool_handle_t *zpool_open(libzfs_handle_t *, const char *);
-extern zpool_handle_t *zpool_open_canfail(libzfs_handle_t *, const char *);
-extern void zpool_close(zpool_handle_t *);
-extern const char *zpool_get_name(zpool_handle_t *);
-extern int zpool_get_state(zpool_handle_t *);
-extern const char *zpool_state_to_name(vdev_state_t, vdev_aux_t);
-extern const char *zpool_pool_state_to_name(pool_state_t);
-extern void zpool_free_handles(libzfs_handle_t *);
-extern int zpool_nextboot(libzfs_handle_t *, uint64_t, uint64_t, const char *);
-
-/*
- * Iterate over all active pools in the system.
- */
-typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
-extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
-extern boolean_t zpool_skip_pool(const char *);
-
-/*
- * Functions to create and destroy pools
- */
-extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
- nvlist_t *, nvlist_t *);
-extern int zpool_destroy(zpool_handle_t *, const char *);
-extern int zpool_add(zpool_handle_t *, nvlist_t *);
-
-typedef struct splitflags {
- /* do not split, but return the config that would be split off */
- int dryrun : 1;
-
- /* after splitting, import the pool */
- int import : 1;
- int name_flags;
-} splitflags_t;
-
-/*
- * Functions to manipulate pool and vdev state
- */
-extern int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t);
-extern int zpool_initialize(zpool_handle_t *, pool_initialize_func_t,
- nvlist_t *);
-extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
-extern int zpool_reguid(zpool_handle_t *);
-extern int zpool_reopen(zpool_handle_t *);
-
-extern int zpool_sync_one(zpool_handle_t *, void *);
-
-extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
- vdev_state_t *);
-extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t);
-extern int zpool_vdev_attach(zpool_handle_t *, const char *,
- const char *, nvlist_t *, int);
-extern int zpool_vdev_detach(zpool_handle_t *, const char *);
-extern int zpool_vdev_remove(zpool_handle_t *, const char *);
-extern int zpool_vdev_remove_cancel(zpool_handle_t *);
-extern int zpool_vdev_indirect_size(zpool_handle_t *, const char *, uint64_t *);
-extern int zpool_vdev_split(zpool_handle_t *, char *, nvlist_t **, nvlist_t *,
- splitflags_t);
-
-extern int zpool_vdev_fault(zpool_handle_t *, uint64_t, vdev_aux_t);
-extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t, vdev_aux_t);
-extern int zpool_vdev_clear(zpool_handle_t *, uint64_t);
-
-extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
- boolean_t *, boolean_t *);
-extern nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
- boolean_t *, boolean_t *, boolean_t *);
-extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, const char *,
- zpool_boot_label_t, uint64_t, int *);
-
-/*
- * Functions to manage pool properties
- */
-extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
-extern int zpool_get_prop(zpool_handle_t *, zpool_prop_t, char *,
- size_t proplen, zprop_source_t *, boolean_t);
-extern uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t,
- zprop_source_t *);
-
-extern const char *zpool_prop_to_name(zpool_prop_t);
-extern const char *zpool_prop_values(zpool_prop_t);
-
-/*
- * Pool health statistics.
- */
-typedef enum {
- /*
- * The following correspond to faults as defined in the (fault.fs.zfs.*)
- * event namespace. Each is associated with a corresponding message ID.
- * This must be kept in sync with the zfs_msgid_table in
- * lib/libzfs/libzfs_status.c.
- */
- ZPOOL_STATUS_CORRUPT_CACHE, /* corrupt /kernel/drv/zpool.cache */
- ZPOOL_STATUS_MISSING_DEV_R, /* missing device with replicas */
- ZPOOL_STATUS_MISSING_DEV_NR, /* missing device with no replicas */
- ZPOOL_STATUS_CORRUPT_LABEL_R, /* bad device label with replicas */
- ZPOOL_STATUS_CORRUPT_LABEL_NR, /* bad device label with no replicas */
- ZPOOL_STATUS_BAD_GUID_SUM, /* sum of device guids didn't match */
- ZPOOL_STATUS_CORRUPT_POOL, /* pool metadata is corrupted */
- ZPOOL_STATUS_CORRUPT_DATA, /* data errors in user (meta)data */
- ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
- ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
- ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */
- ZPOOL_STATUS_HOSTID_ACTIVE, /* currently active on another system */
- ZPOOL_STATUS_HOSTID_REQUIRED, /* multihost=on and hostid=0 */
- ZPOOL_STATUS_IO_FAILURE_WAIT, /* failed I/O, failmode 'wait' */
- ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */
- ZPOOL_STATUS_IO_FAILURE_MMP, /* failed MMP, failmode not 'panic' */
- ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */
-
- /*
- * If the pool has unsupported features but can still be opened in
- * read-only mode, its status is ZPOOL_STATUS_UNSUP_FEAT_WRITE. If the
- * pool has unsupported features but cannot be opened at all, its
- * status is ZPOOL_STATUS_UNSUP_FEAT_READ.
- */
- ZPOOL_STATUS_UNSUP_FEAT_READ, /* unsupported features for read */
- ZPOOL_STATUS_UNSUP_FEAT_WRITE, /* unsupported features for write */
-
- /*
- * These faults have no corresponding message ID. At the time we are
- * checking the status, the original reason for the FMA fault (I/O or
- * checksum errors) has been lost.
- */
- ZPOOL_STATUS_FAULTED_DEV_R, /* faulted device with replicas */
- ZPOOL_STATUS_FAULTED_DEV_NR, /* faulted device with no replicas */
-
- /*
- * The following are not faults per se, but still an error possibly
- * requiring administrative attention. There is no corresponding
- * message ID.
- */
- ZPOOL_STATUS_VERSION_OLDER, /* older legacy on-disk version */
- ZPOOL_STATUS_FEAT_DISABLED, /* supported features are disabled */
- ZPOOL_STATUS_RESILVERING, /* device being resilvered */
- ZPOOL_STATUS_OFFLINE_DEV, /* device offline */
- ZPOOL_STATUS_REMOVED_DEV, /* removed device */
- ZPOOL_STATUS_NON_NATIVE_ASHIFT, /* (e.g. 512e dev with ashift of 9) */
-
- /*
- * Finally, the following indicates a healthy pool.
- */
- ZPOOL_STATUS_OK
-} zpool_status_t;
-
-extern zpool_status_t zpool_get_status(zpool_handle_t *, char **);
-extern zpool_status_t zpool_import_status(nvlist_t *, char **);
-extern void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh);
-
-/*
- * Statistics and configuration functions.
- */
-extern nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
-extern nvlist_t *zpool_get_features(zpool_handle_t *);
-extern int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
-extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
-extern boolean_t zpool_is_bootable(zpool_handle_t *);
-
-/*
- * Import and export functions
- */
-extern int zpool_export(zpool_handle_t *, boolean_t, const char *);
-extern int zpool_export_force(zpool_handle_t *, const char *);
-extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
- char *altroot);
-extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
- nvlist_t *, int);
-extern void zpool_print_unsup_feat(nvlist_t *config);
-
-/*
- * Search for pools to import
- */
-
-typedef struct importargs {
- char **path; /* a list of paths to search */
- int paths; /* number of paths to search */
- char *poolname; /* name of a pool to find */
- uint64_t guid; /* guid of a pool to find */
- char *cachefile; /* cachefile to use for import */
- int can_be_active : 1; /* can the pool be active? */
- int unique : 1; /* does 'poolname' already exist? */
- int exists : 1; /* set on return if pool already exists */
- nvlist_t *policy; /* load policy (max txg, rewind, etc.) */
-} importargs_t;
-
-extern nvlist_t *zpool_search_import(libzfs_handle_t *, importargs_t *);
-extern int zpool_tryimport(libzfs_handle_t *hdl, char *target,
- nvlist_t **configp, importargs_t *args);
-
-/* legacy pool search routines */
-extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
-extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
- char *, uint64_t);
-
-/*
- * Miscellaneous pool functions
- */
-struct zfs_cmd;
-
-extern const char *zfs_history_event_names[];
-
-typedef enum {
- VDEV_NAME_PATH = 1 << 0,
- VDEV_NAME_GUID = 1 << 1,
- VDEV_NAME_FOLLOW_LINKS = 1 << 2,
- VDEV_NAME_TYPE_ID = 1 << 3,
-} vdev_name_t;
-
-extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
- int name_flags);
-extern int zpool_upgrade(zpool_handle_t *, uint64_t);
-extern int zpool_get_history(zpool_handle_t *, nvlist_t **, uint64_t *,
- boolean_t *);
-extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
- nvlist_t ***, uint_t *);
-extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
- size_t len);
-extern int zfs_ioctl(libzfs_handle_t *, int request, struct zfs_cmd *);
-extern int zpool_get_physpath(zpool_handle_t *, char *, size_t);
-extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
- nvlist_t *);
-extern int zpool_checkpoint(zpool_handle_t *);
-extern int zpool_discard_checkpoint(zpool_handle_t *);
-
-/*
- * Basic handle manipulations. These functions do not create or destroy the
- * underlying datasets, only the references to them.
- */
-extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
-extern zfs_handle_t *zfs_handle_dup(zfs_handle_t *);
-extern void zfs_close(zfs_handle_t *);
-extern zfs_type_t zfs_get_type(const zfs_handle_t *);
-extern const char *zfs_get_name(const zfs_handle_t *);
-extern zpool_handle_t *zfs_get_pool_handle(const zfs_handle_t *);
-extern const char *zfs_get_pool_name(const zfs_handle_t *);
-
-/*
- * Property management functions. Some functions are shared with the kernel,
- * and are found in sys/fs/zfs.h.
- */
-
-/*
- * zfs dataset property management
- */
-extern const char *zfs_prop_default_string(zfs_prop_t);
-extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
-extern const char *zfs_prop_column_name(zfs_prop_t);
-extern boolean_t zfs_prop_align_right(zfs_prop_t);
-
-extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
- nvlist_t *, uint64_t, zfs_handle_t *, zpool_handle_t *, const char *);
-
-extern const char *zfs_prop_to_name(zfs_prop_t);
-extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
-extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *);
-extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
- zprop_source_t *, char *, size_t, boolean_t);
-extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
- boolean_t);
-extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
- zprop_source_t *, char *, size_t);
-extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
- uint64_t *propvalue);
-extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
- char *propbuf, int proplen, boolean_t literal);
-extern int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
- uint64_t *propvalue);
-extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
- char *propbuf, int proplen, boolean_t literal);
-extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname,
- char *buf, size_t len);
-extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
-extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
-extern const char *zfs_prop_values(zfs_prop_t);
-extern int zfs_prop_is_string(zfs_prop_t prop);
-extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
-extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
-extern nvlist_t *zfs_get_clones_nvl(zfs_handle_t *);
-
-
-typedef struct zprop_list {
- int pl_prop;
- char *pl_user_prop;
- struct zprop_list *pl_next;
- boolean_t pl_all;
- size_t pl_width;
- size_t pl_recvd_width;
- boolean_t pl_fixed;
-} zprop_list_t;
-
-extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t,
- boolean_t);
-extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *);
-
-#define ZFS_MOUNTPOINT_NONE "none"
-#define ZFS_MOUNTPOINT_LEGACY "legacy"
-
-#define ZFS_FEATURE_DISABLED "disabled"
-#define ZFS_FEATURE_ENABLED "enabled"
-#define ZFS_FEATURE_ACTIVE "active"
-
-#define ZFS_UNSUPPORTED_INACTIVE "inactive"
-#define ZFS_UNSUPPORTED_READONLY "readonly"
-
-/*
- * zpool property management
- */
-extern int zpool_expand_proplist(zpool_handle_t *, zprop_list_t **);
-extern int zpool_prop_get_feature(zpool_handle_t *, const char *, char *,
- size_t);
-extern const char *zpool_prop_default_string(zpool_prop_t);
-extern uint64_t zpool_prop_default_numeric(zpool_prop_t);
-extern const char *zpool_prop_column_name(zpool_prop_t);
-extern boolean_t zpool_prop_align_right(zpool_prop_t);
-
-/*
- * Functions shared by zfs and zpool property management.
- */
-extern int zprop_iter(zprop_func func, void *cb, boolean_t show_all,
- boolean_t ordered, zfs_type_t type);
-extern int zprop_get_list(libzfs_handle_t *, char *, zprop_list_t **,
- zfs_type_t);
-extern void zprop_free_list(zprop_list_t *);
-
-#define ZFS_GET_NCOLS 5
-
-typedef enum {
- GET_COL_NONE,
- GET_COL_NAME,
- GET_COL_PROPERTY,
- GET_COL_VALUE,
- GET_COL_RECVD,
- GET_COL_SOURCE
-} zfs_get_column_t;
-
-/*
- * Functions for printing zfs or zpool properties
- */
-typedef struct zprop_get_cbdata {
- int cb_sources;
- zfs_get_column_t cb_columns[ZFS_GET_NCOLS];
- int cb_colwidths[ZFS_GET_NCOLS + 1];
- boolean_t cb_scripted;
- boolean_t cb_literal;
- boolean_t cb_first;
- zprop_list_t *cb_proplist;
- zfs_type_t cb_type;
-} zprop_get_cbdata_t;
-
-void zprop_print_one_property(const char *, zprop_get_cbdata_t *,
- const char *, const char *, zprop_source_t, const char *,
- const char *);
-
-/*
- * Iterator functions.
- */
-typedef int (*zfs_iter_f)(zfs_handle_t *, void *);
-extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
-extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
-extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
-extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
-extern int zfs_iter_snapshots(zfs_handle_t *, boolean_t, zfs_iter_f, void *,
- uint64_t, uint64_t);
-extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *,
- uint64_t, uint64_t);
-extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
-extern int zfs_iter_bookmarks(zfs_handle_t *, zfs_iter_f, void *);
-
-typedef struct get_all_cb {
- zfs_handle_t **cb_handles;
- size_t cb_alloc;
- size_t cb_used;
-} get_all_cb_t;
-
-void zfs_foreach_mountpoint(libzfs_handle_t *, zfs_handle_t **, size_t,
- zfs_iter_f, void*, boolean_t);
-
-void libzfs_add_handle(get_all_cb_t *, zfs_handle_t *);
-
-/*
- * Functions to create and destroy datasets.
- */
-extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
- nvlist_t *);
-extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
-extern int zfs_destroy(zfs_handle_t *, boolean_t);
-extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
-extern int zfs_destroy_snaps_nvl(libzfs_handle_t *, nvlist_t *, boolean_t);
-extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
-extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
-extern int zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps,
- nvlist_t *props);
-extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
-
-typedef struct renameflags {
- /* recursive rename */
- int recurse : 1;
-
- /* don't unmount file systems */
- int nounmount : 1;
-
- /* force unmount file systems */
- int forceunmount : 1;
-} renameflags_t;
-
-extern int zfs_rename(zfs_handle_t *, const char *, const char *,
- renameflags_t flags);
-
-typedef struct sendflags {
- /* print informational messages (ie, -v was specified) */
- boolean_t verbose;
-
- /* recursive send (ie, -R) */
- boolean_t replicate;
-
- /* for incrementals, do all intermediate snapshots */
- boolean_t doall;
-
- /* if dataset is a clone, do incremental from its origin */
- boolean_t fromorigin;
-
- /* do deduplication */
- boolean_t dedup;
-
- /* send properties (ie, -p) */
- boolean_t props;
-
- /* do not send (no-op, ie. -n) */
- boolean_t dryrun;
-
- /* parsable verbose output (ie. -P) */
- boolean_t parsable;
-
- /* show progress (ie. -v) */
- boolean_t progress;
-
- /* large blocks (>128K) are permitted */
- boolean_t largeblock;
-
- /* WRITE_EMBEDDED records of type DATA are permitted */
- boolean_t embed_data;
-
- /* compressed WRITE records are permitted */
- boolean_t compress;
-
- /* show progress as process title(ie. -V) */
- boolean_t progressastitle;
-} sendflags_t;
-
-typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
-
-extern int zfs_send(zfs_handle_t *, const char *, const char *,
- sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
-extern int zfs_send_one(zfs_handle_t *, const char *, int, sendflags_t flags);
-extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
- const char *);
-extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
- const char *token);
-
-extern int zfs_promote(zfs_handle_t *);
-extern int zfs_hold(zfs_handle_t *, const char *, const char *,
- boolean_t, int);
-extern int zfs_hold_nvl(zfs_handle_t *, int, nvlist_t *);
-extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
-extern int zfs_get_holds(zfs_handle_t *, nvlist_t **);
-extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);
-
-typedef int (*zfs_userspace_cb_t)(void *arg, const char *domain,
- uid_t rid, uint64_t space);
-
-extern int zfs_userspace(zfs_handle_t *, zfs_userquota_prop_t,
- zfs_userspace_cb_t, void *);
-
-extern int zfs_get_fsacl(zfs_handle_t *, nvlist_t **);
-extern int zfs_set_fsacl(zfs_handle_t *, boolean_t, nvlist_t *);
-
-typedef struct recvflags {
- /* print informational messages (ie, -v was specified) */
- boolean_t verbose;
-
- /* the destination is a prefix, not the exact fs (ie, -d) */
- boolean_t isprefix;
-
- /*
- * Only the tail of the sent snapshot path is appended to the
- * destination to determine the received snapshot name (ie, -e).
- */
- boolean_t istail;
-
- /* do not actually do the recv, just check if it would work (ie, -n) */
- boolean_t dryrun;
-
- /* rollback/destroy filesystems as necessary (eg, -F) */
- boolean_t force;
-
- /* set "canmount=off" on all modified filesystems */
- boolean_t canmountoff;
-
- /*
- * Mark the file systems as "resumable" and do not destroy them if the
- * receive is interrupted
- */
- boolean_t resumable;
-
- /* byteswap flag is used internally; callers need not specify */
- boolean_t byteswap;
-
- /* do not mount file systems as they are extracted (private) */
- boolean_t nomount;
-
- /* force unmount while recv snapshot (private) */
- boolean_t forceunmount;
-} recvflags_t;
-
-extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
- recvflags_t *, int, avl_tree_t *);
-
-typedef enum diff_flags {
- ZFS_DIFF_PARSEABLE = 0x1,
- ZFS_DIFF_TIMESTAMP = 0x2,
- ZFS_DIFF_CLASSIFY = 0x4
-} diff_flags_t;
-
-extern int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *,
- int);
-
-/*
- * Miscellaneous functions.
- */
-extern const char *zfs_type_to_name(zfs_type_t);
-extern void zfs_refresh_properties(zfs_handle_t *);
-extern int zfs_name_valid(const char *, zfs_type_t);
-extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t);
-extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
- zfs_type_t);
-extern int zfs_spa_version(zfs_handle_t *, int *);
-extern boolean_t zfs_bookmark_exists(const char *path);
-extern ulong_t get_system_hostid(void);
-
-/*
- * Mount support functions.
- */
-extern boolean_t is_mounted(libzfs_handle_t *, const char *special, char **);
-extern boolean_t zfs_is_mounted(zfs_handle_t *, char **);
-extern int zfs_mount(zfs_handle_t *, const char *, int);
-extern int zfs_mount_at(zfs_handle_t *, const char *, int, const char *);
-extern int zfs_unmount(zfs_handle_t *, const char *, int);
-extern int zfs_unmountall(zfs_handle_t *, int);
-
-/*
- * Share support functions.
- */
-extern boolean_t zfs_is_shared(zfs_handle_t *);
-extern int zfs_share(zfs_handle_t *);
-extern int zfs_unshare(zfs_handle_t *);
-
-/*
- * Protocol-specific share support functions.
- */
-extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
-extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **);
-extern int zfs_share_nfs(zfs_handle_t *);
-extern int zfs_share_smb(zfs_handle_t *);
-extern int zfs_shareall(zfs_handle_t *);
-extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
-extern int zfs_unshare_smb(zfs_handle_t *, const char *);
-extern int zfs_unshareall_nfs(zfs_handle_t *);
-extern int zfs_unshareall_smb(zfs_handle_t *);
-extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
-extern int zfs_unshareall(zfs_handle_t *);
-extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *,
- void *, void *, int, zfs_share_op_t);
-
-/*
- * FreeBSD-specific jail support function.
- */
-extern int zfs_jail(zfs_handle_t *, int, int);
-
-/*
- * When dealing with nvlists, verify() is extremely useful
- */
-#ifndef verify
-#ifdef NDEBUG
-#define verify(EX) ((void)(EX))
-#else
-#define verify(EX) assert(EX)
-#endif
-#endif
-
-/*
- * Utility function to convert a number to a human-readable form.
- */
-extern void zfs_nicenum(uint64_t, char *, size_t);
-extern int zfs_nicestrtonum(libzfs_handle_t *, const char *, uint64_t *);
-
-/*
- * Given a device or file, determine if it is part of a pool.
- */
-extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
- boolean_t *);
-
-/*
- * Label manipulation.
- */
-extern int zpool_read_label(int, nvlist_t **);
-extern int zpool_read_all_labels(int, nvlist_t **);
-extern int zpool_clear_label(int);
-extern int zpool_set_bootenv(zpool_handle_t *, const char *);
-extern int zpool_get_bootenv(zpool_handle_t *, char *, size_t, off_t);
-
-/* is this zvol valid for use as a dump device? */
-extern int zvol_check_dump_config(char *);
-
-/*
- * Management interfaces for SMB ACL files
- */
-
-int zfs_smb_acl_add(libzfs_handle_t *, char *, char *, char *);
-int zfs_smb_acl_remove(libzfs_handle_t *, char *, char *, char *);
-int zfs_smb_acl_purge(libzfs_handle_t *, char *, char *);
-int zfs_smb_acl_rename(libzfs_handle_t *, char *, char *, char *, char *);
-
-/*
- * Enable and disable datasets within a pool by mounting/unmounting and
- * sharing/unsharing them.
- */
-extern int zpool_enable_datasets(zpool_handle_t *, const char *, int);
-extern int zpool_disable_datasets(zpool_handle_t *, boolean_t);
-
-/*
- * Mappings between vdev and FRU.
- */
-extern void libzfs_fru_refresh(libzfs_handle_t *);
-extern const char *libzfs_fru_lookup(libzfs_handle_t *, const char *);
-extern const char *libzfs_fru_devpath(libzfs_handle_t *, const char *);
-extern boolean_t libzfs_fru_compare(libzfs_handle_t *, const char *,
- const char *);
-extern boolean_t libzfs_fru_notself(libzfs_handle_t *, const char *);
-extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *);
-
-#ifndef illumos
-extern int zmount(const char *, const char *, int, char *, char *, int, char *,
- int);
-#endif
-extern int zfs_remap_indirects(libzfs_handle_t *hdl, const char *);
-
-/* Allow consumers to initialize libshare externally for optimal performance */
-extern int zfs_init_libshare_arg(libzfs_handle_t *, int, void *);
-/*
- * For most consumers, zfs_init_libshare_arg is sufficient on its own, and
- * zfs_uninit_libshare is unnecessary. zfs_uninit_libshare should only be called
- * if the caller has already initialized libshare for one set of zfs handles,
- * and wishes to share or unshare filesystems outside of that set. In that case,
- * the caller should uninitialize libshare, and then re-initialize it with the
- * new handles being shared or unshared.
- */
-extern void zfs_uninit_libshare(libzfs_handle_t *);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBZFS_H */
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
deleted file mode 100644
index 7bbb68328f29..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- *
- * Portions Copyright 2007 Ramprakash Jelari
- * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
- * All rights reserved.
- * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
- * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
- */
-
-#include <libintl.h>
-#include <libuutil.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <zone.h>
-
-#include <libzfs.h>
-
-#include "libzfs_impl.h"
-
-/*
- * Structure to keep track of dataset state. Before changing the 'sharenfs' or
- * 'mountpoint' property, we record whether the filesystem was previously
- * mounted/shared. This prior state dictates whether we remount/reshare the
- * dataset after the property has been changed.
- *
- * The interface consists of the following sequence of functions:
- *
- * changelist_gather()
- * changelist_prefix()
- * < change property >
- * changelist_postfix()
- * changelist_free()
- *
- * Other interfaces:
- *
- * changelist_remove() - remove a node from a gathered list
- * changelist_rename() - renames all datasets appropriately when doing a rename
- * changelist_unshare() - unshares all the nodes in a given changelist
- * changelist_haszonedchild() - check if there is any child exported to
- * a local zone
- */
-typedef struct prop_changenode {
- zfs_handle_t *cn_handle;
- int cn_shared;
- int cn_mounted;
- int cn_zoned;
- boolean_t cn_needpost; /* is postfix() needed? */
- uu_list_node_t cn_listnode;
-} prop_changenode_t;
-
-struct prop_changelist {
- zfs_prop_t cl_prop;
- zfs_prop_t cl_realprop;
- zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb */
- uu_list_pool_t *cl_pool;
- uu_list_t *cl_list;
- boolean_t cl_waslegacy;
- boolean_t cl_allchildren;
- boolean_t cl_alldependents;
- int cl_mflags; /* Mount flags */
- int cl_gflags; /* Gather request flags */
- boolean_t cl_haszonedchild;
- boolean_t cl_sorted;
-};
-
-/*
- * If the property is 'mountpoint', go through and unmount filesystems as
- * necessary. We don't do the same for 'sharenfs', because we can just re-share
- * with different options without interrupting service. We do handle 'sharesmb'
- * since there may be old resource names that need to be removed.
- */
-int
-changelist_prefix(prop_changelist_t *clp)
-{
- prop_changenode_t *cn;
- int ret = 0;
-
- if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
- clp->cl_prop != ZFS_PROP_SHARESMB)
- return (0);
-
- for (cn = uu_list_first(clp->cl_list); cn != NULL;
- cn = uu_list_next(clp->cl_list, cn)) {
-
- /* if a previous loop failed, set the remaining to false */
- if (ret == -1) {
- cn->cn_needpost = B_FALSE;
- continue;
- }
-
- /*
- * If we are in the global zone, but this dataset is exported
- * to a local zone, do nothing.
- */
- if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
- continue;
-
- if (!ZFS_IS_VOLUME(cn->cn_handle)) {
- /*
- * Do the property specific processing.
- */
- switch (clp->cl_prop) {
- case ZFS_PROP_MOUNTPOINT:
- if (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)
- break;
- if (zfs_unmount(cn->cn_handle, NULL,
- clp->cl_mflags) != 0) {
- ret = -1;
- cn->cn_needpost = B_FALSE;
- }
- break;
- case ZFS_PROP_SHARESMB:
- (void) zfs_unshare_smb(cn->cn_handle, NULL);
- break;
-
- default:
- break;
- }
- }
- }
-
- if (ret == -1)
- (void) changelist_postfix(clp);
-
- return (ret);
-}
-
-/*
- * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
- * reshare the filesystems as necessary. In changelist_gather() we recorded
- * whether the filesystem was previously shared or mounted. The action we take
- * depends on the previous state, and whether the value was previously 'legacy'.
- * For non-legacy properties, we only remount/reshare the filesystem if it was
- * previously mounted/shared. Otherwise, we always remount/reshare the
- * filesystem.
- */
-int
-changelist_postfix(prop_changelist_t *clp)
-{
- prop_changenode_t *cn;
- char shareopts[ZFS_MAXPROPLEN];
- int errors = 0;
- libzfs_handle_t *hdl;
-#ifdef illumos
- size_t num_datasets = 0, i;
- zfs_handle_t **zhandle_arr;
- sa_init_selective_arg_t sharearg;
-#endif
-
- /*
- * If we're changing the mountpoint, attempt to destroy the underlying
- * mountpoint. All other datasets will have inherited from this dataset
- * (in which case their mountpoints exist in the filesystem in the new
- * location), or have explicit mountpoints set (in which case they won't
- * be in the changelist).
- */
- if ((cn = uu_list_last(clp->cl_list)) == NULL)
- return (0);
-
- if (clp->cl_prop == ZFS_PROP_MOUNTPOINT &&
- !(clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)) {
- remove_mountpoint(cn->cn_handle);
- }
-
- /*
- * It is possible that the changelist_prefix() used libshare
- * to unshare some entries. Since libshare caches data, an
- * attempt to reshare during postfix can fail unless libshare
- * is uninitialized here so that it will reinitialize later.
- */
- if (cn->cn_handle != NULL) {
- hdl = cn->cn_handle->zfs_hdl;
- assert(hdl != NULL);
- zfs_uninit_libshare(hdl);
-
-#ifdef illumos
- /*
- * For efficiencies sake, we initialize libshare for only a few
- * shares (the ones affected here). Future initializations in
- * this process should just use the cached initialization.
- */
- for (cn = uu_list_last(clp->cl_list); cn != NULL;
- cn = uu_list_prev(clp->cl_list, cn)) {
- num_datasets++;
- }
-
- zhandle_arr = zfs_alloc(hdl,
- num_datasets * sizeof (zfs_handle_t *));
- for (i = 0, cn = uu_list_last(clp->cl_list); cn != NULL;
- cn = uu_list_prev(clp->cl_list, cn)) {
- zhandle_arr[i++] = cn->cn_handle;
- zfs_refresh_properties(cn->cn_handle);
- }
- assert(i == num_datasets);
- sharearg.zhandle_arr = zhandle_arr;
- sharearg.zhandle_len = num_datasets;
- errors = zfs_init_libshare_arg(hdl, SA_INIT_SHARE_API_SELECTIVE,
- &sharearg);
- free(zhandle_arr);
-#endif
- }
- /*
- * We walk the datasets in reverse, because we want to mount any parent
- * datasets before mounting the children. We walk all datasets even if
- * there are errors.
- */
- for (cn = uu_list_last(clp->cl_list); cn != NULL;
- cn = uu_list_prev(clp->cl_list, cn)) {
-
- boolean_t sharenfs;
- boolean_t sharesmb;
- boolean_t mounted;
-
- /*
- * If we are in the global zone, but this dataset is exported
- * to a local zone, do nothing.
- */
- if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
- continue;
-
- /* Only do post-processing if it's required */
- if (!cn->cn_needpost)
- continue;
- cn->cn_needpost = B_FALSE;
-
-#ifndef illumos
- zfs_refresh_properties(cn->cn_handle);
-#endif
-
- if (ZFS_IS_VOLUME(cn->cn_handle))
- continue;
-
- /*
- * Remount if previously mounted or mountpoint was legacy,
- * or sharenfs or sharesmb property is set.
- */
- sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
- shareopts, sizeof (shareopts), NULL, NULL, 0,
- B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
-
- sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
- shareopts, sizeof (shareopts), NULL, NULL, 0,
- B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
-
- mounted = (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT) ||
- zfs_is_mounted(cn->cn_handle, NULL);
-
- if (!mounted && (cn->cn_mounted ||
- ((sharenfs || sharesmb || clp->cl_waslegacy) &&
- (zfs_prop_get_int(cn->cn_handle,
- ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) {
-
- if (zfs_mount(cn->cn_handle, NULL, 0) != 0)
- errors++;
- else
- mounted = TRUE;
- }
-
- /*
- * If the file system is mounted we always re-share even
- * if the filesystem is currently shared, so that we can
- * adopt any new options.
- */
- if (sharenfs && mounted)
- errors += zfs_share_nfs(cn->cn_handle);
- else if (cn->cn_shared || clp->cl_waslegacy)
- errors += zfs_unshare_nfs(cn->cn_handle, NULL);
- if (sharesmb && mounted)
- errors += zfs_share_smb(cn->cn_handle);
- else if (cn->cn_shared || clp->cl_waslegacy)
- errors += zfs_unshare_smb(cn->cn_handle, NULL);
- }
-
- return (errors ? -1 : 0);
-}
-
-/*
- * Is this "dataset" a child of "parent"?
- */
-boolean_t
-isa_child_of(const char *dataset, const char *parent)
-{
- int len;
-
- len = strlen(parent);
-
- if (strncmp(dataset, parent, len) == 0 &&
- (dataset[len] == '@' || dataset[len] == '/' ||
- dataset[len] == '\0'))
- return (B_TRUE);
- else
- return (B_FALSE);
-
-}
-
-/*
- * If we rename a filesystem, child filesystem handles are no longer valid
- * since we identify each dataset by its name in the ZFS namespace. As a
- * result, we have to go through and fix up all the names appropriately. We
- * could do this automatically if libzfs kept track of all open handles, but
- * this is a lot less work.
- */
-void
-changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
-{
- prop_changenode_t *cn;
- char newname[ZFS_MAX_DATASET_NAME_LEN];
-
- for (cn = uu_list_first(clp->cl_list); cn != NULL;
- cn = uu_list_next(clp->cl_list, cn)) {
- /*
- * Do not rename a clone that's not in the source hierarchy.
- */
- if (!isa_child_of(cn->cn_handle->zfs_name, src))
- continue;
-
- /*
- * Destroy the previous mountpoint if needed.
- */
- remove_mountpoint(cn->cn_handle);
-
- (void) strlcpy(newname, dst, sizeof (newname));
- (void) strcat(newname, cn->cn_handle->zfs_name + strlen(src));
-
- (void) strlcpy(cn->cn_handle->zfs_name, newname,
- sizeof (cn->cn_handle->zfs_name));
- }
-}
-
-/*
- * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property,
- * unshare all the datasets in the list.
- */
-int
-changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto)
-{
- prop_changenode_t *cn;
- int ret = 0;
-
- if (clp->cl_prop != ZFS_PROP_SHARENFS &&
- clp->cl_prop != ZFS_PROP_SHARESMB)
- return (0);
-
- for (cn = uu_list_first(clp->cl_list); cn != NULL;
- cn = uu_list_next(clp->cl_list, cn)) {
- if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0)
- ret = -1;
- }
-
- return (ret);
-}
-
-/*
- * Check if there is any child exported to a local zone in a given changelist.
- * This information has already been recorded while gathering the changelist
- * via changelist_gather().
- */
-int
-changelist_haszonedchild(prop_changelist_t *clp)
-{
- return (clp->cl_haszonedchild);
-}
-
-/*
- * Remove a node from a gathered list.
- */
-void
-changelist_remove(prop_changelist_t *clp, const char *name)
-{
- prop_changenode_t *cn;
-
- for (cn = uu_list_first(clp->cl_list); cn != NULL;
- cn = uu_list_next(clp->cl_list, cn)) {
-
- if (strcmp(cn->cn_handle->zfs_name, name) == 0) {
- uu_list_remove(clp->cl_list, cn);
- zfs_close(cn->cn_handle);
- free(cn);
- return;
- }
- }
-}
-
-/*
- * Release any memory associated with a changelist.
- */
-void
-changelist_free(prop_changelist_t *clp)
-{
- prop_changenode_t *cn;
- void *cookie;
-
- if (clp->cl_list) {
- cookie = NULL;
- while ((cn = uu_list_teardown(clp->cl_list, &cookie)) != NULL) {
- zfs_close(cn->cn_handle);
- free(cn);
- }
-
- uu_list_destroy(clp->cl_list);
- }
- if (clp->cl_pool)
- uu_list_pool_destroy(clp->cl_pool);
-
- free(clp);
-}
-
-static int
-change_one(zfs_handle_t *zhp, void *data)
-{
- prop_changelist_t *clp = data;
- char property[ZFS_MAXPROPLEN];
- char where[64];
- prop_changenode_t *cn;
- zprop_source_t sourcetype;
- zprop_source_t share_sourcetype;
-
- /*
- * We only want to unmount/unshare those filesystems that may inherit
- * from the target filesystem. If we find any filesystem with a
- * locally set mountpoint, we ignore any children since changing the
- * property will not affect them. If this is a rename, we iterate
- * over all children regardless, since we need them unmounted in
- * order to do the rename. Also, if this is a volume and we're doing
- * a rename, then always add it to the changelist.
- */
-
- if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
- zfs_prop_get(zhp, clp->cl_prop, property,
- sizeof (property), &sourcetype, where, sizeof (where),
- B_FALSE) != 0) {
- zfs_close(zhp);
- return (0);
- }
-
- /*
- * If we are "watching" sharenfs or sharesmb
- * then check out the companion property which is tracked
- * in cl_shareprop
- */
- if (clp->cl_shareprop != ZPROP_INVAL &&
- zfs_prop_get(zhp, clp->cl_shareprop, property,
- sizeof (property), &share_sourcetype, where, sizeof (where),
- B_FALSE) != 0) {
- zfs_close(zhp);
- return (0);
- }
-
- if (clp->cl_alldependents || clp->cl_allchildren ||
- sourcetype == ZPROP_SRC_DEFAULT ||
- sourcetype == ZPROP_SRC_INHERITED ||
- (clp->cl_shareprop != ZPROP_INVAL &&
- (share_sourcetype == ZPROP_SRC_DEFAULT ||
- share_sourcetype == ZPROP_SRC_INHERITED))) {
- if ((cn = zfs_alloc(zfs_get_handle(zhp),
- sizeof (prop_changenode_t))) == NULL) {
- zfs_close(zhp);
- return (-1);
- }
-
- cn->cn_handle = zhp;
- cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
- zfs_is_mounted(zhp, NULL);
- cn->cn_shared = zfs_is_shared(zhp);
- cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
- cn->cn_needpost = B_TRUE;
-
- /* Indicate if any child is exported to a local zone. */
- if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
- clp->cl_haszonedchild = B_TRUE;
-
- uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
-
- if (clp->cl_sorted) {
- uu_list_index_t idx;
-
- (void) uu_list_find(clp->cl_list, cn, NULL,
- &idx);
- uu_list_insert(clp->cl_list, cn, idx);
- } else {
- /*
- * Add this child to beginning of the list. Children
- * below this one in the hierarchy will get added above
- * this one in the list. This produces a list in
- * reverse dataset name order.
- * This is necessary when the original mountpoint
- * is legacy or none.
- */
- verify(uu_list_insert_before(clp->cl_list,
- uu_list_first(clp->cl_list), cn) == 0);
- }
-
- if (!clp->cl_alldependents)
- return (zfs_iter_children(zhp, change_one, data));
- } else {
- zfs_close(zhp);
- }
-
- return (0);
-}
-
-/*ARGSUSED*/
-static int
-compare_mountpoints(const void *a, const void *b, void *unused)
-{
- const prop_changenode_t *ca = a;
- const prop_changenode_t *cb = b;
-
- char mounta[MAXPATHLEN];
- char mountb[MAXPATHLEN];
-
- boolean_t hasmounta, hasmountb;
-
- /*
- * When unsharing or unmounting filesystems, we need to do it in
- * mountpoint order. This allows the user to have a mountpoint
- * hierarchy that is different from the dataset hierarchy, and still
- * allow it to be changed. However, if either dataset doesn't have a
- * mountpoint (because it is a volume or a snapshot), we place it at the
- * end of the list, because it doesn't affect our change at all.
- */
- hasmounta = (zfs_prop_get(ca->cn_handle, ZFS_PROP_MOUNTPOINT, mounta,
- sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
- hasmountb = (zfs_prop_get(cb->cn_handle, ZFS_PROP_MOUNTPOINT, mountb,
- sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
-
- if (!hasmounta && hasmountb)
- return (-1);
- else if (hasmounta && !hasmountb)
- return (1);
- else if (!hasmounta && !hasmountb)
- return (0);
- else
- return (strcmp(mountb, mounta));
-}
-
-/*
- * Given a ZFS handle and a property, construct a complete list of datasets
- * that need to be modified as part of this process. For anything but the
- * 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
- * Otherwise, we iterate over all children and look for any datasets that
- * inherit the property. For each such dataset, we add it to the list and
- * mark whether it was shared beforehand.
- */
-prop_changelist_t *
-changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
- int mnt_flags)
-{
- prop_changelist_t *clp;
- prop_changenode_t *cn;
- zfs_handle_t *temp;
- char property[ZFS_MAXPROPLEN];
- uu_compare_fn_t *compare = NULL;
- boolean_t legacy = B_FALSE;
-
- if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
- return (NULL);
-
- /*
- * For mountpoint-related tasks, we want to sort everything by
- * mountpoint, so that we mount and unmount them in the appropriate
- * order, regardless of their position in the hierarchy.
- */
- if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
- prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
- prop == ZFS_PROP_SHARESMB) {
-
- if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
- property, sizeof (property),
- NULL, NULL, 0, B_FALSE) == 0 &&
- (strcmp(property, "legacy") == 0 ||
- strcmp(property, "none") == 0)) {
-
- legacy = B_TRUE;
- }
- if (!legacy) {
- compare = compare_mountpoints;
- clp->cl_sorted = B_TRUE;
- }
- }
-
- clp->cl_pool = uu_list_pool_create("changelist_pool",
- sizeof (prop_changenode_t),
- offsetof(prop_changenode_t, cn_listnode),
- compare, 0);
- if (clp->cl_pool == NULL) {
- assert(uu_error() == UU_ERROR_NO_MEMORY);
- (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
- changelist_free(clp);
- return (NULL);
- }
-
- clp->cl_list = uu_list_create(clp->cl_pool, NULL,
- clp->cl_sorted ? UU_LIST_SORTED : 0);
- clp->cl_gflags = gather_flags;
- clp->cl_mflags = mnt_flags;
-
- if (clp->cl_list == NULL) {
- assert(uu_error() == UU_ERROR_NO_MEMORY);
- (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
- changelist_free(clp);
- return (NULL);
- }
-
- /*
- * If this is a rename or the 'zoned' property, we pretend we're
- * changing the mountpoint and flag it so we can catch all children in
- * change_one().
- *
- * Flag cl_alldependents to catch all children plus the dependents
- * (clones) that are not in the hierarchy.
- */
- if (prop == ZFS_PROP_NAME) {
- clp->cl_prop = ZFS_PROP_MOUNTPOINT;
- clp->cl_alldependents = B_TRUE;
- } else if (prop == ZFS_PROP_ZONED) {
- clp->cl_prop = ZFS_PROP_MOUNTPOINT;
- clp->cl_allchildren = B_TRUE;
- } else if (prop == ZFS_PROP_CANMOUNT) {
- clp->cl_prop = ZFS_PROP_MOUNTPOINT;
- } else if (prop == ZFS_PROP_VOLSIZE) {
- clp->cl_prop = ZFS_PROP_MOUNTPOINT;
- } else {
- clp->cl_prop = prop;
- }
- clp->cl_realprop = prop;
-
- if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
- clp->cl_prop != ZFS_PROP_SHARENFS &&
- clp->cl_prop != ZFS_PROP_SHARESMB)
- return (clp);
-
- /*
- * If watching SHARENFS or SHARESMB then
- * also watch its companion property.
- */
- if (clp->cl_prop == ZFS_PROP_SHARENFS)
- clp->cl_shareprop = ZFS_PROP_SHARESMB;
- else if (clp->cl_prop == ZFS_PROP_SHARESMB)
- clp->cl_shareprop = ZFS_PROP_SHARENFS;
-
- if (clp->cl_alldependents) {
- if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
- changelist_free(clp);
- return (NULL);
- }
- } else if (zfs_iter_children(zhp, change_one, clp) != 0) {
- changelist_free(clp);
- return (NULL);
- }
-
- /*
- * We have to re-open ourselves because we auto-close all the handles
- * and can't tell the difference.
- */
- if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
- ZFS_TYPE_DATASET)) == NULL) {
- changelist_free(clp);
- return (NULL);
- }
-
- /*
- * Always add ourself to the list. We add ourselves to the end so that
- * we're the last to be unmounted.
- */
- if ((cn = zfs_alloc(zhp->zfs_hdl,
- sizeof (prop_changenode_t))) == NULL) {
- zfs_close(temp);
- changelist_free(clp);
- return (NULL);
- }
-
- cn->cn_handle = temp;
- cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
- zfs_is_mounted(temp, NULL);
- cn->cn_shared = zfs_is_shared(temp);
- cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
- cn->cn_needpost = B_TRUE;
-
- uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
- if (clp->cl_sorted) {
- uu_list_index_t idx;
- (void) uu_list_find(clp->cl_list, cn, NULL, &idx);
- uu_list_insert(clp->cl_list, cn, idx);
- } else {
- /*
- * Add the target dataset to the end of the list.
- * The list is not really unsorted. The list will be
- * in reverse dataset name order. This is necessary
- * when the original mountpoint is legacy or none.
- */
- verify(uu_list_insert_after(clp->cl_list,
- uu_list_last(clp->cl_list), cn) == 0);
- }
-
- /*
- * If the mountpoint property was previously 'legacy', or 'none',
- * record it as the behavior of changelist_postfix() will be different.
- */
- if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) && legacy) {
- /*
- * do not automatically mount ex-legacy datasets if
- * we specifically set canmount to noauto
- */
- if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) !=
- ZFS_CANMOUNT_NOAUTO)
- clp->cl_waslegacy = B_TRUE;
- }
-
- return (clp);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
deleted file mode 100644
index 7545331b40b4..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * CDDL HEADER SART
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
- */
-
-#include "libzfs_compat.h"
-
-int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
-static int zfs_spa_version = -1;
-
-/*
- * Get zfs_ioctl_version
- */
-int
-get_zfs_ioctl_version(void)
-{
- size_t ver_size;
- int ver = ZFS_IOCVER_NONE;
-
- ver_size = sizeof(ver);
- sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
-
- return (ver);
-}
-
-/*
- * Get the SPA version
- */
-static int
-get_zfs_spa_version(void)
-{
- size_t ver_size;
- int ver = 0;
-
- ver_size = sizeof(ver);
- sysctlbyname("vfs.zfs.version.spa", &ver, &ver_size, NULL, 0);
-
- return (ver);
-}
-
-/*
- * This is FreeBSD version of ioctl, because Solaris' ioctl() updates
- * zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
- * error is returned zc_nvlist_dst_size won't be updated.
- */
-int
-zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
-{
- size_t oldsize;
- int ret, cflag = ZFS_CMD_COMPAT_NONE;
-
- if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
- zfs_ioctl_version = get_zfs_ioctl_version();
-
- if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) {
- switch (zfs_ioctl_version) {
- case ZFS_IOCVER_INLANES:
- cflag = ZFS_CMD_COMPAT_INLANES;
- break;
- case ZFS_IOCVER_RESUME:
- cflag = ZFS_CMD_COMPAT_RESUME;
- break;
- case ZFS_IOCVER_EDBP:
- cflag = ZFS_CMD_COMPAT_EDBP;
- break;
- case ZFS_IOCVER_ZCMD:
- cflag = ZFS_CMD_COMPAT_ZCMD;
- break;
- case ZFS_IOCVER_LZC:
- cflag = ZFS_CMD_COMPAT_LZC;
- break;
- case ZFS_IOCVER_DEADMAN:
- cflag = ZFS_CMD_COMPAT_DEADMAN;
- break;
- }
- } else {
- /*
- * If vfs.zfs.version.ioctl is not defined, assume we have v28
- * compatible binaries and use vfs.zfs.version.spa to test for v15
- */
- cflag = ZFS_CMD_COMPAT_V28;
-
- if (zfs_spa_version < 0)
- zfs_spa_version = get_zfs_spa_version();
-
- if (zfs_spa_version == SPA_VERSION_15 ||
- zfs_spa_version == SPA_VERSION_14 ||
- zfs_spa_version == SPA_VERSION_13)
- cflag = ZFS_CMD_COMPAT_V15;
- }
-
- oldsize = zc->zc_nvlist_dst_size;
- ret = zcmd_ioctl_compat(fd, request, zc, cflag);
-
- if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
- ret = -1;
- errno = ENOMEM;
- }
-
- return (ret);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
deleted file mode 100644
index 37616683330a..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * CDDL HEADER SART
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
- */
-
-#ifndef _LIBZFS_COMPAT_H
-#define _LIBZFS_COMPAT_H
-
-#include <zfs_ioctl_compat.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int get_zfs_ioctl_version(void);
-int zcmd_ioctl(int fd, int request, zfs_cmd_t *zc);
-
-#define ioctl(fd, ioc, zc) zcmd_ioctl((fd), (ioc), (zc))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBZFS_COMPAT_H */
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c
deleted file mode 100644
index b33d86432dc5..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright (c) 2015 by Syneto S.R.L. All rights reserved.
- * Copyright 2016 Nexenta Systems, Inc.
- */
-
-/*
- * The pool configuration repository is stored in /etc/zfs/zpool.cache as a
- * single packed nvlist. While it would be nice to just read in this
- * file from userland, this wouldn't work from a local zone. So we have to have
- * a zpool ioctl to return the complete configuration for all pools. In the
- * global zone, this will be identical to reading the file and unpacking it in
- * userland.
- */
-
-#include <errno.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <libintl.h>
-#include <libuutil.h>
-
-#include "libzfs_impl.h"
-
-typedef struct config_node {
- char *cn_name;
- nvlist_t *cn_config;
- uu_avl_node_t cn_avl;
-} config_node_t;
-
-/* ARGSUSED */
-static int
-config_node_compare(const void *a, const void *b, void *unused)
-{
- int ret;
-
- const config_node_t *ca = (config_node_t *)a;
- const config_node_t *cb = (config_node_t *)b;
-
- ret = strcmp(ca->cn_name, cb->cn_name);
-
- if (ret < 0)
- return (-1);
- else if (ret > 0)
- return (1);
- else
- return (0);
-}
-
-void
-namespace_clear(libzfs_handle_t *hdl)
-{
- if (hdl->libzfs_ns_avl) {
- config_node_t *cn;
- void *cookie = NULL;
-
- while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl,
- &cookie)) != NULL) {
- nvlist_free(cn->cn_config);
- free(cn->cn_name);
- free(cn);
- }
-
- uu_avl_destroy(hdl->libzfs_ns_avl);
- hdl->libzfs_ns_avl = NULL;
- }
-
- if (hdl->libzfs_ns_avlpool) {
- uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
- hdl->libzfs_ns_avlpool = NULL;
- }
-}
-
-/*
- * Loads the pool namespace, or re-loads it if the cache has changed.
- */
-static int
-namespace_reload(libzfs_handle_t *hdl)
-{
- nvlist_t *config;
- config_node_t *cn;
- nvpair_t *elem;
- zfs_cmd_t zc = { 0 };
- void *cookie;
-
- if (hdl->libzfs_ns_gen == 0) {
- /*
- * This is the first time we've accessed the configuration
- * cache. Initialize the AVL tree and then fall through to the
- * common code.
- */
- if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
- sizeof (config_node_t),
- offsetof(config_node_t, cn_avl),
- config_node_compare, UU_DEFAULT)) == NULL)
- return (no_memory(hdl));
-
- if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
- NULL, UU_DEFAULT)) == NULL)
- return (no_memory(hdl));
- }
-
- if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
- return (-1);
-
- for (;;) {
- zc.zc_cookie = hdl->libzfs_ns_gen;
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
- switch (errno) {
- case EEXIST:
- /*
- * The namespace hasn't changed.
- */
- zcmd_free_nvlists(&zc);
- return (0);
-
- case ENOMEM:
- if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
- break;
-
- default:
- zcmd_free_nvlists(&zc);
- return (zfs_standard_error(hdl, errno,
- dgettext(TEXT_DOMAIN, "failed to read "
- "pool configuration")));
- }
- } else {
- hdl->libzfs_ns_gen = zc.zc_cookie;
- break;
- }
- }
-
- if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
-
- zcmd_free_nvlists(&zc);
-
- /*
- * Clear out any existing configuration information.
- */
- cookie = NULL;
- while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
- nvlist_free(cn->cn_config);
- free(cn->cn_name);
- free(cn);
- }
-
- elem = NULL;
- while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
- nvlist_t *child;
- uu_avl_index_t where;
-
- if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
- nvlist_free(config);
- return (-1);
- }
-
- if ((cn->cn_name = zfs_strdup(hdl,
- nvpair_name(elem))) == NULL) {
- free(cn);
- nvlist_free(config);
- return (-1);
- }
-
- verify(nvpair_value_nvlist(elem, &child) == 0);
- if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
- free(cn->cn_name);
- free(cn);
- nvlist_free(config);
- return (no_memory(hdl));
- }
- verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
- == NULL);
-
- uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
- }
-
- nvlist_free(config);
- return (0);
-}
-
-/*
- * Retrieve the configuration for the given pool. The configuration is a nvlist
- * describing the vdevs, as well as the statistics associated with each one.
- */
-nvlist_t *
-zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
-{
- if (oldconfig)
- *oldconfig = zhp->zpool_old_config;
- return (zhp->zpool_config);
-}
-
-/*
- * Retrieves a list of enabled features and their refcounts and caches it in
- * the pool handle.
- */
-nvlist_t *
-zpool_get_features(zpool_handle_t *zhp)
-{
- nvlist_t *config, *features;
-
- config = zpool_get_config(zhp, NULL);
-
- if (config == NULL || !nvlist_exists(config,
- ZPOOL_CONFIG_FEATURE_STATS)) {
- int error;
- boolean_t missing = B_FALSE;
-
- error = zpool_refresh_stats(zhp, &missing);
-
- if (error != 0 || missing)
- return (NULL);
-
- config = zpool_get_config(zhp, NULL);
- }
-
- if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
- &features) != 0)
- return (NULL);
-
- return (features);
-}
-
-/*
- * Refresh the vdev statistics associated with the given pool. This is used in
- * iostat to show configuration changes and determine the delta from the last
- * time the function was called. This function can fail, in case the pool has
- * been destroyed.
- */
-int
-zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
-{
- zfs_cmd_t zc = { 0 };
- int error;
- nvlist_t *config;
- libzfs_handle_t *hdl = zhp->zpool_hdl;
-
- *missing = B_FALSE;
- (void) strcpy(zc.zc_name, zhp->zpool_name);
-
- if (zhp->zpool_config_size == 0)
- zhp->zpool_config_size = 1 << 16;
-
- if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
- return (-1);
-
- for (;;) {
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
- &zc) == 0) {
- /*
- * The real error is returned in the zc_cookie field.
- */
- error = zc.zc_cookie;
- break;
- }
-
- if (errno == ENOMEM) {
- if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
- } else {
- zcmd_free_nvlists(&zc);
- if (errno == ENOENT || errno == EINVAL)
- *missing = B_TRUE;
- zhp->zpool_state = POOL_STATE_UNAVAIL;
- return (0);
- }
- }
-
- if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
-
- zcmd_free_nvlists(&zc);
-
- zhp->zpool_config_size = zc.zc_nvlist_dst_size;
-
- if (zhp->zpool_config != NULL) {
- uint64_t oldtxg, newtxg;
-
- verify(nvlist_lookup_uint64(zhp->zpool_config,
- ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0);
- verify(nvlist_lookup_uint64(config,
- ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);
-
- nvlist_free(zhp->zpool_old_config);
-
- if (oldtxg != newtxg) {
- nvlist_free(zhp->zpool_config);
- zhp->zpool_old_config = NULL;
- } else {
- zhp->zpool_old_config = zhp->zpool_config;
- }
- }
-
- zhp->zpool_config = config;
- if (error)
- zhp->zpool_state = POOL_STATE_UNAVAIL;
- else
- zhp->zpool_state = POOL_STATE_ACTIVE;
-
- return (0);
-}
-
-/*
- * The following environment variables are undocumented
- * and should be used for testing purposes only:
- *
- * __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists
- * __ZFS_POOL_RESTRICT - iterate only over the pools it lists
- *
- * This function returns B_TRUE if the pool should be skipped
- * during iteration.
- */
-boolean_t
-zpool_skip_pool(const char *poolname)
-{
- static boolean_t initialized = B_FALSE;
- static const char *exclude = NULL;
- static const char *restricted = NULL;
-
- const char *cur, *end;
- int len;
- int namelen = strlen(poolname);
-
- if (!initialized) {
- initialized = B_TRUE;
- exclude = getenv("__ZFS_POOL_EXCLUDE");
- restricted = getenv("__ZFS_POOL_RESTRICT");
- }
-
- if (exclude != NULL) {
- cur = exclude;
- do {
- end = strchr(cur, ' ');
- len = (NULL == end) ? strlen(cur) : (end - cur);
- if (len == namelen && 0 == strncmp(cur, poolname, len))
- return (B_TRUE);
- cur += (len + 1);
- } while (NULL != end);
- }
-
- if (NULL == restricted)
- return (B_FALSE);
-
- cur = restricted;
- do {
- end = strchr(cur, ' ');
- len = (NULL == end) ? strlen(cur) : (end - cur);
-
- if (len == namelen && 0 == strncmp(cur, poolname, len)) {
- return (B_FALSE);
- }
-
- cur += (len + 1);
- } while (NULL != end);
-
- return (B_TRUE);
-}
-
-/*
- * Iterate over all pools in the system.
- */
-int
-zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
-{
- config_node_t *cn;
- zpool_handle_t *zhp;
- int ret;
-
- /*
- * If someone makes a recursive call to zpool_iter(), we want to avoid
- * refreshing the namespace because that will invalidate the parent
- * context. We allow recursive calls, but simply re-use the same
- * namespace AVL tree.
- */
- if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
- return (-1);
-
- hdl->libzfs_pool_iter++;
- for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
- cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
-
- if (zpool_skip_pool(cn->cn_name))
- continue;
-
- if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
- hdl->libzfs_pool_iter--;
- return (-1);
- }
-
- if (zhp == NULL)
- continue;
-
- if ((ret = func(zhp, data)) != 0) {
- hdl->libzfs_pool_iter--;
- return (ret);
- }
- }
- hdl->libzfs_pool_iter--;
-
- return (0);
-}
-
-/*
- * Iterate over root datasets, calling the given function for each. The zfs
- * handle passed each time must be explicitly closed by the callback.
- */
-int
-zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
-{
- config_node_t *cn;
- zfs_handle_t *zhp;
- int ret;
-
- if (namespace_reload(hdl) != 0)
- return (-1);
-
- for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
- cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
-
- if (zpool_skip_pool(cn->cn_name))
- continue;
-
- if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
- continue;
-
- if ((ret = func(zhp, data)) != 0)
- return (ret);
- }
-
- return (0);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
deleted file mode 100644
index 7075d060c78d..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
+++ /dev/null
@@ -1,5284 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
- * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
- * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
- * Copyright (c) 2013 Martin Matuska. All rights reserved.
- * Copyright (c) 2013 Steven Hartland. All rights reserved.
- * Copyright (c) 2014 Integros [integros.com]
- * Copyright 2017 Nexenta Systems, Inc.
- * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
- * Copyright 2017-2018 RackTop Systems.
- * Copyright (c) 2019 Datto Inc.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <libintl.h>
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <zone.h>
-#include <fcntl.h>
-#include <sys/mntent.h>
-#include <sys/mount.h>
-#include <priv.h>
-#include <pwd.h>
-#include <grp.h>
-#include <stddef.h>
-#ifdef illumos
-#include <idmap.h>
-#endif
-
-#include <sys/dnode.h>
-#include <sys/spa.h>
-#include <sys/zap.h>
-#include <sys/misc.h>
-#include <libzfs.h>
-
-#include "zfs_namecheck.h"
-#include "zfs_prop.h"
-#include "libzfs_impl.h"
-#include "zfs_deleg.h"
-
-static int userquota_propname_decode(const char *propname, boolean_t zoned,
- zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
-
-/*
- * Given a single type (not a mask of types), return the type in a human
- * readable form.
- */
-const char *
-zfs_type_to_name(zfs_type_t type)
-{
- switch (type) {
- case ZFS_TYPE_FILESYSTEM:
- return (dgettext(TEXT_DOMAIN, "filesystem"));
- case ZFS_TYPE_SNAPSHOT:
- return (dgettext(TEXT_DOMAIN, "snapshot"));
- case ZFS_TYPE_VOLUME:
- return (dgettext(TEXT_DOMAIN, "volume"));
- case ZFS_TYPE_POOL:
- return (dgettext(TEXT_DOMAIN, "pool"));
- case ZFS_TYPE_BOOKMARK:
- return (dgettext(TEXT_DOMAIN, "bookmark"));
- default:
- assert(!"unhandled zfs_type_t");
- }
-
- return (NULL);
-}
-
-/*
- * Validate a ZFS path. This is used even before trying to open the dataset, to
- * provide a more meaningful error message. We call zfs_error_aux() to
- * explain exactly why the name was not valid.
- */
-int
-zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
- boolean_t modifying)
-{
- namecheck_err_t why;
- char what;
-
- if (entity_namecheck(path, &why, &what) != 0) {
- if (hdl != NULL) {
- switch (why) {
- case NAME_ERR_TOOLONG:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "name is too long"));
- break;
-
- case NAME_ERR_LEADING_SLASH:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "leading slash in name"));
- break;
-
- case NAME_ERR_EMPTY_COMPONENT:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "empty component in name"));
- break;
-
- case NAME_ERR_TRAILING_SLASH:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "trailing slash in name"));
- break;
-
- case NAME_ERR_INVALCHAR:
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "invalid character "
- "'%c' in name"), what);
- break;
-
- case NAME_ERR_MULTIPLE_DELIMITERS:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "multiple '@' and/or '#' delimiters in "
- "name"));
- break;
-
- case NAME_ERR_NOLETTER:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool doesn't begin with a letter"));
- break;
-
- case NAME_ERR_RESERVED:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "name is reserved"));
- break;
-
- case NAME_ERR_DISKLIKE:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "reserved disk name"));
- break;
-
- default:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "(%d) not defined"), why);
- break;
- }
- }
-
- return (0);
- }
-
- if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
- if (hdl != NULL)
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "snapshot delimiter '@' is not expected here"));
- return (0);
- }
-
- if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
- if (hdl != NULL)
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "missing '@' delimiter in snapshot name"));
- return (0);
- }
-
- if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) {
- if (hdl != NULL)
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "bookmark delimiter '#' is not expected here"));
- return (0);
- }
-
- if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) {
- if (hdl != NULL)
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "missing '#' delimiter in bookmark name"));
- return (0);
- }
-
- if (modifying && strchr(path, '%') != NULL) {
- if (hdl != NULL)
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid character %c in name"), '%');
- return (0);
- }
-
- return (-1);
-}
-
-int
-zfs_name_valid(const char *name, zfs_type_t type)
-{
- if (type == ZFS_TYPE_POOL)
- return (zpool_name_valid(NULL, B_FALSE, name));
- return (zfs_validate_name(NULL, name, type, B_FALSE));
-}
-
-/*
- * This function takes the raw DSL properties, and filters out the user-defined
- * properties into a separate nvlist.
- */
-static nvlist_t *
-process_user_props(zfs_handle_t *zhp, nvlist_t *props)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- nvpair_t *elem;
- nvlist_t *propval;
- nvlist_t *nvl;
-
- if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
- (void) no_memory(hdl);
- return (NULL);
- }
-
- elem = NULL;
- while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
- if (!zfs_prop_user(nvpair_name(elem)))
- continue;
-
- verify(nvpair_value_nvlist(elem, &propval) == 0);
- if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
- nvlist_free(nvl);
- (void) no_memory(hdl);
- return (NULL);
- }
- }
-
- return (nvl);
-}
-
-static zpool_handle_t *
-zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- zpool_handle_t *zph;
-
- if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
- if (hdl->libzfs_pool_handles != NULL)
- zph->zpool_next = hdl->libzfs_pool_handles;
- hdl->libzfs_pool_handles = zph;
- }
- return (zph);
-}
-
-static zpool_handle_t *
-zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- zpool_handle_t *zph = hdl->libzfs_pool_handles;
-
- while ((zph != NULL) &&
- (strncmp(pool_name, zpool_get_name(zph), len) != 0))
- zph = zph->zpool_next;
- return (zph);
-}
-
-/*
- * Returns a handle to the pool that contains the provided dataset.
- * If a handle to that pool already exists then that handle is returned.
- * Otherwise, a new handle is created and added to the list of handles.
- */
-static zpool_handle_t *
-zpool_handle(zfs_handle_t *zhp)
-{
- char *pool_name;
- int len;
- zpool_handle_t *zph;
-
- len = strcspn(zhp->zfs_name, "/@#") + 1;
- pool_name = zfs_alloc(zhp->zfs_hdl, len);
- (void) strlcpy(pool_name, zhp->zfs_name, len);
-
- zph = zpool_find_handle(zhp, pool_name, len);
- if (zph == NULL)
- zph = zpool_add_handle(zhp, pool_name);
-
- free(pool_name);
- return (zph);
-}
-
-void
-zpool_free_handles(libzfs_handle_t *hdl)
-{
- zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
-
- while (zph != NULL) {
- next = zph->zpool_next;
- zpool_close(zph);
- zph = next;
- }
- hdl->libzfs_pool_handles = NULL;
-}
-
-/*
- * Utility function to gather stats (objset and zpl) for the given object.
- */
-static int
-get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
-
- (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
-
- while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
- if (errno == ENOMEM) {
- if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
- return (-1);
- }
- } else {
- return (-1);
- }
- }
- return (0);
-}
-
-/*
- * Utility function to get the received properties of the given object.
- */
-static int
-get_recvd_props_ioctl(zfs_handle_t *zhp)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- nvlist_t *recvdprops;
- zfs_cmd_t zc = { 0 };
- int err;
-
- if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
- return (-1);
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
- while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
- if (errno == ENOMEM) {
- if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
- return (-1);
- }
- } else {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
- }
-
- err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
- zcmd_free_nvlists(&zc);
- if (err != 0)
- return (-1);
-
- nvlist_free(zhp->zfs_recvd_props);
- zhp->zfs_recvd_props = recvdprops;
-
- return (0);
-}
-
-static int
-put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
-{
- nvlist_t *allprops, *userprops;
-
- zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
-
- if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
- return (-1);
- }
-
- /*
- * XXX Why do we store the user props separately, in addition to
- * storing them in zfs_props?
- */
- if ((userprops = process_user_props(zhp, allprops)) == NULL) {
- nvlist_free(allprops);
- return (-1);
- }
-
- nvlist_free(zhp->zfs_props);
- nvlist_free(zhp->zfs_user_props);
-
- zhp->zfs_props = allprops;
- zhp->zfs_user_props = userprops;
-
- return (0);
-}
-
-static int
-get_stats(zfs_handle_t *zhp)
-{
- int rc = 0;
- zfs_cmd_t zc = { 0 };
-
- if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
- return (-1);
- if (get_stats_ioctl(zhp, &zc) != 0)
- rc = -1;
- else if (put_stats_zhdl(zhp, &zc) != 0)
- rc = -1;
- zcmd_free_nvlists(&zc);
- return (rc);
-}
-
-/*
- * Refresh the properties currently stored in the handle.
- */
-void
-zfs_refresh_properties(zfs_handle_t *zhp)
-{
- (void) get_stats(zhp);
-}
-
-/*
- * Makes a handle from the given dataset name. Used by zfs_open() and
- * zfs_iter_* to create child handles on the fly.
- */
-static int
-make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
-{
- if (put_stats_zhdl(zhp, zc) != 0)
- return (-1);
-
- /*
- * We've managed to open the dataset and gather statistics. Determine
- * the high-level type.
- */
- if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
- zhp->zfs_head_type = ZFS_TYPE_VOLUME;
- else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
- zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
- else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
- return (-1);
- else
- abort();
-
- if (zhp->zfs_dmustats.dds_is_snapshot)
- zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
- else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
- zhp->zfs_type = ZFS_TYPE_VOLUME;
- else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
- zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
- else
- abort(); /* we should never see any other types */
-
- if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
- return (-1);
-
- return (0);
-}
-
-zfs_handle_t *
-make_dataset_handle(libzfs_handle_t *hdl, const char *path)
-{
- zfs_cmd_t zc = { 0 };
-
- zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
-
- if (zhp == NULL)
- return (NULL);
-
- zhp->zfs_hdl = hdl;
- (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
- if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
- free(zhp);
- return (NULL);
- }
- if (get_stats_ioctl(zhp, &zc) == -1) {
- zcmd_free_nvlists(&zc);
- free(zhp);
- return (NULL);
- }
- if (make_dataset_handle_common(zhp, &zc) == -1) {
- free(zhp);
- zhp = NULL;
- }
- zcmd_free_nvlists(&zc);
- return (zhp);
-}
-
-zfs_handle_t *
-make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
-{
- zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
-
- if (zhp == NULL)
- return (NULL);
-
- zhp->zfs_hdl = hdl;
- (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
- if (make_dataset_handle_common(zhp, zc) == -1) {
- free(zhp);
- return (NULL);
- }
- return (zhp);
-}
-
-zfs_handle_t *
-make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc)
-{
- zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
-
- if (zhp == NULL)
- return (NULL);
-
- zhp->zfs_hdl = pzhp->zfs_hdl;
- (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
- zhp->zfs_head_type = pzhp->zfs_type;
- zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
- zhp->zpool_hdl = zpool_handle(zhp);
- return (zhp);
-}
-
-zfs_handle_t *
-zfs_handle_dup(zfs_handle_t *zhp_orig)
-{
- zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
-
- if (zhp == NULL)
- return (NULL);
-
- zhp->zfs_hdl = zhp_orig->zfs_hdl;
- zhp->zpool_hdl = zhp_orig->zpool_hdl;
- (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
- sizeof (zhp->zfs_name));
- zhp->zfs_type = zhp_orig->zfs_type;
- zhp->zfs_head_type = zhp_orig->zfs_head_type;
- zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
- if (zhp_orig->zfs_props != NULL) {
- if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
- (void) no_memory(zhp->zfs_hdl);
- zfs_close(zhp);
- return (NULL);
- }
- }
- if (zhp_orig->zfs_user_props != NULL) {
- if (nvlist_dup(zhp_orig->zfs_user_props,
- &zhp->zfs_user_props, 0) != 0) {
- (void) no_memory(zhp->zfs_hdl);
- zfs_close(zhp);
- return (NULL);
- }
- }
- if (zhp_orig->zfs_recvd_props != NULL) {
- if (nvlist_dup(zhp_orig->zfs_recvd_props,
- &zhp->zfs_recvd_props, 0)) {
- (void) no_memory(zhp->zfs_hdl);
- zfs_close(zhp);
- return (NULL);
- }
- }
- zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
- if (zhp_orig->zfs_mntopts != NULL) {
- zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
- zhp_orig->zfs_mntopts);
- }
- zhp->zfs_props_table = zhp_orig->zfs_props_table;
- return (zhp);
-}
-
-boolean_t
-zfs_bookmark_exists(const char *path)
-{
- nvlist_t *bmarks;
- nvlist_t *props;
- char fsname[ZFS_MAX_DATASET_NAME_LEN];
- char *bmark_name;
- char *pound;
- int err;
- boolean_t rv;
-
-
- (void) strlcpy(fsname, path, sizeof (fsname));
- pound = strchr(fsname, '#');
- if (pound == NULL)
- return (B_FALSE);
-
- *pound = '\0';
- bmark_name = pound + 1;
- props = fnvlist_alloc();
- err = lzc_get_bookmarks(fsname, props, &bmarks);
- nvlist_free(props);
- if (err != 0) {
- nvlist_free(bmarks);
- return (B_FALSE);
- }
-
- rv = nvlist_exists(bmarks, bmark_name);
- nvlist_free(bmarks);
- return (rv);
-}
-
-zfs_handle_t *
-make_bookmark_handle(zfs_handle_t *parent, const char *path,
- nvlist_t *bmark_props)
-{
- zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
-
- if (zhp == NULL)
- return (NULL);
-
- /* Fill in the name. */
- zhp->zfs_hdl = parent->zfs_hdl;
- (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
-
- /* Set the property lists. */
- if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
- free(zhp);
- return (NULL);
- }
-
- /* Set the types. */
- zhp->zfs_head_type = parent->zfs_head_type;
- zhp->zfs_type = ZFS_TYPE_BOOKMARK;
-
- if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
- nvlist_free(zhp->zfs_props);
- free(zhp);
- return (NULL);
- }
-
- return (zhp);
-}
-
-struct zfs_open_bookmarks_cb_data {
- const char *path;
- zfs_handle_t *zhp;
-};
-
-static int
-zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data)
-{
- struct zfs_open_bookmarks_cb_data *dp = data;
-
- /*
- * Is it the one we are looking for?
- */
- if (strcmp(dp->path, zfs_get_name(zhp)) == 0) {
- /*
- * We found it. Save it and let the caller know we are done.
- */
- dp->zhp = zhp;
- return (EEXIST);
- }
-
- /*
- * Not found. Close the handle and ask for another one.
- */
- zfs_close(zhp);
- return (0);
-}
-
-/*
- * Opens the given snapshot, bookmark, filesystem, or volume. The 'types'
- * argument is a mask of acceptable types. The function will print an
- * appropriate error message and return NULL if it can't be opened.
- */
-zfs_handle_t *
-zfs_open(libzfs_handle_t *hdl, const char *path, int types)
-{
- zfs_handle_t *zhp;
- char errbuf[1024];
- char *bookp;
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
-
- /*
- * Validate the name before we even try to open it.
- */
- if (!zfs_validate_name(hdl, path, types, B_FALSE)) {
- (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
- return (NULL);
- }
-
- /*
- * Bookmarks needs to be handled separately.
- */
- bookp = strchr(path, '#');
- if (bookp == NULL) {
- /*
- * Try to get stats for the dataset, which will tell us if it
- * exists.
- */
- errno = 0;
- if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
- (void) zfs_standard_error(hdl, errno, errbuf);
- return (NULL);
- }
- } else {
- char dsname[ZFS_MAX_DATASET_NAME_LEN];
- zfs_handle_t *pzhp;
- struct zfs_open_bookmarks_cb_data cb_data = {path, NULL};
-
- /*
- * We need to cut out '#' and everything after '#'
- * to get the parent dataset name only.
- */
- assert(bookp - path < sizeof (dsname));
- (void) strncpy(dsname, path, bookp - path);
- dsname[bookp - path] = '\0';
-
- /*
- * Create handle for the parent dataset.
- */
- errno = 0;
- if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) {
- (void) zfs_standard_error(hdl, errno, errbuf);
- return (NULL);
- }
-
- /*
- * Iterate bookmarks to find the right one.
- */
- errno = 0;
- if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb,
- &cb_data) == 0) && (cb_data.zhp == NULL)) {
- (void) zfs_error(hdl, EZFS_NOENT, errbuf);
- zfs_close(pzhp);
- return (NULL);
- }
- if (cb_data.zhp == NULL) {
- (void) zfs_standard_error(hdl, errno, errbuf);
- zfs_close(pzhp);
- return (NULL);
- }
- zhp = cb_data.zhp;
-
- /*
- * Cleanup.
- */
- zfs_close(pzhp);
- }
-
- if (zhp == NULL) {
- char *at = strchr(path, '@');
-
- if (at != NULL)
- *at = '\0';
- errno = 0;
- if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
- (void) zfs_standard_error(hdl, errno, errbuf);
- return (NULL);
- }
- if (at != NULL)
- *at = '@';
- (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
- zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
- }
-
- if (!(types & zhp->zfs_type)) {
- (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
- zfs_close(zhp);
- return (NULL);
- }
-
- return (zhp);
-}
-
-/*
- * Release a ZFS handle. Nothing to do but free the associated memory.
- */
-void
-zfs_close(zfs_handle_t *zhp)
-{
- if (zhp->zfs_mntopts)
- free(zhp->zfs_mntopts);
- nvlist_free(zhp->zfs_props);
- nvlist_free(zhp->zfs_user_props);
- nvlist_free(zhp->zfs_recvd_props);
- free(zhp);
-}
-
-typedef struct mnttab_node {
- struct mnttab mtn_mt;
- avl_node_t mtn_node;
-} mnttab_node_t;
-
-static int
-libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
-{
- const mnttab_node_t *mtn1 = (const mnttab_node_t *)arg1;
- const mnttab_node_t *mtn2 = (const mnttab_node_t *)arg2;
- int rv;
-
- rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
-
- return (AVL_ISIGN(rv));
-}
-
-void
-libzfs_mnttab_init(libzfs_handle_t *hdl)
-{
- pthread_mutex_init(&hdl->libzfs_mnttab_cache_lock, NULL);
- assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
- avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
- sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
-}
-
-void
-libzfs_mnttab_update(libzfs_handle_t *hdl)
-{
- struct mnttab entry;
-
- rewind(hdl->libzfs_mnttab);
- while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
- mnttab_node_t *mtn;
-
- if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
- continue;
- mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
- mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
- mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
- mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
- mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
- avl_add(&hdl->libzfs_mnttab_cache, mtn);
- }
-}
-
-void
-libzfs_mnttab_fini(libzfs_handle_t *hdl)
-{
- void *cookie = NULL;
- mnttab_node_t *mtn;
-
- while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))
- != NULL) {
- free(mtn->mtn_mt.mnt_special);
- free(mtn->mtn_mt.mnt_mountp);
- free(mtn->mtn_mt.mnt_fstype);
- free(mtn->mtn_mt.mnt_mntopts);
- free(mtn);
- }
- avl_destroy(&hdl->libzfs_mnttab_cache);
- (void) pthread_mutex_destroy(&hdl->libzfs_mnttab_cache_lock);
-}
-
-void
-libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
-{
- hdl->libzfs_mnttab_enable = enable;
-}
-
-int
-libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
- struct mnttab *entry)
-{
- mnttab_node_t find;
- mnttab_node_t *mtn;
- int ret = ENOENT;
-
- if (!hdl->libzfs_mnttab_enable) {
- struct mnttab srch = { 0 };
-
- if (avl_numnodes(&hdl->libzfs_mnttab_cache))
- libzfs_mnttab_fini(hdl);
- rewind(hdl->libzfs_mnttab);
- srch.mnt_special = (char *)fsname;
- srch.mnt_fstype = MNTTYPE_ZFS;
- if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
- return (0);
- else
- return (ENOENT);
- }
-
- pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
- if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
- libzfs_mnttab_update(hdl);
-
- find.mtn_mt.mnt_special = (char *)fsname;
- mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
- if (mtn) {
- *entry = mtn->mtn_mt;
- ret = 0;
- }
- pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
- return (ret);
-}
-
-void
-libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
- const char *mountp, const char *mntopts)
-{
- mnttab_node_t *mtn;
-
- pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
- if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0) {
- mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
- mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
- mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
- mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
- mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
- avl_add(&hdl->libzfs_mnttab_cache, mtn);
- }
- pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
-}
-
-void
-libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
-{
- mnttab_node_t find;
- mnttab_node_t *ret;
-
- pthread_mutex_lock(&hdl->libzfs_mnttab_cache_lock);
- find.mtn_mt.mnt_special = (char *)fsname;
- if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))
- != NULL) {
- avl_remove(&hdl->libzfs_mnttab_cache, ret);
- free(ret->mtn_mt.mnt_special);
- free(ret->mtn_mt.mnt_mountp);
- free(ret->mtn_mt.mnt_fstype);
- free(ret->mtn_mt.mnt_mntopts);
- free(ret);
- }
- pthread_mutex_unlock(&hdl->libzfs_mnttab_cache_lock);
-}
-
-int
-zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
-{
- zpool_handle_t *zpool_handle = zhp->zpool_hdl;
-
- if (zpool_handle == NULL)
- return (-1);
-
- *spa_version = zpool_get_prop_int(zpool_handle,
- ZPOOL_PROP_VERSION, NULL);
- return (0);
-}
-
-/*
- * The choice of reservation property depends on the SPA version.
- */
-static int
-zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
-{
- int spa_version;
-
- if (zfs_spa_version(zhp, &spa_version) < 0)
- return (-1);
-
- if (spa_version >= SPA_VERSION_REFRESERVATION)
- *resv_prop = ZFS_PROP_REFRESERVATION;
- else
- *resv_prop = ZFS_PROP_RESERVATION;
-
- return (0);
-}
-
-/*
- * Given an nvlist of properties to set, validates that they are correct, and
- * parses any numeric properties (index, boolean, etc) if they are specified as
- * strings.
- */
-nvlist_t *
-zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
- uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
- const char *errbuf)
-{
- nvpair_t *elem;
- uint64_t intval;
- char *strval;
- zfs_prop_t prop;
- nvlist_t *ret;
- int chosen_normal = -1;
- int chosen_utf = -1;
-
- if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
- (void) no_memory(hdl);
- return (NULL);
- }
-
- /*
- * Make sure this property is valid and applies to this type.
- */
-
- elem = NULL;
- while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
- const char *propname = nvpair_name(elem);
-
- prop = zfs_name_to_prop(propname);
- if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
- /*
- * This is a user property: make sure it's a
- * string, and that it's less than ZAP_MAXNAMELEN.
- */
- if (nvpair_type(elem) != DATA_TYPE_STRING) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' must be a string"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property name '%s' is too long"),
- propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- (void) nvpair_value_string(elem, &strval);
- if (nvlist_add_string(ret, propname, strval) != 0) {
- (void) no_memory(hdl);
- goto error;
- }
- continue;
- }
-
- /*
- * Currently, only user properties can be modified on
- * snapshots.
- */
- if (type == ZFS_TYPE_SNAPSHOT) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "this property can not be modified for snapshots"));
- (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
- goto error;
- }
-
- if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
- zfs_userquota_prop_t uqtype;
- char newpropname[128];
- char domain[128];
- uint64_t rid;
- uint64_t valary[3];
-
- if (userquota_propname_decode(propname, zoned,
- &uqtype, domain, sizeof (domain), &rid) != 0) {
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN,
- "'%s' has an invalid user/group name"),
- propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (uqtype != ZFS_PROP_USERQUOTA &&
- uqtype != ZFS_PROP_GROUPQUOTA) {
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "'%s' is readonly"),
- propname);
- (void) zfs_error(hdl, EZFS_PROPREADONLY,
- errbuf);
- goto error;
- }
-
- if (nvpair_type(elem) == DATA_TYPE_STRING) {
- (void) nvpair_value_string(elem, &strval);
- if (strcmp(strval, "none") == 0) {
- intval = 0;
- } else if (zfs_nicestrtonum(hdl,
- strval, &intval) != 0) {
- (void) zfs_error(hdl,
- EZFS_BADPROP, errbuf);
- goto error;
- }
- } else if (nvpair_type(elem) ==
- DATA_TYPE_UINT64) {
- (void) nvpair_value_uint64(elem, &intval);
- if (intval == 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "use 'none' to disable "
- "userquota/groupquota"));
- goto error;
- }
- } else {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' must be a number"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- /*
- * Encode the prop name as
- * userquota@<hex-rid>-domain, to make it easy
- * for the kernel to decode.
- */
- (void) snprintf(newpropname, sizeof (newpropname),
- "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
- (longlong_t)rid, domain);
- valary[0] = uqtype;
- valary[1] = rid;
- valary[2] = intval;
- if (nvlist_add_uint64_array(ret, newpropname,
- valary, 3) != 0) {
- (void) no_memory(hdl);
- goto error;
- }
- continue;
- } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' is readonly"),
- propname);
- (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
- goto error;
- }
-
- if (prop == ZPROP_INVAL) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid property '%s'"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (!zfs_prop_valid_for_type(prop, type)) {
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "'%s' does not "
- "apply to datasets of this type"), propname);
- (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
- goto error;
- }
-
- if (zfs_prop_readonly(prop) &&
- (!zfs_prop_setonce(prop) || zhp != NULL)) {
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "'%s' is readonly"),
- propname);
- (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
- goto error;
- }
-
- if (zprop_parse_value(hdl, elem, prop, type, ret,
- &strval, &intval, errbuf) != 0)
- goto error;
-
- /*
- * Perform some additional checks for specific properties.
- */
- switch (prop) {
- case ZFS_PROP_VERSION:
- {
- int version;
-
- if (zhp == NULL)
- break;
- version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
- if (intval < version) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "Can not downgrade; already at version %u"),
- version);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
- }
-
- case ZFS_PROP_VOLBLOCKSIZE:
- case ZFS_PROP_RECORDSIZE:
- {
- int maxbs = SPA_MAXBLOCKSIZE;
- if (zpool_hdl != NULL) {
- maxbs = zpool_get_prop_int(zpool_hdl,
- ZPOOL_PROP_MAXBLOCKSIZE, NULL);
- }
- /*
- * Volumes are limited to a volblocksize of 128KB,
- * because they typically service workloads with
- * small random writes, which incur a large performance
- * penalty with large blocks.
- */
- if (prop == ZFS_PROP_VOLBLOCKSIZE)
- maxbs = SPA_OLD_MAXBLOCKSIZE;
- /*
- * The value must be a power of two between
- * SPA_MINBLOCKSIZE and maxbs.
- */
- if (intval < SPA_MINBLOCKSIZE ||
- intval > maxbs || !ISP2(intval)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' must be power of 2 from 512B "
- "to %uKB"), propname, maxbs >> 10);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
- }
-
- case ZFS_PROP_SPECIAL_SMALL_BLOCKS:
- if (zpool_hdl != NULL) {
- char state[64] = "";
-
- /*
- * Issue a warning but do not fail so that
- * tests for setable properties succeed.
- */
- if (zpool_prop_get_feature(zpool_hdl,
- "feature@allocation_classes", state,
- sizeof (state)) != 0 ||
- strcmp(state, ZFS_FEATURE_ACTIVE) != 0) {
- (void) fprintf(stderr, gettext(
- "%s: property requires a special "
- "device in the pool\n"), propname);
- }
- }
- if (intval != 0 &&
- (intval < SPA_MINBLOCKSIZE ||
- intval > SPA_OLD_MAXBLOCKSIZE || !ISP2(intval))) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid '%s=%d' property: must be zero or "
- "a power of 2 from 512B to 128K"), propname,
- intval);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
-
- case ZFS_PROP_MLSLABEL:
- {
-#ifdef illumos
- /*
- * Verify the mlslabel string and convert to
- * internal hex label string.
- */
-
- m_label_t *new_sl;
- char *hex = NULL; /* internal label string */
-
- /* Default value is already OK. */
- if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
- break;
-
- /* Verify the label can be converted to binary form */
- if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
- (str_to_label(strval, &new_sl, MAC_LABEL,
- L_NO_CORRECTION, NULL) == -1)) {
- goto badlabel;
- }
-
- /* Now translate to hex internal label string */
- if (label_to_str(new_sl, &hex, M_INTERNAL,
- DEF_NAMES) != 0) {
- if (hex)
- free(hex);
- goto badlabel;
- }
- m_label_free(new_sl);
-
- /* If string is already in internal form, we're done. */
- if (strcmp(strval, hex) == 0) {
- free(hex);
- break;
- }
-
- /* Replace the label string with the internal form. */
- (void) nvlist_remove(ret, zfs_prop_to_name(prop),
- DATA_TYPE_STRING);
- verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
- hex) == 0);
- free(hex);
-
- break;
-
-badlabel:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid mlslabel '%s'"), strval);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- m_label_free(new_sl); /* OK if null */
-#else /* !illumos */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "mlslabel is not supported on FreeBSD"));
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
-#endif /* illumos */
- goto error;
-
- }
-
- case ZFS_PROP_MOUNTPOINT:
- {
- namecheck_err_t why;
-
- if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
- strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
- break;
-
- if (mountpoint_namecheck(strval, &why)) {
- switch (why) {
- case NAME_ERR_LEADING_SLASH:
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN,
- "'%s' must be an absolute path, "
- "'none', or 'legacy'"), propname);
- break;
- case NAME_ERR_TOOLONG:
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN,
- "component of '%s' is too long"),
- propname);
- break;
-
- default:
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN,
- "(%d) not defined"),
- why);
- break;
- }
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- }
-
- /*FALLTHRU*/
-
- case ZFS_PROP_SHARESMB:
- case ZFS_PROP_SHARENFS:
- /*
- * For the mountpoint and sharenfs or sharesmb
- * properties, check if it can be set in a
- * global/non-global zone based on
- * the zoned property value:
- *
- * global zone non-global zone
- * --------------------------------------------------
- * zoned=on mountpoint (no) mountpoint (yes)
- * sharenfs (no) sharenfs (no)
- * sharesmb (no) sharesmb (no)
- *
- * zoned=off mountpoint (yes) N/A
- * sharenfs (yes)
- * sharesmb (yes)
- */
- if (zoned) {
- if (getzoneid() == GLOBAL_ZONEID) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' cannot be set on "
- "dataset in a non-global zone"),
- propname);
- (void) zfs_error(hdl, EZFS_ZONED,
- errbuf);
- goto error;
- } else if (prop == ZFS_PROP_SHARENFS ||
- prop == ZFS_PROP_SHARESMB) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' cannot be set in "
- "a non-global zone"), propname);
- (void) zfs_error(hdl, EZFS_ZONED,
- errbuf);
- goto error;
- }
- } else if (getzoneid() != GLOBAL_ZONEID) {
- /*
- * If zoned property is 'off', this must be in
- * a global zone. If not, something is wrong.
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' cannot be set while dataset "
- "'zoned' property is set"), propname);
- (void) zfs_error(hdl, EZFS_ZONED, errbuf);
- goto error;
- }
-
- /*
- * At this point, it is legitimate to set the
- * property. Now we want to make sure that the
- * property value is valid if it is sharenfs.
- */
- if ((prop == ZFS_PROP_SHARENFS ||
- prop == ZFS_PROP_SHARESMB) &&
- strcmp(strval, "on") != 0 &&
- strcmp(strval, "off") != 0) {
- zfs_share_proto_t proto;
-
- if (prop == ZFS_PROP_SHARESMB)
- proto = PROTO_SMB;
- else
- proto = PROTO_NFS;
-
- /*
- * Must be an valid sharing protocol
- * option string so init the libshare
- * in order to enable the parser and
- * then parse the options. We use the
- * control API since we don't care about
- * the current configuration and don't
- * want the overhead of loading it
- * until we actually do something.
- */
-
- if (zfs_init_libshare(hdl,
- SA_INIT_CONTROL_API) != SA_OK) {
- /*
- * An error occurred so we can't do
- * anything
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' cannot be set: problem "
- "in share initialization"),
- propname);
- (void) zfs_error(hdl, EZFS_BADPROP,
- errbuf);
- goto error;
- }
-
- if (zfs_parse_options(strval, proto) != SA_OK) {
- /*
- * There was an error in parsing so
- * deal with it by issuing an error
- * message and leaving after
- * uninitializing the the libshare
- * interface.
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' cannot be set to invalid "
- "options"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP,
- errbuf);
- zfs_uninit_libshare(hdl);
- goto error;
- }
- zfs_uninit_libshare(hdl);
- }
-
- break;
-
- case ZFS_PROP_UTF8ONLY:
- chosen_utf = (int)intval;
- break;
-
- case ZFS_PROP_NORMALIZE:
- chosen_normal = (int)intval;
- break;
-
- default:
- break;
- }
-
- /*
- * For changes to existing volumes, we have some additional
- * checks to enforce.
- */
- if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
- uint64_t volsize = zfs_prop_get_int(zhp,
- ZFS_PROP_VOLSIZE);
- uint64_t blocksize = zfs_prop_get_int(zhp,
- ZFS_PROP_VOLBLOCKSIZE);
- char buf[64];
-
- switch (prop) {
- case ZFS_PROP_RESERVATION:
- if (intval > volsize) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' is greater than current "
- "volume size"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP,
- errbuf);
- goto error;
- }
- break;
-
- case ZFS_PROP_REFRESERVATION:
- if (intval > volsize && intval != UINT64_MAX) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' is greater than current "
- "volume size"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP,
- errbuf);
- goto error;
- }
- break;
-
- case ZFS_PROP_VOLSIZE:
- if (intval % blocksize != 0) {
- zfs_nicenum(blocksize, buf,
- sizeof (buf));
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' must be a multiple of "
- "volume block size (%s)"),
- propname, buf);
- (void) zfs_error(hdl, EZFS_BADPROP,
- errbuf);
- goto error;
- }
-
- if (intval == 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' cannot be zero"),
- propname);
- (void) zfs_error(hdl, EZFS_BADPROP,
- errbuf);
- goto error;
- }
- break;
-
- default:
- break;
- }
- }
- }
-
- /*
- * If normalization was chosen, but no UTF8 choice was made,
- * enforce rejection of non-UTF8 names.
- *
- * If normalization was chosen, but rejecting non-UTF8 names
- * was explicitly not chosen, it is an error.
- */
- if (chosen_normal > 0 && chosen_utf < 0) {
- if (nvlist_add_uint64(ret,
- zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
- (void) no_memory(hdl);
- goto error;
- }
- } else if (chosen_normal > 0 && chosen_utf == 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' must be set 'on' if normalization chosen"),
- zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- return (ret);
-
-error:
- nvlist_free(ret);
- return (NULL);
-}
-
-int
-zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
-{
- uint64_t old_volsize;
- uint64_t new_volsize;
- uint64_t old_reservation;
- uint64_t new_reservation;
- zfs_prop_t resv_prop;
- nvlist_t *props;
-
- /*
- * If this is an existing volume, and someone is setting the volsize,
- * make sure that it matches the reservation, or add it if necessary.
- */
- old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
- if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
- return (-1);
- old_reservation = zfs_prop_get_int(zhp, resv_prop);
-
- props = fnvlist_alloc();
- fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
- zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
-
- if ((zvol_volsize_to_reservation(old_volsize, props) !=
- old_reservation) || nvlist_exists(nvl,
- zfs_prop_to_name(resv_prop))) {
- fnvlist_free(props);
- return (0);
- }
- if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
- &new_volsize) != 0) {
- fnvlist_free(props);
- return (-1);
- }
- new_reservation = zvol_volsize_to_reservation(new_volsize, props);
- fnvlist_free(props);
-
- if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
- new_reservation) != 0) {
- (void) no_memory(zhp->zfs_hdl);
- return (-1);
- }
- return (1);
-}
-
-/*
- * Helper for 'zfs {set|clone} refreservation=auto'. Must be called after
- * zfs_valid_proplist(), as it is what sets the UINT64_MAX sentinal value.
- * Return codes must match zfs_add_synthetic_resv().
- */
-static int
-zfs_fix_auto_resv(zfs_handle_t *zhp, nvlist_t *nvl)
-{
- uint64_t volsize;
- uint64_t resvsize;
- zfs_prop_t prop;
- nvlist_t *props;
-
- if (!ZFS_IS_VOLUME(zhp)) {
- return (0);
- }
-
- if (zfs_which_resv_prop(zhp, &prop) != 0) {
- return (-1);
- }
-
- if (prop != ZFS_PROP_REFRESERVATION) {
- return (0);
- }
-
- if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(prop), &resvsize) != 0) {
- /* No value being set, so it can't be "auto" */
- return (0);
- }
- if (resvsize != UINT64_MAX) {
- /* Being set to a value other than "auto" */
- return (0);
- }
-
- props = fnvlist_alloc();
-
- fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
- zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
-
- if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
- &volsize) != 0) {
- volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
- }
-
- resvsize = zvol_volsize_to_reservation(volsize, props);
- fnvlist_free(props);
-
- (void) nvlist_remove_all(nvl, zfs_prop_to_name(prop));
- if (nvlist_add_uint64(nvl, zfs_prop_to_name(prop), resvsize) != 0) {
- (void) no_memory(zhp->zfs_hdl);
- return (-1);
- }
- return (1);
-}
-
-void
-zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
- char *errbuf)
-{
- switch (err) {
-
- case ENOSPC:
- /*
- * For quotas and reservations, ENOSPC indicates
- * something different; setting a quota or reservation
- * doesn't use any disk space.
- */
- switch (prop) {
- case ZFS_PROP_QUOTA:
- case ZFS_PROP_REFQUOTA:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "size is less than current used or "
- "reserved space"));
- (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
- break;
-
- case ZFS_PROP_RESERVATION:
- case ZFS_PROP_REFRESERVATION:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "size is greater than available space"));
- (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
- break;
-
- default:
- (void) zfs_standard_error(hdl, err, errbuf);
- break;
- }
- break;
-
- case EBUSY:
- (void) zfs_standard_error(hdl, EBUSY, errbuf);
- break;
-
- case EROFS:
- (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
- break;
-
- case E2BIG:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property value too long"));
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- break;
-
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool and or dataset must be upgraded to set this "
- "property or value"));
- (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
- break;
-
- case ERANGE:
- case EDOM:
- if (prop == ZFS_PROP_COMPRESSION ||
- prop == ZFS_PROP_RECORDSIZE) {
- (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property setting is not allowed on "
- "bootable datasets"));
- (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
- } else if (prop == ZFS_PROP_CHECKSUM ||
- prop == ZFS_PROP_DEDUP) {
- (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property setting is not allowed on "
- "root pools"));
- (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
- } else {
- (void) zfs_standard_error(hdl, err, errbuf);
- }
- break;
-
- case EINVAL:
- if (prop == ZPROP_INVAL) {
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- } else {
- (void) zfs_standard_error(hdl, err, errbuf);
- }
- break;
-
- case EOVERFLOW:
- /*
- * This platform can't address a volume this big.
- */
-#ifdef _ILP32
- if (prop == ZFS_PROP_VOLSIZE) {
- (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
- break;
- }
-#endif
- /* FALLTHROUGH */
- default:
- (void) zfs_standard_error(hdl, err, errbuf);
- }
-}
-
-/*
- * Given a property name and value, set the property for the given dataset.
- */
-int
-zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
-{
- int ret = -1;
- char errbuf[1024];
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- nvlist_t *nvl = NULL;
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
- zhp->zfs_name);
-
- if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
- nvlist_add_string(nvl, propname, propval) != 0) {
- (void) no_memory(hdl);
- goto error;
- }
-
- ret = zfs_prop_set_list(zhp, nvl);
-
-error:
- nvlist_free(nvl);
- return (ret);
-}
-
-
-
-/*
- * Given an nvlist of property names and values, set the properties for the
- * given dataset.
- */
-int
-zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
-{
- zfs_cmd_t zc = { 0 };
- int ret = -1;
- prop_changelist_t **cls = NULL;
- int cl_idx;
- char errbuf[1024];
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- nvlist_t *nvl;
- int nvl_len;
- int added_resv = 0;
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
- zhp->zfs_name);
-
- if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
- zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
- errbuf)) == NULL)
- goto error;
-
- /*
- * We have to check for any extra properties which need to be added
- * before computing the length of the nvlist.
- */
- for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
- elem != NULL;
- elem = nvlist_next_nvpair(nvl, elem)) {
- if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
- (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
- goto error;
- }
- }
-
- if (added_resv != 1 &&
- (added_resv = zfs_fix_auto_resv(zhp, nvl)) == -1) {
- goto error;
- }
-
- /*
- * Check how many properties we're setting and allocate an array to
- * store changelist pointers for postfix().
- */
- nvl_len = 0;
- for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
- elem != NULL;
- elem = nvlist_next_nvpair(nvl, elem))
- nvl_len++;
- if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
- goto error;
-
- cl_idx = 0;
- for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
- elem != NULL;
- elem = nvlist_next_nvpair(nvl, elem)) {
-
- zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
-
- assert(cl_idx < nvl_len);
- /*
- * We don't want to unmount & remount the dataset when changing
- * its canmount property to 'on' or 'noauto'. We only use
- * the changelist logic to unmount when setting canmount=off.
- */
- if (prop != ZFS_PROP_CANMOUNT ||
- (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF &&
- zfs_is_mounted(zhp, NULL))) {
- cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
- if (cls[cl_idx] == NULL)
- goto error;
- }
-
- if (prop == ZFS_PROP_MOUNTPOINT &&
- changelist_haszonedchild(cls[cl_idx])) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "child dataset with inherited mountpoint is used "
- "in a non-global zone"));
- ret = zfs_error(hdl, EZFS_ZONED, errbuf);
- goto error;
- }
-
- /* We don't support those properties on FreeBSD. */
- switch (prop) {
- case ZFS_PROP_DEVICES:
- case ZFS_PROP_ISCSIOPTIONS:
- case ZFS_PROP_XATTR:
- case ZFS_PROP_VSCAN:
- case ZFS_PROP_NBMAND:
- case ZFS_PROP_MLSLABEL:
- (void) snprintf(errbuf, sizeof (errbuf),
- "property '%s' not supported on FreeBSD",
- nvpair_name(elem));
- ret = zfs_error(hdl, EZFS_PERM, errbuf);
- goto error;
- }
-
- if (cls[cl_idx] != NULL &&
- (ret = changelist_prefix(cls[cl_idx])) != 0)
- goto error;
-
- cl_idx++;
- }
- assert(cl_idx == nvl_len);
-
- /*
- * Execute the corresponding ioctl() to set this list of properties.
- */
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
- if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
- (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
- goto error;
-
- ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
-
- if (ret != 0) {
- if (zc.zc_nvlist_dst_filled == B_FALSE) {
- (void) zfs_standard_error(hdl, errno, errbuf);
- goto error;
- }
-
- /* Get the list of unset properties back and report them. */
- nvlist_t *errorprops = NULL;
- if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
- goto error;
- for (nvpair_t *elem = nvlist_next_nvpair(errorprops, NULL);
- elem != NULL;
- elem = nvlist_next_nvpair(errorprops, elem)) {
- zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
- zfs_setprop_error(hdl, prop, errno, errbuf);
- }
- nvlist_free(errorprops);
-
- if (added_resv && errno == ENOSPC) {
- /* clean up the volsize property we tried to set */
- uint64_t old_volsize = zfs_prop_get_int(zhp,
- ZFS_PROP_VOLSIZE);
- nvlist_free(nvl);
- nvl = NULL;
- zcmd_free_nvlists(&zc);
-
- if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
- goto error;
- if (nvlist_add_uint64(nvl,
- zfs_prop_to_name(ZFS_PROP_VOLSIZE),
- old_volsize) != 0)
- goto error;
- if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
- goto error;
- (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
- }
- } else {
- for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
- if (cls[cl_idx] != NULL) {
- int clp_err = changelist_postfix(cls[cl_idx]);
- if (clp_err != 0)
- ret = clp_err;
- }
- }
-
- /*
- * Refresh the statistics so the new property value
- * is reflected.
- */
- if (ret == 0)
- (void) get_stats(zhp);
- }
-
-error:
- nvlist_free(nvl);
- zcmd_free_nvlists(&zc);
- if (cls != NULL) {
- for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
- if (cls[cl_idx] != NULL)
- changelist_free(cls[cl_idx]);
- }
- free(cls);
- }
- return (ret);
-}
-
-/*
- * Given a property, inherit the value from the parent dataset, or if received
- * is TRUE, revert to the received value, if any.
- */
-int
-zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
-{
- zfs_cmd_t zc = { 0 };
- int ret;
- prop_changelist_t *cl;
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- char errbuf[1024];
- zfs_prop_t prop;
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
-
- zc.zc_cookie = received;
- if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
- /*
- * For user properties, the amount of work we have to do is very
- * small, so just do it here.
- */
- if (!zfs_prop_user(propname)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid property"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
-
- if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
- return (zfs_standard_error(hdl, errno, errbuf));
-
- return (0);
- }
-
- /*
- * Verify that this property is inheritable.
- */
- if (zfs_prop_readonly(prop))
- return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
-
- if (!zfs_prop_inheritable(prop) && !received)
- return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
-
- /*
- * Check to see if the value applies to this type
- */
- if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
- return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
-
- /*
- * Normalize the name, to get rid of shorthand abbreviations.
- */
- propname = zfs_prop_to_name(prop);
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
-
- if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
- zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "dataset is used in a non-global zone"));
- return (zfs_error(hdl, EZFS_ZONED, errbuf));
- }
-
- /*
- * Determine datasets which will be affected by this change, if any.
- */
- if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
- return (-1);
-
- if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "child dataset with inherited mountpoint is used "
- "in a non-global zone"));
- ret = zfs_error(hdl, EZFS_ZONED, errbuf);
- goto error;
- }
-
- if ((ret = changelist_prefix(cl)) != 0)
- goto error;
-
- if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
- return (zfs_standard_error(hdl, errno, errbuf));
- } else {
-
- if ((ret = changelist_postfix(cl)) != 0)
- goto error;
-
- /*
- * Refresh the statistics so the new property is reflected.
- */
- (void) get_stats(zhp);
- }
-
-error:
- changelist_free(cl);
- return (ret);
-}
-
-/*
- * True DSL properties are stored in an nvlist. The following two functions
- * extract them appropriately.
- */
-static uint64_t
-getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
-{
- nvlist_t *nv;
- uint64_t value;
-
- *source = NULL;
- if (nvlist_lookup_nvlist(zhp->zfs_props,
- zfs_prop_to_name(prop), &nv) == 0) {
- verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
- (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
- } else {
- verify(!zhp->zfs_props_table ||
- zhp->zfs_props_table[prop] == B_TRUE);
- value = zfs_prop_default_numeric(prop);
- *source = "";
- }
-
- return (value);
-}
-
-static const char *
-getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
-{
- nvlist_t *nv;
- const char *value;
-
- *source = NULL;
- if (nvlist_lookup_nvlist(zhp->zfs_props,
- zfs_prop_to_name(prop), &nv) == 0) {
- value = fnvlist_lookup_string(nv, ZPROP_VALUE);
- (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
- } else {
- verify(!zhp->zfs_props_table ||
- zhp->zfs_props_table[prop] == B_TRUE);
- value = zfs_prop_default_string(prop);
- *source = "";
- }
-
- return (value);
-}
-
-static boolean_t
-zfs_is_recvd_props_mode(zfs_handle_t *zhp)
-{
- return (zhp->zfs_props == zhp->zfs_recvd_props);
-}
-
-static void
-zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
-{
- *cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
- zhp->zfs_props = zhp->zfs_recvd_props;
-}
-
-static void
-zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
-{
- zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
- *cookie = 0;
-}
-
-/*
- * Internal function for getting a numeric property. Both zfs_prop_get() and
- * zfs_prop_get_int() are built using this interface.
- *
- * Certain properties can be overridden using 'mount -o'. In this case, scan
- * the contents of the /etc/mnttab entry, searching for the appropriate options.
- * If they differ from the on-disk values, report the current values and mark
- * the source "temporary".
- */
-static int
-get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
- char **source, uint64_t *val)
-{
- zfs_cmd_t zc = { 0 };
- nvlist_t *zplprops = NULL;
- struct mnttab mnt;
- char *mntopt_on = NULL;
- char *mntopt_off = NULL;
- boolean_t received = zfs_is_recvd_props_mode(zhp);
-
- *source = NULL;
-
- switch (prop) {
- case ZFS_PROP_ATIME:
- mntopt_on = MNTOPT_ATIME;
- mntopt_off = MNTOPT_NOATIME;
- break;
-
- case ZFS_PROP_DEVICES:
- mntopt_on = MNTOPT_DEVICES;
- mntopt_off = MNTOPT_NODEVICES;
- break;
-
- case ZFS_PROP_EXEC:
- mntopt_on = MNTOPT_EXEC;
- mntopt_off = MNTOPT_NOEXEC;
- break;
-
- case ZFS_PROP_READONLY:
- mntopt_on = MNTOPT_RO;
- mntopt_off = MNTOPT_RW;
- break;
-
- case ZFS_PROP_SETUID:
- mntopt_on = MNTOPT_SETUID;
- mntopt_off = MNTOPT_NOSETUID;
- break;
-
- case ZFS_PROP_XATTR:
- mntopt_on = MNTOPT_XATTR;
- mntopt_off = MNTOPT_NOXATTR;
- break;
-
- case ZFS_PROP_NBMAND:
- mntopt_on = MNTOPT_NBMAND;
- mntopt_off = MNTOPT_NONBMAND;
- break;
-
- default:
- break;
- }
-
- /*
- * Because looking up the mount options is potentially expensive
- * (iterating over all of /etc/mnttab), we defer its calculation until
- * we're looking up a property which requires its presence.
- */
- if (!zhp->zfs_mntcheck &&
- (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- struct mnttab entry;
-
- if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
- zhp->zfs_mntopts = zfs_strdup(hdl,
- entry.mnt_mntopts);
- if (zhp->zfs_mntopts == NULL)
- return (-1);
- }
-
- zhp->zfs_mntcheck = B_TRUE;
- }
-
- if (zhp->zfs_mntopts == NULL)
- mnt.mnt_mntopts = "";
- else
- mnt.mnt_mntopts = zhp->zfs_mntopts;
-
- switch (prop) {
- case ZFS_PROP_ATIME:
- case ZFS_PROP_DEVICES:
- case ZFS_PROP_EXEC:
- case ZFS_PROP_READONLY:
- case ZFS_PROP_SETUID:
- case ZFS_PROP_XATTR:
- case ZFS_PROP_NBMAND:
- *val = getprop_uint64(zhp, prop, source);
-
- if (received)
- break;
-
- if (hasmntopt(&mnt, mntopt_on) && !*val) {
- *val = B_TRUE;
- if (src)
- *src = ZPROP_SRC_TEMPORARY;
- } else if (hasmntopt(&mnt, mntopt_off) && *val) {
- *val = B_FALSE;
- if (src)
- *src = ZPROP_SRC_TEMPORARY;
- }
- break;
-
- case ZFS_PROP_CANMOUNT:
- case ZFS_PROP_VOLSIZE:
- case ZFS_PROP_QUOTA:
- case ZFS_PROP_REFQUOTA:
- case ZFS_PROP_RESERVATION:
- case ZFS_PROP_REFRESERVATION:
- case ZFS_PROP_FILESYSTEM_LIMIT:
- case ZFS_PROP_SNAPSHOT_LIMIT:
- case ZFS_PROP_FILESYSTEM_COUNT:
- case ZFS_PROP_SNAPSHOT_COUNT:
- *val = getprop_uint64(zhp, prop, source);
-
- if (*source == NULL) {
- /* not default, must be local */
- *source = zhp->zfs_name;
- }
- break;
-
- case ZFS_PROP_MOUNTED:
- *val = (zhp->zfs_mntopts != NULL);
- break;
-
- case ZFS_PROP_NUMCLONES:
- *val = zhp->zfs_dmustats.dds_num_clones;
- break;
-
- case ZFS_PROP_VERSION:
- case ZFS_PROP_NORMALIZE:
- case ZFS_PROP_UTF8ONLY:
- case ZFS_PROP_CASE:
- if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
- zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
- return (-1);
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
- if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
- nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
- val) != 0) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
- nvlist_free(zplprops);
- zcmd_free_nvlists(&zc);
- break;
-
- case ZFS_PROP_INCONSISTENT:
- *val = zhp->zfs_dmustats.dds_inconsistent;
- break;
-
- default:
- switch (zfs_prop_get_type(prop)) {
- case PROP_TYPE_NUMBER:
- case PROP_TYPE_INDEX:
- *val = getprop_uint64(zhp, prop, source);
- /*
- * If we tried to use a default value for a
- * readonly property, it means that it was not
- * present. Note this only applies to "truly"
- * readonly properties, not set-once properties
- * like volblocksize.
- */
- if (zfs_prop_readonly(prop) &&
- !zfs_prop_setonce(prop) &&
- *source != NULL && (*source)[0] == '\0') {
- *source = NULL;
- return (-1);
- }
- break;
-
- case PROP_TYPE_STRING:
- default:
- zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
- "cannot get non-numeric property"));
- return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
- dgettext(TEXT_DOMAIN, "internal error")));
- }
- }
-
- return (0);
-}
-
-/*
- * Calculate the source type, given the raw source string.
- */
-static void
-get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
- char *statbuf, size_t statlen)
-{
- if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
- return;
-
- if (source == NULL) {
- *srctype = ZPROP_SRC_NONE;
- } else if (source[0] == '\0') {
- *srctype = ZPROP_SRC_DEFAULT;
- } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
- *srctype = ZPROP_SRC_RECEIVED;
- } else {
- if (strcmp(source, zhp->zfs_name) == 0) {
- *srctype = ZPROP_SRC_LOCAL;
- } else {
- (void) strlcpy(statbuf, source, statlen);
- *srctype = ZPROP_SRC_INHERITED;
- }
- }
-
-}
-
-int
-zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
- size_t proplen, boolean_t literal)
-{
- zfs_prop_t prop;
- int err = 0;
-
- if (zhp->zfs_recvd_props == NULL)
- if (get_recvd_props_ioctl(zhp) != 0)
- return (-1);
-
- prop = zfs_name_to_prop(propname);
-
- if (prop != ZPROP_INVAL) {
- uint64_t cookie;
- if (!nvlist_exists(zhp->zfs_recvd_props, propname))
- return (-1);
- zfs_set_recvd_props_mode(zhp, &cookie);
- err = zfs_prop_get(zhp, prop, propbuf, proplen,
- NULL, NULL, 0, literal);
- zfs_unset_recvd_props_mode(zhp, &cookie);
- } else {
- nvlist_t *propval;
- char *recvdval;
- if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
- propname, &propval) != 0)
- return (-1);
- verify(nvlist_lookup_string(propval, ZPROP_VALUE,
- &recvdval) == 0);
- (void) strlcpy(propbuf, recvdval, proplen);
- }
-
- return (err == 0 ? 0 : -1);
-}
-
-static int
-get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
-{
- nvlist_t *value;
- nvpair_t *pair;
-
- value = zfs_get_clones_nvl(zhp);
- if (value == NULL)
- return (-1);
-
- propbuf[0] = '\0';
- for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
- pair = nvlist_next_nvpair(value, pair)) {
- if (propbuf[0] != '\0')
- (void) strlcat(propbuf, ",", proplen);
- (void) strlcat(propbuf, nvpair_name(pair), proplen);
- }
-
- return (0);
-}
-
-struct get_clones_arg {
- uint64_t numclones;
- nvlist_t *value;
- const char *origin;
- char buf[ZFS_MAX_DATASET_NAME_LEN];
-};
-
-int
-get_clones_cb(zfs_handle_t *zhp, void *arg)
-{
- struct get_clones_arg *gca = arg;
-
- if (gca->numclones == 0) {
- zfs_close(zhp);
- return (0);
- }
-
- if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
- NULL, NULL, 0, B_TRUE) != 0)
- goto out;
- if (strcmp(gca->buf, gca->origin) == 0) {
- fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
- gca->numclones--;
- }
-
-out:
- (void) zfs_iter_children(zhp, get_clones_cb, gca);
- zfs_close(zhp);
- return (0);
-}
-
-nvlist_t *
-zfs_get_clones_nvl(zfs_handle_t *zhp)
-{
- nvlist_t *nv, *value;
-
- if (nvlist_lookup_nvlist(zhp->zfs_props,
- zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
- struct get_clones_arg gca;
-
- /*
- * if this is a snapshot, then the kernel wasn't able
- * to get the clones. Do it by slowly iterating.
- */
- if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
- return (NULL);
- if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
- return (NULL);
- if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
- nvlist_free(nv);
- return (NULL);
- }
-
- gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
- gca.value = value;
- gca.origin = zhp->zfs_name;
-
- if (gca.numclones != 0) {
- zfs_handle_t *root;
- char pool[ZFS_MAX_DATASET_NAME_LEN];
- char *cp = pool;
-
- /* get the pool name */
- (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
- (void) strsep(&cp, "/@");
- root = zfs_open(zhp->zfs_hdl, pool,
- ZFS_TYPE_FILESYSTEM);
-
- (void) get_clones_cb(root, &gca);
- }
-
- if (gca.numclones != 0 ||
- nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
- nvlist_add_nvlist(zhp->zfs_props,
- zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
- nvlist_free(nv);
- nvlist_free(value);
- return (NULL);
- }
- nvlist_free(nv);
- nvlist_free(value);
- verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
- zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
- }
-
- verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
-
- return (value);
-}
-
-/*
- * Accepts a property and value and checks that the value
- * matches the one found by the channel program. If they are
- * not equal, print both of them.
- */
-void
-zcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval,
- const char *strval)
-{
- if (!zhp->zfs_hdl->libzfs_prop_debug)
- return;
- int error;
- char *poolname = zhp->zpool_hdl->zpool_name;
- const char *program =
- "args = ...\n"
- "ds = args['dataset']\n"
- "prop = args['property']\n"
- "value, setpoint = zfs.get_prop(ds, prop)\n"
- "return {value=value, setpoint=setpoint}\n";
- nvlist_t *outnvl;
- nvlist_t *retnvl;
- nvlist_t *argnvl = fnvlist_alloc();
-
- fnvlist_add_string(argnvl, "dataset", zhp->zfs_name);
- fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop));
-
- error = lzc_channel_program_nosync(poolname, program,
- 10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl);
-
- if (error == 0) {
- retnvl = fnvlist_lookup_nvlist(outnvl, "return");
- if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) {
- int64_t ans;
- error = nvlist_lookup_int64(retnvl, "value", &ans);
- if (error != 0) {
- (void) fprintf(stderr, "zcp check error: %u\n",
- error);
- return;
- }
- if (ans != intval) {
- (void) fprintf(stderr,
- "%s: zfs found %lld, but zcp found %lld\n",
- zfs_prop_to_name(prop),
- (longlong_t)intval, (longlong_t)ans);
- }
- } else {
- char *str_ans;
- error = nvlist_lookup_string(retnvl, "value", &str_ans);
- if (error != 0) {
- (void) fprintf(stderr, "zcp check error: %u\n",
- error);
- return;
- }
- if (strcmp(strval, str_ans) != 0) {
- (void) fprintf(stderr,
- "%s: zfs found %s, but zcp found %s\n",
- zfs_prop_to_name(prop),
- strval, str_ans);
- }
- }
- } else {
- (void) fprintf(stderr,
- "zcp check failed, channel program error: %u\n", error);
- }
- nvlist_free(argnvl);
- nvlist_free(outnvl);
-}
-
-/*
- * Retrieve a property from the given object. If 'literal' is specified, then
- * numbers are left as exact values. Otherwise, numbers are converted to a
- * human-readable form.
- *
- * Returns 0 on success, or -1 on error.
- */
-int
-zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
- zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
-{
- char *source = NULL;
- uint64_t val;
- const char *str;
- const char *strval;
- boolean_t received = zfs_is_recvd_props_mode(zhp);
-
- /*
- * Check to see if this property applies to our object
- */
- if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
- return (-1);
-
- if (received && zfs_prop_readonly(prop))
- return (-1);
-
- if (src)
- *src = ZPROP_SRC_NONE;
-
- switch (prop) {
- case ZFS_PROP_CREATION:
- /*
- * 'creation' is a time_t stored in the statistics. We convert
- * this into a string unless 'literal' is specified.
- */
- {
- val = getprop_uint64(zhp, prop, &source);
- time_t time = (time_t)val;
- struct tm t;
-
- if (literal ||
- localtime_r(&time, &t) == NULL ||
- strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
- &t) == 0)
- (void) snprintf(propbuf, proplen, "%llu", val);
- }
- zcp_check(zhp, prop, val, NULL);
- break;
-
- case ZFS_PROP_MOUNTPOINT:
- /*
- * Getting the precise mountpoint can be tricky.
- *
- * - for 'none' or 'legacy', return those values.
- * - for inherited mountpoints, we want to take everything
- * after our ancestor and append it to the inherited value.
- *
- * If the pool has an alternate root, we want to prepend that
- * root to any values we return.
- */
-
- str = getprop_string(zhp, prop, &source);
-
- if (str[0] == '/') {
- char buf[MAXPATHLEN];
- char *root = buf;
- const char *relpath;
-
- /*
- * If we inherit the mountpoint, even from a dataset
- * with a received value, the source will be the path of
- * the dataset we inherit from. If source is
- * ZPROP_SOURCE_VAL_RECVD, the received value is not
- * inherited.
- */
- if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
- relpath = "";
- } else {
- relpath = zhp->zfs_name + strlen(source);
- if (relpath[0] == '/')
- relpath++;
- }
-
- if ((zpool_get_prop(zhp->zpool_hdl,
- ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
- B_FALSE)) || (strcmp(root, "-") == 0))
- root[0] = '\0';
- /*
- * Special case an alternate root of '/'. This will
- * avoid having multiple leading slashes in the
- * mountpoint path.
- */
- if (strcmp(root, "/") == 0)
- root++;
-
- /*
- * If the mountpoint is '/' then skip over this
- * if we are obtaining either an alternate root or
- * an inherited mountpoint.
- */
- if (str[1] == '\0' && (root[0] != '\0' ||
- relpath[0] != '\0'))
- str++;
-
- if (relpath[0] == '\0')
- (void) snprintf(propbuf, proplen, "%s%s",
- root, str);
- else
- (void) snprintf(propbuf, proplen, "%s%s%s%s",
- root, str, relpath[0] == '@' ? "" : "/",
- relpath);
- } else {
- /* 'legacy' or 'none' */
- (void) strlcpy(propbuf, str, proplen);
- }
- zcp_check(zhp, prop, NULL, propbuf);
- break;
-
- case ZFS_PROP_ORIGIN:
- str = getprop_string(zhp, prop, &source);
- if (str == NULL)
- return (-1);
- (void) strlcpy(propbuf, str, proplen);
- zcp_check(zhp, prop, NULL, str);
- break;
-
- case ZFS_PROP_CLONES:
- if (get_clones_string(zhp, propbuf, proplen) != 0)
- return (-1);
- break;
-
- case ZFS_PROP_QUOTA:
- case ZFS_PROP_REFQUOTA:
- case ZFS_PROP_RESERVATION:
- case ZFS_PROP_REFRESERVATION:
-
- if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
- return (-1);
- /*
- * If quota or reservation is 0, we translate this into 'none'
- * (unless literal is set), and indicate that it's the default
- * value. Otherwise, we print the number nicely and indicate
- * that its set locally.
- */
- if (val == 0) {
- if (literal)
- (void) strlcpy(propbuf, "0", proplen);
- else
- (void) strlcpy(propbuf, "none", proplen);
- } else {
- if (literal)
- (void) snprintf(propbuf, proplen, "%llu",
- (u_longlong_t)val);
- else
- zfs_nicenum(val, propbuf, proplen);
- }
- zcp_check(zhp, prop, val, NULL);
- break;
-
- case ZFS_PROP_FILESYSTEM_LIMIT:
- case ZFS_PROP_SNAPSHOT_LIMIT:
- case ZFS_PROP_FILESYSTEM_COUNT:
- case ZFS_PROP_SNAPSHOT_COUNT:
-
- if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
- return (-1);
-
- /*
- * If limit is UINT64_MAX, we translate this into 'none' (unless
- * literal is set), and indicate that it's the default value.
- * Otherwise, we print the number nicely and indicate that it's
- * set locally.
- */
- if (literal) {
- (void) snprintf(propbuf, proplen, "%llu",
- (u_longlong_t)val);
- } else if (val == UINT64_MAX) {
- (void) strlcpy(propbuf, "none", proplen);
- } else {
- zfs_nicenum(val, propbuf, proplen);
- }
-
- zcp_check(zhp, prop, val, NULL);
- break;
-
- case ZFS_PROP_REFRATIO:
- case ZFS_PROP_COMPRESSRATIO:
- if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
- return (-1);
- (void) snprintf(propbuf, proplen, "%llu.%02llux",
- (u_longlong_t)(val / 100),
- (u_longlong_t)(val % 100));
- zcp_check(zhp, prop, val, NULL);
- break;
-
- case ZFS_PROP_TYPE:
- switch (zhp->zfs_type) {
- case ZFS_TYPE_FILESYSTEM:
- str = "filesystem";
- break;
- case ZFS_TYPE_VOLUME:
- str = "volume";
- break;
- case ZFS_TYPE_SNAPSHOT:
- str = "snapshot";
- break;
- case ZFS_TYPE_BOOKMARK:
- str = "bookmark";
- break;
- default:
- abort();
- }
- (void) snprintf(propbuf, proplen, "%s", str);
- zcp_check(zhp, prop, NULL, propbuf);
- break;
-
- case ZFS_PROP_MOUNTED:
- /*
- * The 'mounted' property is a pseudo-property that described
- * whether the filesystem is currently mounted. Even though
- * it's a boolean value, the typical values of "on" and "off"
- * don't make sense, so we translate to "yes" and "no".
- */
- if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
- src, &source, &val) != 0)
- return (-1);
- if (val)
- (void) strlcpy(propbuf, "yes", proplen);
- else
- (void) strlcpy(propbuf, "no", proplen);
- break;
-
- case ZFS_PROP_NAME:
- /*
- * The 'name' property is a pseudo-property derived from the
- * dataset name. It is presented as a real property to simplify
- * consumers.
- */
- (void) strlcpy(propbuf, zhp->zfs_name, proplen);
- zcp_check(zhp, prop, NULL, propbuf);
- break;
-
- case ZFS_PROP_MLSLABEL:
- {
-#ifdef illumos
- m_label_t *new_sl = NULL;
- char *ascii = NULL; /* human readable label */
-
- (void) strlcpy(propbuf,
- getprop_string(zhp, prop, &source), proplen);
-
- if (literal || (strcasecmp(propbuf,
- ZFS_MLSLABEL_DEFAULT) == 0))
- break;
-
- /*
- * Try to translate the internal hex string to
- * human-readable output. If there are any
- * problems just use the hex string.
- */
-
- if (str_to_label(propbuf, &new_sl, MAC_LABEL,
- L_NO_CORRECTION, NULL) == -1) {
- m_label_free(new_sl);
- break;
- }
-
- if (label_to_str(new_sl, &ascii, M_LABEL,
- DEF_NAMES) != 0) {
- if (ascii)
- free(ascii);
- m_label_free(new_sl);
- break;
- }
- m_label_free(new_sl);
-
- (void) strlcpy(propbuf, ascii, proplen);
- free(ascii);
-#else /* !illumos */
- propbuf[0] = '\0';
-#endif /* illumos */
- }
- break;
-
- case ZFS_PROP_GUID:
- case ZFS_PROP_CREATETXG:
- /*
- * GUIDs are stored as numbers, but they are identifiers.
- * We don't want them to be pretty printed, because pretty
- * printing mangles the ID into a truncated and useless value.
- */
- if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
- return (-1);
- (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
- zcp_check(zhp, prop, val, NULL);
- break;
-
- default:
- switch (zfs_prop_get_type(prop)) {
- case PROP_TYPE_NUMBER:
- if (get_numeric_property(zhp, prop, src,
- &source, &val) != 0) {
- return (-1);
- }
-
- if (literal) {
- (void) snprintf(propbuf, proplen, "%llu",
- (u_longlong_t)val);
- } else {
- zfs_nicenum(val, propbuf, proplen);
- }
- zcp_check(zhp, prop, val, NULL);
- break;
-
- case PROP_TYPE_STRING:
- str = getprop_string(zhp, prop, &source);
- if (str == NULL)
- return (-1);
-
- (void) strlcpy(propbuf, str, proplen);
- zcp_check(zhp, prop, NULL, str);
- break;
-
- case PROP_TYPE_INDEX:
- if (get_numeric_property(zhp, prop, src,
- &source, &val) != 0)
- return (-1);
- if (zfs_prop_index_to_string(prop, val, &strval) != 0)
- return (-1);
-
- (void) strlcpy(propbuf, strval, proplen);
- zcp_check(zhp, prop, NULL, strval);
- break;
-
- default:
- abort();
- }
- }
-
- get_source(zhp, src, source, statbuf, statlen);
-
- return (0);
-}
-
-/*
- * Utility function to get the given numeric property. Does no validation that
- * the given property is the appropriate type; should only be used with
- * hard-coded property types.
- */
-uint64_t
-zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
-{
- char *source;
- uint64_t val;
-
- (void) get_numeric_property(zhp, prop, NULL, &source, &val);
-
- return (val);
-}
-
-int
-zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
-{
- char buf[64];
-
- (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
- return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
-}
-
-/*
- * Similar to zfs_prop_get(), but returns the value as an integer.
- */
-int
-zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
- zprop_source_t *src, char *statbuf, size_t statlen)
-{
- char *source;
-
- /*
- * Check to see if this property applies to our object
- */
- if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
- return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
- dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
- zfs_prop_to_name(prop)));
- }
-
- if (src)
- *src = ZPROP_SRC_NONE;
-
- if (get_numeric_property(zhp, prop, src, &source, value) != 0)
- return (-1);
-
- get_source(zhp, src, source, statbuf, statlen);
-
- return (0);
-}
-
-static int
-idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
- char **domainp, idmap_rid_t *ridp)
-{
-#ifdef illumos
- idmap_get_handle_t *get_hdl = NULL;
- idmap_stat status;
- int err = EINVAL;
-
- if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
- goto out;
-
- if (isuser) {
- err = idmap_get_sidbyuid(get_hdl, id,
- IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
- } else {
- err = idmap_get_sidbygid(get_hdl, id,
- IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
- }
- if (err == IDMAP_SUCCESS &&
- idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
- status == IDMAP_SUCCESS)
- err = 0;
- else
- err = EINVAL;
-out:
- if (get_hdl)
- idmap_get_destroy(get_hdl);
- return (err);
-#else /* !illumos */
- assert(!"invalid code path");
- return (EINVAL); // silence compiler warning
-#endif /* illumos */
-}
-
-/*
- * convert the propname into parameters needed by kernel
- * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
- * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
- */
-static int
-userquota_propname_decode(const char *propname, boolean_t zoned,
- zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
-{
- zfs_userquota_prop_t type;
- char *cp, *end;
- char *numericsid = NULL;
- boolean_t isuser;
-
- domain[0] = '\0';
- *ridp = 0;
- /* Figure out the property type ({user|group}{quota|space}) */
- for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
- if (strncmp(propname, zfs_userquota_prop_prefixes[type],
- strlen(zfs_userquota_prop_prefixes[type])) == 0)
- break;
- }
- if (type == ZFS_NUM_USERQUOTA_PROPS)
- return (EINVAL);
- *typep = type;
-
- isuser = (type == ZFS_PROP_USERQUOTA ||
- type == ZFS_PROP_USERUSED);
-
- cp = strchr(propname, '@') + 1;
-
- if (strchr(cp, '@')) {
-#ifdef illumos
- /*
- * It's a SID name (eg "user@domain") that needs to be
- * turned into S-1-domainID-RID.
- */
- int flag = 0;
- idmap_stat stat, map_stat;
- uid_t pid;
- idmap_rid_t rid;
- idmap_get_handle_t *gh = NULL;
-
- stat = idmap_get_create(&gh);
- if (stat != IDMAP_SUCCESS) {
- idmap_get_destroy(gh);
- return (ENOMEM);
- }
- if (zoned && getzoneid() == GLOBAL_ZONEID)
- return (ENOENT);
- if (isuser) {
- stat = idmap_getuidbywinname(cp, NULL, flag, &pid);
- if (stat < 0)
- return (ENOENT);
- stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid,
- &rid, &map_stat);
- } else {
- stat = idmap_getgidbywinname(cp, NULL, flag, &pid);
- if (stat < 0)
- return (ENOENT);
- stat = idmap_get_sidbygid(gh, pid, flag, &numericsid,
- &rid, &map_stat);
- }
- if (stat < 0) {
- idmap_get_destroy(gh);
- return (ENOENT);
- }
- stat = idmap_get_mappings(gh);
- idmap_get_destroy(gh);
-
- if (stat < 0) {
- return (ENOENT);
- }
- if (numericsid == NULL)
- return (ENOENT);
- cp = numericsid;
- *ridp = rid;
- /* will be further decoded below */
-#else /* !illumos */
- return (ENOENT);
-#endif /* illumos */
- }
-
- if (strncmp(cp, "S-1-", 4) == 0) {
- /* It's a numeric SID (eg "S-1-234-567-89") */
- (void) strlcpy(domain, cp, domainlen);
- errno = 0;
- if (*ridp == 0) {
- cp = strrchr(domain, '-');
- *cp = '\0';
- cp++;
- *ridp = strtoull(cp, &end, 10);
- } else {
- end = "";
- }
- if (numericsid) {
- free(numericsid);
- numericsid = NULL;
- }
- if (errno != 0 || *end != '\0')
- return (EINVAL);
- } else if (!isdigit(*cp)) {
- /*
- * It's a user/group name (eg "user") that needs to be
- * turned into a uid/gid
- */
- if (zoned && getzoneid() == GLOBAL_ZONEID)
- return (ENOENT);
- if (isuser) {
- struct passwd *pw;
- pw = getpwnam(cp);
- if (pw == NULL)
- return (ENOENT);
- *ridp = pw->pw_uid;
- } else {
- struct group *gr;
- gr = getgrnam(cp);
- if (gr == NULL)
- return (ENOENT);
- *ridp = gr->gr_gid;
- }
- } else {
- /* It's a user/group ID (eg "12345"). */
- uid_t id = strtoul(cp, &end, 10);
- idmap_rid_t rid;
- char *mapdomain;
-
- if (*end != '\0')
- return (EINVAL);
- if (id > MAXUID) {
- /* It's an ephemeral ID. */
- if (idmap_id_to_numeric_domain_rid(id, isuser,
- &mapdomain, &rid) != 0)
- return (ENOENT);
- (void) strlcpy(domain, mapdomain, domainlen);
- *ridp = rid;
- } else {
- *ridp = id;
- }
- }
-
- ASSERT3P(numericsid, ==, NULL);
- return (0);
-}
-
-static int
-zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
- uint64_t *propvalue, zfs_userquota_prop_t *typep)
-{
- int err;
- zfs_cmd_t zc = { 0 };
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
- err = userquota_propname_decode(propname,
- zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
- typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
- zc.zc_objset_type = *typep;
- if (err)
- return (err);
-
- err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
- if (err)
- return (err);
-
- *propvalue = zc.zc_cookie;
- return (0);
-}
-
-int
-zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
- uint64_t *propvalue)
-{
- zfs_userquota_prop_t type;
-
- return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
- &type));
-}
-
-int
-zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
- char *propbuf, int proplen, boolean_t literal)
-{
- int err;
- uint64_t propvalue;
- zfs_userquota_prop_t type;
-
- err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
- &type);
-
- if (err)
- return (err);
-
- if (literal) {
- (void) snprintf(propbuf, proplen, "%llu", propvalue);
- } else if (propvalue == 0 &&
- (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
- (void) strlcpy(propbuf, "none", proplen);
- } else {
- zfs_nicenum(propvalue, propbuf, proplen);
- }
- return (0);
-}
-
-int
-zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
- uint64_t *propvalue)
-{
- int err;
- zfs_cmd_t zc = { 0 };
- const char *snapname;
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
- snapname = strchr(propname, '@') + 1;
- if (strchr(snapname, '@')) {
- (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
- } else {
- /* snapname is the short name, append it to zhp's fsname */
- char *cp;
-
- (void) strlcpy(zc.zc_value, zhp->zfs_name,
- sizeof (zc.zc_value));
- cp = strchr(zc.zc_value, '@');
- if (cp != NULL)
- *cp = '\0';
- (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
- (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
- }
-
- err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
- if (err)
- return (err);
-
- *propvalue = zc.zc_cookie;
- return (0);
-}
-
-int
-zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
- char *propbuf, int proplen, boolean_t literal)
-{
- int err;
- uint64_t propvalue;
-
- err = zfs_prop_get_written_int(zhp, propname, &propvalue);
-
- if (err)
- return (err);
-
- if (literal) {
- (void) snprintf(propbuf, proplen, "%llu", propvalue);
- } else {
- zfs_nicenum(propvalue, propbuf, proplen);
- }
- return (0);
-}
-
-/*
- * Returns the name of the given zfs handle.
- */
-const char *
-zfs_get_name(const zfs_handle_t *zhp)
-{
- return (zhp->zfs_name);
-}
-
-/*
- * Returns the name of the parent pool for the given zfs handle.
- */
-const char *
-zfs_get_pool_name(const zfs_handle_t *zhp)
-{
- return (zhp->zpool_hdl->zpool_name);
-}
-
-/*
- * Returns the type of the given zfs handle.
- */
-zfs_type_t
-zfs_get_type(const zfs_handle_t *zhp)
-{
- return (zhp->zfs_type);
-}
-
-/*
- * Is one dataset name a child dataset of another?
- *
- * Needs to handle these cases:
- * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo"
- * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar"
- * Descendant? No. No. No. Yes.
- */
-static boolean_t
-is_descendant(const char *ds1, const char *ds2)
-{
- size_t d1len = strlen(ds1);
-
- /* ds2 can't be a descendant if it's smaller */
- if (strlen(ds2) < d1len)
- return (B_FALSE);
-
- /* otherwise, compare strings and verify that there's a '/' char */
- return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
-}
-
-/*
- * Given a complete name, return just the portion that refers to the parent.
- * Will return -1 if there is no parent (path is just the name of the
- * pool).
- */
-static int
-parent_name(const char *path, char *buf, size_t buflen)
-{
- char *slashp;
-
- (void) strlcpy(buf, path, buflen);
-
- if ((slashp = strrchr(buf, '/')) == NULL)
- return (-1);
- *slashp = '\0';
-
- return (0);
-}
-
-/*
- * If accept_ancestor is false, then check to make sure that the given path has
- * a parent, and that it exists. If accept_ancestor is true, then find the
- * closest existing ancestor for the given path. In prefixlen return the
- * length of already existing prefix of the given path. We also fetch the
- * 'zoned' property, which is used to validate property settings when creating
- * new datasets.
- */
-static int
-check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
- boolean_t accept_ancestor, int *prefixlen)
-{
- zfs_cmd_t zc = { 0 };
- char parent[ZFS_MAX_DATASET_NAME_LEN];
- char *slash;
- zfs_handle_t *zhp;
- char errbuf[1024];
- uint64_t is_zoned;
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
-
- /* get parent, and check to see if this is just a pool */
- if (parent_name(path, parent, sizeof (parent)) != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "missing dataset name"));
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
- }
-
- /* check to see if the pool exists */
- if ((slash = strchr(parent, '/')) == NULL)
- slash = parent + strlen(parent);
- (void) strncpy(zc.zc_name, parent, slash - parent);
- zc.zc_name[slash - parent] = '\0';
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
- errno == ENOENT) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "no such pool '%s'"), zc.zc_name);
- return (zfs_error(hdl, EZFS_NOENT, errbuf));
- }
-
- /* check to see if the parent dataset exists */
- while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
- if (errno == ENOENT && accept_ancestor) {
- /*
- * Go deeper to find an ancestor, give up on top level.
- */
- if (parent_name(parent, parent, sizeof (parent)) != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "no such pool '%s'"), zc.zc_name);
- return (zfs_error(hdl, EZFS_NOENT, errbuf));
- }
- } else if (errno == ENOENT) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "parent does not exist"));
- return (zfs_error(hdl, EZFS_NOENT, errbuf));
- } else
- return (zfs_standard_error(hdl, errno, errbuf));
- }
-
- is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
- if (zoned != NULL)
- *zoned = is_zoned;
-
- /* we are in a non-global zone, but parent is in the global zone */
- if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
- (void) zfs_standard_error(hdl, EPERM, errbuf);
- zfs_close(zhp);
- return (-1);
- }
-
- /* make sure parent is a filesystem */
- if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "parent is not a filesystem"));
- (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
- zfs_close(zhp);
- return (-1);
- }
-
- zfs_close(zhp);
- if (prefixlen != NULL)
- *prefixlen = strlen(parent);
- return (0);
-}
-
-/*
- * Finds whether the dataset of the given type(s) exists.
- */
-boolean_t
-zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
-{
- zfs_handle_t *zhp;
-
- if (!zfs_validate_name(hdl, path, types, B_FALSE))
- return (B_FALSE);
-
- /*
- * Try to get stats for the dataset, which will tell us if it exists.
- */
- if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
- int ds_type = zhp->zfs_type;
-
- zfs_close(zhp);
- if (types & ds_type)
- return (B_TRUE);
- }
- return (B_FALSE);
-}
-
-/*
- * Given a path to 'target', create all the ancestors between
- * the prefixlen portion of the path, and the target itself.
- * Fail if the initial prefixlen-ancestor does not already exist.
- */
-int
-create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
-{
- zfs_handle_t *h;
- char *cp;
- const char *opname;
-
- /* make sure prefix exists */
- cp = target + prefixlen;
- if (*cp != '/') {
- assert(strchr(cp, '/') == NULL);
- h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
- } else {
- *cp = '\0';
- h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
- *cp = '/';
- }
- if (h == NULL)
- return (-1);
- zfs_close(h);
-
- /*
- * Attempt to create, mount, and share any ancestor filesystems,
- * up to the prefixlen-long one.
- */
- for (cp = target + prefixlen + 1;
- (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) {
-
- *cp = '\0';
-
- h = make_dataset_handle(hdl, target);
- if (h) {
- /* it already exists, nothing to do here */
- zfs_close(h);
- continue;
- }
-
- if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
- NULL) != 0) {
- opname = dgettext(TEXT_DOMAIN, "create");
- goto ancestorerr;
- }
-
- h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
- if (h == NULL) {
- opname = dgettext(TEXT_DOMAIN, "open");
- goto ancestorerr;
- }
-
- if (zfs_mount(h, NULL, 0) != 0) {
- opname = dgettext(TEXT_DOMAIN, "mount");
- goto ancestorerr;
- }
-
- if (zfs_share(h) != 0) {
- opname = dgettext(TEXT_DOMAIN, "share");
- goto ancestorerr;
- }
-
- zfs_close(h);
- }
-
- return (0);
-
-ancestorerr:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "failed to %s ancestor '%s'"), opname, target);
- return (-1);
-}
-
-/*
- * Creates non-existing ancestors of the given path.
- */
-int
-zfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
-{
- int prefix;
- char *path_copy;
- char errbuf[1024];
- int rc = 0;
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot create '%s'"), path);
-
- /*
- * Check that we are not passing the nesting limit
- * before we start creating any ancestors.
- */
- if (dataset_nestcheck(path) != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "maximum name nesting depth exceeded"));
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
- }
-
- if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
- return (-1);
-
- if ((path_copy = strdup(path)) != NULL) {
- rc = create_parents(hdl, path_copy, prefix);
- free(path_copy);
- }
- if (path_copy == NULL || rc != 0)
- return (-1);
-
- return (0);
-}
-
-/*
- * Create a new filesystem or volume.
- */
-int
-zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
- nvlist_t *props)
-{
- int ret;
- uint64_t size = 0;
- uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
- char errbuf[1024];
- uint64_t zoned;
- enum lzc_dataset_type ost;
- zpool_handle_t *zpool_handle;
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot create '%s'"), path);
-
- /* validate the path, taking care to note the extended error message */
- if (!zfs_validate_name(hdl, path, type, B_TRUE))
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
-
- if (dataset_nestcheck(path) != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "maximum name nesting depth exceeded"));
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
- }
-
- /* validate parents exist */
- if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
- return (-1);
-
- /*
- * The failure modes when creating a dataset of a different type over
- * one that already exists is a little strange. In particular, if you
- * try to create a dataset on top of an existing dataset, the ioctl()
- * will return ENOENT, not EEXIST. To prevent this from happening, we
- * first try to see if the dataset exists.
- */
- if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "dataset already exists"));
- return (zfs_error(hdl, EZFS_EXISTS, errbuf));
- }
-
- if (type == ZFS_TYPE_VOLUME)
- ost = LZC_DATSET_TYPE_ZVOL;
- else
- ost = LZC_DATSET_TYPE_ZFS;
-
- /* open zpool handle for prop validation */
- char pool_path[ZFS_MAX_DATASET_NAME_LEN];
- (void) strlcpy(pool_path, path, sizeof (pool_path));
-
- /* truncate pool_path at first slash */
- char *p = strchr(pool_path, '/');
- if (p != NULL)
- *p = '\0';
-
- if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL)
- return (-1);
-
- if (props && (props = zfs_valid_proplist(hdl, type, props,
- zoned, NULL, zpool_handle, errbuf)) == 0) {
- zpool_close(zpool_handle);
- return (-1);
- }
- zpool_close(zpool_handle);
-
- if (type == ZFS_TYPE_VOLUME) {
- /*
- * If we are creating a volume, the size and block size must
- * satisfy a few restraints. First, the blocksize must be a
- * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the
- * volsize must be a multiple of the block size, and cannot be
- * zero.
- */
- if (props == NULL || nvlist_lookup_uint64(props,
- zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
- nvlist_free(props);
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "missing volume size"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
-
- if ((ret = nvlist_lookup_uint64(props,
- zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
- &blocksize)) != 0) {
- if (ret == ENOENT) {
- blocksize = zfs_prop_default_numeric(
- ZFS_PROP_VOLBLOCKSIZE);
- } else {
- nvlist_free(props);
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "missing volume block size"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
- }
-
- if (size == 0) {
- nvlist_free(props);
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "volume size cannot be zero"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
-
- if (size % blocksize != 0) {
- nvlist_free(props);
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "volume size must be a multiple of volume block "
- "size"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
- }
-
- /* create the dataset */
- ret = lzc_create(path, ost, props);
- nvlist_free(props);
-
- /* check for failure */
- if (ret != 0) {
- char parent[ZFS_MAX_DATASET_NAME_LEN];
- (void) parent_name(path, parent, sizeof (parent));
-
- switch (errno) {
- case ENOENT:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "no such parent '%s'"), parent);
- return (zfs_error(hdl, EZFS_NOENT, errbuf));
-
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded to set this "
- "property or value"));
- return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
- case ERANGE:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid property value(s) specified"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
-#ifdef _ILP32
- case EOVERFLOW:
- /*
- * This platform can't address a volume this big.
- */
- if (type == ZFS_TYPE_VOLUME)
- return (zfs_error(hdl, EZFS_VOLTOOBIG,
- errbuf));
-#endif
- /* FALLTHROUGH */
- default:
- return (zfs_standard_error(hdl, errno, errbuf));
- }
- }
-
- return (0);
-}
-
-/*
- * Destroys the given dataset. The caller must make sure that the filesystem
- * isn't mounted, and that there are no active dependents. If the file system
- * does not exist this function does nothing.
- */
-int
-zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
-{
- int error;
-
- if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT && defer)
- return (EINVAL);
-
- if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
- nvlist_t *nv = fnvlist_alloc();
- fnvlist_add_boolean(nv, zhp->zfs_name);
- error = lzc_destroy_bookmarks(nv, NULL);
- fnvlist_free(nv);
- if (error != 0) {
- return (zfs_standard_error_fmt(zhp->zfs_hdl, error,
- dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
- zhp->zfs_name));
- }
- return (0);
- }
-
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
- nvlist_t *nv = fnvlist_alloc();
- fnvlist_add_boolean(nv, zhp->zfs_name);
- error = lzc_destroy_snaps(nv, defer, NULL);
- fnvlist_free(nv);
- } else {
- error = lzc_destroy(zhp->zfs_name);
- }
-
- if (error != 0 && error != ENOENT) {
- return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
- dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
- zhp->zfs_name));
- }
-
- remove_mountpoint(zhp);
-
- return (0);
-}
-
-struct destroydata {
- nvlist_t *nvl;
- const char *snapname;
-};
-
-static int
-zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
-{
- struct destroydata *dd = arg;
- char name[ZFS_MAX_DATASET_NAME_LEN];
- int rv = 0;
-
- (void) snprintf(name, sizeof (name),
- "%s@%s", zhp->zfs_name, dd->snapname);
-
- if (lzc_exists(name))
- verify(nvlist_add_boolean(dd->nvl, name) == 0);
-
- rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
- zfs_close(zhp);
- return (rv);
-}
-
-/*
- * Destroys all snapshots with the given name in zhp & descendants.
- */
-int
-zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
-{
- int ret;
- struct destroydata dd = { 0 };
-
- dd.snapname = snapname;
- verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
- (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
-
- if (nvlist_empty(dd.nvl)) {
- ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
- dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
- zhp->zfs_name, snapname);
- } else {
- ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
- }
- nvlist_free(dd.nvl);
- return (ret);
-}
-
-/*
- * Destroys all the snapshots named in the nvlist.
- */
-int
-zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
-{
- int ret;
- nvlist_t *errlist = NULL;
-
- ret = lzc_destroy_snaps(snaps, defer, &errlist);
-
- if (ret == 0) {
- nvlist_free(errlist);
- return (0);
- }
-
- if (nvlist_empty(errlist)) {
- char errbuf[1024];
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
-
- ret = zfs_standard_error(hdl, ret, errbuf);
- }
- for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
- pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
- char errbuf[1024];
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
- nvpair_name(pair));
-
- switch (fnvpair_value_int32(pair)) {
- case EEXIST:
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "snapshot is cloned"));
- ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
- break;
- default:
- ret = zfs_standard_error(hdl, errno, errbuf);
- break;
- }
- }
-
- nvlist_free(errlist);
- return (ret);
-}
-
-/*
- * Clones the given dataset. The target must be of the same type as the source.
- */
-int
-zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
-{
- char parent[ZFS_MAX_DATASET_NAME_LEN];
- int ret;
- char errbuf[1024];
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- uint64_t zoned;
-
- assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot create '%s'"), target);
-
- /* validate the target/clone name */
- if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
-
- /* validate parents exist */
- if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
- return (-1);
-
- (void) parent_name(target, parent, sizeof (parent));
-
- /* do the clone */
-
- if (props) {
- zfs_type_t type;
-
- if (ZFS_IS_VOLUME(zhp)) {
- type = ZFS_TYPE_VOLUME;
- } else {
- type = ZFS_TYPE_FILESYSTEM;
- }
- if ((props = zfs_valid_proplist(hdl, type, props, zoned,
- zhp, zhp->zpool_hdl, errbuf)) == NULL)
- return (-1);
- if (zfs_fix_auto_resv(zhp, props) == -1) {
- nvlist_free(props);
- return (-1);
- }
- }
-
- ret = lzc_clone(target, zhp->zfs_name, props);
- nvlist_free(props);
-
- if (ret != 0) {
- switch (errno) {
-
- case ENOENT:
- /*
- * The parent doesn't exist. We should have caught this
- * above, but there may a race condition that has since
- * destroyed the parent.
- *
- * At this point, we don't know whether it's the source
- * that doesn't exist anymore, or whether the target
- * dataset doesn't exist.
- */
- zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
- "no such parent '%s'"), parent);
- return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
-
- case EXDEV:
- zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
- "source and target pools differ"));
- return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
- errbuf));
-
- default:
- return (zfs_standard_error(zhp->zfs_hdl, errno,
- errbuf));
- }
- }
-
- return (ret);
-}
-
-/*
- * Promotes the given clone fs to be the clone parent.
- */
-int
-zfs_promote(zfs_handle_t *zhp)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- char snapname[ZFS_MAX_DATASET_NAME_LEN];
- int ret;
- char errbuf[1024];
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot promote '%s'"), zhp->zfs_name);
-
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "snapshots can not be promoted"));
- return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
- }
-
- if (zhp->zfs_dmustats.dds_origin[0] == '\0') {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "not a cloned filesystem"));
- return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
- }
-
- if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
-
- ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname));
-
- if (ret != 0) {
- switch (ret) {
- case EEXIST:
- /* There is a conflicting snapshot name. */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "conflicting snapshot '%s' from parent '%s'"),
- snapname, zhp->zfs_dmustats.dds_origin);
- return (zfs_error(hdl, EZFS_EXISTS, errbuf));
-
- default:
- return (zfs_standard_error(hdl, ret, errbuf));
- }
- }
- return (ret);
-}
-
-typedef struct snapdata {
- nvlist_t *sd_nvl;
- const char *sd_snapname;
-} snapdata_t;
-
-static int
-zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
-{
- snapdata_t *sd = arg;
- char name[ZFS_MAX_DATASET_NAME_LEN];
- int rv = 0;
-
- if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
- (void) snprintf(name, sizeof (name),
- "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
-
- fnvlist_add_boolean(sd->sd_nvl, name);
-
- rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
- }
- zfs_close(zhp);
-
- return (rv);
-}
-
-int
-zfs_remap_indirects(libzfs_handle_t *hdl, const char *fs)
-{
- int err;
- char errbuf[1024];
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot remap dataset '%s'"), fs);
-
- err = lzc_remap(fs);
-
- if (err != 0) {
- switch (err) {
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded"));
- (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
- break;
- case EINVAL:
- (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
- break;
- default:
- (void) zfs_standard_error(hdl, err, errbuf);
- break;
- }
- }
-
- return (err);
-}
-
-/*
- * Creates snapshots. The keys in the snaps nvlist are the snapshots to be
- * created.
- */
-int
-zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
-{
- int ret;
- char errbuf[1024];
- nvpair_t *elem;
- nvlist_t *errors;
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot create snapshots "));
-
- elem = NULL;
- while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
- const char *snapname = nvpair_name(elem);
-
- /* validate the target name */
- if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
- B_TRUE)) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "cannot create snapshot '%s'"), snapname);
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
- }
- }
-
- /*
- * get pool handle for prop validation. assumes all snaps are in the
- * same pool, as does lzc_snapshot (below).
- */
- char pool[ZFS_MAX_DATASET_NAME_LEN];
- elem = nvlist_next_nvpair(snaps, NULL);
- (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
- pool[strcspn(pool, "/@")] = '\0';
- zpool_handle_t *zpool_hdl = zpool_open(hdl, pool);
-
- if (props != NULL &&
- (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
- props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
- zpool_close(zpool_hdl);
- return (-1);
- }
- zpool_close(zpool_hdl);
-
- ret = lzc_snapshot(snaps, props, &errors);
-
- if (ret != 0) {
- boolean_t printed = B_FALSE;
- for (elem = nvlist_next_nvpair(errors, NULL);
- elem != NULL;
- elem = nvlist_next_nvpair(errors, elem)) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "cannot create snapshot '%s'"), nvpair_name(elem));
- (void) zfs_standard_error(hdl,
- fnvpair_value_int32(elem), errbuf);
- printed = B_TRUE;
- }
- if (!printed) {
- switch (ret) {
- case EXDEV:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "multiple snapshots of same "
- "fs not allowed"));
- (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
-
- break;
- default:
- (void) zfs_standard_error(hdl, ret, errbuf);
- }
- }
- }
-
- nvlist_free(props);
- nvlist_free(errors);
- return (ret);
-}
-
-int
-zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
- nvlist_t *props)
-{
- int ret;
- snapdata_t sd = { 0 };
- char fsname[ZFS_MAX_DATASET_NAME_LEN];
- char *cp;
- zfs_handle_t *zhp;
- char errbuf[1024];
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot snapshot %s"), path);
-
- if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
-
- (void) strlcpy(fsname, path, sizeof (fsname));
- cp = strchr(fsname, '@');
- *cp = '\0';
- sd.sd_snapname = cp + 1;
-
- if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
- ZFS_TYPE_VOLUME)) == NULL) {
- return (-1);
- }
-
- verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
- if (recursive) {
- (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
- } else {
- fnvlist_add_boolean(sd.sd_nvl, path);
- }
-
- ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
- nvlist_free(sd.sd_nvl);
- zfs_close(zhp);
- return (ret);
-}
-
-/*
- * Destroy any more recent snapshots. We invoke this callback on any dependents
- * of the snapshot first. If the 'cb_dependent' member is non-zero, then this
- * is a dependent and we should just destroy it without checking the transaction
- * group.
- */
-typedef struct rollback_data {
- const char *cb_target; /* the snapshot */
- uint64_t cb_create; /* creation time reference */
- boolean_t cb_error;
- boolean_t cb_force;
-} rollback_data_t;
-
-static int
-rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
-{
- rollback_data_t *cbp = data;
- prop_changelist_t *clp;
-
- /* We must destroy this clone; first unmount it */
- clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
- cbp->cb_force ? MS_FORCE: 0);
- if (clp == NULL || changelist_prefix(clp) != 0) {
- cbp->cb_error = B_TRUE;
- zfs_close(zhp);
- return (0);
- }
- if (zfs_destroy(zhp, B_FALSE) != 0)
- cbp->cb_error = B_TRUE;
- else
- changelist_remove(clp, zhp->zfs_name);
- (void) changelist_postfix(clp);
- changelist_free(clp);
-
- zfs_close(zhp);
- return (0);
-}
-
-static int
-rollback_destroy(zfs_handle_t *zhp, void *data)
-{
- rollback_data_t *cbp = data;
-
- if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
- cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
- rollback_destroy_dependent, cbp);
-
- cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
- }
-
- zfs_close(zhp);
- return (0);
-}
-
-/*
- * Given a dataset, rollback to a specific snapshot, discarding any
- * data changes since then and making it the active dataset.
- *
- * Any snapshots and bookmarks more recent than the target are
- * destroyed, along with their dependents (i.e. clones).
- */
-int
-zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
-{
- rollback_data_t cb = { 0 };
- int err;
- boolean_t restore_resv = 0;
- uint64_t min_txg = 0, old_volsize = 0, new_volsize;
- zfs_prop_t resv_prop;
-
- assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
- zhp->zfs_type == ZFS_TYPE_VOLUME);
-
- /*
- * Destroy all recent snapshots and their dependents.
- */
- cb.cb_force = force;
- cb.cb_target = snap->zfs_name;
- cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
-
- if (cb.cb_create > 0)
- min_txg = cb.cb_create;
-
- (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb,
- min_txg, 0);
-
- (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
-
- if (cb.cb_error)
- return (-1);
-
- /*
- * Now that we have verified that the snapshot is the latest,
- * rollback to the given snapshot.
- */
-
- if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
- if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
- return (-1);
- old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
- restore_resv =
- (old_volsize == zfs_prop_get_int(zhp, resv_prop));
- }
-
- /*
- * Pass both the filesystem and the wanted snapshot names,
- * we would get an error back if the snapshot is destroyed or
- * a new snapshot is created before this request is processed.
- */
- err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name);
- if (err != 0) {
- char errbuf[1024];
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
- zhp->zfs_name);
- switch (err) {
- case EEXIST:
- zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
- "there is a snapshot or bookmark more recent "
- "than '%s'"), snap->zfs_name);
- (void) zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf);
- break;
- case ESRCH:
- zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
- "'%s' is not found among snapshots of '%s'"),
- snap->zfs_name, zhp->zfs_name);
- (void) zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf);
- break;
- case EINVAL:
- (void) zfs_error(zhp->zfs_hdl, EZFS_BADTYPE, errbuf);
- break;
- default:
- (void) zfs_standard_error(zhp->zfs_hdl, err, errbuf);
- }
- return (err);
- }
-
- /*
- * For volumes, if the pre-rollback volsize matched the pre-
- * rollback reservation and the volsize has changed then set
- * the reservation property to the post-rollback volsize.
- * Make a new handle since the rollback closed the dataset.
- */
- if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
- (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
- if (restore_resv) {
- new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
- if (old_volsize != new_volsize)
- err = zfs_prop_set_int(zhp, resv_prop,
- new_volsize);
- }
- zfs_close(zhp);
- }
- return (err);
-}
-
-/*
- * Renames the given dataset.
- */
-int
-zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
- renameflags_t flags)
-{
- int ret = 0;
- zfs_cmd_t zc = { 0 };
- char *delim;
- prop_changelist_t *cl = NULL;
- zfs_handle_t *zhrp = NULL;
- char *parentname = NULL;
- char parent[ZFS_MAX_DATASET_NAME_LEN];
- char property[ZFS_MAXPROPLEN];
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- char errbuf[1024];
-
- /* if we have the same exact name, just return success */
- if (strcmp(zhp->zfs_name, target) == 0)
- return (0);
-
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot rename to '%s'"), target);
-
- if (source != NULL) {
- /*
- * This is recursive snapshots rename, put snapshot name
- * (that might not exist) into zfs_name.
- */
- assert(flags.recurse);
-
- (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name));
- (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name));
- zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
- }
-
- /* make sure source name is valid */
- if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
-
- /*
- * Make sure the target name is valid
- */
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
- zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
- const char sep = zhp->zfs_type == ZFS_TYPE_SNAPSHOT ? '@' : '#';
-
- if ((strchr(target, sep) == NULL) || *target == sep) {
- /*
- * Snapshot target name is abbreviated,
- * reconstruct full dataset name
- */
- (void) strlcpy(parent, zhp->zfs_name, sizeof (parent));
- delim = strchr(parent, sep);
- if (strchr(target, sep) == NULL)
- *(++delim) = '\0';
- else
- *delim = '\0';
- (void) strlcat(parent, target, sizeof (parent));
- target = parent;
- } else {
- /*
- * Make sure we're renaming within the same dataset.
- */
- delim = strchr(target, sep);
- if (strncmp(zhp->zfs_name, target, delim - target)
- != 0 || zhp->zfs_name[delim - target] != sep) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "%s must be part of same dataset"),
- zhp->zfs_type == ZFS_TYPE_SNAPSHOT ?
- "snapshots" : "bookmarks");
- return (zfs_error(hdl, EZFS_CROSSTARGET,
- errbuf));
- }
- }
-
- if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
- } else {
- if (flags.recurse) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "recursive rename must be a snapshot"));
- return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
- }
-
- if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
-
- /* validate parents */
- if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
- return (-1);
-
- /* make sure we're in the same pool */
- verify((delim = strchr(target, '/')) != NULL);
- if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
- zhp->zfs_name[delim - target] != '/') {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "datasets must be within same pool"));
- return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
- }
-
- /* new name cannot be a child of the current dataset name */
- if (is_descendant(zhp->zfs_name, target)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "New dataset name cannot be a descendant of "
- "current dataset name"));
- return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
- }
- }
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
-
- if (getzoneid() == GLOBAL_ZONEID &&
- zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "dataset is used in a non-global zone"));
- return (zfs_error(hdl, EZFS_ZONED, errbuf));
- }
-
- /*
- * Avoid unmounting file systems with mountpoint property set to
- * 'legacy' or 'none' even if -u option is not given.
- */
- if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
- !flags.recurse && !flags.nounmount &&
- zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property,
- sizeof (property), NULL, NULL, 0, B_FALSE) == 0 &&
- (strcmp(property, "legacy") == 0 ||
- strcmp(property, "none") == 0)) {
- flags.nounmount = B_TRUE;
- }
- if (flags.recurse) {
- parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
- if (parentname == NULL) {
- ret = -1;
- goto error;
- }
- delim = strchr(parentname, '@');
- *delim = '\0';
- zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
- if (zhrp == NULL) {
- ret = -1;
- goto error;
- }
- } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT &&
- zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
- if ((cl = changelist_gather(zhp, ZFS_PROP_NAME,
- flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0,
- flags.forceunmount ? MS_FORCE : 0)) == NULL) {
- return (-1);
- }
-
- if (changelist_haszonedchild(cl)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "child dataset with inherited mountpoint is used "
- "in a non-global zone"));
- (void) zfs_error(hdl, EZFS_ZONED, errbuf);
- ret = -1;
- goto error;
- }
-
- if ((ret = changelist_prefix(cl)) != 0)
- goto error;
- }
-
- if (ZFS_IS_VOLUME(zhp))
- zc.zc_objset_type = DMU_OST_ZVOL;
- else
- zc.zc_objset_type = DMU_OST_ZFS;
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
-
- zc.zc_cookie = flags.recurse ? 1 : 0;
- if (flags.nounmount)
- zc.zc_cookie |= 2;
-
- if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
- /*
- * if it was recursive, the one that actually failed will
- * be in zc.zc_name
- */
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot rename '%s'"), zc.zc_name);
-
- if (flags.recurse && errno == EEXIST) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "a child dataset already has a snapshot "
- "with the new name"));
- (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
- } else if (errno == EINVAL) {
- (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
- } else {
- (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
- }
-
- /*
- * On failure, we still want to remount any filesystems that
- * were previously mounted, so we don't alter the system state.
- */
- if (cl != NULL)
- (void) changelist_postfix(cl);
- } else {
- if (cl != NULL) {
- changelist_rename(cl, zfs_get_name(zhp), target);
- ret = changelist_postfix(cl);
- }
- }
-
-error:
- if (parentname != NULL) {
- free(parentname);
- }
- if (zhrp != NULL) {
- zfs_close(zhrp);
- }
- if (cl != NULL) {
- changelist_free(cl);
- }
- return (ret);
-}
-
-nvlist_t *
-zfs_get_user_props(zfs_handle_t *zhp)
-{
- return (zhp->zfs_user_props);
-}
-
-nvlist_t *
-zfs_get_recvd_props(zfs_handle_t *zhp)
-{
- if (zhp->zfs_recvd_props == NULL)
- if (get_recvd_props_ioctl(zhp) != 0)
- return (NULL);
- return (zhp->zfs_recvd_props);
-}
-
-/*
- * This function is used by 'zfs list' to determine the exact set of columns to
- * display, and their maximum widths. This does two main things:
- *
- * - If this is a list of all properties, then expand the list to include
- * all native properties, and set a flag so that for each dataset we look
- * for new unique user properties and add them to the list.
- *
- * - For non fixed-width properties, keep track of the maximum width seen
- * so that we can size the column appropriately. If the user has
- * requested received property values, we also need to compute the width
- * of the RECEIVED column.
- */
-int
-zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
- boolean_t literal)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- zprop_list_t *entry;
- zprop_list_t **last, **start;
- nvlist_t *userprops, *propval;
- nvpair_t *elem;
- char *strval;
- char buf[ZFS_MAXPROPLEN];
-
- if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
- return (-1);
-
- userprops = zfs_get_user_props(zhp);
-
- entry = *plp;
- if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
- /*
- * Go through and add any user properties as necessary. We
- * start by incrementing our list pointer to the first
- * non-native property.
- */
- start = plp;
- while (*start != NULL) {
- if ((*start)->pl_prop == ZPROP_INVAL)
- break;
- start = &(*start)->pl_next;
- }
-
- elem = NULL;
- while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
- /*
- * See if we've already found this property in our list.
- */
- for (last = start; *last != NULL;
- last = &(*last)->pl_next) {
- if (strcmp((*last)->pl_user_prop,
- nvpair_name(elem)) == 0)
- break;
- }
-
- if (*last == NULL) {
- if ((entry = zfs_alloc(hdl,
- sizeof (zprop_list_t))) == NULL ||
- ((entry->pl_user_prop = zfs_strdup(hdl,
- nvpair_name(elem)))) == NULL) {
- free(entry);
- return (-1);
- }
-
- entry->pl_prop = ZPROP_INVAL;
- entry->pl_width = strlen(nvpair_name(elem));
- entry->pl_all = B_TRUE;
- *last = entry;
- }
- }
- }
-
- /*
- * Now go through and check the width of any non-fixed columns
- */
- for (entry = *plp; entry != NULL; entry = entry->pl_next) {
- if (entry->pl_fixed && !literal)
- continue;
-
- if (entry->pl_prop != ZPROP_INVAL) {
- if (zfs_prop_get(zhp, entry->pl_prop,
- buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
- if (strlen(buf) > entry->pl_width)
- entry->pl_width = strlen(buf);
- }
- if (received && zfs_prop_get_recvd(zhp,
- zfs_prop_to_name(entry->pl_prop),
- buf, sizeof (buf), literal) == 0)
- if (strlen(buf) > entry->pl_recvd_width)
- entry->pl_recvd_width = strlen(buf);
- } else {
- if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
- &propval) == 0) {
- verify(nvlist_lookup_string(propval,
- ZPROP_VALUE, &strval) == 0);
- if (strlen(strval) > entry->pl_width)
- entry->pl_width = strlen(strval);
- }
- if (received && zfs_prop_get_recvd(zhp,
- entry->pl_user_prop,
- buf, sizeof (buf), literal) == 0)
- if (strlen(buf) > entry->pl_recvd_width)
- entry->pl_recvd_width = strlen(buf);
- }
- }
-
- return (0);
-}
-
-int
-zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
- char *resource, void *export, void *sharetab,
- int sharemax, zfs_share_op_t operation)
-{
- zfs_cmd_t zc = { 0 };
- int error;
-
- (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
- if (resource)
- (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
- zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
- zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
- zc.zc_share.z_sharetype = operation;
- zc.zc_share.z_sharemax = sharemax;
- error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
- return (error);
-}
-
-void
-zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
-{
- nvpair_t *curr;
-
- /*
- * Keep a reference to the props-table against which we prune the
- * properties.
- */
- zhp->zfs_props_table = props;
-
- curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
-
- while (curr) {
- zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
- nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
-
- /*
- * User properties will result in ZPROP_INVAL, and since we
- * only know how to prune standard ZFS properties, we always
- * leave these in the list. This can also happen if we
- * encounter an unknown DSL property (when running older
- * software, for example).
- */
- if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
- (void) nvlist_remove(zhp->zfs_props,
- nvpair_name(curr), nvpair_type(curr));
- curr = next;
- }
-}
-
-#ifdef illumos
-static int
-zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
- zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
-{
- zfs_cmd_t zc = { 0 };
- nvlist_t *nvlist = NULL;
- int error;
-
- (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
- zc.zc_cookie = (uint64_t)cmd;
-
- if (cmd == ZFS_SMB_ACL_RENAME) {
- if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
- (void) no_memory(hdl);
- return (0);
- }
- }
-
- switch (cmd) {
- case ZFS_SMB_ACL_ADD:
- case ZFS_SMB_ACL_REMOVE:
- (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
- break;
- case ZFS_SMB_ACL_RENAME:
- if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
- resource1) != 0) {
- (void) no_memory(hdl);
- return (-1);
- }
- if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
- resource2) != 0) {
- (void) no_memory(hdl);
- return (-1);
- }
- if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
- nvlist_free(nvlist);
- return (-1);
- }
- break;
- case ZFS_SMB_ACL_PURGE:
- break;
- default:
- return (-1);
- }
- error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
- nvlist_free(nvlist);
- return (error);
-}
-
-int
-zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
- char *path, char *resource)
-{
- return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
- resource, NULL));
-}
-
-int
-zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
- char *path, char *resource)
-{
- return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
- resource, NULL));
-}
-
-int
-zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
-{
- return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
- NULL, NULL));
-}
-
-int
-zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
- char *oldname, char *newname)
-{
- return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
- oldname, newname));
-}
-#endif /* illumos */
-
-int
-zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
- zfs_userspace_cb_t func, void *arg)
-{
- zfs_cmd_t zc = { 0 };
- zfs_useracct_t buf[100];
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- int ret;
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
- zc.zc_objset_type = type;
- zc.zc_nvlist_dst = (uintptr_t)buf;
-
- for (;;) {
- zfs_useracct_t *zua = buf;
-
- zc.zc_nvlist_dst_size = sizeof (buf);
- if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
- char errbuf[1024];
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "cannot get used/quota for %s"), zc.zc_name);
- return (zfs_standard_error_fmt(hdl, errno, errbuf));
- }
- if (zc.zc_nvlist_dst_size == 0)
- break;
-
- while (zc.zc_nvlist_dst_size > 0) {
- if ((ret = func(arg, zua->zu_domain, zua->zu_rid,
- zua->zu_space)) != 0)
- return (ret);
- zua++;
- zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
- }
- }
-
- return (0);
-}
-
-struct holdarg {
- nvlist_t *nvl;
- const char *snapname;
- const char *tag;
- boolean_t recursive;
- int error;
-};
-
-static int
-zfs_hold_one(zfs_handle_t *zhp, void *arg)
-{
- struct holdarg *ha = arg;
- char name[ZFS_MAX_DATASET_NAME_LEN];
- int rv = 0;
-
- (void) snprintf(name, sizeof (name),
- "%s@%s", zhp->zfs_name, ha->snapname);
-
- if (lzc_exists(name))
- fnvlist_add_string(ha->nvl, name, ha->tag);
-
- if (ha->recursive)
- rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
- zfs_close(zhp);
- return (rv);
-}
-
-int
-zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
- boolean_t recursive, int cleanup_fd)
-{
- int ret;
- struct holdarg ha;
-
- ha.nvl = fnvlist_alloc();
- ha.snapname = snapname;
- ha.tag = tag;
- ha.recursive = recursive;
- (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
-
- if (nvlist_empty(ha.nvl)) {
- char errbuf[1024];
-
- fnvlist_free(ha.nvl);
- ret = ENOENT;
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "cannot hold snapshot '%s@%s'"),
- zhp->zfs_name, snapname);
- (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
- return (ret);
- }
-
- ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
- fnvlist_free(ha.nvl);
-
- return (ret);
-}
-
-int
-zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
-{
- int ret;
- nvlist_t *errors;
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- char errbuf[1024];
- nvpair_t *elem;
-
- errors = NULL;
- ret = lzc_hold(holds, cleanup_fd, &errors);
-
- if (ret == 0) {
- /* There may be errors even in the success case. */
- fnvlist_free(errors);
- return (0);
- }
-
- if (nvlist_empty(errors)) {
- /* no hold-specific errors */
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot hold"));
- switch (ret) {
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded"));
- (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
- break;
- case EINVAL:
- (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
- break;
- default:
- (void) zfs_standard_error(hdl, ret, errbuf);
- }
- }
-
- for (elem = nvlist_next_nvpair(errors, NULL);
- elem != NULL;
- elem = nvlist_next_nvpair(errors, elem)) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "cannot hold snapshot '%s'"), nvpair_name(elem));
- switch (fnvpair_value_int32(elem)) {
- case E2BIG:
- /*
- * Temporary tags wind up having the ds object id
- * prepended. So even if we passed the length check
- * above, it's still possible for the tag to wind
- * up being slightly too long.
- */
- (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
- break;
- case EINVAL:
- (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
- break;
- case EEXIST:
- (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
- break;
- default:
- (void) zfs_standard_error(hdl,
- fnvpair_value_int32(elem), errbuf);
- }
- }
-
- fnvlist_free(errors);
- return (ret);
-}
-
-static int
-zfs_release_one(zfs_handle_t *zhp, void *arg)
-{
- struct holdarg *ha = arg;
- char name[ZFS_MAX_DATASET_NAME_LEN];
- int rv = 0;
- nvlist_t *existing_holds;
-
- (void) snprintf(name, sizeof (name),
- "%s@%s", zhp->zfs_name, ha->snapname);
-
- if (lzc_get_holds(name, &existing_holds) != 0) {
- ha->error = ENOENT;
- } else if (!nvlist_exists(existing_holds, ha->tag)) {
- ha->error = ESRCH;
- } else {
- nvlist_t *torelease = fnvlist_alloc();
- fnvlist_add_boolean(torelease, ha->tag);
- fnvlist_add_nvlist(ha->nvl, name, torelease);
- fnvlist_free(torelease);
- }
-
- if (ha->recursive)
- rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
- zfs_close(zhp);
- return (rv);
-}
-
-int
-zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
- boolean_t recursive)
-{
- int ret;
- struct holdarg ha;
- nvlist_t *errors = NULL;
- nvpair_t *elem;
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- char errbuf[1024];
-
- ha.nvl = fnvlist_alloc();
- ha.snapname = snapname;
- ha.tag = tag;
- ha.recursive = recursive;
- ha.error = 0;
- (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
-
- if (nvlist_empty(ha.nvl)) {
- fnvlist_free(ha.nvl);
- ret = ha.error;
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "cannot release hold from snapshot '%s@%s'"),
- zhp->zfs_name, snapname);
- if (ret == ESRCH) {
- (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
- } else {
- (void) zfs_standard_error(hdl, ret, errbuf);
- }
- return (ret);
- }
-
- ret = lzc_release(ha.nvl, &errors);
- fnvlist_free(ha.nvl);
-
- if (ret == 0) {
- /* There may be errors even in the success case. */
- fnvlist_free(errors);
- return (0);
- }
-
- if (nvlist_empty(errors)) {
- /* no hold-specific errors */
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot release"));
- switch (errno) {
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded"));
- (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
- break;
- default:
- (void) zfs_standard_error_fmt(hdl, errno, errbuf);
- }
- }
-
- for (elem = nvlist_next_nvpair(errors, NULL);
- elem != NULL;
- elem = nvlist_next_nvpair(errors, elem)) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "cannot release hold from snapshot '%s'"),
- nvpair_name(elem));
- switch (fnvpair_value_int32(elem)) {
- case ESRCH:
- (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
- break;
- case EINVAL:
- (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
- break;
- default:
- (void) zfs_standard_error_fmt(hdl,
- fnvpair_value_int32(elem), errbuf);
- }
- }
-
- fnvlist_free(errors);
- return (ret);
-}
-
-int
-zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
-{
- zfs_cmd_t zc = { 0 };
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- int nvsz = 2048;
- void *nvbuf;
- int err = 0;
- char errbuf[1024];
-
- assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
- zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
-
-tryagain:
-
- nvbuf = malloc(nvsz);
- if (nvbuf == NULL) {
- err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
- goto out;
- }
-
- zc.zc_nvlist_dst_size = nvsz;
- zc.zc_nvlist_dst = (uintptr_t)nvbuf;
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
- zc.zc_name);
- switch (errno) {
- case ENOMEM:
- free(nvbuf);
- nvsz = zc.zc_nvlist_dst_size;
- goto tryagain;
-
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded"));
- err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
- break;
- case EINVAL:
- err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
- break;
- case ENOENT:
- err = zfs_error(hdl, EZFS_NOENT, errbuf);
- break;
- default:
- err = zfs_standard_error_fmt(hdl, errno, errbuf);
- break;
- }
- } else {
- /* success */
- int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
- if (rc) {
- (void) snprintf(errbuf, sizeof (errbuf), dgettext(
- TEXT_DOMAIN, "cannot get permissions on '%s'"),
- zc.zc_name);
- err = zfs_standard_error_fmt(hdl, rc, errbuf);
- }
- }
-
- free(nvbuf);
-out:
- return (err);
-}
-
-int
-zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
-{
- zfs_cmd_t zc = { 0 };
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- char *nvbuf;
- char errbuf[1024];
- size_t nvsz;
- int err;
-
- assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
- zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
-
- err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
- assert(err == 0);
-
- nvbuf = malloc(nvsz);
-
- err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
- assert(err == 0);
-
- zc.zc_nvlist_src_size = nvsz;
- zc.zc_nvlist_src = (uintptr_t)nvbuf;
- zc.zc_perm_action = un;
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
- if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
- zc.zc_name);
- switch (errno) {
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded"));
- err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
- break;
- case EINVAL:
- err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
- break;
- case ENOENT:
- err = zfs_error(hdl, EZFS_NOENT, errbuf);
- break;
- default:
- err = zfs_standard_error_fmt(hdl, errno, errbuf);
- break;
- }
- }
-
- free(nvbuf);
-
- return (err);
-}
-
-int
-zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
-{
- int err;
- char errbuf[1024];
-
- err = lzc_get_holds(zhp->zfs_name, nvl);
-
- if (err != 0) {
- libzfs_handle_t *hdl = zhp->zfs_hdl;
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
- zhp->zfs_name);
- switch (err) {
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded"));
- err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
- break;
- case EINVAL:
- err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
- break;
- case ENOENT:
- err = zfs_error(hdl, EZFS_NOENT, errbuf);
- break;
- default:
- err = zfs_standard_error_fmt(hdl, errno, errbuf);
- break;
- }
- }
-
- return (err);
-}
-
-/*
- * Convert the zvol's volume size to an appropriate reservation.
- * Note: If this routine is updated, it is necessary to update the ZFS test
- * suite's shell version in reservation.kshlib.
- */
-uint64_t
-zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
-{
- uint64_t numdb;
- uint64_t nblocks, volblocksize;
- int ncopies;
- char *strval;
-
- if (nvlist_lookup_string(props,
- zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
- ncopies = atoi(strval);
- else
- ncopies = 1;
- if (nvlist_lookup_uint64(props,
- zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
- &volblocksize) != 0)
- volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
- nblocks = volsize/volblocksize;
- /* start with metadnode L0-L6 */
- numdb = 7;
- /* calculate number of indirects */
- while (nblocks > 1) {
- nblocks += DNODES_PER_LEVEL - 1;
- nblocks /= DNODES_PER_LEVEL;
- numdb += nblocks;
- }
- numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
- volsize *= ncopies;
- /*
- * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
- * compressed, but in practice they compress down to about
- * 1100 bytes
- */
- numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
- volsize += numdb;
- return (volsize);
-}
-
-/*
- * Attach/detach the given filesystem to/from the given jail.
- */
-int
-zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- zfs_cmd_t zc = { 0 };
- char errbuf[1024];
- unsigned long cmd;
- int ret;
-
- if (attach) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
- } else {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name);
- }
-
- switch (zhp->zfs_type) {
- case ZFS_TYPE_VOLUME:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "volumes can not be jailed"));
- return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
- case ZFS_TYPE_SNAPSHOT:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "snapshots can not be jailed"));
- return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
- }
- assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
-
- (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- zc.zc_objset_type = DMU_OST_ZFS;
- zc.zc_jailid = jailid;
-
- cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL;
- if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0)
- zfs_standard_error(hdl, errno, errbuf);
-
- return (ret);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
deleted file mode 100644
index db132190154c..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
+++ /dev/null
@@ -1,834 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2015, 2018 by Delphix. All rights reserved.
- * Copyright 2016 Joyent, Inc.
- * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
- */
-
-/*
- * zfs diff support
- */
-#include <ctype.h>
-#include <errno.h>
-#include <libintl.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <sys/zfs_ioctl.h>
-#include <libzfs.h>
-#include "libzfs_impl.h"
-
-#define ZDIFF_SNAPDIR "/.zfs/snapshot/"
-#define ZDIFF_SHARESDIR "/.zfs/shares/"
-#define ZDIFF_PREFIX "zfs-diff-%d"
-
-#define ZDIFF_ADDED '+'
-#define ZDIFF_MODIFIED 'M'
-#define ZDIFF_REMOVED '-'
-#define ZDIFF_RENAMED 'R'
-
-typedef struct differ_info {
- zfs_handle_t *zhp;
- char *fromsnap;
- char *frommnt;
- char *tosnap;
- char *tomnt;
- char *ds;
- char *dsmnt;
- char *tmpsnap;
- char errbuf[1024];
- boolean_t isclone;
- boolean_t scripted;
- boolean_t classify;
- boolean_t timestamped;
- uint64_t shares;
- int zerr;
- int cleanupfd;
- int outputfd;
- int datafd;
-} differ_info_t;
-
-/*
- * Given a {dsname, object id}, get the object path
- */
-static int
-get_stats_for_obj(differ_info_t *di, const char *dsname, uint64_t obj,
- char *pn, int maxlen, zfs_stat_t *sb)
-{
- zfs_cmd_t zc = { 0 };
- int error;
-
- (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
- zc.zc_obj = obj;
-
- errno = 0;
- error = ioctl(di->zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_STATS, &zc);
- di->zerr = errno;
-
- /* we can get stats even if we failed to get a path */
- (void) memcpy(sb, &zc.zc_stat, sizeof (zfs_stat_t));
- if (error == 0) {
- ASSERT(di->zerr == 0);
- (void) strlcpy(pn, zc.zc_value, maxlen);
- return (0);
- }
-
- if (di->zerr == ESTALE) {
- (void) snprintf(pn, maxlen, "(on_delete_queue)");
- return (0);
- } else if (di->zerr == EPERM) {
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "The sys_config privilege or diff delegated permission "
- "is needed\nto discover path names"));
- return (-1);
- } else {
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "Unable to determine path or stats for "
- "object %jd in %s"), (uintmax_t)obj, dsname);
- return (-1);
- }
-}
-
-/*
- * stream_bytes
- *
- * Prints a file name out a character at a time. If the character is
- * not in the range of what we consider "printable" ASCII, display it
- * as an escaped 3-digit octal value. ASCII values less than a space
- * are all control characters and we declare the upper end as the
- * DELete character. This also is the last 7-bit ASCII character.
- * We choose to treat all 8-bit ASCII as not printable for this
- * application.
- */
-static void
-stream_bytes(FILE *fp, const char *string)
-{
- char c;
-
- while ((c = *string++) != '\0') {
- if (c > ' ' && c != '\\' && c < '\177') {
- (void) fprintf(fp, "%c", c);
- } else {
- (void) fprintf(fp, "\\%03o", (uint8_t)c);
- }
- }
-}
-
-static void
-print_what(FILE *fp, mode_t what)
-{
- char symbol;
-
- switch (what & S_IFMT) {
- case S_IFBLK:
- symbol = 'B';
- break;
- case S_IFCHR:
- symbol = 'C';
- break;
- case S_IFDIR:
- symbol = '/';
- break;
-#ifdef S_IFDOOR
- case S_IFDOOR:
- symbol = '>';
- break;
-#endif
- case S_IFIFO:
- symbol = '|';
- break;
- case S_IFLNK:
- symbol = '@';
- break;
-#ifdef S_IFPORT
- case S_IFPORT:
- symbol = 'P';
- break;
-#endif
- case S_IFSOCK:
- symbol = '=';
- break;
- case S_IFREG:
- symbol = 'F';
- break;
- default:
- symbol = '?';
- break;
- }
- (void) fprintf(fp, "%c", symbol);
-}
-
-static void
-print_cmn(FILE *fp, differ_info_t *di, const char *file)
-{
- stream_bytes(fp, di->dsmnt);
- stream_bytes(fp, file);
-}
-
-static void
-print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new,
- zfs_stat_t *isb)
-{
- if (di->timestamped)
- (void) fprintf(fp, "%10lld.%09lld\t",
- (longlong_t)isb->zs_ctime[0],
- (longlong_t)isb->zs_ctime[1]);
- (void) fprintf(fp, "%c\t", ZDIFF_RENAMED);
- if (di->classify) {
- print_what(fp, isb->zs_mode);
- (void) fprintf(fp, "\t");
- }
- print_cmn(fp, di, old);
- if (di->scripted)
- (void) fprintf(fp, "\t");
- else
- (void) fprintf(fp, " -> ");
- print_cmn(fp, di, new);
- (void) fprintf(fp, "\n");
-}
-
-static void
-print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file,
- zfs_stat_t *isb)
-{
- if (di->timestamped)
- (void) fprintf(fp, "%10lld.%09lld\t",
- (longlong_t)isb->zs_ctime[0],
- (longlong_t)isb->zs_ctime[1]);
- (void) fprintf(fp, "%c\t", ZDIFF_MODIFIED);
- if (di->classify) {
- print_what(fp, isb->zs_mode);
- (void) fprintf(fp, "\t");
- }
- print_cmn(fp, di, file);
- (void) fprintf(fp, "\t(%+d)", delta);
- (void) fprintf(fp, "\n");
-}
-
-static void
-print_file(FILE *fp, differ_info_t *di, char type, const char *file,
- zfs_stat_t *isb)
-{
- if (di->timestamped)
- (void) fprintf(fp, "%10lld.%09lld\t",
- (longlong_t)isb->zs_ctime[0],
- (longlong_t)isb->zs_ctime[1]);
- (void) fprintf(fp, "%c\t", type);
- if (di->classify) {
- print_what(fp, isb->zs_mode);
- (void) fprintf(fp, "\t");
- }
- print_cmn(fp, di, file);
- (void) fprintf(fp, "\n");
-}
-
-static int
-write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj)
-{
- struct zfs_stat fsb, tsb;
- mode_t fmode, tmode;
- char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN];
- int fobjerr, tobjerr;
- int change;
-
- if (dobj == di->shares)
- return (0);
-
- /*
- * Check the from and to snapshots for info on the object. If
- * we get ENOENT, then the object just didn't exist in that
- * snapshot. If we get ENOTSUP, then we tried to get
- * info on a non-ZPL object, which we don't care about anyway.
- */
- fobjerr = get_stats_for_obj(di, di->fromsnap, dobj, fobjname,
- MAXPATHLEN, &fsb);
- if (fobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
- return (-1);
-
- tobjerr = get_stats_for_obj(di, di->tosnap, dobj, tobjname,
- MAXPATHLEN, &tsb);
- if (tobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
- return (-1);
-
- /*
- * Unallocated object sharing the same meta dnode block
- */
- if (fobjerr && tobjerr) {
- ASSERT(di->zerr == ENOENT || di->zerr == ENOTSUP);
- di->zerr = 0;
- return (0);
- }
-
- di->zerr = 0; /* negate get_stats_for_obj() from side that failed */
- fmode = fsb.zs_mode & S_IFMT;
- tmode = tsb.zs_mode & S_IFMT;
- if (fmode == S_IFDIR || tmode == S_IFDIR || fsb.zs_links == 0 ||
- tsb.zs_links == 0)
- change = 0;
- else
- change = tsb.zs_links - fsb.zs_links;
-
- if (fobjerr) {
- if (change) {
- print_link_change(fp, di, change, tobjname, &tsb);
- return (0);
- }
- print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
- return (0);
- } else if (tobjerr) {
- if (change) {
- print_link_change(fp, di, change, fobjname, &fsb);
- return (0);
- }
- print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
- return (0);
- }
-
- if (fmode != tmode && fsb.zs_gen == tsb.zs_gen)
- tsb.zs_gen++; /* Force a generational difference */
-
- /* Simple modification or no change */
- if (fsb.zs_gen == tsb.zs_gen) {
- /* No apparent changes. Could we assert !this? */
- if (fsb.zs_ctime[0] == tsb.zs_ctime[0] &&
- fsb.zs_ctime[1] == tsb.zs_ctime[1])
- return (0);
- if (change) {
- print_link_change(fp, di, change,
- change > 0 ? fobjname : tobjname, &tsb);
- } else if (strcmp(fobjname, tobjname) == 0) {
- print_file(fp, di, ZDIFF_MODIFIED, fobjname, &tsb);
- } else {
- print_rename(fp, di, fobjname, tobjname, &tsb);
- }
- return (0);
- } else {
- /* file re-created or object re-used */
- print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
- print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
- return (0);
- }
-}
-
-static int
-write_inuse_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
-{
- uint64_t o;
- int err;
-
- for (o = dr->ddr_first; o <= dr->ddr_last; o++) {
- if ((err = write_inuse_diffs_one(fp, di, o)) != 0)
- return (err);
- }
- return (0);
-}
-
-static int
-describe_free(FILE *fp, differ_info_t *di, uint64_t object, char *namebuf,
- int maxlen)
-{
- struct zfs_stat sb;
-
- if (get_stats_for_obj(di, di->fromsnap, object, namebuf,
- maxlen, &sb) != 0) {
- return (-1);
- }
- /* Don't print if in the delete queue on from side */
- if (di->zerr == ESTALE) {
- di->zerr = 0;
- return (0);
- }
-
- print_file(fp, di, ZDIFF_REMOVED, namebuf, &sb);
- return (0);
-}
-
-static int
-write_free_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
-{
- zfs_cmd_t zc = { 0 };
- libzfs_handle_t *lhdl = di->zhp->zfs_hdl;
- char fobjname[MAXPATHLEN];
-
- (void) strlcpy(zc.zc_name, di->fromsnap, sizeof (zc.zc_name));
- zc.zc_obj = dr->ddr_first - 1;
-
- ASSERT(di->zerr == 0);
-
- while (zc.zc_obj < dr->ddr_last) {
- int err;
-
- err = ioctl(lhdl->libzfs_fd, ZFS_IOC_NEXT_OBJ, &zc);
- if (err == 0) {
- if (zc.zc_obj == di->shares) {
- zc.zc_obj++;
- continue;
- }
- if (zc.zc_obj > dr->ddr_last) {
- break;
- }
- err = describe_free(fp, di, zc.zc_obj, fobjname,
- MAXPATHLEN);
- if (err)
- break;
- } else if (errno == ESRCH) {
- break;
- } else {
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "next allocated object (> %jd) find failure"),
- (uintmax_t)zc.zc_obj);
- di->zerr = errno;
- break;
- }
- }
- if (di->zerr)
- return (-1);
- return (0);
-}
-
-static void *
-differ(void *arg)
-{
- differ_info_t *di = arg;
- dmu_diff_record_t dr;
- FILE *ofp;
- int err = 0;
-
- if ((ofp = fdopen(di->outputfd, "w")) == NULL) {
- di->zerr = errno;
- (void) strerror_r(errno, di->errbuf, sizeof (di->errbuf));
- (void) close(di->datafd);
- return ((void *)-1);
- }
-
- for (;;) {
- char *cp = (char *)&dr;
- int len = sizeof (dr);
- int rv;
-
- do {
- rv = read(di->datafd, cp, len);
- cp += rv;
- len -= rv;
- } while (len > 0 && rv > 0);
-
- if (rv < 0 || (rv == 0 && len != sizeof (dr))) {
- di->zerr = EPIPE;
- break;
- } else if (rv == 0) {
- /* end of file at a natural breaking point */
- break;
- }
-
- switch (dr.ddr_type) {
- case DDR_FREE:
- err = write_free_diffs(ofp, di, &dr);
- break;
- case DDR_INUSE:
- err = write_inuse_diffs(ofp, di, &dr);
- break;
- default:
- di->zerr = EPIPE;
- break;
- }
-
- if (err || di->zerr)
- break;
- }
-
- (void) fclose(ofp);
- (void) close(di->datafd);
- if (err)
- return ((void *)-1);
- if (di->zerr) {
- ASSERT(di->zerr == EPIPE);
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "Internal error: bad data from diff IOCTL"));
- return ((void *)-1);
- }
- return ((void *)0);
-}
-
-static int
-find_shares_object(differ_info_t *di)
-{
- char fullpath[MAXPATHLEN];
- struct stat64 sb = { 0 };
-
- (void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
- (void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
-
- if (stat64(fullpath, &sb) != 0) {
-#ifdef illumos
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
- return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
-#else
- return (0);
-#endif
- }
-
- di->shares = (uint64_t)sb.st_ino;
- return (0);
-}
-
-static int
-make_temp_snapshot(differ_info_t *di)
-{
- libzfs_handle_t *hdl = di->zhp->zfs_hdl;
- zfs_cmd_t zc = { 0 };
-
- (void) snprintf(zc.zc_value, sizeof (zc.zc_value),
- ZDIFF_PREFIX, getpid());
- (void) strlcpy(zc.zc_name, di->ds, sizeof (zc.zc_name));
- zc.zc_cleanup_fd = di->cleanupfd;
-
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_TMP_SNAPSHOT, &zc) != 0) {
- int err = errno;
- if (err == EPERM) {
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN, "The diff delegated "
- "permission is needed in order\nto create a "
- "just-in-time snapshot for diffing\n"));
- return (zfs_error(hdl, EZFS_DIFF, di->errbuf));
- } else {
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN, "Cannot create just-in-time "
- "snapshot of '%s'"), zc.zc_name);
- return (zfs_standard_error(hdl, err, di->errbuf));
- }
- }
-
- di->tmpsnap = zfs_strdup(hdl, zc.zc_value);
- di->tosnap = zfs_asprintf(hdl, "%s@%s", di->ds, di->tmpsnap);
- return (0);
-}
-
-static void
-teardown_differ_info(differ_info_t *di)
-{
- free(di->ds);
- free(di->dsmnt);
- free(di->fromsnap);
- free(di->frommnt);
- free(di->tosnap);
- free(di->tmpsnap);
- free(di->tomnt);
- (void) close(di->cleanupfd);
-}
-
-static int
-get_snapshot_names(differ_info_t *di, const char *fromsnap,
- const char *tosnap)
-{
- libzfs_handle_t *hdl = di->zhp->zfs_hdl;
- char *atptrf = NULL;
- char *atptrt = NULL;
- int fdslen, fsnlen;
- int tdslen, tsnlen;
-
- /*
- * Can accept
- * dataset@snap1
- * dataset@snap1 dataset@snap2
- * dataset@snap1 @snap2
- * dataset@snap1 dataset
- * @snap1 dataset@snap2
- */
- if (tosnap == NULL) {
- /* only a from snapshot given, must be valid */
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "Badly formed snapshot name %s"), fromsnap);
-
- if (!zfs_validate_name(hdl, fromsnap, ZFS_TYPE_SNAPSHOT,
- B_FALSE)) {
- return (zfs_error(hdl, EZFS_INVALIDNAME,
- di->errbuf));
- }
-
- atptrf = strchr(fromsnap, '@');
- ASSERT(atptrf != NULL);
- fdslen = atptrf - fromsnap;
-
- di->fromsnap = zfs_strdup(hdl, fromsnap);
- di->ds = zfs_strdup(hdl, fromsnap);
- di->ds[fdslen] = '\0';
-
- /* the to snap will be a just-in-time snap of the head */
- return (make_temp_snapshot(di));
- }
-
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "Unable to determine which snapshots to compare"));
-
- atptrf = strchr(fromsnap, '@');
- atptrt = strchr(tosnap, '@');
- fdslen = atptrf ? atptrf - fromsnap : strlen(fromsnap);
- tdslen = atptrt ? atptrt - tosnap : strlen(tosnap);
- fsnlen = strlen(fromsnap) - fdslen; /* includes @ sign */
- tsnlen = strlen(tosnap) - tdslen; /* includes @ sign */
-
- if (fsnlen <= 1 || tsnlen == 1 || (fdslen == 0 && tdslen == 0) ||
- (fsnlen == 0 && tsnlen == 0)) {
- return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
- } else if ((fdslen > 0 && tdslen > 0) &&
- ((tdslen != fdslen || strncmp(fromsnap, tosnap, fdslen) != 0))) {
- /*
- * not the same dataset name, might be okay if
- * tosnap is a clone of a fromsnap descendant.
- */
- char origin[ZFS_MAX_DATASET_NAME_LEN];
- zprop_source_t src;
- zfs_handle_t *zhp;
-
- di->ds = zfs_alloc(di->zhp->zfs_hdl, tdslen + 1);
- (void) strncpy(di->ds, tosnap, tdslen);
- di->ds[tdslen] = '\0';
-
- zhp = zfs_open(hdl, di->ds, ZFS_TYPE_FILESYSTEM);
- while (zhp != NULL) {
- if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
- sizeof (origin), &src, NULL, 0, B_FALSE) != 0) {
- (void) zfs_close(zhp);
- zhp = NULL;
- break;
- }
- if (strncmp(origin, fromsnap, fsnlen) == 0)
- break;
-
- (void) zfs_close(zhp);
- zhp = zfs_open(hdl, origin, ZFS_TYPE_FILESYSTEM);
- }
-
- if (zhp == NULL) {
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "Not an earlier snapshot from the same fs"));
- return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
- } else {
- (void) zfs_close(zhp);
- }
-
- di->isclone = B_TRUE;
- di->fromsnap = zfs_strdup(hdl, fromsnap);
- if (tsnlen) {
- di->tosnap = zfs_strdup(hdl, tosnap);
- } else {
- return (make_temp_snapshot(di));
- }
- } else {
- int dslen = fdslen ? fdslen : tdslen;
-
- di->ds = zfs_alloc(hdl, dslen + 1);
- (void) strncpy(di->ds, fdslen ? fromsnap : tosnap, dslen);
- di->ds[dslen] = '\0';
-
- di->fromsnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrf);
- if (tsnlen) {
- di->tosnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrt);
- } else {
- return (make_temp_snapshot(di));
- }
- }
- return (0);
-}
-
-static int
-get_mountpoint(differ_info_t *di, char *dsnm, char **mntpt)
-{
- boolean_t mounted;
-
- mounted = is_mounted(di->zhp->zfs_hdl, dsnm, mntpt);
- if (mounted == B_FALSE) {
- (void) snprintf(di->errbuf, sizeof (di->errbuf),
- dgettext(TEXT_DOMAIN,
- "Cannot diff an unmounted snapshot"));
- return (zfs_error(di->zhp->zfs_hdl, EZFS_BADTYPE, di->errbuf));
- }
-
- /* Avoid a double slash at the beginning of root-mounted datasets */
- if (**mntpt == '/' && *(*mntpt + 1) == '\0')
- **mntpt = '\0';
- return (0);
-}
-
-static int
-get_mountpoints(differ_info_t *di)
-{
- char *strptr;
- char *frommntpt;
-
- /*
- * first get the mountpoint for the parent dataset
- */
- if (get_mountpoint(di, di->ds, &di->dsmnt) != 0)
- return (-1);
-
- strptr = strchr(di->tosnap, '@');
- ASSERT3P(strptr, !=, NULL);
- di->tomnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", di->dsmnt,
- ZDIFF_SNAPDIR, ++strptr);
-
- strptr = strchr(di->fromsnap, '@');
- ASSERT3P(strptr, !=, NULL);
-
- frommntpt = di->dsmnt;
- if (di->isclone) {
- char *mntpt;
- int err;
-
- *strptr = '\0';
- err = get_mountpoint(di, di->fromsnap, &mntpt);
- *strptr = '@';
- if (err != 0)
- return (-1);
- frommntpt = mntpt;
- }
-
- di->frommnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", frommntpt,
- ZDIFF_SNAPDIR, ++strptr);
-
- if (di->isclone)
- free(frommntpt);
-
- return (0);
-}
-
-static int
-setup_differ_info(zfs_handle_t *zhp, const char *fromsnap,
- const char *tosnap, differ_info_t *di)
-{
- di->zhp = zhp;
-
- di->cleanupfd = open(ZFS_DEV, O_RDWR|O_EXCL);
- VERIFY(di->cleanupfd >= 0);
-
- if (get_snapshot_names(di, fromsnap, tosnap) != 0)
- return (-1);
-
- if (get_mountpoints(di) != 0)
- return (-1);
-
- if (find_shares_object(di) != 0)
- return (-1);
-
- return (0);
-}
-
-int
-zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap,
- const char *tosnap, int flags)
-{
- zfs_cmd_t zc = { 0 };
- char errbuf[1024];
- differ_info_t di = { 0 };
- pthread_t tid;
- int pipefd[2];
- int iocerr;
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "zfs diff failed"));
-
- if (setup_differ_info(zhp, fromsnap, tosnap, &di)) {
- teardown_differ_info(&di);
- return (-1);
- }
-
- if (pipe(pipefd)) {
- zfs_error_aux(zhp->zfs_hdl, strerror(errno));
- teardown_differ_info(&di);
- return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED, errbuf));
- }
-
- di.scripted = (flags & ZFS_DIFF_PARSEABLE);
- di.classify = (flags & ZFS_DIFF_CLASSIFY);
- di.timestamped = (flags & ZFS_DIFF_TIMESTAMP);
-
- di.outputfd = outfd;
- di.datafd = pipefd[0];
-
- if (pthread_create(&tid, NULL, differ, &di)) {
- zfs_error_aux(zhp->zfs_hdl, strerror(errno));
- (void) close(pipefd[0]);
- (void) close(pipefd[1]);
- teardown_differ_info(&di);
- return (zfs_error(zhp->zfs_hdl,
- EZFS_THREADCREATEFAILED, errbuf));
- }
-
- /* do the ioctl() */
- (void) strlcpy(zc.zc_value, di.fromsnap, strlen(di.fromsnap) + 1);
- (void) strlcpy(zc.zc_name, di.tosnap, strlen(di.tosnap) + 1);
- zc.zc_cookie = pipefd[1];
-
- iocerr = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DIFF, &zc);
- if (iocerr != 0) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "Unable to obtain diffs"));
- if (errno == EPERM) {
- zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
- "\n The sys_mount privilege or diff delegated "
- "permission is needed\n to execute the "
- "diff ioctl"));
- } else if (errno == EXDEV) {
- zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
- "\n Not an earlier snapshot from the same fs"));
- } else if (errno != EPIPE || di.zerr == 0) {
- zfs_error_aux(zhp->zfs_hdl, strerror(errno));
- }
- (void) close(pipefd[1]);
- (void) pthread_cancel(tid);
- (void) pthread_join(tid, NULL);
- teardown_differ_info(&di);
- if (di.zerr != 0 && di.zerr != EPIPE) {
- zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
- return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
- } else {
- return (zfs_error(zhp->zfs_hdl, EZFS_DIFFDATA, errbuf));
- }
- }
-
- (void) close(pipefd[1]);
- (void) pthread_join(tid, NULL);
-
- if (di.zerr != 0) {
- zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
- return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
- }
- teardown_differ_info(&di);
- return (0);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c
deleted file mode 100644
index 474470c416ea..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <dlfcn.h>
-#include <errno.h>
-#include <libintl.h>
-#include <link.h>
-#include <pthread.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include <libzfs.h>
-
-#include <fm/libtopo.h>
-#include <sys/fm/protocol.h>
-#include <sys/systeminfo.h>
-
-#include "libzfs_impl.h"
-
-/*
- * This file is responsible for determining the relationship between I/O
- * devices paths and physical locations. In the world of MPxIO and external
- * enclosures, the device path is not synonymous with the physical location.
- * If you remove a drive and insert it into a different slot, it will end up
- * with the same path under MPxIO. If you recable storage enclosures, the
- * device paths may change. All of this makes it difficult to implement the
- * 'autoreplace' property, which is supposed to automatically manage disk
- * replacement based on physical slot.
- *
- * In order to work around these limitations, we have a per-vdev FRU property
- * that is the libtopo path (minus disk-specific authority information) to the
- * physical location of the device on the system. This is an optional
- * property, and is only needed when using the 'autoreplace' property or when
- * generating FMA faults against vdevs.
- */
-
-/*
- * Because the FMA packages depend on ZFS, we have to dlopen() libtopo in case
- * it is not present. We only need this once per library instance, so it is
- * not part of the libzfs handle.
- */
-static void *_topo_dlhandle;
-static topo_hdl_t *(*_topo_open)(int, const char *, int *);
-static void (*_topo_close)(topo_hdl_t *);
-static char *(*_topo_snap_hold)(topo_hdl_t *, const char *, int *);
-static void (*_topo_snap_release)(topo_hdl_t *);
-static topo_walk_t *(*_topo_walk_init)(topo_hdl_t *, const char *,
- topo_walk_cb_t, void *, int *);
-static int (*_topo_walk_step)(topo_walk_t *, int);
-static void (*_topo_walk_fini)(topo_walk_t *);
-static void (*_topo_hdl_strfree)(topo_hdl_t *, char *);
-static char *(*_topo_node_name)(tnode_t *);
-static int (*_topo_prop_get_string)(tnode_t *, const char *, const char *,
- char **, int *);
-static int (*_topo_node_fru)(tnode_t *, nvlist_t **, nvlist_t *, int *);
-static int (*_topo_fmri_nvl2str)(topo_hdl_t *, nvlist_t *, char **, int *);
-static int (*_topo_fmri_strcmp_noauth)(topo_hdl_t *, const char *,
- const char *);
-
-#define ZFS_FRU_HASH_SIZE 257
-
-static size_t
-fru_strhash(const char *key)
-{
- ulong_t g, h = 0;
- const char *p;
-
- for (p = key; *p != '\0'; p++) {
- h = (h << 4) + *p;
-
- if ((g = (h & 0xf0000000)) != 0) {
- h ^= (g >> 24);
- h ^= g;
- }
- }
-
- return (h % ZFS_FRU_HASH_SIZE);
-}
-
-static int
-libzfs_fru_gather(topo_hdl_t *thp, tnode_t *tn, void *arg)
-{
- libzfs_handle_t *hdl = arg;
- nvlist_t *fru;
- char *devpath, *frustr;
- int err;
- libzfs_fru_t *frup;
- size_t idx;
-
- /*
- * If this is the chassis node, and we don't yet have the system
- * chassis ID, then fill in this value now.
- */
- if (hdl->libzfs_chassis_id[0] == '\0' &&
- strcmp(_topo_node_name(tn), "chassis") == 0) {
- if (_topo_prop_get_string(tn, FM_FMRI_AUTHORITY,
- FM_FMRI_AUTH_CHASSIS, &devpath, &err) == 0)
- (void) strlcpy(hdl->libzfs_chassis_id, devpath,
- sizeof (hdl->libzfs_chassis_id));
- }
-
- /*
- * Skip non-disk nodes.
- */
- if (strcmp(_topo_node_name(tn), "disk") != 0)
- return (TOPO_WALK_NEXT);
-
- /*
- * Get the devfs path and FRU.
- */
- if (_topo_prop_get_string(tn, "io", "devfs-path", &devpath, &err) != 0)
- return (TOPO_WALK_NEXT);
-
- if (libzfs_fru_lookup(hdl, devpath) != NULL) {
- _topo_hdl_strfree(thp, devpath);
- return (TOPO_WALK_NEXT);
- }
-
- if (_topo_node_fru(tn, &fru, NULL, &err) != 0) {
- _topo_hdl_strfree(thp, devpath);
- return (TOPO_WALK_NEXT);
- }
-
- /*
- * Convert the FRU into a string.
- */
- if (_topo_fmri_nvl2str(thp, fru, &frustr, &err) != 0) {
- nvlist_free(fru);
- _topo_hdl_strfree(thp, devpath);
- return (TOPO_WALK_NEXT);
- }
-
- nvlist_free(fru);
-
- /*
- * Finally, we have a FRU string and device path. Add it to the hash.
- */
- if ((frup = calloc(sizeof (libzfs_fru_t), 1)) == NULL) {
- _topo_hdl_strfree(thp, devpath);
- _topo_hdl_strfree(thp, frustr);
- return (TOPO_WALK_NEXT);
- }
-
- if ((frup->zf_device = strdup(devpath)) == NULL ||
- (frup->zf_fru = strdup(frustr)) == NULL) {
- free(frup->zf_device);
- free(frup);
- _topo_hdl_strfree(thp, devpath);
- _topo_hdl_strfree(thp, frustr);
- return (TOPO_WALK_NEXT);
- }
-
- _topo_hdl_strfree(thp, devpath);
- _topo_hdl_strfree(thp, frustr);
-
- idx = fru_strhash(frup->zf_device);
- frup->zf_chain = hdl->libzfs_fru_hash[idx];
- hdl->libzfs_fru_hash[idx] = frup;
- frup->zf_next = hdl->libzfs_fru_list;
- hdl->libzfs_fru_list = frup;
-
- return (TOPO_WALK_NEXT);
-}
-
-/*
- * Called during initialization to setup the dynamic libtopo connection.
- */
-#pragma init(libzfs_init_fru)
-static void
-libzfs_init_fru(void)
-{
- char path[MAXPATHLEN];
- char isa[257];
-
-#if defined(_LP64)
- if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
- isa[0] = '\0';
-#else
- isa[0] = '\0';
-#endif
- (void) snprintf(path, sizeof (path),
- "/usr/lib/fm/%s/libtopo.so", isa);
-
- if ((_topo_dlhandle = dlopen(path, RTLD_LAZY)) == NULL)
- return;
-
- _topo_open = (topo_hdl_t *(*)())
- dlsym(_topo_dlhandle, "topo_open");
- _topo_close = (void (*)())
- dlsym(_topo_dlhandle, "topo_close");
- _topo_snap_hold = (char *(*)())
- dlsym(_topo_dlhandle, "topo_snap_hold");
- _topo_snap_release = (void (*)())
- dlsym(_topo_dlhandle, "topo_snap_release");
- _topo_walk_init = (topo_walk_t *(*)())
- dlsym(_topo_dlhandle, "topo_walk_init");
- _topo_walk_step = (int (*)())
- dlsym(_topo_dlhandle, "topo_walk_step");
- _topo_walk_fini = (void (*)())
- dlsym(_topo_dlhandle, "topo_walk_fini");
- _topo_hdl_strfree = (void (*)())
- dlsym(_topo_dlhandle, "topo_hdl_strfree");
- _topo_node_name = (char *(*)())
- dlsym(_topo_dlhandle, "topo_node_name");
- _topo_prop_get_string = (int (*)())
- dlsym(_topo_dlhandle, "topo_prop_get_string");
- _topo_node_fru = (int (*)())
- dlsym(_topo_dlhandle, "topo_node_fru");
- _topo_fmri_nvl2str = (int (*)())
- dlsym(_topo_dlhandle, "topo_fmri_nvl2str");
- _topo_fmri_strcmp_noauth = (int (*)())
- dlsym(_topo_dlhandle, "topo_fmri_strcmp_noauth");
-
- if (_topo_open == NULL || _topo_close == NULL ||
- _topo_snap_hold == NULL || _topo_snap_release == NULL ||
- _topo_walk_init == NULL || _topo_walk_step == NULL ||
- _topo_walk_fini == NULL || _topo_hdl_strfree == NULL ||
- _topo_node_name == NULL || _topo_prop_get_string == NULL ||
- _topo_node_fru == NULL || _topo_fmri_nvl2str == NULL ||
- _topo_fmri_strcmp_noauth == NULL) {
- (void) dlclose(_topo_dlhandle);
- _topo_dlhandle = NULL;
- }
-}
-
-/*
- * Refresh the mappings from device path -> FMRI. We do this by walking the
- * hc topology looking for disk nodes, and recording the io/devfs-path and FRU.
- * Note that we strip out the disk-specific authority information (serial,
- * part, revision, etc) so that we are left with only the identifying
- * characteristics of the slot (hc path and chassis-id).
- */
-void
-libzfs_fru_refresh(libzfs_handle_t *hdl)
-{
- int err;
- char *uuid;
- topo_hdl_t *thp;
- topo_walk_t *twp;
-
- if (_topo_dlhandle == NULL)
- return;
-
- /*
- * Clear the FRU hash and initialize our basic structures.
- */
- libzfs_fru_clear(hdl, B_FALSE);
-
- if ((hdl->libzfs_topo_hdl = _topo_open(TOPO_VERSION,
- NULL, &err)) == NULL)
- return;
-
- thp = hdl->libzfs_topo_hdl;
-
- if ((uuid = _topo_snap_hold(thp, NULL, &err)) == NULL)
- return;
-
- _topo_hdl_strfree(thp, uuid);
-
- if (hdl->libzfs_fru_hash == NULL &&
- (hdl->libzfs_fru_hash =
- calloc(ZFS_FRU_HASH_SIZE, sizeof (void *))) == NULL)
- return;
-
- /*
- * We now have a topo snapshot, so iterate over the hc topology looking
- * for disks to add to the hash.
- */
- twp = _topo_walk_init(thp, FM_FMRI_SCHEME_HC,
- libzfs_fru_gather, hdl, &err);
- if (twp != NULL) {
- (void) _topo_walk_step(twp, TOPO_WALK_CHILD);
- _topo_walk_fini(twp);
- }
-}
-
-/*
- * Given a devfs path, return the FRU for the device, if known. This will
- * automatically call libzfs_fru_refresh() if it hasn't already been called by
- * the consumer. The string returned is valid until the next call to
- * libzfs_fru_refresh().
- */
-const char *
-libzfs_fru_lookup(libzfs_handle_t *hdl, const char *devpath)
-{
- size_t idx = fru_strhash(devpath);
- libzfs_fru_t *frup;
-
- if (hdl->libzfs_fru_hash == NULL)
- libzfs_fru_refresh(hdl);
-
- if (hdl->libzfs_fru_hash == NULL)
- return (NULL);
-
- for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
- frup = frup->zf_chain) {
- if (strcmp(devpath, frup->zf_device) == 0)
- return (frup->zf_fru);
- }
-
- return (NULL);
-}
-
-/*
- * Given a fru path, return the device path. This will automatically call
- * libzfs_fru_refresh() if it hasn't already been called by the consumer. The
- * string returned is valid until the next call to libzfs_fru_refresh().
- */
-const char *
-libzfs_fru_devpath(libzfs_handle_t *hdl, const char *fru)
-{
- libzfs_fru_t *frup;
- size_t idx;
-
- if (hdl->libzfs_fru_hash == NULL)
- libzfs_fru_refresh(hdl);
-
- if (hdl->libzfs_fru_hash == NULL)
- return (NULL);
-
- for (idx = 0; idx < ZFS_FRU_HASH_SIZE; idx++) {
- for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
- frup = frup->zf_next) {
- if (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl,
- fru, frup->zf_fru))
- return (frup->zf_device);
- }
- }
-
- return (NULL);
-}
-
-/*
- * Change the stored FRU for the given vdev.
- */
-int
-zpool_fru_set(zpool_handle_t *zhp, uint64_t vdev_guid, const char *fru)
-{
- zfs_cmd_t zc = { 0 };
-
- (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- (void) strncpy(zc.zc_value, fru, sizeof (zc.zc_value));
- zc.zc_guid = vdev_guid;
-
- if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SETFRU, &zc) != 0)
- return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
- dgettext(TEXT_DOMAIN, "cannot set FRU")));
-
- return (0);
-}
-
-/*
- * Compare to two FRUs, ignoring any authority information.
- */
-boolean_t
-libzfs_fru_compare(libzfs_handle_t *hdl, const char *a, const char *b)
-{
- if (hdl->libzfs_fru_hash == NULL)
- libzfs_fru_refresh(hdl);
-
- if (hdl->libzfs_fru_hash == NULL)
- return (strcmp(a, b) == 0);
-
- return (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl, a, b));
-}
-
-/*
- * This special function checks to see whether the FRU indicates it's supposed
- * to be in the system chassis, but the chassis-id doesn't match. This can
- * happen in a clustered case, where both head nodes have the same logical
- * disk, but opening the device on the other head node is meaningless.
- */
-boolean_t
-libzfs_fru_notself(libzfs_handle_t *hdl, const char *fru)
-{
- const char *chassisid;
- size_t len;
-
- if (hdl->libzfs_fru_hash == NULL)
- libzfs_fru_refresh(hdl);
-
- if (hdl->libzfs_chassis_id[0] == '\0')
- return (B_FALSE);
-
- if (strstr(fru, "/chassis=0/") == NULL)
- return (B_FALSE);
-
- if ((chassisid = strstr(fru, ":chassis-id=")) == NULL)
- return (B_FALSE);
-
- chassisid += 12;
- len = strlen(hdl->libzfs_chassis_id);
- if (strncmp(chassisid, hdl->libzfs_chassis_id, len) == 0 &&
- (chassisid[len] == '/' || chassisid[len] == ':'))
- return (B_FALSE);
-
- return (B_TRUE);
-}
-
-/*
- * Clear memory associated with the FRU hash.
- */
-void
-libzfs_fru_clear(libzfs_handle_t *hdl, boolean_t final)
-{
- libzfs_fru_t *frup;
-
- while ((frup = hdl->libzfs_fru_list) != NULL) {
- hdl->libzfs_fru_list = frup->zf_next;
- free(frup->zf_device);
- free(frup->zf_fru);
- free(frup);
- }
-
- hdl->libzfs_fru_list = NULL;
-
- if (hdl->libzfs_topo_hdl != NULL) {
- _topo_snap_release(hdl->libzfs_topo_hdl);
- _topo_close(hdl->libzfs_topo_hdl);
- hdl->libzfs_topo_hdl = NULL;
- }
-
- if (final) {
- free(hdl->libzfs_fru_hash);
- } else if (hdl->libzfs_fru_hash != NULL) {
- bzero(hdl->libzfs_fru_hash,
- ZFS_FRU_HASH_SIZE * sizeof (void *));
- }
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
deleted file mode 100644
index a0338afadb8f..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * CDDL HEADER SART
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
- * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
- */
-
-#ifndef _LIBZFS_IMPL_H
-#define _LIBZFS_IMPL_H
-
-#include <sys/fs/zfs.h>
-#include <sys/spa.h>
-#include <sys/nvpair.h>
-#include <sys/dmu.h>
-#include <sys/zfs_ioctl.h>
-
-#include <libshare.h>
-#include <libuutil.h>
-#include <libzfs.h>
-#include <libzfs_core.h>
-#include <libzfs_compat.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef VERIFY
-#undef VERIFY
-#endif
-#define VERIFY verify
-
-typedef struct libzfs_fru {
- char *zf_device;
- char *zf_fru;
- struct libzfs_fru *zf_chain;
- struct libzfs_fru *zf_next;
-} libzfs_fru_t;
-
-struct libzfs_handle {
- int libzfs_error;
- int libzfs_fd;
- FILE *libzfs_mnttab;
- FILE *libzfs_sharetab;
- zpool_handle_t *libzfs_pool_handles;
- uu_avl_pool_t *libzfs_ns_avlpool;
- uu_avl_t *libzfs_ns_avl;
- uint64_t libzfs_ns_gen;
- int libzfs_desc_active;
- char libzfs_action[1024];
- char libzfs_desc[1024];
- int libzfs_printerr;
- int libzfs_storeerr; /* stuff error messages into buffer */
- void *libzfs_sharehdl; /* libshare handle */
- boolean_t libzfs_mnttab_enable;
- /*
- * We need a lock to handle the case where parallel mount
- * threads are populating the mnttab cache simultaneously. The
- * lock only protects the integrity of the avl tree, and does
- * not protect the contents of the mnttab entries themselves.
- */
- pthread_mutex_t libzfs_mnttab_cache_lock;
- avl_tree_t libzfs_mnttab_cache;
- int libzfs_pool_iter;
- libzfs_fru_t **libzfs_fru_hash;
- libzfs_fru_t *libzfs_fru_list;
- char libzfs_chassis_id[256];
- boolean_t libzfs_prop_debug;
-};
-
-struct zfs_handle {
- libzfs_handle_t *zfs_hdl;
- zpool_handle_t *zpool_hdl;
- char zfs_name[ZFS_MAX_DATASET_NAME_LEN];
- zfs_type_t zfs_type; /* type including snapshot */
- zfs_type_t zfs_head_type; /* type excluding snapshot */
- dmu_objset_stats_t zfs_dmustats;
- nvlist_t *zfs_props;
- nvlist_t *zfs_user_props;
- nvlist_t *zfs_recvd_props;
- boolean_t zfs_mntcheck;
- char *zfs_mntopts;
- uint8_t *zfs_props_table;
-};
-
-/*
- * This is different from checking zfs_type, because it will also catch
- * snapshots of volumes.
- */
-#define ZFS_IS_VOLUME(zhp) ((zhp)->zfs_head_type == ZFS_TYPE_VOLUME)
-
-struct zpool_handle {
- libzfs_handle_t *zpool_hdl;
- zpool_handle_t *zpool_next;
- char zpool_name[ZFS_MAX_DATASET_NAME_LEN];
- int zpool_state;
- size_t zpool_config_size;
- nvlist_t *zpool_config;
- nvlist_t *zpool_old_config;
- nvlist_t *zpool_props;
- diskaddr_t zpool_start_block;
-};
-
-typedef enum {
- PROTO_NFS = 0,
- PROTO_SMB = 1,
- PROTO_END = 2
-} zfs_share_proto_t;
-
-/*
- * The following can be used as a bitmask and any new values
- * added must preserve that capability.
- */
-typedef enum {
- SHARED_NOT_SHARED = 0x0,
- SHARED_NFS = 0x2,
- SHARED_SMB = 0x4
-} zfs_share_type_t;
-
-#define CONFIG_BUF_MINSIZE 262144
-
-int zfs_error(libzfs_handle_t *, int, const char *);
-int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
-void zfs_error_aux(libzfs_handle_t *, const char *, ...);
-void *zfs_alloc(libzfs_handle_t *, size_t);
-void *zfs_realloc(libzfs_handle_t *, void *, size_t, size_t);
-char *zfs_asprintf(libzfs_handle_t *, const char *, ...);
-char *zfs_strdup(libzfs_handle_t *, const char *);
-int no_memory(libzfs_handle_t *);
-
-int zfs_standard_error(libzfs_handle_t *, int, const char *);
-int zfs_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
-int zpool_standard_error(libzfs_handle_t *, int, const char *);
-int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
-
-int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
- size_t *);
-zfs_handle_t *make_dataset_handle_zc(libzfs_handle_t *, zfs_cmd_t *);
-zfs_handle_t *make_dataset_simple_handle_zc(zfs_handle_t *, zfs_cmd_t *);
-
-int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t,
- nvlist_t *, char **, uint64_t *, const char *);
-int zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp,
- zfs_type_t type);
-
-/*
- * Use this changelist_gather() flag to force attempting mounts
- * on each change node regardless of whether or not it is currently
- * mounted.
- */
-#define CL_GATHER_MOUNT_ALWAYS 0x01
-/*
- * Use this changelist_gather() flag to prevent unmounting of file systems.
- */
-#define CL_GATHER_DONT_UNMOUNT 0x02
-
-typedef struct prop_changelist prop_changelist_t;
-
-int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
-int zcmd_write_src_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *);
-int zcmd_write_conf_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *);
-int zcmd_expand_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *);
-int zcmd_read_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t **);
-void zcmd_free_nvlists(zfs_cmd_t *);
-
-int changelist_prefix(prop_changelist_t *);
-int changelist_postfix(prop_changelist_t *);
-void changelist_rename(prop_changelist_t *, const char *, const char *);
-void changelist_remove(prop_changelist_t *, const char *);
-void changelist_free(prop_changelist_t *);
-prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int, int);
-int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
-int changelist_haszonedchild(prop_changelist_t *);
-
-void remove_mountpoint(zfs_handle_t *);
-int create_parents(libzfs_handle_t *, char *, int);
-boolean_t isa_child_of(const char *dataset, const char *parent);
-
-zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
-zfs_handle_t *make_bookmark_handle(zfs_handle_t *, const char *,
- nvlist_t *props);
-
-int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
-
-boolean_t zpool_name_valid(libzfs_handle_t *, boolean_t, const char *);
-
-int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
- boolean_t modifying);
-
-void namespace_clear(libzfs_handle_t *);
-
-/*
- * libshare (sharemgr) interfaces used internally.
- */
-
-extern int zfs_init_libshare(libzfs_handle_t *, int);
-extern int zfs_parse_options(char *, zfs_share_proto_t);
-
-extern int zfs_unshare_proto(zfs_handle_t *,
- const char *, zfs_share_proto_t *);
-
-extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBZFS_IMPL_H */
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
deleted file mode 100644
index 87c8dd14898b..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
+++ /dev/null
@@ -1,1929 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
- * Copyright 2015 RackTop Systems.
- * Copyright 2016 Nexenta Systems, Inc.
- */
-
-/*
- * Pool import support functions.
- *
- * To import a pool, we rely on reading the configuration information from the
- * ZFS label of each device. If we successfully read the label, then we
- * organize the configuration information in the following hierarchy:
- *
- * pool guid -> toplevel vdev guid -> label txg
- *
- * Duplicate entries matching this same tuple will be discarded. Once we have
- * examined every device, we pick the best label txg config for each toplevel
- * vdev. We then arrange these toplevel vdevs into a complete pool config, and
- * update any paths that have changed. Finally, we attempt to import the pool
- * using our derived config, and record the results.
- */
-
-#include <aio.h>
-#include <ctype.h>
-#include <devid.h>
-#include <dirent.h>
-#include <errno.h>
-#include <libintl.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <thread_pool.h>
-#include <libgeom.h>
-
-#include <sys/vdev_impl.h>
-
-#include "libzfs.h"
-#include "libzfs_impl.h"
-
-/*
- * Intermediate structures used to gather configuration information.
- */
-typedef struct config_entry {
- uint64_t ce_txg;
- nvlist_t *ce_config;
- struct config_entry *ce_next;
-} config_entry_t;
-
-typedef struct vdev_entry {
- uint64_t ve_guid;
- config_entry_t *ve_configs;
- struct vdev_entry *ve_next;
-} vdev_entry_t;
-
-typedef struct pool_entry {
- uint64_t pe_guid;
- vdev_entry_t *pe_vdevs;
- struct pool_entry *pe_next;
-} pool_entry_t;
-
-typedef struct name_entry {
- char *ne_name;
- uint64_t ne_guid;
- struct name_entry *ne_next;
-} name_entry_t;
-
-typedef struct pool_list {
- pool_entry_t *pools;
- name_entry_t *names;
-} pool_list_t;
-
-static char *
-get_devid(const char *path)
-{
-#ifdef have_devid
- int fd;
- ddi_devid_t devid;
- char *minor, *ret;
-
- if ((fd = open(path, O_RDONLY)) < 0)
- return (NULL);
-
- minor = NULL;
- ret = NULL;
- if (devid_get(fd, &devid) == 0) {
- if (devid_get_minor_name(fd, &minor) == 0)
- ret = devid_str_encode(devid, minor);
- if (minor != NULL)
- devid_str_free(minor);
- devid_free(devid);
- }
- (void) close(fd);
-
- return (ret);
-#else
- return (NULL);
-#endif
-}
-
-
-/*
- * Go through and fix up any path and/or devid information for the given vdev
- * configuration.
- */
-static int
-fix_paths(nvlist_t *nv, name_entry_t *names)
-{
- nvlist_t **child;
- uint_t c, children;
- uint64_t guid;
- name_entry_t *ne, *best;
- char *path, *devid;
- int matched;
-
- if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
- &child, &children) == 0) {
- for (c = 0; c < children; c++)
- if (fix_paths(child[c], names) != 0)
- return (-1);
- return (0);
- }
-
- /*
- * This is a leaf (file or disk) vdev. In either case, go through
- * the name list and see if we find a matching guid. If so, replace
- * the path and see if we can calculate a new devid.
- *
- * There may be multiple names associated with a particular guid, in
- * which case we have overlapping slices or multiple paths to the same
- * disk. If this is the case, then we want to pick the path that is
- * the most similar to the original, where "most similar" is the number
- * of matching characters starting from the end of the path. This will
- * preserve slice numbers even if the disks have been reorganized, and
- * will also catch preferred disk names if multiple paths exist.
- */
- verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0);
- if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
- path = NULL;
-
- matched = 0;
- best = NULL;
- for (ne = names; ne != NULL; ne = ne->ne_next) {
- if (ne->ne_guid == guid) {
- const char *src, *dst;
- int count;
-
- if (path == NULL) {
- best = ne;
- break;
- }
-
- src = ne->ne_name + strlen(ne->ne_name) - 1;
- dst = path + strlen(path) - 1;
- for (count = 0; src >= ne->ne_name && dst >= path;
- src--, dst--, count++)
- if (*src != *dst)
- break;
-
- /*
- * At this point, 'count' is the number of characters
- * matched from the end.
- */
- if (count > matched || best == NULL) {
- best = ne;
- matched = count;
- }
- }
- }
-
- if (best == NULL)
- return (0);
-
- if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) != 0)
- return (-1);
-
- if ((devid = get_devid(best->ne_name)) == NULL) {
- (void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
- } else {
- if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0) {
- devid_str_free(devid);
- return (-1);
- }
- devid_str_free(devid);
- }
-
- return (0);
-}
-
-/*
- * Add the given configuration to the list of known devices.
- */
-static int
-add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
- nvlist_t *config)
-{
- uint64_t pool_guid, vdev_guid, top_guid, txg, state;
- pool_entry_t *pe;
- vdev_entry_t *ve;
- config_entry_t *ce;
- name_entry_t *ne;
-
- /*
- * If this is a hot spare not currently in use or level 2 cache
- * device, add it to the list of names to translate, but don't do
- * anything else.
- */
- if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
- &state) == 0 &&
- (state == POOL_STATE_SPARE || state == POOL_STATE_L2CACHE) &&
- nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0) {
- if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL)
- return (-1);
-
- if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
- free(ne);
- return (-1);
- }
-
- ne->ne_guid = vdev_guid;
- ne->ne_next = pl->names;
- pl->names = ne;
-
- return (0);
- }
-
- /*
- * If we have a valid config but cannot read any of these fields, then
- * it means we have a half-initialized label. In vdev_label_init()
- * we write a label with txg == 0 so that we can identify the device
- * in case the user refers to the same disk later on. If we fail to
- * create the pool, we'll be left with a label in this state
- * which should not be considered part of a valid pool.
- */
- if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
- &pool_guid) != 0 ||
- nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
- &vdev_guid) != 0 ||
- nvlist_lookup_uint64(config, ZPOOL_CONFIG_TOP_GUID,
- &top_guid) != 0 ||
- nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
- &txg) != 0 || txg == 0) {
- return (0);
- }
-
- /*
- * First, see if we know about this pool. If not, then add it to the
- * list of known pools.
- */
- for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
- if (pe->pe_guid == pool_guid)
- break;
- }
-
- if (pe == NULL) {
- if ((pe = zfs_alloc(hdl, sizeof (pool_entry_t))) == NULL) {
- return (-1);
- }
- pe->pe_guid = pool_guid;
- pe->pe_next = pl->pools;
- pl->pools = pe;
- }
-
- /*
- * Second, see if we know about this toplevel vdev. Add it if its
- * missing.
- */
- for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
- if (ve->ve_guid == top_guid)
- break;
- }
-
- if (ve == NULL) {
- if ((ve = zfs_alloc(hdl, sizeof (vdev_entry_t))) == NULL) {
- return (-1);
- }
- ve->ve_guid = top_guid;
- ve->ve_next = pe->pe_vdevs;
- pe->pe_vdevs = ve;
- }
-
- /*
- * Third, see if we have a config with a matching transaction group. If
- * so, then we do nothing. Otherwise, add it to the list of known
- * configs.
- */
- for (ce = ve->ve_configs; ce != NULL; ce = ce->ce_next) {
- if (ce->ce_txg == txg)
- break;
- }
-
- if (ce == NULL) {
- if ((ce = zfs_alloc(hdl, sizeof (config_entry_t))) == NULL) {
- return (-1);
- }
- ce->ce_txg = txg;
- ce->ce_config = fnvlist_dup(config);
- ce->ce_next = ve->ve_configs;
- ve->ve_configs = ce;
- }
-
- /*
- * At this point we've successfully added our config to the list of
- * known configs. The last thing to do is add the vdev guid -> path
- * mappings so that we can fix up the configuration as necessary before
- * doing the import.
- */
- if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL)
- return (-1);
-
- if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
- free(ne);
- return (-1);
- }
-
- ne->ne_guid = vdev_guid;
- ne->ne_next = pl->names;
- pl->names = ne;
-
- return (0);
-}
-
-/*
- * Returns true if the named pool matches the given GUID.
- */
-static int
-pool_active(libzfs_handle_t *hdl, const char *name, uint64_t guid,
- boolean_t *isactive)
-{
- zpool_handle_t *zhp;
- uint64_t theguid;
-
- if (zpool_open_silent(hdl, name, &zhp) != 0)
- return (-1);
-
- if (zhp == NULL) {
- *isactive = B_FALSE;
- return (0);
- }
-
- verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID,
- &theguid) == 0);
-
- zpool_close(zhp);
-
- *isactive = (theguid == guid);
- return (0);
-}
-
-static nvlist_t *
-refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
-{
- nvlist_t *nvl;
- zfs_cmd_t zc = { 0 };
- int err, dstbuf_size;
-
- if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0)
- return (NULL);
-
- dstbuf_size = MAX(CONFIG_BUF_MINSIZE, zc.zc_nvlist_conf_size * 4);
-
- if (zcmd_alloc_dst_nvlist(hdl, &zc, dstbuf_size) != 0) {
- zcmd_free_nvlists(&zc);
- return (NULL);
- }
-
- while ((err = ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_TRYIMPORT,
- &zc)) != 0 && errno == ENOMEM) {
- if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
- zcmd_free_nvlists(&zc);
- return (NULL);
- }
- }
-
- if (err) {
- zcmd_free_nvlists(&zc);
- return (NULL);
- }
-
- if (zcmd_read_dst_nvlist(hdl, &zc, &nvl) != 0) {
- zcmd_free_nvlists(&zc);
- return (NULL);
- }
-
- zcmd_free_nvlists(&zc);
- return (nvl);
-}
-
-/*
- * Determine if the vdev id is a hole in the namespace.
- */
-boolean_t
-vdev_is_hole(uint64_t *hole_array, uint_t holes, uint_t id)
-{
- for (int c = 0; c < holes; c++) {
-
- /* Top-level is a hole */
- if (hole_array[c] == id)
- return (B_TRUE);
- }
- return (B_FALSE);
-}
-
-/*
- * Convert our list of pools into the definitive set of configurations. We
- * start by picking the best config for each toplevel vdev. Once that's done,
- * we assemble the toplevel vdevs into a full config for the pool. We make a
- * pass to fix up any incorrect paths, and then add it to the main list to
- * return to the user.
- */
-static nvlist_t *
-get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok,
- nvlist_t *policy)
-{
- pool_entry_t *pe;
- vdev_entry_t *ve;
- config_entry_t *ce;
- nvlist_t *ret = NULL, *config = NULL, *tmp = NULL, *nvtop, *nvroot;
- nvlist_t **spares, **l2cache;
- uint_t i, nspares, nl2cache;
- boolean_t config_seen;
- uint64_t best_txg;
- char *name, *hostname = NULL;
- uint64_t guid;
- uint_t children = 0;
- nvlist_t **child = NULL;
- uint_t holes;
- uint64_t *hole_array, max_id;
- uint_t c;
- boolean_t isactive;
- uint64_t hostid;
- nvlist_t *nvl;
- boolean_t found_one = B_FALSE;
- boolean_t valid_top_config = B_FALSE;
-
- if (nvlist_alloc(&ret, 0, 0) != 0)
- goto nomem;
-
- for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
- uint64_t id, max_txg = 0;
-
- if (nvlist_alloc(&config, NV_UNIQUE_NAME, 0) != 0)
- goto nomem;
- config_seen = B_FALSE;
-
- /*
- * Iterate over all toplevel vdevs. Grab the pool configuration
- * from the first one we find, and then go through the rest and
- * add them as necessary to the 'vdevs' member of the config.
- */
- for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
-
- /*
- * Determine the best configuration for this vdev by
- * selecting the config with the latest transaction
- * group.
- */
- best_txg = 0;
- for (ce = ve->ve_configs; ce != NULL;
- ce = ce->ce_next) {
-
- if (ce->ce_txg > best_txg) {
- tmp = ce->ce_config;
- best_txg = ce->ce_txg;
- }
- }
-
- /*
- * We rely on the fact that the max txg for the
- * pool will contain the most up-to-date information
- * about the valid top-levels in the vdev namespace.
- */
- if (best_txg > max_txg) {
- (void) nvlist_remove(config,
- ZPOOL_CONFIG_VDEV_CHILDREN,
- DATA_TYPE_UINT64);
- (void) nvlist_remove(config,
- ZPOOL_CONFIG_HOLE_ARRAY,
- DATA_TYPE_UINT64_ARRAY);
-
- max_txg = best_txg;
- hole_array = NULL;
- holes = 0;
- max_id = 0;
- valid_top_config = B_FALSE;
-
- if (nvlist_lookup_uint64(tmp,
- ZPOOL_CONFIG_VDEV_CHILDREN, &max_id) == 0) {
- verify(nvlist_add_uint64(config,
- ZPOOL_CONFIG_VDEV_CHILDREN,
- max_id) == 0);
- valid_top_config = B_TRUE;
- }
-
- if (nvlist_lookup_uint64_array(tmp,
- ZPOOL_CONFIG_HOLE_ARRAY, &hole_array,
- &holes) == 0) {
- verify(nvlist_add_uint64_array(config,
- ZPOOL_CONFIG_HOLE_ARRAY,
- hole_array, holes) == 0);
- }
- }
-
- if (!config_seen) {
- /*
- * Copy the relevant pieces of data to the pool
- * configuration:
- *
- * version
- * pool guid
- * name
- * comment (if available)
- * pool state
- * hostid (if available)
- * hostname (if available)
- */
- uint64_t state, version;
- char *comment = NULL;
-
- version = fnvlist_lookup_uint64(tmp,
- ZPOOL_CONFIG_VERSION);
- fnvlist_add_uint64(config,
- ZPOOL_CONFIG_VERSION, version);
- guid = fnvlist_lookup_uint64(tmp,
- ZPOOL_CONFIG_POOL_GUID);
- fnvlist_add_uint64(config,
- ZPOOL_CONFIG_POOL_GUID, guid);
- name = fnvlist_lookup_string(tmp,
- ZPOOL_CONFIG_POOL_NAME);
- fnvlist_add_string(config,
- ZPOOL_CONFIG_POOL_NAME, name);
-
- if (nvlist_lookup_string(tmp,
- ZPOOL_CONFIG_COMMENT, &comment) == 0)
- fnvlist_add_string(config,
- ZPOOL_CONFIG_COMMENT, comment);
-
- state = fnvlist_lookup_uint64(tmp,
- ZPOOL_CONFIG_POOL_STATE);
- fnvlist_add_uint64(config,
- ZPOOL_CONFIG_POOL_STATE, state);
-
- hostid = 0;
- if (nvlist_lookup_uint64(tmp,
- ZPOOL_CONFIG_HOSTID, &hostid) == 0) {
- fnvlist_add_uint64(config,
- ZPOOL_CONFIG_HOSTID, hostid);
- hostname = fnvlist_lookup_string(tmp,
- ZPOOL_CONFIG_HOSTNAME);
- fnvlist_add_string(config,
- ZPOOL_CONFIG_HOSTNAME, hostname);
- }
-
- config_seen = B_TRUE;
- }
-
- /*
- * Add this top-level vdev to the child array.
- */
- verify(nvlist_lookup_nvlist(tmp,
- ZPOOL_CONFIG_VDEV_TREE, &nvtop) == 0);
- verify(nvlist_lookup_uint64(nvtop, ZPOOL_CONFIG_ID,
- &id) == 0);
-
- if (id >= children) {
- nvlist_t **newchild;
-
- newchild = zfs_alloc(hdl, (id + 1) *
- sizeof (nvlist_t *));
- if (newchild == NULL)
- goto nomem;
-
- for (c = 0; c < children; c++)
- newchild[c] = child[c];
-
- free(child);
- child = newchild;
- children = id + 1;
- }
- if (nvlist_dup(nvtop, &child[id], 0) != 0)
- goto nomem;
-
- }
-
- /*
- * If we have information about all the top-levels then
- * clean up the nvlist which we've constructed. This
- * means removing any extraneous devices that are
- * beyond the valid range or adding devices to the end
- * of our array which appear to be missing.
- */
- if (valid_top_config) {
- if (max_id < children) {
- for (c = max_id; c < children; c++)
- nvlist_free(child[c]);
- children = max_id;
- } else if (max_id > children) {
- nvlist_t **newchild;
-
- newchild = zfs_alloc(hdl, (max_id) *
- sizeof (nvlist_t *));
- if (newchild == NULL)
- goto nomem;
-
- for (c = 0; c < children; c++)
- newchild[c] = child[c];
-
- free(child);
- child = newchild;
- children = max_id;
- }
- }
-
- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
- &guid) == 0);
-
- /*
- * The vdev namespace may contain holes as a result of
- * device removal. We must add them back into the vdev
- * tree before we process any missing devices.
- */
- if (holes > 0) {
- ASSERT(valid_top_config);
-
- for (c = 0; c < children; c++) {
- nvlist_t *holey;
-
- if (child[c] != NULL ||
- !vdev_is_hole(hole_array, holes, c))
- continue;
-
- if (nvlist_alloc(&holey, NV_UNIQUE_NAME,
- 0) != 0)
- goto nomem;
-
- /*
- * Holes in the namespace are treated as
- * "hole" top-level vdevs and have a
- * special flag set on them.
- */
- if (nvlist_add_string(holey,
- ZPOOL_CONFIG_TYPE,
- VDEV_TYPE_HOLE) != 0 ||
- nvlist_add_uint64(holey,
- ZPOOL_CONFIG_ID, c) != 0 ||
- nvlist_add_uint64(holey,
- ZPOOL_CONFIG_GUID, 0ULL) != 0) {
- nvlist_free(holey);
- goto nomem;
- }
- child[c] = holey;
- }
- }
-
- /*
- * Look for any missing top-level vdevs. If this is the case,
- * create a faked up 'missing' vdev as a placeholder. We cannot
- * simply compress the child array, because the kernel performs
- * certain checks to make sure the vdev IDs match their location
- * in the configuration.
- */
- for (c = 0; c < children; c++) {
- if (child[c] == NULL) {
- nvlist_t *missing;
- if (nvlist_alloc(&missing, NV_UNIQUE_NAME,
- 0) != 0)
- goto nomem;
- if (nvlist_add_string(missing,
- ZPOOL_CONFIG_TYPE,
- VDEV_TYPE_MISSING) != 0 ||
- nvlist_add_uint64(missing,
- ZPOOL_CONFIG_ID, c) != 0 ||
- nvlist_add_uint64(missing,
- ZPOOL_CONFIG_GUID, 0ULL) != 0) {
- nvlist_free(missing);
- goto nomem;
- }
- child[c] = missing;
- }
- }
-
- /*
- * Put all of this pool's top-level vdevs into a root vdev.
- */
- if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0)
- goto nomem;
- if (nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
- VDEV_TYPE_ROOT) != 0 ||
- nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) != 0 ||
- nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, guid) != 0 ||
- nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
- child, children) != 0) {
- nvlist_free(nvroot);
- goto nomem;
- }
-
- for (c = 0; c < children; c++)
- nvlist_free(child[c]);
- free(child);
- children = 0;
- child = NULL;
-
- /*
- * Go through and fix up any paths and/or devids based on our
- * known list of vdev GUID -> path mappings.
- */
- if (fix_paths(nvroot, pl->names) != 0) {
- nvlist_free(nvroot);
- goto nomem;
- }
-
- /*
- * Add the root vdev to this pool's configuration.
- */
- if (nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
- nvroot) != 0) {
- nvlist_free(nvroot);
- goto nomem;
- }
- nvlist_free(nvroot);
-
- /*
- * zdb uses this path to report on active pools that were
- * imported or created using -R.
- */
- if (active_ok)
- goto add_pool;
-
- /*
- * Determine if this pool is currently active, in which case we
- * can't actually import it.
- */
- verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
- &name) == 0);
- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
- &guid) == 0);
-
- if (pool_active(hdl, name, guid, &isactive) != 0)
- goto error;
-
- if (isactive) {
- nvlist_free(config);
- config = NULL;
- continue;
- }
-
- if (policy != NULL) {
- if (nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY,
- policy) != 0)
- goto nomem;
- }
-
- if ((nvl = refresh_config(hdl, config)) == NULL) {
- nvlist_free(config);
- config = NULL;
- continue;
- }
-
- nvlist_free(config);
- config = nvl;
-
- /*
- * Go through and update the paths for spares, now that we have
- * them.
- */
- verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
- &nvroot) == 0);
- if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
- &spares, &nspares) == 0) {
- for (i = 0; i < nspares; i++) {
- if (fix_paths(spares[i], pl->names) != 0)
- goto nomem;
- }
- }
-
- /*
- * Update the paths for l2cache devices.
- */
- if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
- &l2cache, &nl2cache) == 0) {
- for (i = 0; i < nl2cache; i++) {
- if (fix_paths(l2cache[i], pl->names) != 0)
- goto nomem;
- }
- }
-
- /*
- * Restore the original information read from the actual label.
- */
- (void) nvlist_remove(config, ZPOOL_CONFIG_HOSTID,
- DATA_TYPE_UINT64);
- (void) nvlist_remove(config, ZPOOL_CONFIG_HOSTNAME,
- DATA_TYPE_STRING);
- if (hostid != 0) {
- verify(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID,
- hostid) == 0);
- verify(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME,
- hostname) == 0);
- }
-
-add_pool:
- /*
- * Add this pool to the list of configs.
- */
- verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
- &name) == 0);
- if (nvlist_add_nvlist(ret, name, config) != 0)
- goto nomem;
-
- found_one = B_TRUE;
- nvlist_free(config);
- config = NULL;
- }
-
- if (!found_one) {
- nvlist_free(ret);
- ret = NULL;
- }
-
- return (ret);
-
-nomem:
- (void) no_memory(hdl);
-error:
- nvlist_free(config);
- nvlist_free(ret);
- for (c = 0; c < children; c++)
- nvlist_free(child[c]);
- free(child);
-
- return (NULL);
-}
-
-/*
- * Return the offset of the given label.
- */
-static uint64_t
-label_offset(uint64_t size, int l)
-{
- ASSERT(P2PHASE_TYPED(size, sizeof (vdev_label_t), uint64_t) == 0);
- return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ?
- 0 : size - VDEV_LABELS * sizeof (vdev_label_t)));
-}
-
-/*
- * Given a file descriptor, read the label information and return an nvlist
- * describing the configuration, if there is one.
- * Return 0 on success, or -1 on failure
- */
-int
-zpool_read_label(int fd, nvlist_t **config)
-{
- struct stat64 statbuf;
- int l;
- vdev_label_t *label;
- uint64_t state, txg, size;
-
- *config = NULL;
-
- if (fstat64(fd, &statbuf) == -1)
- return (-1);
- size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
-
- if ((label = malloc(sizeof (vdev_label_t))) == NULL)
- return (-1);
-
- for (l = 0; l < VDEV_LABELS; l++) {
- if (pread64(fd, label, sizeof (vdev_label_t),
- label_offset(size, l)) != sizeof (vdev_label_t))
- continue;
-
- if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist,
- sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0)
- continue;
-
- if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE,
- &state) != 0 || state > POOL_STATE_L2CACHE) {
- nvlist_free(*config);
- continue;
- }
-
- if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
- (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG,
- &txg) != 0 || txg == 0)) {
- nvlist_free(*config);
- continue;
- }
-
- free(label);
- return (0);
- }
-
- free(label);
- *config = NULL;
- errno = ENOENT;
- return (-1);
-}
-
-/*
- * Given a file descriptor, read the label information and return an nvlist
- * describing the configuration, if there is one.
- * returns the number of valid labels found
- * If a label is found, returns it via config. The caller is responsible for
- * freeing it.
- */
-int
-zpool_read_all_labels(int fd, nvlist_t **config)
-{
- struct stat64 statbuf;
- struct aiocb aiocbs[VDEV_LABELS];
- struct aiocb *aiocbps[VDEV_LABELS];
- int l;
- vdev_phys_t *labels;
- uint64_t state, txg, size;
- int nlabels = 0;
-
- *config = NULL;
-
- if (fstat64(fd, &statbuf) == -1)
- return (0);
- size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
-
- if ((labels = calloc(VDEV_LABELS, sizeof (vdev_phys_t))) == NULL)
- return (0);
-
- memset(aiocbs, 0, sizeof(aiocbs));
- for (l = 0; l < VDEV_LABELS; l++) {
- aiocbs[l].aio_fildes = fd;
- aiocbs[l].aio_offset = label_offset(size, l) + VDEV_SKIP_SIZE;
- aiocbs[l].aio_buf = &labels[l];
- aiocbs[l].aio_nbytes = sizeof(vdev_phys_t);
- aiocbs[l].aio_lio_opcode = LIO_READ;
- aiocbps[l] = &aiocbs[l];
- }
-
- if (lio_listio(LIO_WAIT, aiocbps, VDEV_LABELS, NULL) != 0) {
- if (errno == EAGAIN || errno == EINTR || errno == EIO) {
- for (l = 0; l < VDEV_LABELS; l++) {
- errno = 0;
- int r = aio_error(&aiocbs[l]);
- if (r != EINVAL)
- (void)aio_return(&aiocbs[l]);
- }
- }
- free(labels);
- return (0);
- }
-
- for (l = 0; l < VDEV_LABELS; l++) {
- nvlist_t *temp = NULL;
-
- if (aio_return(&aiocbs[l]) != sizeof(vdev_phys_t))
- continue;
-
- if (nvlist_unpack(labels[l].vp_nvlist,
- sizeof (labels[l].vp_nvlist), &temp, 0) != 0)
- continue;
-
- if (nvlist_lookup_uint64(temp, ZPOOL_CONFIG_POOL_STATE,
- &state) != 0 || state > POOL_STATE_L2CACHE) {
- nvlist_free(temp);
- temp = NULL;
- continue;
- }
-
- if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
- (nvlist_lookup_uint64(temp, ZPOOL_CONFIG_POOL_TXG,
- &txg) != 0 || txg == 0)) {
- nvlist_free(temp);
- temp = NULL;
- continue;
- }
- if (temp)
- *config = temp;
-
- nlabels++;
- }
-
- free(labels);
- return (nlabels);
-}
-
-typedef struct rdsk_node {
- char *rn_name;
- int rn_dfd;
- libzfs_handle_t *rn_hdl;
- nvlist_t *rn_config;
- avl_tree_t *rn_avl;
- avl_node_t rn_node;
- boolean_t rn_nozpool;
-} rdsk_node_t;
-
-static int
-slice_cache_compare(const void *arg1, const void *arg2)
-{
- const char *nm1 = ((rdsk_node_t *)arg1)->rn_name;
- const char *nm2 = ((rdsk_node_t *)arg2)->rn_name;
- char *nm1slice, *nm2slice;
- int rv;
-
- /*
- * slices zero and two are the most likely to provide results,
- * so put those first
- */
- nm1slice = strstr(nm1, "s0");
- nm2slice = strstr(nm2, "s0");
- if (nm1slice && !nm2slice) {
- return (-1);
- }
- if (!nm1slice && nm2slice) {
- return (1);
- }
- nm1slice = strstr(nm1, "s2");
- nm2slice = strstr(nm2, "s2");
- if (nm1slice && !nm2slice) {
- return (-1);
- }
- if (!nm1slice && nm2slice) {
- return (1);
- }
-
- rv = strcmp(nm1, nm2);
- if (rv == 0)
- return (0);
- return (rv > 0 ? 1 : -1);
-}
-
-#ifdef illumos
-static void
-check_one_slice(avl_tree_t *r, char *diskname, uint_t partno,
- diskaddr_t size, uint_t blksz)
-{
- rdsk_node_t tmpnode;
- rdsk_node_t *node;
- char sname[MAXNAMELEN];
-
- tmpnode.rn_name = &sname[0];
- (void) snprintf(tmpnode.rn_name, MAXNAMELEN, "%s%u",
- diskname, partno);
- /*
- * protect against division by zero for disk labels that
- * contain a bogus sector size
- */
- if (blksz == 0)
- blksz = DEV_BSIZE;
- /* too small to contain a zpool? */
- if ((size < (SPA_MINDEVSIZE / blksz)) &&
- (node = avl_find(r, &tmpnode, NULL)))
- node->rn_nozpool = B_TRUE;
-}
-#endif /* illumos */
-
-static void
-nozpool_all_slices(avl_tree_t *r, const char *sname)
-{
-#ifdef illumos
- char diskname[MAXNAMELEN];
- char *ptr;
- int i;
-
- (void) strncpy(diskname, sname, MAXNAMELEN);
- if (((ptr = strrchr(diskname, 's')) == NULL) &&
- ((ptr = strrchr(diskname, 'p')) == NULL))
- return;
- ptr[0] = 's';
- ptr[1] = '\0';
- for (i = 0; i < NDKMAP; i++)
- check_one_slice(r, diskname, i, 0, 1);
- ptr[0] = 'p';
- for (i = 0; i <= FD_NUMPART; i++)
- check_one_slice(r, diskname, i, 0, 1);
-#endif /* illumos */
-}
-
-#ifdef illumos
-static void
-check_slices(avl_tree_t *r, int fd, const char *sname)
-{
- struct extvtoc vtoc;
- struct dk_gpt *gpt;
- char diskname[MAXNAMELEN];
- char *ptr;
- int i;
-
- (void) strncpy(diskname, sname, MAXNAMELEN);
- if ((ptr = strrchr(diskname, 's')) == NULL || !isdigit(ptr[1]))
- return;
- ptr[1] = '\0';
-
- if (read_extvtoc(fd, &vtoc) >= 0) {
- for (i = 0; i < NDKMAP; i++)
- check_one_slice(r, diskname, i,
- vtoc.v_part[i].p_size, vtoc.v_sectorsz);
- } else if (efi_alloc_and_read(fd, &gpt) >= 0) {
- /*
- * on x86 we'll still have leftover links that point
- * to slices s[9-15], so use NDKMAP instead
- */
- for (i = 0; i < NDKMAP; i++)
- check_one_slice(r, diskname, i,
- gpt->efi_parts[i].p_size, gpt->efi_lbasize);
- /* nodes p[1-4] are never used with EFI labels */
- ptr[0] = 'p';
- for (i = 1; i <= FD_NUMPART; i++)
- check_one_slice(r, diskname, i, 0, 1);
- efi_free(gpt);
- }
-}
-#endif /* illumos */
-
-static void
-zpool_open_func(void *arg)
-{
- rdsk_node_t *rn = arg;
- struct stat64 statbuf;
- nvlist_t *config;
- int fd;
-
- if (rn->rn_nozpool)
- return;
- if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) {
- /* symlink to a device that's no longer there */
- if (errno == ENOENT)
- nozpool_all_slices(rn->rn_avl, rn->rn_name);
- return;
- }
- /*
- * Ignore failed stats. We only want regular
- * files, character devs and block devs.
- */
- if (fstat64(fd, &statbuf) != 0 ||
- (!S_ISREG(statbuf.st_mode) &&
- !S_ISCHR(statbuf.st_mode) &&
- !S_ISBLK(statbuf.st_mode))) {
- (void) close(fd);
- return;
- }
- /* this file is too small to hold a zpool */
-#ifdef illumos
- if (S_ISREG(statbuf.st_mode) &&
- statbuf.st_size < SPA_MINDEVSIZE) {
- (void) close(fd);
- return;
- } else if (!S_ISREG(statbuf.st_mode)) {
- /*
- * Try to read the disk label first so we don't have to
- * open a bunch of minor nodes that can't have a zpool.
- */
- check_slices(rn->rn_avl, fd, rn->rn_name);
- }
-#else /* !illumos */
- if (statbuf.st_size < SPA_MINDEVSIZE) {
- (void) close(fd);
- return;
- }
-#endif /* illumos */
-
- if ((zpool_read_label(fd, &config)) != 0 && errno == ENOMEM) {
- (void) close(fd);
- (void) no_memory(rn->rn_hdl);
- return;
- }
- (void) close(fd);
-
- rn->rn_config = config;
-}
-
-/*
- * Given a file descriptor, clear (zero) the label information.
- */
-int
-zpool_clear_label(int fd)
-{
- struct stat64 statbuf;
- int l;
- vdev_label_t *label;
- uint64_t size;
-
- if (fstat64(fd, &statbuf) == -1)
- return (0);
- size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
-
- if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL)
- return (-1);
-
- for (l = 0; l < VDEV_LABELS; l++) {
- if (pwrite64(fd, label, sizeof (vdev_label_t),
- label_offset(size, l)) != sizeof (vdev_label_t)) {
- free(label);
- return (-1);
- }
- }
-
- free(label);
- return (0);
-}
-
-/*
- * Given a list of directories to search, find all pools stored on disk. This
- * includes partial pools which are not available to import. If no args are
- * given (argc is 0), then the default directory (/dev/dsk) is searched.
- * poolname or guid (but not both) are provided by the caller when trying
- * to import a specific pool.
- */
-static nvlist_t *
-zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
-{
- int i, dirs = iarg->paths;
- struct dirent64 *dp;
- char path[MAXPATHLEN];
- char *end, **dir = iarg->path;
- size_t pathleft;
- nvlist_t *ret = NULL;
- static char *default_dir = "/dev";
- pool_list_t pools = { 0 };
- pool_entry_t *pe, *penext;
- vdev_entry_t *ve, *venext;
- config_entry_t *ce, *cenext;
- name_entry_t *ne, *nenext;
- avl_tree_t slice_cache;
- rdsk_node_t *slice;
- void *cookie;
- boolean_t skip_zvols = B_FALSE;
- int value;
- size_t size = sizeof(value);
-
- if (dirs == 0) {
- dirs = 1;
- dir = &default_dir;
- }
-
- if (sysctlbyname("vfs.zfs.vol.recursive", &value, &size, NULL, 0) == 0
- && value == 0) {
- skip_zvols = B_TRUE;
- }
-
- /*
- * Go through and read the label configuration information from every
- * possible device, organizing the information according to pool GUID
- * and toplevel GUID.
- */
- for (i = 0; i < dirs; i++) {
- tpool_t *t;
- char rdsk[MAXPATHLEN];
- int dfd;
- boolean_t config_failed = B_FALSE;
- DIR *dirp;
-
- /* use realpath to normalize the path */
- if (realpath(dir[i], path) == 0) {
- (void) zfs_error_fmt(hdl, EZFS_BADPATH,
- dgettext(TEXT_DOMAIN, "cannot open '%s'"), dir[i]);
- goto error;
- }
- end = &path[strlen(path)];
- *end++ = '/';
- *end = 0;
- pathleft = &path[sizeof (path)] - end;
-
-#ifdef illumos
- /*
- * Using raw devices instead of block devices when we're
- * reading the labels skips a bunch of slow operations during
- * close(2) processing, so we replace /dev/dsk with /dev/rdsk.
- */
- if (strcmp(path, ZFS_DISK_ROOTD) == 0)
- (void) strlcpy(rdsk, ZFS_RDISK_ROOTD, sizeof (rdsk));
- else
-#endif
- (void) strlcpy(rdsk, path, sizeof (rdsk));
-
- if ((dfd = open64(rdsk, O_RDONLY)) < 0 ||
- (dirp = fdopendir(dfd)) == NULL) {
- if (dfd >= 0)
- (void) close(dfd);
- zfs_error_aux(hdl, strerror(errno));
- (void) zfs_error_fmt(hdl, EZFS_BADPATH,
- dgettext(TEXT_DOMAIN, "cannot open '%s'"),
- rdsk);
- goto error;
- }
-
- avl_create(&slice_cache, slice_cache_compare,
- sizeof (rdsk_node_t), offsetof(rdsk_node_t, rn_node));
-
- if (strcmp(rdsk, "/dev/") == 0) {
- struct gmesh mesh;
- struct gclass *mp;
- struct ggeom *gp;
- struct gprovider *pp;
-
- errno = geom_gettree(&mesh);
- if (errno != 0) {
- zfs_error_aux(hdl, strerror(errno));
- (void) zfs_error_fmt(hdl, EZFS_BADPATH,
- dgettext(TEXT_DOMAIN, "cannot get GEOM tree"));
- goto error;
- }
-
- LIST_FOREACH(mp, &mesh.lg_class, lg_class) {
- if (skip_zvols &&
- strcmp(mp->lg_name, "ZFS::ZVOL") == 0) {
- continue;
- }
- LIST_FOREACH(gp, &mp->lg_geom, lg_geom) {
- LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
- slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
- slice->rn_name = zfs_strdup(hdl, pp->lg_name);
- slice->rn_avl = &slice_cache;
- slice->rn_dfd = dfd;
- slice->rn_hdl = hdl;
- slice->rn_nozpool = B_FALSE;
- avl_add(&slice_cache, slice);
- }
- }
- }
-
- geom_deletetree(&mesh);
- goto skipdir;
- }
-
- /*
- * This is not MT-safe, but we have no MT consumers of libzfs
- */
- while ((dp = readdir64(dirp)) != NULL) {
- const char *name = dp->d_name;
- if (name[0] == '.' &&
- (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
- continue;
-
- slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
- slice->rn_name = zfs_strdup(hdl, name);
- slice->rn_avl = &slice_cache;
- slice->rn_dfd = dfd;
- slice->rn_hdl = hdl;
- slice->rn_nozpool = B_FALSE;
- avl_add(&slice_cache, slice);
- }
-skipdir:
- /*
- * create a thread pool to do all of this in parallel;
- * rn_nozpool is not protected, so this is racy in that
- * multiple tasks could decide that the same slice can
- * not hold a zpool, which is benign. Also choose
- * double the number of processors; we hold a lot of
- * locks in the kernel, so going beyond this doesn't
- * buy us much.
- */
- t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN),
- 0, NULL);
- for (slice = avl_first(&slice_cache); slice;
- (slice = avl_walk(&slice_cache, slice,
- AVL_AFTER)))
- (void) tpool_dispatch(t, zpool_open_func, slice);
- tpool_wait(t);
- tpool_destroy(t);
-
- cookie = NULL;
- while ((slice = avl_destroy_nodes(&slice_cache,
- &cookie)) != NULL) {
- if (slice->rn_config != NULL && !config_failed) {
- nvlist_t *config = slice->rn_config;
- boolean_t matched = B_TRUE;
-
- if (iarg->poolname != NULL) {
- char *pname;
-
- matched = nvlist_lookup_string(config,
- ZPOOL_CONFIG_POOL_NAME,
- &pname) == 0 &&
- strcmp(iarg->poolname, pname) == 0;
- } else if (iarg->guid != 0) {
- uint64_t this_guid;
-
- matched = nvlist_lookup_uint64(config,
- ZPOOL_CONFIG_POOL_GUID,
- &this_guid) == 0 &&
- iarg->guid == this_guid;
- }
- if (matched) {
- /*
- * use the non-raw path for the config
- */
- (void) strlcpy(end, slice->rn_name,
- pathleft);
- if (add_config(hdl, &pools, path,
- config) != 0)
- config_failed = B_TRUE;
- }
- nvlist_free(config);
- }
- free(slice->rn_name);
- free(slice);
- }
- avl_destroy(&slice_cache);
-
- (void) closedir(dirp);
-
- if (config_failed)
- goto error;
- }
-
- ret = get_configs(hdl, &pools, iarg->can_be_active, iarg->policy);
-
-error:
- for (pe = pools.pools; pe != NULL; pe = penext) {
- penext = pe->pe_next;
- for (ve = pe->pe_vdevs; ve != NULL; ve = venext) {
- venext = ve->ve_next;
- for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
- cenext = ce->ce_next;
- nvlist_free(ce->ce_config);
- free(ce);
- }
- free(ve);
- }
- free(pe);
- }
-
- for (ne = pools.names; ne != NULL; ne = nenext) {
- nenext = ne->ne_next;
- free(ne->ne_name);
- free(ne);
- }
-
- return (ret);
-}
-
-nvlist_t *
-zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv)
-{
- importargs_t iarg = { 0 };
-
- iarg.paths = argc;
- iarg.path = argv;
-
- return (zpool_find_import_impl(hdl, &iarg));
-}
-
-/*
- * Given a cache file, return the contents as a list of importable pools.
- * poolname or guid (but not both) are provided by the caller when trying
- * to import a specific pool.
- */
-nvlist_t *
-zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
- char *poolname, uint64_t guid)
-{
- char *buf;
- int fd;
- struct stat64 statbuf;
- nvlist_t *raw, *src, *dst;
- nvlist_t *pools;
- nvpair_t *elem;
- char *name;
- uint64_t this_guid;
- boolean_t active;
-
- verify(poolname == NULL || guid == 0);
-
- if ((fd = open(cachefile, O_RDONLY)) < 0) {
- zfs_error_aux(hdl, "%s", strerror(errno));
- (void) zfs_error(hdl, EZFS_BADCACHE,
- dgettext(TEXT_DOMAIN, "failed to open cache file"));
- return (NULL);
- }
-
- if (fstat64(fd, &statbuf) != 0) {
- zfs_error_aux(hdl, "%s", strerror(errno));
- (void) close(fd);
- (void) zfs_error(hdl, EZFS_BADCACHE,
- dgettext(TEXT_DOMAIN, "failed to get size of cache file"));
- return (NULL);
- }
-
- if ((buf = zfs_alloc(hdl, statbuf.st_size)) == NULL) {
- (void) close(fd);
- return (NULL);
- }
-
- if (read(fd, buf, statbuf.st_size) != statbuf.st_size) {
- (void) close(fd);
- free(buf);
- (void) zfs_error(hdl, EZFS_BADCACHE,
- dgettext(TEXT_DOMAIN,
- "failed to read cache file contents"));
- return (NULL);
- }
-
- (void) close(fd);
-
- if (nvlist_unpack(buf, statbuf.st_size, &raw, 0) != 0) {
- free(buf);
- (void) zfs_error(hdl, EZFS_BADCACHE,
- dgettext(TEXT_DOMAIN,
- "invalid or corrupt cache file contents"));
- return (NULL);
- }
-
- free(buf);
-
- /*
- * Go through and get the current state of the pools and refresh their
- * state.
- */
- if (nvlist_alloc(&pools, 0, 0) != 0) {
- (void) no_memory(hdl);
- nvlist_free(raw);
- return (NULL);
- }
-
- elem = NULL;
- while ((elem = nvlist_next_nvpair(raw, elem)) != NULL) {
- src = fnvpair_value_nvlist(elem);
-
- name = fnvlist_lookup_string(src, ZPOOL_CONFIG_POOL_NAME);
- if (poolname != NULL && strcmp(poolname, name) != 0)
- continue;
-
- this_guid = fnvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID);
- if (guid != 0 && guid != this_guid)
- continue;
-
- if (pool_active(hdl, name, this_guid, &active) != 0) {
- nvlist_free(raw);
- nvlist_free(pools);
- return (NULL);
- }
-
- if (active)
- continue;
-
- if (nvlist_add_string(src, ZPOOL_CONFIG_CACHEFILE,
- cachefile) != 0) {
- (void) no_memory(hdl);
- nvlist_free(raw);
- nvlist_free(pools);
- return (NULL);
- }
-
- if ((dst = refresh_config(hdl, src)) == NULL) {
- nvlist_free(raw);
- nvlist_free(pools);
- return (NULL);
- }
-
- if (nvlist_add_nvlist(pools, nvpair_name(elem), dst) != 0) {
- (void) no_memory(hdl);
- nvlist_free(dst);
- nvlist_free(raw);
- nvlist_free(pools);
- return (NULL);
- }
- nvlist_free(dst);
- }
-
- nvlist_free(raw);
- return (pools);
-}
-
-static int
-name_or_guid_exists(zpool_handle_t *zhp, void *data)
-{
- importargs_t *import = data;
- int found = 0;
-
- if (import->poolname != NULL) {
- char *pool_name;
-
- verify(nvlist_lookup_string(zhp->zpool_config,
- ZPOOL_CONFIG_POOL_NAME, &pool_name) == 0);
- if (strcmp(pool_name, import->poolname) == 0)
- found = 1;
- } else {
- uint64_t pool_guid;
-
- verify(nvlist_lookup_uint64(zhp->zpool_config,
- ZPOOL_CONFIG_POOL_GUID, &pool_guid) == 0);
- if (pool_guid == import->guid)
- found = 1;
- }
-
- zpool_close(zhp);
- return (found);
-}
-
-nvlist_t *
-zpool_search_import(libzfs_handle_t *hdl, importargs_t *import)
-{
- nvlist_t *pools = NULL;
-
- verify(import->poolname == NULL || import->guid == 0);
-
- if (import->unique)
- import->exists = zpool_iter(hdl, name_or_guid_exists, import);
-
- if (import->cachefile != NULL)
- pools = zpool_find_import_cached(hdl, import->cachefile,
- import->poolname, import->guid);
- else
- pools = zpool_find_import_impl(hdl, import);
-
- return (pools);
-}
-
-static boolean_t
-pool_match(nvlist_t *cfg, char *tgt)
-{
- uint64_t v, guid = strtoull(tgt, NULL, 0);
- char *s;
-
- if (guid != 0) {
- if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &v) == 0)
- return (v == guid);
- } else {
- if (nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &s) == 0)
- return (strcmp(s, tgt) == 0);
- }
- return (B_FALSE);
-}
-
-int
-zpool_tryimport(libzfs_handle_t *hdl, char *target, nvlist_t **configp,
- importargs_t *args)
-{
- nvlist_t *pools;
- nvlist_t *match = NULL;
- nvlist_t *config = NULL;
- char *sepp = NULL;
- int count = 0;
- char *targetdup = strdup(target);
-
- *configp = NULL;
-
- if ((sepp = strpbrk(targetdup, "/@")) != NULL) {
- *sepp = '\0';
- }
-
- pools = zpool_search_import(hdl, args);
-
- if (pools != NULL) {
- nvpair_t *elem = NULL;
- while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
- VERIFY0(nvpair_value_nvlist(elem, &config));
- if (pool_match(config, targetdup)) {
- count++;
- if (match != NULL) {
- /* multiple matches found */
- continue;
- } else {
- match = config;
- }
- }
- }
- }
-
- if (count == 0) {
- free(targetdup);
- return (ENOENT);
- }
-
- if (count > 1) {
- free(targetdup);
- return (EINVAL);
- }
-
- *configp = match;
- free(targetdup);
-
- return (0);
-}
-
-boolean_t
-find_guid(nvlist_t *nv, uint64_t guid)
-{
- uint64_t tmp;
- nvlist_t **child;
- uint_t c, children;
-
- verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &tmp) == 0);
- if (tmp == guid)
- return (B_TRUE);
-
- if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
- &child, &children) == 0) {
- for (c = 0; c < children; c++)
- if (find_guid(child[c], guid))
- return (B_TRUE);
- }
-
- return (B_FALSE);
-}
-
-typedef struct aux_cbdata {
- const char *cb_type;
- uint64_t cb_guid;
- zpool_handle_t *cb_zhp;
-} aux_cbdata_t;
-
-static int
-find_aux(zpool_handle_t *zhp, void *data)
-{
- aux_cbdata_t *cbp = data;
- nvlist_t **list;
- uint_t i, count;
- uint64_t guid;
- nvlist_t *nvroot;
-
- verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
- &nvroot) == 0);
-
- if (nvlist_lookup_nvlist_array(nvroot, cbp->cb_type,
- &list, &count) == 0) {
- for (i = 0; i < count; i++) {
- verify(nvlist_lookup_uint64(list[i],
- ZPOOL_CONFIG_GUID, &guid) == 0);
- if (guid == cbp->cb_guid) {
- cbp->cb_zhp = zhp;
- return (1);
- }
- }
- }
-
- zpool_close(zhp);
- return (0);
-}
-
-/*
- * Determines if the pool is in use. If so, it returns true and the state of
- * the pool as well as the name of the pool. Both strings are allocated and
- * must be freed by the caller.
- */
-int
-zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,
- boolean_t *inuse)
-{
- nvlist_t *config;
- char *name;
- boolean_t ret;
- uint64_t guid, vdev_guid;
- zpool_handle_t *zhp;
- nvlist_t *pool_config;
- uint64_t stateval, isspare;
- aux_cbdata_t cb = { 0 };
- boolean_t isactive;
-
- *inuse = B_FALSE;
-
- if (zpool_read_label(fd, &config) != 0 && errno == ENOMEM) {
- (void) no_memory(hdl);
- return (-1);
- }
-
- if (config == NULL)
- return (0);
-
- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
- &stateval) == 0);
- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
- &vdev_guid) == 0);
-
- if (stateval != POOL_STATE_SPARE && stateval != POOL_STATE_L2CACHE) {
- verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
- &name) == 0);
- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
- &guid) == 0);
- }
-
- switch (stateval) {
- case POOL_STATE_EXPORTED:
- /*
- * A pool with an exported state may in fact be imported
- * read-only, so check the in-core state to see if it's
- * active and imported read-only. If it is, set
- * its state to active.
- */
- if (pool_active(hdl, name, guid, &isactive) == 0 && isactive &&
- (zhp = zpool_open_canfail(hdl, name)) != NULL) {
- if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
- stateval = POOL_STATE_ACTIVE;
-
- /*
- * All we needed the zpool handle for is the
- * readonly prop check.
- */
- zpool_close(zhp);
- }
-
- ret = B_TRUE;
- break;
-
- case POOL_STATE_ACTIVE:
- /*
- * For an active pool, we have to determine if it's really part
- * of a currently active pool (in which case the pool will exist
- * and the guid will be the same), or whether it's part of an
- * active pool that was disconnected without being explicitly
- * exported.
- */
- if (pool_active(hdl, name, guid, &isactive) != 0) {
- nvlist_free(config);
- return (-1);
- }
-
- if (isactive) {
- /*
- * Because the device may have been removed while
- * offlined, we only report it as active if the vdev is
- * still present in the config. Otherwise, pretend like
- * it's not in use.
- */
- if ((zhp = zpool_open_canfail(hdl, name)) != NULL &&
- (pool_config = zpool_get_config(zhp, NULL))
- != NULL) {
- nvlist_t *nvroot;
-
- verify(nvlist_lookup_nvlist(pool_config,
- ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
- ret = find_guid(nvroot, vdev_guid);
- } else {
- ret = B_FALSE;
- }
-
- /*
- * If this is an active spare within another pool, we
- * treat it like an unused hot spare. This allows the
- * user to create a pool with a hot spare that currently
- * in use within another pool. Since we return B_TRUE,
- * libdiskmgt will continue to prevent generic consumers
- * from using the device.
- */
- if (ret && nvlist_lookup_uint64(config,
- ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare)
- stateval = POOL_STATE_SPARE;
-
- if (zhp != NULL)
- zpool_close(zhp);
- } else {
- stateval = POOL_STATE_POTENTIALLY_ACTIVE;
- ret = B_TRUE;
- }
- break;
-
- case POOL_STATE_SPARE:
- /*
- * For a hot spare, it can be either definitively in use, or
- * potentially active. To determine if it's in use, we iterate
- * over all pools in the system and search for one with a spare
- * with a matching guid.
- *
- * Due to the shared nature of spares, we don't actually report
- * the potentially active case as in use. This means the user
- * can freely create pools on the hot spares of exported pools,
- * but to do otherwise makes the resulting code complicated, and
- * we end up having to deal with this case anyway.
- */
- cb.cb_zhp = NULL;
- cb.cb_guid = vdev_guid;
- cb.cb_type = ZPOOL_CONFIG_SPARES;
- if (zpool_iter(hdl, find_aux, &cb) == 1) {
- name = (char *)zpool_get_name(cb.cb_zhp);
- ret = B_TRUE;
- } else {
- ret = B_FALSE;
- }
- break;
-
- case POOL_STATE_L2CACHE:
-
- /*
- * Check if any pool is currently using this l2cache device.
- */
- cb.cb_zhp = NULL;
- cb.cb_guid = vdev_guid;
- cb.cb_type = ZPOOL_CONFIG_L2CACHE;
- if (zpool_iter(hdl, find_aux, &cb) == 1) {
- name = (char *)zpool_get_name(cb.cb_zhp);
- ret = B_TRUE;
- } else {
- ret = B_FALSE;
- }
- break;
-
- default:
- ret = B_FALSE;
- }
-
-
- if (ret) {
- if ((*namestr = zfs_strdup(hdl, name)) == NULL) {
- if (cb.cb_zhp)
- zpool_close(cb.cb_zhp);
- nvlist_free(config);
- return (-1);
- }
- *state = (pool_state_t)stateval;
- }
-
- if (cb.cb_zhp)
- zpool_close(cb.cb_zhp);
-
- nvlist_free(config);
- *inuse = ret;
- return (0);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
deleted file mode 100644
index 36138676e7db..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
- * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2019 Datto Inc.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <libintl.h>
-#include <libzfs.h>
-
-#include "libzfs_impl.h"
-
-int
-zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data)
-{
- nvlist_t *nvl = zfs_get_clones_nvl(zhp);
- nvpair_t *pair;
-
- if (nvl == NULL)
- return (0);
-
- for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
- pair = nvlist_next_nvpair(nvl, pair)) {
- zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair),
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
- if (clone != NULL) {
- int err = func(clone, data);
- if (err != 0)
- return (err);
- }
- }
- return (0);
-}
-
-static int
-zfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc)
-{
- int rc;
- uint64_t orig_cookie;
-
- orig_cookie = zc->zc_cookie;
-top:
- (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
- rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
-
- if (rc == -1) {
- switch (errno) {
- case ENOMEM:
- /* expand nvlist memory and try again */
- if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
- zcmd_free_nvlists(zc);
- return (-1);
- }
- zc->zc_cookie = orig_cookie;
- goto top;
- /*
- * An errno value of ESRCH indicates normal completion.
- * If ENOENT is returned, then the underlying dataset
- * has been removed since we obtained the handle.
- */
- case ESRCH:
- case ENOENT:
- rc = 1;
- break;
- default:
- rc = zfs_standard_error(zhp->zfs_hdl, errno,
- dgettext(TEXT_DOMAIN,
- "cannot iterate filesystems"));
- break;
- }
- }
- return (rc);
-}
-
-/*
- * Iterate over all child filesystems
- */
-int
-zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
-{
- zfs_cmd_t zc = { 0 };
- zfs_handle_t *nzhp;
- int ret;
-
- if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
- return (0);
-
- if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
- return (-1);
-
- while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
- &zc)) == 0) {
- /*
- * Silently ignore errors, as the only plausible explanation is
- * that the pool has since been removed.
- */
- if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
- &zc)) == NULL) {
- continue;
- }
-
- if ((ret = func(nzhp, data)) != 0) {
- zcmd_free_nvlists(&zc);
- return (ret);
- }
- }
- zcmd_free_nvlists(&zc);
- return ((ret < 0) ? ret : 0);
-}
-
-/*
- * Iterate over all snapshots
- */
-int
-zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
- void *data, uint64_t min_txg, uint64_t max_txg)
-{
- zfs_cmd_t zc = { 0 };
- zfs_handle_t *nzhp;
- int ret;
- nvlist_t *range_nvl = NULL;
-
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
- zhp->zfs_type == ZFS_TYPE_BOOKMARK)
- return (0);
-
- zc.zc_simple = simple;
-
- if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
- return (-1);
-
- if (min_txg != 0) {
- range_nvl = fnvlist_alloc();
- fnvlist_add_uint64(range_nvl, SNAP_ITER_MIN_TXG, min_txg);
- }
- if (max_txg != 0) {
- if (range_nvl == NULL)
- range_nvl = fnvlist_alloc();
- fnvlist_add_uint64(range_nvl, SNAP_ITER_MAX_TXG, max_txg);
- }
-
- if (range_nvl != NULL &&
- zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, range_nvl) != 0) {
- zcmd_free_nvlists(&zc);
- fnvlist_free(range_nvl);
- return (-1);
- }
-
- while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
- &zc)) == 0) {
-
- if (simple)
- nzhp = make_dataset_simple_handle_zc(zhp, &zc);
- else
- nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc);
- if (nzhp == NULL)
- continue;
-
- if ((ret = func(nzhp, data)) != 0) {
- zcmd_free_nvlists(&zc);
- fnvlist_free(range_nvl);
- return (ret);
- }
- }
- zcmd_free_nvlists(&zc);
- fnvlist_free(range_nvl);
- return ((ret < 0) ? ret : 0);
-}
-
-/*
- * Iterate over all bookmarks
- */
-int
-zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
-{
- zfs_handle_t *nzhp;
- nvlist_t *props = NULL;
- nvlist_t *bmarks = NULL;
- int err;
-
- if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0)
- return (0);
-
- /* Setup the requested properties nvlist. */
- props = fnvlist_alloc();
- fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
- fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
- fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));
-
- if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
- goto out;
-
- for (nvpair_t *pair = nvlist_next_nvpair(bmarks, NULL);
- pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
- char name[ZFS_MAX_DATASET_NAME_LEN];
- char *bmark_name;
- nvlist_t *bmark_props;
-
- bmark_name = nvpair_name(pair);
- bmark_props = fnvpair_value_nvlist(pair);
-
- (void) snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name,
- bmark_name);
-
- nzhp = make_bookmark_handle(zhp, name, bmark_props);
- if (nzhp == NULL)
- continue;
-
- if ((err = func(nzhp, data)) != 0)
- goto out;
- }
-
-out:
- fnvlist_free(props);
- fnvlist_free(bmarks);
-
- return (err);
-}
-
-/*
- * Routines for dealing with the sorted snapshot functionality
- */
-typedef struct zfs_node {
- zfs_handle_t *zn_handle;
- avl_node_t zn_avlnode;
-} zfs_node_t;
-
-static int
-zfs_sort_snaps(zfs_handle_t *zhp, void *data)
-{
- avl_tree_t *avl = data;
- zfs_node_t *node;
- zfs_node_t search;
-
- search.zn_handle = zhp;
- node = avl_find(avl, &search, NULL);
- if (node) {
- /*
- * If this snapshot was renamed while we were creating the
- * AVL tree, it's possible that we already inserted it under
- * its old name. Remove the old handle before adding the new
- * one.
- */
- zfs_close(node->zn_handle);
- avl_remove(avl, node);
- free(node);
- }
-
- node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t));
- node->zn_handle = zhp;
- avl_add(avl, node);
-
- return (0);
-}
-
-static int
-zfs_snapshot_compare(const void *larg, const void *rarg)
-{
- zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
- zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
- uint64_t lcreate, rcreate;
-
- /*
- * Sort them according to creation time. We use the hidden
- * CREATETXG property to get an absolute ordering of snapshots.
- */
- lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
- rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
-
- return (AVL_CMP(lcreate, rcreate));
-}
-
-int
-zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data,
- uint64_t min_txg, uint64_t max_txg)
-{
- int ret = 0;
- zfs_node_t *node;
- avl_tree_t avl;
- void *cookie = NULL;
-
- avl_create(&avl, zfs_snapshot_compare,
- sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
-
- ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl, min_txg,
- max_txg);
-
- for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
- ret |= callback(node->zn_handle, data);
-
- while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL)
- free(node);
-
- avl_destroy(&avl);
-
- return (ret);
-}
-
-typedef struct {
- char *ssa_first;
- char *ssa_last;
- boolean_t ssa_seenfirst;
- boolean_t ssa_seenlast;
- zfs_iter_f ssa_func;
- void *ssa_arg;
-} snapspec_arg_t;
-
-static int
-snapspec_cb(zfs_handle_t *zhp, void *arg)
-{
- snapspec_arg_t *ssa = arg;
- const char *shortsnapname;
- int err = 0;
-
- if (ssa->ssa_seenlast)
- return (0);
-
- shortsnapname = strchr(zfs_get_name(zhp), '@') + 1;
- if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0)
- ssa->ssa_seenfirst = B_TRUE;
- if (strcmp(shortsnapname, ssa->ssa_last) == 0)
- ssa->ssa_seenlast = B_TRUE;
-
- if (ssa->ssa_seenfirst) {
- err = ssa->ssa_func(zhp, ssa->ssa_arg);
- } else {
- zfs_close(zhp);
- }
-
- return (err);
-}
-
-/*
- * spec is a string like "A,B%C,D"
- *
- * <snaps>, where <snaps> can be:
- * <snap> (single snapshot)
- * <snap>%<snap> (range of snapshots, inclusive)
- * %<snap> (range of snapshots, starting with earliest)
- * <snap>% (range of snapshots, ending with last)
- * % (all snapshots)
- * <snaps>[,...] (comma separated list of the above)
- *
- * If a snapshot can not be opened, continue trying to open the others, but
- * return ENOENT at the end.
- */
-int
-zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
- zfs_iter_f func, void *arg)
-{
- char *buf, *comma_separated, *cp;
- int err = 0;
- int ret = 0;
-
- buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig);
- cp = buf;
-
- while ((comma_separated = strsep(&cp, ",")) != NULL) {
- char *pct = strchr(comma_separated, '%');
- if (pct != NULL) {
- snapspec_arg_t ssa = { 0 };
- ssa.ssa_func = func;
- ssa.ssa_arg = arg;
-
- if (pct == comma_separated)
- ssa.ssa_seenfirst = B_TRUE;
- else
- ssa.ssa_first = comma_separated;
- *pct = '\0';
- ssa.ssa_last = pct + 1;
-
- /*
- * If there is a lastname specified, make sure it
- * exists.
- */
- if (ssa.ssa_last[0] != '\0') {
- char snapname[ZFS_MAX_DATASET_NAME_LEN];
- (void) snprintf(snapname, sizeof (snapname),
- "%s@%s", zfs_get_name(fs_zhp),
- ssa.ssa_last);
- if (!zfs_dataset_exists(fs_zhp->zfs_hdl,
- snapname, ZFS_TYPE_SNAPSHOT)) {
- ret = ENOENT;
- continue;
- }
- }
-
- err = zfs_iter_snapshots_sorted(fs_zhp,
- snapspec_cb, &ssa, 0, 0);
- if (ret == 0)
- ret = err;
- if (ret == 0 && (!ssa.ssa_seenfirst ||
- (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) {
- ret = ENOENT;
- }
- } else {
- char snapname[ZFS_MAX_DATASET_NAME_LEN];
- zfs_handle_t *snap_zhp;
- (void) snprintf(snapname, sizeof (snapname), "%s@%s",
- zfs_get_name(fs_zhp), comma_separated);
- snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl,
- snapname);
- if (snap_zhp == NULL) {
- ret = ENOENT;
- continue;
- }
- err = func(snap_zhp, arg);
- if (ret == 0)
- ret = err;
- }
- }
-
- free(buf);
- return (ret);
-}
-
-/*
- * Iterate over all children, snapshots and filesystems
- * Process snapshots before filesystems because they are nearer the input
- * handle: this is extremely important when used with zfs_iter_f functions
- * looking for data, following the logic that we would like to find it as soon
- * and as close as possible.
- */
-int
-zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
-{
- int ret;
-
- if ((ret = zfs_iter_snapshots(zhp, B_FALSE, func, data, 0, 0)) != 0)
- return (ret);
-
- return (zfs_iter_filesystems(zhp, func, data));
-}
-
-
-typedef struct iter_stack_frame {
- struct iter_stack_frame *next;
- zfs_handle_t *zhp;
-} iter_stack_frame_t;
-
-typedef struct iter_dependents_arg {
- boolean_t first;
- boolean_t allowrecursion;
- iter_stack_frame_t *stack;
- zfs_iter_f func;
- void *data;
-} iter_dependents_arg_t;
-
-static int
-iter_dependents_cb(zfs_handle_t *zhp, void *arg)
-{
- iter_dependents_arg_t *ida = arg;
- int err = 0;
- boolean_t first = ida->first;
- ida->first = B_FALSE;
-
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
- err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
- } else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
- iter_stack_frame_t isf;
- iter_stack_frame_t *f;
-
- /*
- * check if there is a cycle by seeing if this fs is already
- * on the stack.
- */
- for (f = ida->stack; f != NULL; f = f->next) {
- if (f->zhp->zfs_dmustats.dds_guid ==
- zhp->zfs_dmustats.dds_guid) {
- if (ida->allowrecursion) {
- zfs_close(zhp);
- return (0);
- } else {
- zfs_error_aux(zhp->zfs_hdl,
- dgettext(TEXT_DOMAIN,
- "recursive dependency at '%s'"),
- zfs_get_name(zhp));
- err = zfs_error(zhp->zfs_hdl,
- EZFS_RECURSIVE,
- dgettext(TEXT_DOMAIN,
- "cannot determine dependent "
- "datasets"));
- zfs_close(zhp);
- return (err);
- }
- }
- }
-
- isf.zhp = zhp;
- isf.next = ida->stack;
- ida->stack = &isf;
- err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
- if (err == 0) {
- err = zfs_iter_snapshots(zhp, B_FALSE,
- iter_dependents_cb, ida, 0, 0);
- }
- ida->stack = isf.next;
- }
-
- if (!first && err == 0)
- err = ida->func(zhp, ida->data);
- else
- zfs_close(zhp);
-
- return (err);
-}
-
-int
-zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
- zfs_iter_f func, void *data)
-{
- iter_dependents_arg_t ida;
- ida.allowrecursion = allowrecursion;
- ida.stack = NULL;
- ida.func = func;
- ida.data = data;
- ida.first = B_TRUE;
- return (iter_dependents_cb(zfs_handle_dup(zhp), &ida));
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
deleted file mode 100644
index 9d4948cc7173..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
+++ /dev/null
@@ -1,1734 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
- * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
- * Copyright 2017 Joyent, Inc.
- * Copyright 2017 RackTop Systems.
- * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
- */
-
-/*
- * Routines to manage ZFS mounts. We separate all the nasty routines that have
- * to deal with the OS. The following functions are the main entry points --
- * they are used by mount and unmount and when changing a filesystem's
- * mountpoint.
- *
- * zfs_is_mounted()
- * zfs_mount()
- * zfs_unmount()
- * zfs_unmountall()
- *
- * This file also contains the functions used to manage sharing filesystems via
- * NFS and iSCSI:
- *
- * zfs_is_shared()
- * zfs_share()
- * zfs_unshare()
- *
- * zfs_is_shared_nfs()
- * zfs_is_shared_smb()
- * zfs_share_proto()
- * zfs_shareall();
- * zfs_unshare_nfs()
- * zfs_unshare_smb()
- * zfs_unshareall_nfs()
- * zfs_unshareall_smb()
- * zfs_unshareall()
- * zfs_unshareall_bypath()
- *
- * The following functions are available for pool consumers, and will
- * mount/unmount and share/unshare all datasets within pool:
- *
- * zpool_enable_datasets()
- * zpool_disable_datasets()
- */
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <libintl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <unistd.h>
-#include <zone.h>
-#include <sys/mntent.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-
-#include <libzfs.h>
-
-#include "libzfs_impl.h"
-#include <thread_pool.h>
-
-#include <libshare.h>
-#define MAXISALEN 257 /* based on sysinfo(2) man page */
-
-static int mount_tp_nthr = 512; /* tpool threads for multi-threaded mounting */
-
-static void zfs_mount_task(void *);
-static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
-zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
- zfs_share_proto_t);
-
-/*
- * The share protocols table must be in the same order as the zfs_share_proto_t
- * enum in libzfs_impl.h
- */
-typedef struct {
- zfs_prop_t p_prop;
- char *p_name;
- int p_share_err;
- int p_unshare_err;
-} proto_table_t;
-
-proto_table_t proto_table[PROTO_END] = {
- {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
- {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
-};
-
-zfs_share_proto_t nfs_only[] = {
- PROTO_NFS,
- PROTO_END
-};
-
-zfs_share_proto_t smb_only[] = {
- PROTO_SMB,
- PROTO_END
-};
-zfs_share_proto_t share_all_proto[] = {
- PROTO_NFS,
- PROTO_SMB,
- PROTO_END
-};
-
-/*
- * Search the sharetab for the given mountpoint and protocol, returning
- * a zfs_share_type_t value.
- */
-static zfs_share_type_t
-is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
-{
- char buf[MAXPATHLEN], *tab;
- char *ptr;
-
- if (hdl->libzfs_sharetab == NULL)
- return (SHARED_NOT_SHARED);
-
- (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
-
- while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
-
- /* the mountpoint is the first entry on each line */
- if ((tab = strchr(buf, '\t')) == NULL)
- continue;
-
- *tab = '\0';
- if (strcmp(buf, mountpoint) == 0) {
-#ifdef illumos
- /*
- * the protocol field is the third field
- * skip over second field
- */
- ptr = ++tab;
- if ((tab = strchr(ptr, '\t')) == NULL)
- continue;
- ptr = ++tab;
- if ((tab = strchr(ptr, '\t')) == NULL)
- continue;
- *tab = '\0';
- if (strcmp(ptr,
- proto_table[proto].p_name) == 0) {
- switch (proto) {
- case PROTO_NFS:
- return (SHARED_NFS);
- case PROTO_SMB:
- return (SHARED_SMB);
- default:
- return (0);
- }
- }
-#else
- if (proto == PROTO_NFS)
- return (SHARED_NFS);
-#endif
- }
- }
-
- return (SHARED_NOT_SHARED);
-}
-
-#ifdef illumos
-static boolean_t
-dir_is_empty_stat(const char *dirname)
-{
- struct stat st;
-
- /*
- * We only want to return false if the given path is a non empty
- * directory, all other errors are handled elsewhere.
- */
- if (stat(dirname, &st) < 0 || !S_ISDIR(st.st_mode)) {
- return (B_TRUE);
- }
-
- /*
- * An empty directory will still have two entries in it, one
- * entry for each of "." and "..".
- */
- if (st.st_size > 2) {
- return (B_FALSE);
- }
-
- return (B_TRUE);
-}
-
-static boolean_t
-dir_is_empty_readdir(const char *dirname)
-{
- DIR *dirp;
- struct dirent64 *dp;
- int dirfd;
-
- if ((dirfd = openat(AT_FDCWD, dirname,
- O_RDONLY | O_NDELAY | O_LARGEFILE | O_CLOEXEC, 0)) < 0) {
- return (B_TRUE);
- }
-
- if ((dirp = fdopendir(dirfd)) == NULL) {
- (void) close(dirfd);
- return (B_TRUE);
- }
-
- while ((dp = readdir64(dirp)) != NULL) {
-
- if (strcmp(dp->d_name, ".") == 0 ||
- strcmp(dp->d_name, "..") == 0)
- continue;
-
- (void) closedir(dirp);
- return (B_FALSE);
- }
-
- (void) closedir(dirp);
- return (B_TRUE);
-}
-
-/*
- * Returns true if the specified directory is empty. If we can't open the
- * directory at all, return true so that the mount can fail with a more
- * informative error message.
- */
-static boolean_t
-dir_is_empty(const char *dirname)
-{
- struct statvfs64 st;
-
- /*
- * If the statvfs call fails or the filesystem is not a ZFS
- * filesystem, fall back to the slow path which uses readdir.
- */
- if ((statvfs64(dirname, &st) != 0) ||
- (strcmp(st.f_basetype, "zfs") != 0)) {
- return (dir_is_empty_readdir(dirname));
- }
-
- /*
- * At this point, we know the provided path is on a ZFS
- * filesystem, so we can use stat instead of readdir to
- * determine if the directory is empty or not. We try to avoid
- * using readdir because that requires opening "dirname"; this
- * open file descriptor can potentially end up in a child
- * process if there's a concurrent fork, thus preventing the
- * zfs_mount() from otherwise succeeding (the open file
- * descriptor inherited by the child process will cause the
- * parent's mount to fail with EBUSY). The performance
- * implications of replacing the open, read, and close with a
- * single stat is nice; but is not the main motivation for the
- * added complexity.
- */
- return (dir_is_empty_stat(dirname));
-}
-#endif
-
-/*
- * Checks to see if the mount is active. If the filesystem is mounted, we fill
- * in 'where' with the current mountpoint, and return 1. Otherwise, we return
- * 0.
- */
-boolean_t
-is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
-{
- struct mnttab entry;
-
- if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0)
- return (B_FALSE);
-
- if (where != NULL)
- *where = zfs_strdup(zfs_hdl, entry.mnt_mountp);
-
- return (B_TRUE);
-}
-
-boolean_t
-zfs_is_mounted(zfs_handle_t *zhp, char **where)
-{
- return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where));
-}
-
-static boolean_t
-zfs_is_mountable_internal(zfs_handle_t *zhp, const char *mountpoint)
-{
-
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
- getzoneid() == GLOBAL_ZONEID)
- return (B_FALSE);
-
- return (B_TRUE);
-}
-
-/*
- * Returns true if the given dataset is mountable, false otherwise. Returns the
- * mountpoint in 'buf'.
- */
-static boolean_t
-zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
- zprop_source_t *source)
-{
- char sourceloc[MAXNAMELEN];
- zprop_source_t sourcetype;
-
- if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
- return (B_FALSE);
-
- verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
- &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
-
- if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
- strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
- return (B_FALSE);
-
- if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF)
- return (B_FALSE);
-
- if (!zfs_is_mountable_internal(zhp, buf))
- return (B_FALSE);
-
- if (source)
- *source = sourcetype;
-
- return (B_TRUE);
-}
-
-/*
- * Mount the given filesystem.
- */
-int
-zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
-{
- char mountpoint[ZFS_MAXPROPLEN];
-
- if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
- return (0);
-
- return (zfs_mount_at(zhp, options, flags, mountpoint));
-}
-
-int
-zfs_mount_at(zfs_handle_t *zhp, const char *options, int flags,
- const char *mountpoint)
-{
- struct stat buf;
- char mntopts[MNT_LINE_MAX];
- libzfs_handle_t *hdl = zhp->zfs_hdl;
-
- if (options == NULL)
- mntopts[0] = '\0';
- else
- (void) strlcpy(mntopts, options, sizeof (mntopts));
-
- /*
- * If the pool is imported read-only then all mounts must be read-only
- */
- if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
- flags |= MS_RDONLY;
-
- if (!zfs_is_mountable_internal(zhp, mountpoint))
- return (B_FALSE);
-
- /* Create the directory if it doesn't already exist */
- if (lstat(mountpoint, &buf) != 0) {
- if (mkdirp(mountpoint, 0755) != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "failed to create mountpoint"));
- return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
- dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
- mountpoint));
- }
- }
-
-#ifdef illumos /* FreeBSD: overlay mounts are not checked. */
- /*
- * Determine if the mountpoint is empty. If so, refuse to perform the
- * mount. We don't perform this check if MS_OVERLAY is specified, which
- * would defeat the point. We also avoid this check if 'remount' is
- * specified.
- */
- if ((flags & MS_OVERLAY) == 0 &&
- strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
- !dir_is_empty(mountpoint)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "directory is not empty"));
- return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
- dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
- }
-#endif
-
- /* perform the mount */
- if (zmount(zfs_get_name(zhp), mountpoint, flags,
- MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
- /*
- * Generic errors are nasty, but there are just way too many
- * from mount(), and they're well-understood. We pick a few
- * common ones to improve upon.
- */
- if (errno == EBUSY) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "mountpoint or dataset is busy"));
- } else if (errno == EPERM) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "Insufficient privileges"));
- } else if (errno == ENOTSUP) {
- char buf[256];
- int spa_version;
-
- VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
- (void) snprintf(buf, sizeof (buf),
- dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
- "file system on a version %d pool. Pool must be"
- " upgraded to mount this file system."),
- (u_longlong_t)zfs_prop_get_int(zhp,
- ZFS_PROP_VERSION), spa_version);
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
- } else {
- zfs_error_aux(hdl, strerror(errno));
- }
- return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
- dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
- zhp->zfs_name));
- }
-
- /* add the mounted entry into our cache */
- libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint,
- mntopts);
- return (0);
-}
-
-/*
- * Unmount a single filesystem.
- */
-static int
-unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
-{
- if (umount2(mountpoint, flags) != 0) {
- zfs_error_aux(hdl, strerror(errno));
- return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
- dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
- mountpoint));
- }
-
- return (0);
-}
-
-/*
- * Unmount the given filesystem.
- */
-int
-zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- struct mnttab entry;
- char *mntpt = NULL;
-
- /* check to see if we need to unmount the filesystem */
- if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
- libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {
- /*
- * mountpoint may have come from a call to
- * getmnt/getmntany if it isn't NULL. If it is NULL,
- * we know it comes from libzfs_mnttab_find which can
- * then get freed later. We strdup it to play it safe.
- */
- if (mountpoint == NULL)
- mntpt = zfs_strdup(hdl, entry.mnt_mountp);
- else
- mntpt = zfs_strdup(hdl, mountpoint);
-
- /*
- * Unshare and unmount the filesystem
- */
- if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
- return (-1);
-
- if (unmount_one(hdl, mntpt, flags) != 0) {
- free(mntpt);
- (void) zfs_shareall(zhp);
- return (-1);
- }
- libzfs_mnttab_remove(hdl, zhp->zfs_name);
- free(mntpt);
- }
-
- return (0);
-}
-
-/*
- * Unmount this filesystem and any children inheriting the mountpoint property.
- * To do this, just act like we're changing the mountpoint property, but don't
- * remount the filesystems afterwards.
- */
-int
-zfs_unmountall(zfs_handle_t *zhp, int flags)
-{
- prop_changelist_t *clp;
- int ret;
-
- clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags);
- if (clp == NULL)
- return (-1);
-
- ret = changelist_prefix(clp);
- changelist_free(clp);
-
- return (ret);
-}
-
-boolean_t
-zfs_is_shared(zfs_handle_t *zhp)
-{
- zfs_share_type_t rc = 0;
- zfs_share_proto_t *curr_proto;
-
- if (ZFS_IS_VOLUME(zhp))
- return (B_FALSE);
-
- for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
- curr_proto++)
- rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
-
- return (rc ? B_TRUE : B_FALSE);
-}
-
-int
-zfs_share(zfs_handle_t *zhp)
-{
- assert(!ZFS_IS_VOLUME(zhp));
- return (zfs_share_proto(zhp, share_all_proto));
-}
-
-int
-zfs_unshare(zfs_handle_t *zhp)
-{
- assert(!ZFS_IS_VOLUME(zhp));
- return (zfs_unshareall(zhp));
-}
-
-/*
- * Check to see if the filesystem is currently shared.
- */
-zfs_share_type_t
-zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
-{
- char *mountpoint;
- zfs_share_type_t rc;
-
- if (!zfs_is_mounted(zhp, &mountpoint))
- return (SHARED_NOT_SHARED);
-
- if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))
- != SHARED_NOT_SHARED) {
- if (where != NULL)
- *where = mountpoint;
- else
- free(mountpoint);
- return (rc);
- } else {
- free(mountpoint);
- return (SHARED_NOT_SHARED);
- }
-}
-
-boolean_t
-zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
-{
- return (zfs_is_shared_proto(zhp, where,
- PROTO_NFS) != SHARED_NOT_SHARED);
-}
-
-boolean_t
-zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
-{
- return (zfs_is_shared_proto(zhp, where,
- PROTO_SMB) != SHARED_NOT_SHARED);
-}
-
-/*
- * Make sure things will work if libshare isn't installed by using
- * wrapper functions that check to see that the pointers to functions
- * initialized in _zfs_init_libshare() are actually present.
- */
-
-#ifdef illumos
-static sa_handle_t (*_sa_init)(int);
-static sa_handle_t (*_sa_init_arg)(int, void *);
-static void (*_sa_fini)(sa_handle_t);
-static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
-static int (*_sa_enable_share)(sa_share_t, char *);
-static int (*_sa_disable_share)(sa_share_t, char *);
-static char *(*_sa_errorstr)(int);
-static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *);
-static boolean_t (*_sa_needs_refresh)(sa_handle_t *);
-static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t);
-static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t,
- char *, char *, zprop_source_t, char *, char *, char *);
-static void (*_sa_update_sharetab_ts)(sa_handle_t);
-#endif
-
-/*
- * _zfs_init_libshare()
- *
- * Find the libshare.so.1 entry points that we use here and save the
- * values to be used later. This is triggered by the runtime loader.
- * Make sure the correct ISA version is loaded.
- */
-
-#pragma init(_zfs_init_libshare)
-static void
-_zfs_init_libshare(void)
-{
-#ifdef illumos
- void *libshare;
- char path[MAXPATHLEN];
- char isa[MAXISALEN];
-
-#if defined(_LP64)
- if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
- isa[0] = '\0';
-#else
- isa[0] = '\0';
-#endif
- (void) snprintf(path, MAXPATHLEN,
- "/usr/lib/%s/libshare.so.1", isa);
-
- if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) {
- _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init");
- _sa_init_arg = (sa_handle_t (*)(int, void *))dlsym(libshare,
- "sa_init_arg");
- _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini");
- _sa_find_share = (sa_share_t (*)(sa_handle_t, char *))
- dlsym(libshare, "sa_find_share");
- _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
- "sa_enable_share");
- _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
- "sa_disable_share");
- _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr");
- _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *))
- dlsym(libshare, "sa_parse_legacy_options");
- _sa_needs_refresh = (boolean_t (*)(sa_handle_t *))
- dlsym(libshare, "sa_needs_refresh");
- _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t))
- dlsym(libshare, "sa_get_zfs_handle");
- _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t,
- sa_share_t, char *, char *, zprop_source_t, char *,
- char *, char *))dlsym(libshare, "sa_zfs_process_share");
- _sa_update_sharetab_ts = (void (*)(sa_handle_t))
- dlsym(libshare, "sa_update_sharetab_ts");
- if (_sa_init == NULL || _sa_init_arg == NULL ||
- _sa_fini == NULL || _sa_find_share == NULL ||
- _sa_enable_share == NULL || _sa_disable_share == NULL ||
- _sa_errorstr == NULL || _sa_parse_legacy_options == NULL ||
- _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL ||
- _sa_zfs_process_share == NULL ||
- _sa_update_sharetab_ts == NULL) {
- _sa_init = NULL;
- _sa_init_arg = NULL;
- _sa_fini = NULL;
- _sa_disable_share = NULL;
- _sa_enable_share = NULL;
- _sa_errorstr = NULL;
- _sa_parse_legacy_options = NULL;
- (void) dlclose(libshare);
- _sa_needs_refresh = NULL;
- _sa_get_zfs_handle = NULL;
- _sa_zfs_process_share = NULL;
- _sa_update_sharetab_ts = NULL;
- }
- }
-#endif
-}
-
-/*
- * zfs_init_libshare(zhandle, service)
- *
- * Initialize the libshare API if it hasn't already been initialized.
- * In all cases it returns 0 if it succeeded and an error if not. The
- * service value is which part(s) of the API to initialize and is a
- * direct map to the libshare sa_init(service) interface.
- */
-static int
-zfs_init_libshare_impl(libzfs_handle_t *zhandle, int service, void *arg)
-{
-#ifdef illumos
- /*
- * libshare is either not installed or we're in a branded zone. The
- * rest of the wrapper functions around the libshare calls already
- * handle NULL function pointers, but we don't want the callers of
- * zfs_init_libshare() to fail prematurely if libshare is not available.
- */
- if (_sa_init == NULL)
- return (SA_OK);
-
- /*
- * Attempt to refresh libshare. This is necessary if there was a cache
- * miss for a new ZFS dataset that was just created, or if state of the
- * sharetab file has changed since libshare was last initialized. We
- * want to make sure so check timestamps to see if a different process
- * has updated any of the configuration. If there was some non-ZFS
- * change, we need to re-initialize the internal cache.
- */
- if (_sa_needs_refresh != NULL &&
- _sa_needs_refresh(zhandle->libzfs_sharehdl)) {
- zfs_uninit_libshare(zhandle);
- zhandle->libzfs_sharehdl = _sa_init_arg(service, arg);
- }
-
- if (zhandle && zhandle->libzfs_sharehdl == NULL)
- zhandle->libzfs_sharehdl = _sa_init_arg(service, arg);
-
- if (zhandle->libzfs_sharehdl == NULL)
- return (SA_NO_MEMORY);
-#endif
-
- return (SA_OK);
-}
-int
-zfs_init_libshare(libzfs_handle_t *zhandle, int service)
-{
- return (zfs_init_libshare_impl(zhandle, service, NULL));
-}
-
-int
-zfs_init_libshare_arg(libzfs_handle_t *zhandle, int service, void *arg)
-{
- return (zfs_init_libshare_impl(zhandle, service, arg));
-}
-
-
-/*
- * zfs_uninit_libshare(zhandle)
- *
- * Uninitialize the libshare API if it hasn't already been
- * uninitialized. It is OK to call multiple times.
- */
-void
-zfs_uninit_libshare(libzfs_handle_t *zhandle)
-{
- if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
-#ifdef illumos
- if (_sa_fini != NULL)
- _sa_fini(zhandle->libzfs_sharehdl);
-#endif
- zhandle->libzfs_sharehdl = NULL;
- }
-}
-
-/*
- * zfs_parse_options(options, proto)
- *
- * Call the legacy parse interface to get the protocol specific
- * options using the NULL arg to indicate that this is a "parse" only.
- */
-int
-zfs_parse_options(char *options, zfs_share_proto_t proto)
-{
-#ifdef illumos
- if (_sa_parse_legacy_options != NULL) {
- return (_sa_parse_legacy_options(NULL, options,
- proto_table[proto].p_name));
- }
- return (SA_CONFIG_ERR);
-#else
- return (SA_OK);
-#endif
-}
-
-#ifdef illumos
-/*
- * zfs_sa_find_share(handle, path)
- *
- * wrapper around sa_find_share to find a share path in the
- * configuration.
- */
-static sa_share_t
-zfs_sa_find_share(sa_handle_t handle, char *path)
-{
- if (_sa_find_share != NULL)
- return (_sa_find_share(handle, path));
- return (NULL);
-}
-
-/*
- * zfs_sa_enable_share(share, proto)
- *
- * Wrapper for sa_enable_share which enables a share for a specified
- * protocol.
- */
-static int
-zfs_sa_enable_share(sa_share_t share, char *proto)
-{
- if (_sa_enable_share != NULL)
- return (_sa_enable_share(share, proto));
- return (SA_CONFIG_ERR);
-}
-
-/*
- * zfs_sa_disable_share(share, proto)
- *
- * Wrapper for sa_enable_share which disables a share for a specified
- * protocol.
- */
-static int
-zfs_sa_disable_share(sa_share_t share, char *proto)
-{
- if (_sa_disable_share != NULL)
- return (_sa_disable_share(share, proto));
- return (SA_CONFIG_ERR);
-}
-#endif /* illumos */
-
-/*
- * Share the given filesystem according to the options in the specified
- * protocol specific properties (sharenfs, sharesmb). We rely
- * on "libshare" to the dirty work for us.
- */
-static int
-zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
-{
- char mountpoint[ZFS_MAXPROPLEN];
- char shareopts[ZFS_MAXPROPLEN];
- char sourcestr[ZFS_MAXPROPLEN];
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- zfs_share_proto_t *curr_proto;
- zprop_source_t sourcetype;
- int error, ret;
-
- if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
- return (0);
-
- for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
- /*
- * Return success if there are no share options.
- */
- if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
- shareopts, sizeof (shareopts), &sourcetype, sourcestr,
- ZFS_MAXPROPLEN, B_FALSE) != 0 ||
- strcmp(shareopts, "off") == 0)
- continue;
-#ifdef illumos
- ret = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_HANDLE,
- zhp);
- if (ret != SA_OK) {
- (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
- dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
- zfs_get_name(zhp), _sa_errorstr != NULL ?
- _sa_errorstr(ret) : "");
- return (-1);
- }
-#endif
-
- /*
- * If the 'zoned' property is set, then zfs_is_mountable()
- * will have already bailed out if we are in the global zone.
- * But local zones cannot be NFS servers, so we ignore it for
- * local zones as well.
- */
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
- continue;
-
-#ifdef illumos
- share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
- if (share == NULL) {
- /*
- * This may be a new file system that was just
- * created so isn't in the internal cache
- * (second time through). Rather than
- * reloading the entire configuration, we can
- * assume ZFS has done the checking and it is
- * safe to add this to the internal
- * configuration.
- */
- if (_sa_zfs_process_share(hdl->libzfs_sharehdl,
- NULL, NULL, mountpoint,
- proto_table[*curr_proto].p_name, sourcetype,
- shareopts, sourcestr, zhp->zfs_name) != SA_OK) {
- (void) zfs_error_fmt(hdl,
- proto_table[*curr_proto].p_share_err,
- dgettext(TEXT_DOMAIN, "cannot share '%s'"),
- zfs_get_name(zhp));
- return (-1);
- }
- share = zfs_sa_find_share(hdl->libzfs_sharehdl,
- mountpoint);
- }
- if (share != NULL) {
- int err;
- err = zfs_sa_enable_share(share,
- proto_table[*curr_proto].p_name);
- if (err != SA_OK) {
- (void) zfs_error_fmt(hdl,
- proto_table[*curr_proto].p_share_err,
- dgettext(TEXT_DOMAIN, "cannot share '%s'"),
- zfs_get_name(zhp));
- return (-1);
- }
- } else
-#else
- if (*curr_proto != PROTO_NFS) {
- fprintf(stderr, "Unsupported share protocol: %d.\n",
- *curr_proto);
- continue;
- }
-
- if (strcmp(shareopts, "on") == 0)
- error = fsshare(ZFS_EXPORTS_PATH, mountpoint, "");
- else
- error = fsshare(ZFS_EXPORTS_PATH, mountpoint, shareopts);
- if (error != 0)
-#endif
- {
- (void) zfs_error_fmt(hdl,
- proto_table[*curr_proto].p_share_err,
- dgettext(TEXT_DOMAIN, "cannot share '%s'"),
- zfs_get_name(zhp));
- return (-1);
- }
-
- }
- return (0);
-}
-
-
-int
-zfs_share_nfs(zfs_handle_t *zhp)
-{
- return (zfs_share_proto(zhp, nfs_only));
-}
-
-int
-zfs_share_smb(zfs_handle_t *zhp)
-{
- return (zfs_share_proto(zhp, smb_only));
-}
-
-int
-zfs_shareall(zfs_handle_t *zhp)
-{
- return (zfs_share_proto(zhp, share_all_proto));
-}
-
-/*
- * Unshare a filesystem by mountpoint.
- */
-static int
-unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
- zfs_share_proto_t proto)
-{
-#ifdef illumos
- sa_share_t share;
- int err;
- char *mntpt;
-
- /*
- * Mountpoint could get trashed if libshare calls getmntany
- * which it does during API initialization, so strdup the
- * value.
- */
- mntpt = zfs_strdup(hdl, mountpoint);
-
- /*
- * make sure libshare initialized, initialize everything because we
- * don't know what other unsharing may happen later. Functions up the
- * stack are allowed to initialize instead a subset of shares at the
- * time the set is known.
- */
- if ((err = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_NAME,
- (void *)name)) != SA_OK) {
- free(mntpt); /* don't need the copy anymore */
- return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
- dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
- name, _sa_errorstr(err)));
- }
-
- share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
- free(mntpt); /* don't need the copy anymore */
-
- if (share != NULL) {
- err = zfs_sa_disable_share(share, proto_table[proto].p_name);
- if (err != SA_OK) {
- return (zfs_error_fmt(hdl,
- proto_table[proto].p_unshare_err,
- dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
- name, _sa_errorstr(err)));
- }
- } else {
- return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
- dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"),
- name));
- }
-#else
- char buf[MAXPATHLEN];
- FILE *fp;
- int err;
-
- if (proto != PROTO_NFS) {
- fprintf(stderr, "No SMB support in FreeBSD yet.\n");
- return (EOPNOTSUPP);
- }
-
- err = fsunshare(ZFS_EXPORTS_PATH, mountpoint);
- if (err != 0) {
- zfs_error_aux(hdl, "%s", strerror(err));
- return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
- dgettext(TEXT_DOMAIN,
- "cannot unshare '%s'"), name));
- }
-#endif
- return (0);
-}
-
-/*
- * Unshare the given filesystem.
- */
-int
-zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
- zfs_share_proto_t *proto)
-{
- libzfs_handle_t *hdl = zhp->zfs_hdl;
- struct mnttab entry;
- char *mntpt = NULL;
-
- /* check to see if need to unmount the filesystem */
- rewind(zhp->zfs_hdl->libzfs_mnttab);
- if (mountpoint != NULL)
- mountpoint = mntpt = zfs_strdup(hdl, mountpoint);
-
- if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
- libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) {
- zfs_share_proto_t *curr_proto;
-
- if (mountpoint == NULL)
- mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
-
- for (curr_proto = proto; *curr_proto != PROTO_END;
- curr_proto++) {
-
- if (is_shared(hdl, mntpt, *curr_proto) &&
- unshare_one(hdl, zhp->zfs_name,
- mntpt, *curr_proto) != 0) {
- if (mntpt != NULL)
- free(mntpt);
- return (-1);
- }
- }
- }
- if (mntpt != NULL)
- free(mntpt);
-
- return (0);
-}
-
-int
-zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
-{
- return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
-}
-
-int
-zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
-{
- return (zfs_unshare_proto(zhp, mountpoint, smb_only));
-}
-
-/*
- * Same as zfs_unmountall(), but for NFS and SMB unshares.
- */
-int
-zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
-{
- prop_changelist_t *clp;
- int ret;
-
- clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0);
- if (clp == NULL)
- return (-1);
-
- ret = changelist_unshare(clp, proto);
- changelist_free(clp);
-
- return (ret);
-}
-
-int
-zfs_unshareall_nfs(zfs_handle_t *zhp)
-{
- return (zfs_unshareall_proto(zhp, nfs_only));
-}
-
-int
-zfs_unshareall_smb(zfs_handle_t *zhp)
-{
- return (zfs_unshareall_proto(zhp, smb_only));
-}
-
-int
-zfs_unshareall(zfs_handle_t *zhp)
-{
- return (zfs_unshareall_proto(zhp, share_all_proto));
-}
-
-int
-zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
-{
- return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
-}
-
-/*
- * Remove the mountpoint associated with the current dataset, if necessary.
- * We only remove the underlying directory if:
- *
- * - The mountpoint is not 'none' or 'legacy'
- * - The mountpoint is non-empty
- * - The mountpoint is the default or inherited
- * - The 'zoned' property is set, or we're in a local zone
- *
- * Any other directories we leave alone.
- */
-void
-remove_mountpoint(zfs_handle_t *zhp)
-{
- char mountpoint[ZFS_MAXPROPLEN];
- zprop_source_t source;
-
- if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
- &source))
- return;
-
- if (source == ZPROP_SRC_DEFAULT ||
- source == ZPROP_SRC_INHERITED) {
- /*
- * Try to remove the directory, silently ignoring any errors.
- * The filesystem may have since been removed or moved around,
- * and this error isn't really useful to the administrator in
- * any way.
- */
- (void) rmdir(mountpoint);
- }
-}
-
-/*
- * Add the given zfs handle to the cb_handles array, dynamically reallocating
- * the array if it is out of space
- */
-void
-libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
-{
- if (cbp->cb_alloc == cbp->cb_used) {
- size_t newsz;
- zfs_handle_t **newhandles;
-
- newsz = cbp->cb_alloc != 0 ? cbp->cb_alloc * 2 : 64;
- newhandles = zfs_realloc(zhp->zfs_hdl,
- cbp->cb_handles, cbp->cb_alloc * sizeof (zfs_handle_t *),
- newsz * sizeof (zfs_handle_t *));
- cbp->cb_handles = newhandles;
- cbp->cb_alloc = newsz;
- }
- cbp->cb_handles[cbp->cb_used++] = zhp;
-}
-
-/*
- * Recursive helper function used during file system enumeration
- */
-static int
-zfs_iter_cb(zfs_handle_t *zhp, void *data)
-{
- get_all_cb_t *cbp = data;
-
- if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
- zfs_close(zhp);
- return (0);
- }
-
- if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
- zfs_close(zhp);
- return (0);
- }
-
- /*
- * If this filesystem is inconsistent and has a receive resume
- * token, we can not mount it.
- */
- if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
- zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
- NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
- zfs_close(zhp);
- return (0);
- }
-
- libzfs_add_handle(cbp, zhp);
- if (zfs_iter_filesystems(zhp, zfs_iter_cb, cbp) != 0) {
- zfs_close(zhp);
- return (-1);
- }
- return (0);
-}
-
-/*
- * Sort comparator that compares two mountpoint paths. We sort these paths so
- * that subdirectories immediately follow their parents. This means that we
- * effectively treat the '/' character as the lowest value non-nul char.
- * Since filesystems from non-global zones can have the same mountpoint
- * as other filesystems, the comparator sorts global zone filesystems to
- * the top of the list. This means that the global zone will traverse the
- * filesystem list in the correct order and can stop when it sees the
- * first zoned filesystem. In a non-global zone, only the delegated
- * filesystems are seen.
- *
- * An example sorted list using this comparator would look like:
- *
- * /foo
- * /foo/bar
- * /foo/bar/baz
- * /foo/baz
- * /foo.bar
- * /foo (NGZ1)
- * /foo (NGZ2)
- *
- * The mount code depend on this ordering to deterministically iterate
- * over filesystems in order to spawn parallel mount tasks.
- */
-static int
-mountpoint_cmp(const void *arga, const void *argb)
-{
- zfs_handle_t *const *zap = arga;
- zfs_handle_t *za = *zap;
- zfs_handle_t *const *zbp = argb;
- zfs_handle_t *zb = *zbp;
- char mounta[MAXPATHLEN];
- char mountb[MAXPATHLEN];
- const char *a = mounta;
- const char *b = mountb;
- boolean_t gota, gotb;
- uint64_t zoneda, zonedb;
-
- zoneda = zfs_prop_get_int(za, ZFS_PROP_ZONED);
- zonedb = zfs_prop_get_int(zb, ZFS_PROP_ZONED);
- if (zoneda && !zonedb)
- return (1);
- if (!zoneda && zonedb)
- return (-1);
- gota = (zfs_get_type(za) == ZFS_TYPE_FILESYSTEM);
- if (gota)
- verify(zfs_prop_get(za, ZFS_PROP_MOUNTPOINT, mounta,
- sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
- gotb = (zfs_get_type(zb) == ZFS_TYPE_FILESYSTEM);
- if (gotb)
- verify(zfs_prop_get(zb, ZFS_PROP_MOUNTPOINT, mountb,
- sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
-
- if (gota && gotb) {
- while (*a != '\0' && (*a == *b)) {
- a++;
- b++;
- }
- if (*a == *b)
- return (0);
- if (*a == '\0')
- return (-1);
- if (*b == '\0')
- return (1);
- if (*a == '/')
- return (-1);
- if (*b == '/')
- return (1);
- return (*a < *b ? -1 : *a > *b);
- }
-
- if (gota)
- return (-1);
- if (gotb)
- return (1);
-
- /*
- * If neither filesystem has a mountpoint, revert to sorting by
- * datset name.
- */
- return (strcmp(zfs_get_name(za), zfs_get_name(zb)));
-}
-
-/*
- * Return true if path2 is a child of path1 or path2 equals path1 or
- * path1 is "/" (path2 is always a child of "/").
- */
-static boolean_t
-libzfs_path_contains(const char *path1, const char *path2)
-{
- return (strcmp(path1, path2) == 0 || strcmp(path1, "/") == 0 ||
- (strstr(path2, path1) == path2 && path2[strlen(path1)] == '/'));
-}
-
-
-static int
-non_descendant_idx(zfs_handle_t **handles, size_t num_handles, int idx)
-{
- char parent[ZFS_MAXPROPLEN];
- char child[ZFS_MAXPROPLEN];
- int i;
-
- verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, parent,
- sizeof (parent), NULL, NULL, 0, B_FALSE) == 0);
-
- for (i = idx + 1; i < num_handles; i++) {
- verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT, child,
- sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
- if (!libzfs_path_contains(parent, child))
- break;
- }
- return (i);
-}
-
-typedef struct mnt_param {
- libzfs_handle_t *mnt_hdl;
- tpool_t *mnt_tp;
- zfs_handle_t **mnt_zhps; /* filesystems to mount */
- size_t mnt_num_handles;
- int mnt_idx; /* Index of selected entry to mount */
- zfs_iter_f mnt_func;
- void *mnt_data;
-} mnt_param_t;
-
-/*
- * Allocate and populate the parameter struct for mount function, and
- * schedule mounting of the entry selected by idx.
- */
-static void
-zfs_dispatch_mount(libzfs_handle_t *hdl, zfs_handle_t **handles,
- size_t num_handles, int idx, zfs_iter_f func, void *data, tpool_t *tp)
-{
- mnt_param_t *mnt_param = zfs_alloc(hdl, sizeof (mnt_param_t));
-
- mnt_param->mnt_hdl = hdl;
- mnt_param->mnt_tp = tp;
- mnt_param->mnt_zhps = handles;
- mnt_param->mnt_num_handles = num_handles;
- mnt_param->mnt_idx = idx;
- mnt_param->mnt_func = func;
- mnt_param->mnt_data = data;
-
- (void) tpool_dispatch(tp, zfs_mount_task, (void*)mnt_param);
-}
-
-/*
- * This is the structure used to keep state of mounting or sharing operations
- * during a call to zpool_enable_datasets().
- */
-typedef struct mount_state {
- /*
- * ms_mntstatus is set to -1 if any mount fails. While multiple threads
- * could update this variable concurrently, no synchronization is
- * needed as it's only ever set to -1.
- */
- int ms_mntstatus;
- int ms_mntflags;
- const char *ms_mntopts;
-} mount_state_t;
-
-static int
-zfs_mount_one(zfs_handle_t *zhp, void *arg)
-{
- mount_state_t *ms = arg;
- int ret = 0;
-
- if (zfs_mount(zhp, ms->ms_mntopts, ms->ms_mntflags) != 0)
- ret = ms->ms_mntstatus = -1;
- return (ret);
-}
-
-static int
-zfs_share_one(zfs_handle_t *zhp, void *arg)
-{
- mount_state_t *ms = arg;
- int ret = 0;
-
- if (zfs_share(zhp) != 0)
- ret = ms->ms_mntstatus = -1;
- return (ret);
-}
-
-/*
- * Thread pool function to mount one file system. On completion, it finds and
- * schedules its children to be mounted. This depends on the sorting done in
- * zfs_foreach_mountpoint(). Note that the degenerate case (chain of entries
- * each descending from the previous) will have no parallelism since we always
- * have to wait for the parent to finish mounting before we can schedule
- * its children.
- */
-static void
-zfs_mount_task(void *arg)
-{
- mnt_param_t *mp = arg;
- int idx = mp->mnt_idx;
- zfs_handle_t **handles = mp->mnt_zhps;
- size_t num_handles = mp->mnt_num_handles;
- char mountpoint[ZFS_MAXPROPLEN];
-
- verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, mountpoint,
- sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
-
- if (mp->mnt_func(handles[idx], mp->mnt_data) != 0)
- return;
-
- /*
- * We dispatch tasks to mount filesystems with mountpoints underneath
- * this one. We do this by dispatching the next filesystem with a
- * descendant mountpoint of the one we just mounted, then skip all of
- * its descendants, dispatch the next descendant mountpoint, and so on.
- * The non_descendant_idx() function skips over filesystems that are
- * descendants of the filesystem we just dispatched.
- */
- for (int i = idx + 1; i < num_handles;
- i = non_descendant_idx(handles, num_handles, i)) {
- char child[ZFS_MAXPROPLEN];
- verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT,
- child, sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
-
- if (!libzfs_path_contains(mountpoint, child))
- break; /* not a descendant, return */
- zfs_dispatch_mount(mp->mnt_hdl, handles, num_handles, i,
- mp->mnt_func, mp->mnt_data, mp->mnt_tp);
- }
- free(mp);
-}
-
-/*
- * Issue the func callback for each ZFS handle contained in the handles
- * array. This function is used to mount all datasets, and so this function
- * guarantees that filesystems for parent mountpoints are called before their
- * children. As such, before issuing any callbacks, we first sort the array
- * of handles by mountpoint.
- *
- * Callbacks are issued in one of two ways:
- *
- * 1. Sequentially: If the parallel argument is B_FALSE or the ZFS_SERIAL_MOUNT
- * environment variable is set, then we issue callbacks sequentially.
- *
- * 2. In parallel: If the parallel argument is B_TRUE and the ZFS_SERIAL_MOUNT
- * environment variable is not set, then we use a tpool to dispatch threads
- * to mount filesystems in parallel. This function dispatches tasks to mount
- * the filesystems at the top-level mountpoints, and these tasks in turn
- * are responsible for recursively mounting filesystems in their children
- * mountpoints.
- */
-void
-zfs_foreach_mountpoint(libzfs_handle_t *hdl, zfs_handle_t **handles,
- size_t num_handles, zfs_iter_f func, void *data, boolean_t parallel)
-{
- zoneid_t zoneid = getzoneid();
-
- /*
- * The ZFS_SERIAL_MOUNT environment variable is an undocumented
- * variable that can be used as a convenience to do a/b comparison
- * of serial vs. parallel mounting.
- */
- boolean_t serial_mount = !parallel ||
- (getenv("ZFS_SERIAL_MOUNT") != NULL);
-
- /*
- * Sort the datasets by mountpoint. See mountpoint_cmp for details
- * of how these are sorted.
- */
- qsort(handles, num_handles, sizeof (zfs_handle_t *), mountpoint_cmp);
-
- if (serial_mount) {
- for (int i = 0; i < num_handles; i++) {
- func(handles[i], data);
- }
- return;
- }
-
- /*
- * Issue the callback function for each dataset using a parallel
- * algorithm that uses a thread pool to manage threads.
- */
- tpool_t *tp = tpool_create(1, mount_tp_nthr, 0, NULL);
-
- /*
- * There may be multiple "top level" mountpoints outside of the pool's
- * root mountpoint, e.g.: /foo /bar. Dispatch a mount task for each of
- * these.
- */
- for (int i = 0; i < num_handles;
- i = non_descendant_idx(handles, num_handles, i)) {
- /*
- * Since the mountpoints have been sorted so that the zoned
- * filesystems are at the end, a zoned filesystem seen from
- * the global zone means that we're done.
- */
- if (zoneid == GLOBAL_ZONEID &&
- zfs_prop_get_int(handles[i], ZFS_PROP_ZONED))
- break;
- zfs_dispatch_mount(hdl, handles, num_handles, i, func, data,
- tp);
- }
-
- tpool_wait(tp); /* wait for all scheduled mounts to complete */
- tpool_destroy(tp);
-}
-
-/*
- * Mount and share all datasets within the given pool. This assumes that no
- * datasets within the pool are currently mounted.
- */
-#pragma weak zpool_mount_datasets = zpool_enable_datasets
-int
-zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
-{
- get_all_cb_t cb = { 0 };
- mount_state_t ms = { 0 };
- zfs_handle_t *zfsp;
- int ret = 0;
-
- if ((zfsp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
- ZFS_TYPE_DATASET)) == NULL)
- goto out;
-
- /*
- * Gather all non-snapshot datasets within the pool. Start by adding
- * the root filesystem for this pool to the list, and then iterate
- * over all child filesystems.
- */
- libzfs_add_handle(&cb, zfsp);
- if (zfs_iter_filesystems(zfsp, zfs_iter_cb, &cb) != 0)
- goto out;
-
- /*
- * Mount all filesystems
- */
- ms.ms_mntopts = mntopts;
- ms.ms_mntflags = flags;
- zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
- zfs_mount_one, &ms, B_TRUE);
- if (ms.ms_mntstatus != 0)
- ret = ms.ms_mntstatus;
-
- /*
- * Share all filesystems that need to be shared. This needs to be
- * a separate pass because libshare is not mt-safe, and so we need
- * to share serially.
- */
- ms.ms_mntstatus = 0;
- zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
- zfs_share_one, &ms, B_FALSE);
- if (ms.ms_mntstatus != 0)
- ret = ms.ms_mntstatus;
-
-out:
- for (int i = 0; i < cb.cb_used; i++)
- zfs_close(cb.cb_handles[i]);
- free(cb.cb_handles);
-
- return (ret);
-}
-
-static int
-mountpoint_compare(const void *a, const void *b)
-{
- const char *mounta = *((char **)a);
- const char *mountb = *((char **)b);
-
- return (strcmp(mountb, mounta));
-}
-
-/* alias for 2002/240 */
-#pragma weak zpool_unmount_datasets = zpool_disable_datasets
-/*
- * Unshare and unmount all datasets within the given pool. We don't want to
- * rely on traversing the DSL to discover the filesystems within the pool,
- * because this may be expensive (if not all of them are mounted), and can fail
- * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and
- * gather all the filesystems that are currently mounted.
- */
-int
-zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
-{
- int used, alloc;
- struct mnttab entry;
- size_t namelen;
- char **mountpoints = NULL;
- zfs_handle_t **datasets = NULL;
- libzfs_handle_t *hdl = zhp->zpool_hdl;
- int i;
- int ret = -1;
- int flags = (force ? MS_FORCE : 0);
-#ifdef illumos
- sa_init_selective_arg_t sharearg;
-#endif
-
- namelen = strlen(zhp->zpool_name);
-
- rewind(hdl->libzfs_mnttab);
- used = alloc = 0;
- while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
- /*
- * Ignore non-ZFS entries.
- */
- if (entry.mnt_fstype == NULL ||
- strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
- continue;
-
- /*
- * Ignore filesystems not within this pool.
- */
- if (entry.mnt_mountp == NULL ||
- strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 ||
- (entry.mnt_special[namelen] != '/' &&
- entry.mnt_special[namelen] != '\0'))
- continue;
-
- /*
- * At this point we've found a filesystem within our pool. Add
- * it to our growing list.
- */
- if (used == alloc) {
- if (alloc == 0) {
- if ((mountpoints = zfs_alloc(hdl,
- 8 * sizeof (void *))) == NULL)
- goto out;
-
- if ((datasets = zfs_alloc(hdl,
- 8 * sizeof (void *))) == NULL)
- goto out;
-
- alloc = 8;
- } else {
- void *ptr;
-
- if ((ptr = zfs_realloc(hdl, mountpoints,
- alloc * sizeof (void *),
- alloc * 2 * sizeof (void *))) == NULL)
- goto out;
- mountpoints = ptr;
-
- if ((ptr = zfs_realloc(hdl, datasets,
- alloc * sizeof (void *),
- alloc * 2 * sizeof (void *))) == NULL)
- goto out;
- datasets = ptr;
-
- alloc *= 2;
- }
- }
-
- if ((mountpoints[used] = zfs_strdup(hdl,
- entry.mnt_mountp)) == NULL)
- goto out;
-
- /*
- * This is allowed to fail, in case there is some I/O error. It
- * is only used to determine if we need to remove the underlying
- * mountpoint, so failure is not fatal.
- */
- datasets[used] = make_dataset_handle(hdl, entry.mnt_special);
-
- used++;
- }
-
- /*
- * At this point, we have the entire list of filesystems, so sort it by
- * mountpoint.
- */
-#ifdef illumos
- sharearg.zhandle_arr = datasets;
- sharearg.zhandle_len = used;
- ret = zfs_init_libshare_arg(hdl, SA_INIT_SHARE_API_SELECTIVE,
- &sharearg);
- if (ret != 0)
- goto out;
-#endif
- qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
-
- /*
- * Walk through and first unshare everything.
- */
- for (i = 0; i < used; i++) {
- zfs_share_proto_t *curr_proto;
- for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
- curr_proto++) {
- if (is_shared(hdl, mountpoints[i], *curr_proto) &&
- unshare_one(hdl, mountpoints[i],
- mountpoints[i], *curr_proto) != 0)
- goto out;
- }
- }
-
- /*
- * Now unmount everything, removing the underlying directories as
- * appropriate.
- */
- for (i = 0; i < used; i++) {
- if (unmount_one(hdl, mountpoints[i], flags) != 0)
- goto out;
- }
-
- for (i = 0; i < used; i++) {
- if (datasets[i])
- remove_mountpoint(datasets[i]);
- }
-
- ret = 0;
-out:
- for (i = 0; i < used; i++) {
- if (datasets[i])
- zfs_close(datasets[i]);
- free(mountpoints[i]);
- }
- free(datasets);
- free(mountpoints);
-
- return (ret);
-}
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
deleted file mode 100644
index 434f77e27da9..000000000000
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
+++ /dev/null
@@ -1,4669 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
- * Copyright 2016 Nexenta Systems, Inc.
- * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
- * Copyright (c) 2017 Datto Inc.
- * Copyright (c) 2017, Intel Corporation.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <errno.h>
-#include <devid.h>
-#include <fcntl.h>
-#include <libintl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <unistd.h>
-#include <libgen.h>
-#include <sys/zfs_ioctl.h>
-#include <dlfcn.h>
-
-#include "zfs_namecheck.h"
-#include "zfs_prop.h"
-#include "libzfs_impl.h"
-#include "zfs_comutil.h"
-#include "zfeature_common.h"
-
-static int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *);
-static boolean_t zpool_vdev_is_interior(const char *name);
-
-#define BACKUP_SLICE "s2"
-
-typedef struct prop_flags {
- int create:1; /* Validate property on creation */
- int import:1; /* Validate property on import */
-} prop_flags_t;
-
-/*
- * ====================================================================
- * zpool property functions
- * ====================================================================
- */
-
-static int
-zpool_get_all_props(zpool_handle_t *zhp)
-{
- zfs_cmd_t zc = { 0 };
- libzfs_handle_t *hdl = zhp->zpool_hdl;
-
- (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
-
- if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
- return (-1);
-
- while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
- if (errno == ENOMEM) {
- if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
- } else {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
- }
-
- if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
- zcmd_free_nvlists(&zc);
- return (-1);
- }
-
- zcmd_free_nvlists(&zc);
-
- return (0);
-}
-
-static int
-zpool_props_refresh(zpool_handle_t *zhp)
-{
- nvlist_t *old_props;
-
- old_props = zhp->zpool_props;
-
- if (zpool_get_all_props(zhp) != 0)
- return (-1);
-
- nvlist_free(old_props);
- return (0);
-}
-
-static char *
-zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
- zprop_source_t *src)
-{
- nvlist_t *nv, *nvl;
- uint64_t ival;
- char *value;
- zprop_source_t source;
-
- nvl = zhp->zpool_props;
- if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
- verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
- source = ival;
- verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
- } else {
- source = ZPROP_SRC_DEFAULT;
- if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
- value = "-";
- }
-
- if (src)
- *src = source;
-
- return (value);
-}
-
-uint64_t
-zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
-{
- nvlist_t *nv, *nvl;
- uint64_t value;
- zprop_source_t source;
-
- if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
- /*
- * zpool_get_all_props() has most likely failed because
- * the pool is faulted, but if all we need is the top level
- * vdev's guid then get it from the zhp config nvlist.
- */
- if ((prop == ZPOOL_PROP_GUID) &&
- (nvlist_lookup_nvlist(zhp->zpool_config,
- ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
- (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
- == 0)) {
- return (value);
- }
- return (zpool_prop_default_numeric(prop));
- }
-
- nvl = zhp->zpool_props;
- if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
- verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
- source = value;
- verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
- } else {
- source = ZPROP_SRC_DEFAULT;
- value = zpool_prop_default_numeric(prop);
- }
-
- if (src)
- *src = source;
-
- return (value);
-}
-
-/*
- * Map VDEV STATE to printed strings.
- */
-const char *
-zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
-{
- switch (state) {
- case VDEV_STATE_CLOSED:
- case VDEV_STATE_OFFLINE:
- return (gettext("OFFLINE"));
- case VDEV_STATE_REMOVED:
- return (gettext("REMOVED"));
- case VDEV_STATE_CANT_OPEN:
- if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
- return (gettext("FAULTED"));
- else if (aux == VDEV_AUX_SPLIT_POOL)
- return (gettext("SPLIT"));
- else
- return (gettext("UNAVAIL"));
- case VDEV_STATE_FAULTED:
- return (gettext("FAULTED"));
- case VDEV_STATE_DEGRADED:
- return (gettext("DEGRADED"));
- case VDEV_STATE_HEALTHY:
- return (gettext("ONLINE"));
-
- default:
- break;
- }
-
- return (gettext("UNKNOWN"));
-}
-
-/*
- * Map POOL STATE to printed strings.
- */
-const char *
-zpool_pool_state_to_name(pool_state_t state)
-{
- switch (state) {
- case POOL_STATE_ACTIVE:
- return (gettext("ACTIVE"));
- case POOL_STATE_EXPORTED:
- return (gettext("EXPORTED"));
- case POOL_STATE_DESTROYED:
- return (gettext("DESTROYED"));
- case POOL_STATE_SPARE:
- return (gettext("SPARE"));
- case POOL_STATE_L2CACHE:
- return (gettext("L2CACHE"));
- case POOL_STATE_UNINITIALIZED:
- return (gettext("UNINITIALIZED"));
- case POOL_STATE_UNAVAIL:
- return (gettext("UNAVAIL"));
- case POOL_STATE_POTENTIALLY_ACTIVE:
- return (gettext("POTENTIALLY_ACTIVE"));
- }
-
- return (gettext("UNKNOWN"));
-}
-
-/*
- * Get a zpool property value for 'prop' and return the value in
- * a pre-allocated buffer.
- */
-int
-zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
- zprop_source_t *srctype, boolean_t literal)
-{
- uint64_t intval;
- const char *strval;
- zprop_source_t src = ZPROP_SRC_NONE;
- nvlist_t *nvroot;
- vdev_stat_t *vs;
- uint_t vsc;
-
- if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
- switch (prop) {
- case ZPOOL_PROP_NAME:
- (void) strlcpy(buf, zpool_get_name(zhp), len);
- break;
-
- case ZPOOL_PROP_HEALTH:
- (void) strlcpy(buf,
- zpool_pool_state_to_name(POOL_STATE_UNAVAIL), len);
- break;
-
- case ZPOOL_PROP_GUID:
- intval = zpool_get_prop_int(zhp, prop, &src);
- (void) snprintf(buf, len, "%llu", intval);
- break;
-
- case ZPOOL_PROP_ALTROOT:
- case ZPOOL_PROP_CACHEFILE:
- case ZPOOL_PROP_COMMENT:
- if (zhp->zpool_props != NULL ||
- zpool_get_all_props(zhp) == 0) {
- (void) strlcpy(buf,
- zpool_get_prop_string(zhp, prop, &src),
- len);
- break;
- }
- /* FALLTHROUGH */
- default:
- (void) strlcpy(buf, "-", len);
- break;
- }
-
- if (srctype != NULL)
- *srctype = src;
- return (0);
- }
-
- if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
- prop != ZPOOL_PROP_NAME)
- return (-1);
-
- switch (zpool_prop_get_type(prop)) {
- case PROP_TYPE_STRING:
- (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
- len);
- break;
-
- case PROP_TYPE_NUMBER:
- intval = zpool_get_prop_int(zhp, prop, &src);
-
- switch (prop) {
- case ZPOOL_PROP_SIZE:
- case ZPOOL_PROP_ALLOCATED:
- case ZPOOL_PROP_FREE:
- case ZPOOL_PROP_FREEING:
- case ZPOOL_PROP_LEAKED:
- if (literal) {
- (void) snprintf(buf, len, "%llu",
- (u_longlong_t)intval);
- } else {
- (void) zfs_nicenum(intval, buf, len);
- }
- break;
- case ZPOOL_PROP_BOOTSIZE:
- case ZPOOL_PROP_EXPANDSZ:
- case ZPOOL_PROP_CHECKPOINT:
- if (intval == 0) {
- (void) strlcpy(buf, "-", len);
- } else if (literal) {
- (void) snprintf(buf, len, "%llu",
- (u_longlong_t)intval);
- } else {
- (void) zfs_nicenum(intval, buf, len);
- }
- break;
- case ZPOOL_PROP_CAPACITY:
- if (literal) {
- (void) snprintf(buf, len, "%llu",
- (u_longlong_t)intval);
- } else {
- (void) snprintf(buf, len, "%llu%%",
- (u_longlong_t)intval);
- }
- break;
- case ZPOOL_PROP_FRAGMENTATION:
- if (intval == UINT64_MAX) {
- (void) strlcpy(buf, "-", len);
- } else {
- (void) snprintf(buf, len, "%llu%%",
- (u_longlong_t)intval);
- }
- break;
- case ZPOOL_PROP_DEDUPRATIO:
- (void) snprintf(buf, len, "%llu.%02llux",
- (u_longlong_t)(intval / 100),
- (u_longlong_t)(intval % 100));
- break;
- case ZPOOL_PROP_HEALTH:
- verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
- ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
- verify(nvlist_lookup_uint64_array(nvroot,
- ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
- == 0);
-
- (void) strlcpy(buf, zpool_state_to_name(intval,
- vs->vs_aux), len);
- break;
- case ZPOOL_PROP_VERSION:
- if (intval >= SPA_VERSION_FEATURES) {
- (void) snprintf(buf, len, "-");
- break;
- }
- /* FALLTHROUGH */
- default:
- (void) snprintf(buf, len, "%llu", intval);
- }
- break;
-
- case PROP_TYPE_INDEX:
- intval = zpool_get_prop_int(zhp, prop, &src);
- if (zpool_prop_index_to_string(prop, intval, &strval)
- != 0)
- return (-1);
- (void) strlcpy(buf, strval, len);
- break;
-
- default:
- abort();
- }
-
- if (srctype)
- *srctype = src;
-
- return (0);
-}
-
-/*
- * Check if the bootfs name has the same pool name as it is set to.
- * Assuming bootfs is a valid dataset name.
- */
-static boolean_t
-bootfs_name_valid(const char *pool, const char *bootfs)
-{
- int len = strlen(pool);
-
- if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
- return (B_FALSE);
-
- if (strncmp(pool, bootfs, len) == 0 &&
- (bootfs[len] == '/' || bootfs[len] == '\0'))
- return (B_TRUE);
-
- return (B_FALSE);
-}
-
-boolean_t
-zpool_is_bootable(zpool_handle_t *zhp)
-{
- char bootfs[ZFS_MAX_DATASET_NAME_LEN];
-
- return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
- sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
- sizeof (bootfs)) != 0);
-}
-
-
-/*
- * Given an nvlist of zpool properties to be set, validate that they are
- * correct, and parse any numeric properties (index, boolean, etc) if they are
- * specified as strings.
- */
-static nvlist_t *
-zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
- nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
-{
- nvpair_t *elem;
- nvlist_t *retprops;
- zpool_prop_t prop;
- char *strval;
- uint64_t intval;
- char *slash, *check;
- struct stat64 statbuf;
- zpool_handle_t *zhp;
-
- if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
- (void) no_memory(hdl);
- return (NULL);
- }
-
- elem = NULL;
- while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
- const char *propname = nvpair_name(elem);
-
- prop = zpool_name_to_prop(propname);
- if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
- int err;
- char *fname = strchr(propname, '@') + 1;
-
- err = zfeature_lookup_name(fname, NULL);
- if (err != 0) {
- ASSERT3U(err, ==, ENOENT);
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid feature '%s'"), fname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (nvpair_type(elem) != DATA_TYPE_STRING) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' must be a string"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- (void) nvpair_value_string(elem, &strval);
- if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' can only be set to "
- "'enabled'"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (nvlist_add_uint64(retprops, propname, 0) != 0) {
- (void) no_memory(hdl);
- goto error;
- }
- continue;
- }
-
- /*
- * Make sure this property is valid and applies to this type.
- */
- if (prop == ZPOOL_PROP_INVAL) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid property '%s'"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (zpool_prop_readonly(prop)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
- "is readonly"), propname);
- (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
- goto error;
- }
-
- if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
- &strval, &intval, errbuf) != 0)
- goto error;
-
- /*
- * Perform additional checking for specific properties.
- */
- switch (prop) {
- case ZPOOL_PROP_VERSION:
- if (intval < version ||
- !SPA_VERSION_IS_SUPPORTED(intval)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' number %d is invalid."),
- propname, intval);
- (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
- goto error;
- }
- break;
-
- case ZPOOL_PROP_BOOTSIZE:
- if (!flags.create) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' can only be set during pool "
- "creation"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
-
- case ZPOOL_PROP_BOOTFS:
- if (flags.create || flags.import) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' cannot be set at creation "
- "or import time"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (version < SPA_VERSION_BOOTFS) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded to support "
- "'%s' property"), propname);
- (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
- goto error;
- }
-
- /*
- * bootfs property value has to be a dataset name and
- * the dataset has to be in the same pool as it sets to.
- */
- if (strval[0] != '\0' && !bootfs_name_valid(poolname,
- strval)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
- "is an invalid name"), strval);
- (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
- goto error;
- }
-
- if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "could not open pool '%s'"), poolname);
- (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
- goto error;
- }
- zpool_close(zhp);
- break;
-
- case ZPOOL_PROP_ALTROOT:
- if (!flags.create && !flags.import) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' can only be set during pool "
- "creation or import"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (strval[0] != '/') {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "bad alternate root '%s'"), strval);
- (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
- goto error;
- }
- break;
-
- case ZPOOL_PROP_CACHEFILE:
- if (strval[0] == '\0')
- break;
-
- if (strcmp(strval, "none") == 0)
- break;
-
- if (strval[0] != '/') {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' must be empty, an "
- "absolute path, or 'none'"), propname);
- (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
- goto error;
- }
-
- slash = strrchr(strval, '/');
-
- if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
- strcmp(slash, "/..") == 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' is not a valid file"), strval);
- (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
- goto error;
- }
-
- *slash = '\0';
-
- if (strval[0] != '\0' &&
- (stat64(strval, &statbuf) != 0 ||
- !S_ISDIR(statbuf.st_mode))) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "'%s' is not a valid directory"),
- strval);
- (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
- goto error;
- }
-
- *slash = '/';
- break;
-
- case ZPOOL_PROP_COMMENT:
- for (check = strval; *check != '\0'; check++) {
- if (!isprint(*check)) {
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN,
- "comment may only have printable "
- "characters"));
- (void) zfs_error(hdl, EZFS_BADPROP,
- errbuf);
- goto error;
- }
- }
- if (strlen(strval) > ZPROP_MAX_COMMENT) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "comment must not exceed %d characters"),
- ZPROP_MAX_COMMENT);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
-
- case ZPOOL_PROP_READONLY:
- if (!flags.import) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' can only be set at "
- "import time"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
-
- case ZPOOL_PROP_TNAME:
- if (!flags.create) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' can only be set at "
- "creation time"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
-
- case ZPOOL_PROP_MULTIHOST:
- if (get_system_hostid() == 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "requires a non-zero system hostid"));
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
- break;
-
- default:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s'(%d) not defined"), propname, prop);
- break;
- }
- }
-
- return (retprops);
-error:
- nvlist_free(retprops);
- return (NULL);
-}
-
-/*
- * Set zpool property : propname=propval.
- */
-int
-zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
-{
- zfs_cmd_t zc = { 0 };
- int ret = -1;
- char errbuf[1024];
- nvlist_t *nvl = NULL;
- nvlist_t *realprops;
- uint64_t version;
- prop_flags_t flags = { 0 };
-
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
- zhp->zpool_name);
-
- if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
- return (no_memory(zhp->zpool_hdl));
-
- if (nvlist_add_string(nvl, propname, propval) != 0) {
- nvlist_free(nvl);
- return (no_memory(zhp->zpool_hdl));
- }
-
- version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
- if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
- zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) {
- nvlist_free(nvl);
- return (-1);
- }
-
- nvlist_free(nvl);
- nvl = realprops;
-
- /*
- * Execute the corresponding ioctl() to set this property.
- */
- (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
-
- if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
- nvlist_free(nvl);
- return (-1);
- }
-
- ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
-
- zcmd_free_nvlists(&zc);
- nvlist_free(nvl);
-
- if (ret)
- (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
- else
- (void) zpool_props_refresh(zhp);
-
- return (ret);
-}
-
-int
-zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
-{
- libzfs_handle_t *hdl = zhp->zpool_hdl;
- zprop_list_t *entry;
- char buf[ZFS_MAXPROPLEN];
- nvlist_t *features = NULL;
- zprop_list_t **last;
- boolean_t firstexpand = (NULL == *plp);
-
- if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
- return (-1);
-
- last = plp;
- while (*last != NULL)
- last = &(*last)->pl_next;
-
- if ((*plp)->pl_all)
- features = zpool_get_features(zhp);
-
- if ((*plp)->pl_all && firstexpand) {
- for (int i = 0; i < SPA_FEATURES; i++) {
- zprop_list_t *entry = zfs_alloc(hdl,
- sizeof (zprop_list_t));
- entry->pl_prop = ZPROP_INVAL;
- entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s",
- spa_feature_table[i].fi_uname);
- entry->pl_width = strlen(entry->pl_user_prop);
- entry->pl_all = B_TRUE;
-
- *last = entry;
- last = &entry->pl_next;
- }
- }
-
- /* add any unsupported features */
- for (nvpair_t *nvp = nvlist_next_nvpair(features, NULL);
- nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) {
- char *propname;
- boolean_t found;
- zprop_list_t *entry;
-
- if (zfeature_is_supported(nvpair_name(nvp)))
- continue;
-
- propname = zfs_asprintf(hdl, "unsupported@%s",
- nvpair_name(nvp));
-
- /*
- * Before adding the property to the list make sure that no
- * other pool already added the same property.
- */
- found = B_FALSE;
- entry = *plp;
- while (entry != NULL) {
- if (entry->pl_user_prop != NULL &&
- strcmp(propname, entry->pl_user_prop) == 0) {
- found = B_TRUE;
- break;
- }
- entry = entry->pl_next;
- }
- if (found) {
- free(propname);
- continue;
- }
-
- entry = zfs_alloc(hdl, sizeof (zprop_list_t));
- entry->pl_prop = ZPROP_INVAL;
- entry->pl_user_prop = propname;
- entry->pl_width = strlen(entry->pl_user_prop);
- entry->pl_all = B_TRUE;
-
- *last = entry;
- last = &entry->pl_next;
- }
-
- for (entry = *plp; entry != NULL; entry = entry->pl_next) {
-
- if (entry->pl_fixed)
- continue;
-
- if (entry->pl_prop != ZPROP_INVAL &&
- zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
- NULL, B_FALSE) == 0) {
- if (strlen(buf) > entry->pl_width)
- entry->pl_width = strlen(buf);
- }
- }
-
- return (0);
-}
-
-/*
- * Get the state for the given feature on the given ZFS pool.
- */
-int
-zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
- size_t len)
-{
- uint64_t refcount;
- boolean_t found = B_FALSE;
- nvlist_t *features = zpool_get_features(zhp);
- boolean_t supported;
- const char *feature = strchr(propname, '@') + 1;
-
- supported = zpool_prop_feature(propname);
- ASSERT(supported || zpool_prop_unsupported(propname));
-
- /*
- * Convert from feature name to feature guid. This conversion is
- * unecessary for unsupported@... properties because they already
- * use guids.
- */
- if (supported) {
- int ret;
- spa_feature_t fid;
-
- ret = zfeature_lookup_name(feature, &fid);
- if (ret != 0) {
- (void) strlcpy(buf, "-", len);
- return (ENOTSUP);
- }
- feature = spa_feature_table[fid].fi_guid;
- }
-
- if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
- found = B_TRUE;
-
- if (supported) {
- if (!found) {
- (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len);
- } else {
- if (refcount == 0)
- (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len);
- else
- (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len);
- }
- } else {
- if (found) {
- if (refcount == 0) {
- (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE);
- } else {
- (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY);
- }
- } else {
- (void) strlcpy(buf, "-", len);
- return (ENOTSUP);
- }
- }
-
- return (0);
-}
-
-/*
- * Don't start the slice at the default block of 34; many storage
- * devices will use a stripe width of 128k, so start there instead.
- */
-#define NEW_START_BLOCK 256
-
-/*
- * Validate the given pool name, optionally putting an extended error message in
- * 'buf'.
- */
-boolean_t
-zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
-{
- namecheck_err_t why;
- char what;
- int ret;
-
- ret = pool_namecheck(pool, &why, &what);
-
- /*
- * The rules for reserved pool names were extended at a later point.
- * But we need to support users with existing pools that may now be
- * invalid. So we only check for this expanded set of names during a
- * create (or import), and only in userland.
- */
- if (ret == 0 && !isopen &&
- (strncmp(pool, "mirror", 6) == 0 ||
- strncmp(pool, "raidz", 5) == 0 ||
- strncmp(pool, "spare", 5) == 0 ||
- strcmp(pool, "log") == 0)) {
- if (hdl != NULL)
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "name is reserved"));
- return (B_FALSE);
- }
-
-
- if (ret != 0) {
- if (hdl != NULL) {
- switch (why) {
- case NAME_ERR_TOOLONG:
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "name is too long"));
- break;
-
- case NAME_ERR_INVALCHAR:
- zfs_error_aux(hdl,
- dgettext(TEXT_DOMAIN, "invalid character "
- "'%c' in pool name"), what);
- break;
-
- case NAME_ERR_NOLETTER:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "name must begin with a letter"));
- break;
-
- case NAME_ERR_RESERVED:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "name is reserved"));
- break;
-
- case NAME_ERR_DISKLIKE:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool name is reserved"));
- break;
-
- case NAME_ERR_LEADING_SLASH:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "leading slash in name"));
- break;
-
- case NAME_ERR_EMPTY_COMPONENT:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "empty component in name"));
- break;
-
- case NAME_ERR_TRAILING_SLASH:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "trailing slash in name"));
- break;
-
- case NAME_ERR_MULTIPLE_DELIMITERS:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "multiple '@' and/or '#' delimiters in "
- "name"));
- break;
-
- default:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "(%d) not defined"), why);
- break;
- }
- }
- return (B_FALSE);
- }
-
- return (B_TRUE);
-}
-
-/*
- * Open a handle to the given pool, even if the pool is currently in the FAULTED
- * state.
- */
-zpool_handle_t *
-zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
-{
- zpool_handle_t *zhp;
- boolean_t missing;
-
- /*
- * Make sure the pool name is valid.
- */
- if (!zpool_name_valid(hdl, B_TRUE, pool)) {
- (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
- dgettext(TEXT_DOMAIN, "cannot open '%s'"),
- pool);
- return (NULL);
- }
-
- if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
- return (NULL);
-
- zhp->zpool_hdl = hdl;
- (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
-
- if (zpool_refresh_stats(zhp, &missing) != 0) {
- zpool_close(zhp);
- return (NULL);
- }
-
- if (missing) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
- (void) zfs_error_fmt(hdl, EZFS_NOENT,
- dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool);
- zpool_close(zhp);
- return (NULL);
- }
-
- return (zhp);
-}
-
-/*
- * Like the above, but silent on error. Used when iterating over pools (because
- * the configuration cache may be out of date).
- */
-int
-zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
-{
- zpool_handle_t *zhp;
- boolean_t missing;
-
- if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
- return (-1);
-
- zhp->zpool_hdl = hdl;
- (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
-
- if (zpool_refresh_stats(zhp, &missing) != 0) {
- zpool_close(zhp);
- return (-1);
- }
-
- if (missing) {
- zpool_close(zhp);
- *ret = NULL;
- return (0);
- }
-
- *ret = zhp;
- return (0);
-}
-
-/*
- * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
- * state.
- */
-zpool_handle_t *
-zpool_open(libzfs_handle_t *hdl, const char *pool)
-{
- zpool_handle_t *zhp;
-
- if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
- return (NULL);
-
- if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
- (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
- dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
- zpool_close(zhp);
- return (NULL);
- }
-
- return (zhp);
-}
-
-/*
- * Close the handle. Simply frees the memory associated with the handle.
- */
-void
-zpool_close(zpool_handle_t *zhp)
-{
- nvlist_free(zhp->zpool_config);
- nvlist_free(zhp->zpool_old_config);
- nvlist_free(zhp->zpool_props);
- free(zhp);
-}
-
-/*
- * Return the name of the pool.
- */
-const char *
-zpool_get_name(zpool_handle_t *zhp)
-{
- return (zhp->zpool_name);
-}
-
-
-/*
- * Return the state of the pool (ACTIVE or UNAVAILABLE)
- */
-int
-zpool_get_state(zpool_handle_t *zhp)
-{
- return (zhp->zpool_state);
-}
-
-/*
- * Check if vdev list contains a special vdev
- */
-static boolean_t
-zpool_has_special_vdev(nvlist_t *nvroot)
-{
- nvlist_t **child;
- uint_t children;
-
- if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, &child,
- &children) == 0) {
- for (uint_t c = 0; c < children; c++) {
- char *bias;
-
- if (nvlist_lookup_string(child[c],
- ZPOOL_CONFIG_ALLOCATION_BIAS, &bias) == 0 &&
- strcmp(bias, VDEV_ALLOC_BIAS_SPECIAL) == 0) {
- return (B_TRUE);
- }
- }
- }
- return (B_FALSE);
-}
-
-/*
- * Create the named pool, using the provided vdev list. It is assumed
- * that the consumer has already validated the contents of the nvlist, so we
- * don't have to worry about error semantics.
- */
-int
-zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
- nvlist_t *props, nvlist_t *fsprops)
-{
- zfs_cmd_t zc = { 0 };
- nvlist_t *zc_fsprops = NULL;
- nvlist_t *zc_props = NULL;
- char msg[1024];
- int ret = -1;
-
- (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
- "cannot create '%s'"), pool);
-
- if (!zpool_name_valid(hdl, B_FALSE, pool))
- return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
-
- if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
- return (-1);
-
- if (props) {
- prop_flags_t flags = { .create = B_TRUE, .import = B_FALSE };
-
- if ((zc_props = zpool_valid_proplist(hdl, pool, props,
- SPA_VERSION_1, flags, msg)) == NULL) {
- goto create_failed;
- }
- }
-
- if (fsprops) {
- uint64_t zoned;
- char *zonestr;
-
- zoned = ((nvlist_lookup_string(fsprops,
- zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
- strcmp(zonestr, "on") == 0);
-
- if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
- fsprops, zoned, NULL, NULL, msg)) == NULL) {
- goto create_failed;
- }
-
- if (nvlist_exists(zc_fsprops,
- zfs_prop_to_name(ZFS_PROP_SPECIAL_SMALL_BLOCKS)) &&
- !zpool_has_special_vdev(nvroot)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "%s property requires a special vdev"),
- zfs_prop_to_name(ZFS_PROP_SPECIAL_SMALL_BLOCKS));
- (void) zfs_error(hdl, EZFS_BADPROP, msg);
- goto create_failed;
- }
-
- if (!zc_props &&
- (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
- goto create_failed;
- }
- if (nvlist_add_nvlist(zc_props,
- ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
- goto create_failed;
- }
- }
-
- if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
- goto create_failed;
-
- (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
-
- if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
-
- zcmd_free_nvlists(&zc);
- nvlist_free(zc_props);
- nvlist_free(zc_fsprops);
-
- switch (errno) {
- case EBUSY:
- /*
- * This can happen if the user has specified the same
- * device multiple times. We can't reliably detect this
- * until we try to add it and see we already have a
- * label.
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "one or more vdevs refer to the same device"));
- return (zfs_error(hdl, EZFS_BADDEV, msg));
-
- case ERANGE:
- /*
- * This happens if the record size is smaller or larger
- * than the allowed size range, or not a power of 2.
- *
- * NOTE: although zfs_valid_proplist is called earlier,
- * this case may have slipped through since the
- * pool does not exist yet and it is therefore
- * impossible to read properties e.g. max blocksize
- * from the pool.
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "record size invalid"));
- return (zfs_error(hdl, EZFS_BADPROP, msg));
-
- case EOVERFLOW:
- /*
- * This occurs when one of the devices is below
- * SPA_MINDEVSIZE. Unfortunately, we can't detect which
- * device was the problem device since there's no
- * reliable way to determine device size from userland.
- */
- {
- char buf[64];
-
- zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
-
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "one or more devices is less than the "
- "minimum size (%s)"), buf);
- }
- return (zfs_error(hdl, EZFS_BADDEV, msg));
-
- case ENOSPC:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "one or more devices is out of space"));
- return (zfs_error(hdl, EZFS_BADDEV, msg));
-
- case ENOTBLK:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "cache device must be a disk or disk slice"));
- return (zfs_error(hdl, EZFS_BADDEV, msg));
-
- default:
- return (zpool_standard_error(hdl, errno, msg));
- }
- }
-
-create_failed:
- zcmd_free_nvlists(&zc);
- nvlist_free(zc_props);
- nvlist_free(zc_fsprops);
- return (ret);
-}
-
-/*
- * Destroy the given pool. It is up to the caller to ensure that there are no
- * datasets left in the pool.
- */
-int
-zpool_destroy(zpool_handle_t *zhp, const char *log_str)
-{
- zfs_cmd_t zc = { 0 };
- zfs_handle_t *zfp = NULL;
- libzfs_handle_t *hdl = zhp->zpool_hdl;
- char msg[1024];
-
- if (zhp->zpool_state == POOL_STATE_ACTIVE &&
- (zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL)
- return (-1);
-
- (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- zc.zc_history = (uint64_t)(uintptr_t)log_str;
-
- if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
- (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
- "cannot destroy '%s'"), zhp->zpool_name);
-
- if (errno == EROFS) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "one or more devices is read only"));
- (void) zfs_error(hdl, EZFS_BADDEV, msg);
- } else {
- (void) zpool_standard_error(hdl, errno, msg);
- }
-
- if (zfp)
- zfs_close(zfp);
- return (-1);
- }
-
- if (zfp) {
- remove_mountpoint(zfp);
- zfs_close(zfp);
- }
-
- return (0);
-}
-
-/*
- * Create a checkpoint in the given pool.
- */
-int
-zpool_checkpoint(zpool_handle_t *zhp)
-{
- libzfs_handle_t *hdl = zhp->zpool_hdl;
- char msg[1024];
- int error;
-
- error = lzc_pool_checkpoint(zhp->zpool_name);
- if (error != 0) {
- (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
- "cannot checkpoint '%s'"), zhp->zpool_name);
- (void) zpool_standard_error(hdl, error, msg);
- return (-1);
- }
-
- return (0);
-}
-
-/*
- * Discard the checkpoint from the given pool.
- */
-int
-zpool_discard_checkpoint(zpool_handle_t *zhp)
-{
- libzfs_handle_t *hdl = zhp->zpool_hdl;
- char msg[1024];
- int error;
-
- error = lzc_pool_checkpoint_discard(zhp->zpool_name);
- if (error != 0) {
- (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
- "cannot discard checkpoint in '%s'"), zhp->zpool_name);
- (void) zpool_standard_error(hdl, error, msg);
- return (-1);
- }
-
- return (0);
-}
-
-/*
- * Add the given vdevs to the pool. The caller must have already performed the
- * necessary verification to ensure that the vdev specification is well-formed.
- */
-int
-zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
-{
- zfs_cmd_t zc = { 0 };
- int ret;
- libzfs_handle_t *hdl = zhp->zpool_hdl;
- char msg[1024];
- nvlist_t **spares, **l2cache;
- uint_t nspares, nl2cache;
-
- (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
- "cannot add to '%s'"), zhp->zpool_name);
-
- if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
- SPA_VERSION_SPARES &&
- nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
- &spares, &nspares) == 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
- "upgraded to add hot spares"));
- return (zfs_error(hdl, EZFS_BADVERSION, msg));
- }
-
- if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
- SPA_VERSION_L2CACHE &&
- nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
- &l2cache, &nl2cache) == 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
- "upgraded to add cache devices"));
- return (zfs_error(hdl, EZFS_BADVERSION, msg));
- }
-
- if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
- return (-1);
- (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
-
- if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
- switch (errno) {
- case EBUSY:
- /*
- * This can happen if the user has specified the same
- * device multiple times. We can't reliably detect this
- * until we try to add it and see we already have a
- * label.
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "one or more vdevs refer to the same device"));
- (void) zfs_error(hdl, EZFS_BADDEV, msg);
- break;
-
- case EINVAL:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "invalid config; a pool with removing/removed "
- "vdevs does not support adding raidz vdevs"));
- (void) zfs_error(hdl, EZFS_BADDEV, msg);
- break;
-
- case EOVERFLOW:
- /*
- * This occurrs when one of the devices is below
- * SPA_MINDEVSIZE. Unfortunately, we can't detect which
- * device was the problem device since there's no
- * reliable way to determine device size from userland.
- */
- {
- char buf[64];
-
- zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
-
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "device is less than the minimum "
- "size (%s)"), buf);
- }
- (void) zfs_error(hdl, EZFS_BADDEV, msg);
- break;
-
- case ENOTSUP:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "pool must be upgraded to add these vdevs"));
- (void) zfs_error(hdl, EZFS_BADVERSION, msg);
- break;
-
- case EDOM:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "root pool can not have multiple vdevs"
- " or separate logs"));
- (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
- break;
-
- case ENOTBLK:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "cache device must be a disk or disk slice"));
- (void) zfs_error(hdl, EZFS_BADDEV, msg);
- break;
-
- default:
- (void) zpool_standard_error(hdl, errno, msg);
- }
-
- ret = -1;
- } else {
- ret = 0;
- }
-
- zcmd_free_nvlists(&zc);
-
- return (ret);
-}
-
-/*
- * Exports the pool from the system. The caller must ensure that there are no
- * mounted datasets in the pool.
- */
-static int
-zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
- const char *log_str)
-{
- zfs_cmd_t zc = { 0 };
- char msg[1024];
-
- (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
- "cannot export '%s'"), zhp->zpool_name);
-
- (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- zc.zc_cookie = force;
- zc.zc_guid = hardforce;
- zc.zc_history = (uint64_t)(uintptr_t)log_str;
-
- if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
- switch (errno) {
- case EXDEV:
- zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
- "use '-f' to override the following errors:\n"
- "'%s' has an active shared spare which could be"
- " used by other pools once '%s' is exported."),
- zhp->zpool_name, zhp->zpool_name);
- return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
- msg));
- default:
- return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
- msg));
- }
- }
-
- return (0);
-}
-
-int
-zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
-{
- return (zpool_export_common(zhp, force, B_FALSE, log_str));
-}
-
-int
-zpool_export_force(zpool_handle_t *zhp, const char *log_str)
-{
- return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
-}
-
-static void
-zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
- nvlist_t *config)
-{
- nvlist_t *nv = NULL;
- uint64_t rewindto;
- int64_t loss = -1;
- struct tm t;
- char timestr[128];
-
- if (!hdl->libzfs_printerr || config == NULL)
- return;
-
- if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
- nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) {
- return;
- }
-
- if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
- return;
- (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
-
- if (localtime_r((time_t *)&rewindto, &t) != NULL &&
- strftime(timestr, 128, 0, &t) != 0) {
- if (dryrun) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "Would be able to return %s "
- "to its state as of %s.\n"),
- name, timestr);
- } else {
- (void) printf(dgettext(TEXT_DOMAIN,
- "Pool %s returned to its state as of %s.\n"),
- name, timestr);
- }
- if (loss > 120) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "%s approximately %lld "),
- dryrun ? "Would discard" : "Discarded",
- (loss + 30) / 60);
- (void) printf(dgettext(TEXT_DOMAIN,
- "minutes of transactions.\n"));
- } else if (loss > 0) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "%s approximately %lld "),
- dryrun ? "Would discard" : "Discarded", loss);
- (void) printf(dgettext(TEXT_DOMAIN,
- "seconds of transactions.\n"));
- }
- }
-}
-
-void
-zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
- nvlist_t *config)
-{
- nvlist_t *nv = NULL;
- int64_t loss = -1;
- uint64_t edata = UINT64_MAX;
- uint64_t rewindto;
- struct tm t;
- char timestr[128];
-
- if (!hdl->libzfs_printerr)
- return;
-
- if (reason >= 0)
- (void) printf(dgettext(TEXT_DOMAIN, "action: "));
- else
- (void) printf(dgettext(TEXT_DOMAIN, "\t"));
-
- /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
- if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
- nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
- nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
- goto no_info;
-
- (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
- (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
- &edata);
-
- (void) printf(dgettext(TEXT_DOMAIN,
- "Recovery is possible, but will result in some data loss.\n"));
-
- if (localtime_r((time_t *)&rewindto, &t) != NULL &&
- strftime(timestr, 128, 0, &t) != 0) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "\tReturning the pool to its state as of %s\n"
- "\tshould correct the problem. "),
- timestr);
- } else {
- (void) printf(dgettext(TEXT_DOMAIN,
- "\tReverting the pool to an earlier state "
- "should correct the problem.\n\t"));
- }
-
- if (loss > 120) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "Approximately %lld minutes of data\n"
- "\tmust be discarded, irreversibly. "), (loss + 30) / 60);
- } else if (loss > 0) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "Approximately %lld seconds of data\n"
- "\tmust be discarded, irreversibly. "), loss);
- }
- if (edata != 0 && edata != UINT64_MAX) {
- if (edata == 1) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "After rewind, at least\n"
- "\tone persistent user-data error will remain. "));
- } else {
- (void) printf(dgettext(TEXT_DOMAIN,
- "After rewind, several\n"
- "\tpersistent user-data errors will remain. "));
- }
- }
- (void) printf(dgettext(TEXT_DOMAIN,
- "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "),
- reason >= 0 ? "clear" : "import", name);
-