aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am9
-rw-r--r--lib/libnvpair/Makefile.am7
-rw-r--r--lib/libspl/Makefile.am9
-rw-r--r--lib/libspl/include/os/Makefile.am4
-rw-r--r--lib/libspl/include/os/freebsd/Makefile.am1
-rw-r--r--lib/libspl/include/os/freebsd/sys/Makefile.am12
-rw-r--r--lib/libspl/include/os/freebsd/sys/byteorder.h311
-rw-r--r--lib/libspl/include/os/freebsd/sys/file.h42
-rw-r--r--lib/libspl/include/os/freebsd/sys/mnttab.h85
-rw-r--r--lib/libspl/include/os/freebsd/sys/mount.h108
-rw-r--r--lib/libspl/include/os/freebsd/sys/param.h70
-rw-r--r--lib/libspl/include/os/freebsd/sys/stat.h71
-rw-r--r--lib/libspl/include/os/freebsd/sys/sysmacros.h1
-rw-r--r--lib/libspl/include/os/freebsd/sys/uio.h98
-rw-r--r--lib/libspl/include/os/freebsd/sys/vfs.h37
-rw-r--r--lib/libspl/include/os/freebsd/sys/zfs_context_os.h38
-rw-r--r--lib/libspl/os/freebsd/getexecname.c70
-rw-r--r--lib/libspl/os/freebsd/gethostid.c36
-rw-r--r--lib/libspl/os/freebsd/getmntany.c67
-rw-r--r--lib/libspl/os/freebsd/mnttab.c216
-rw-r--r--lib/libuutil/Makefile.am4
-rw-r--r--lib/libzfs/Makefile.am15
-rw-r--r--lib/libzfs/libzfs_util.c2
-rw-r--r--lib/libzfs/os/freebsd/libzfs_compat.c323
-rw-r--r--lib/libzfs/os/freebsd/libzfs_fsshare.c406
-rw-r--r--lib/libzfs/os/freebsd/libzfs_ioctl_compat.c432
-rw-r--r--lib/libzfs/os/freebsd/libzfs_zmount.c147
-rw-r--r--lib/libzfs_core/Makefile.am6
-rw-r--r--lib/libzfs_core/libzfs_core_compat.h47
-rw-r--r--lib/libzpool/Makefile.am5
-rw-r--r--lib/libzutil/Makefile.am13
-rw-r--r--lib/libzutil/os/freebsd/zutil_compat.c74
-rw-r--r--lib/libzutil/os/freebsd/zutil_device_path_os.c132
-rw-r--r--lib/libzutil/os/freebsd/zutil_import_os.c239
34 files changed, 3132 insertions, 5 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 8dff773df..4f59aa359 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,6 +1,13 @@
# NB: GNU Automake Manual, Chapter 8.3.5: Libtool Convenience Libraries
# These six libraries are intermediary build components.
-SUBDIRS = libavl libefi libicp libshare libspl libtpool libzutil libunicode
+SUBDIRS = libavl libicp libshare libspl libtpool
+
+if BUILD_LINUX
+SUBDIRS += libefi
+endif
+
+# libzutil depends on libefi if present
+SUBDIRS += libzutil libunicode
# These four libraries, which are installed as the final build product,
# incorporate the six convenience libraries given above.
diff --git a/lib/libnvpair/Makefile.am b/lib/libnvpair/Makefile.am
index 6626b6d05..984ca520c 100644
--- a/lib/libnvpair/Makefile.am
+++ b/lib/libnvpair/Makefile.am
@@ -24,7 +24,14 @@ nodist_libnvpair_la_SOURCES = \
$(USER_C) \
$(KERNEL_C)
+if BUILD_FREEBSD
+libnvpair_la_LIBADD = $(LIBTIRPC_LIBS) -L/usr/local/lib -lintl
+libnvpair_la_LDFLAGS = -version-info 3:0:0
+else
libnvpair_la_LIBADD = $(LIBTIRPC_LIBS)
libnvpair_la_LDFLAGS = -version-info 1:1:0
+endif
+
+
EXTRA_DIST = $(USER_C)
diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am
index 3101b5fc5..77d8aba0e 100644
--- a/lib/libspl/Makefile.am
+++ b/lib/libspl/Makefile.am
@@ -42,6 +42,15 @@ USER_C += \
os/linux/getmntany.c
endif
+if BUILD_FREEBSD
+USER_C += \
+ os/freebsd/getexecname.c \
+ os/freebsd/gethostid.c \
+ os/freebsd/getmntany.c \
+ os/freebsd/mnttab.c
+
+endif
+
USER_ASM = atomic.S
nodist_libspl_la_SOURCES = \
diff --git a/lib/libspl/include/os/Makefile.am b/lib/libspl/include/os/Makefile.am
index 09c0beec4..7b362e02a 100644
--- a/lib/libspl/include/os/Makefile.am
+++ b/lib/libspl/include/os/Makefile.am
@@ -1,3 +1,7 @@
+if BUILD_FREEBSD
+SUBDIRS = freebsd
+endif
+
if BUILD_LINUX
SUBDIRS = linux
endif
diff --git a/lib/libspl/include/os/freebsd/Makefile.am b/lib/libspl/include/os/freebsd/Makefile.am
new file mode 100644
index 000000000..081839c48
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = sys
diff --git a/lib/libspl/include/os/freebsd/sys/Makefile.am b/lib/libspl/include/os/freebsd/sys/Makefile.am
new file mode 100644
index 000000000..896c93871
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/Makefile.am
@@ -0,0 +1,12 @@
+libspldir = $(includedir)/libspl/sys
+libspl_HEADERS = \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/byteorder.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/file.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/mnttab.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/mount.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/param.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/stat.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/sysmacros.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/uio.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/vfs.h \
+ $(top_srcdir)/lib/libspl/include/os/freebsd/sys/zfs_context_os.h
diff --git a/lib/libspl/include/os/freebsd/sys/byteorder.h b/lib/libspl/include/os/freebsd/sys/byteorder.h
new file mode 100644
index 000000000..74649cc4e
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/byteorder.h
@@ -0,0 +1,311 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef _SYS_BYTEORDER_H
+#define _SYS_BYTEORDER_H
+
+/*
+ * XXX FIXME
+ * on FreeBSD _BIG_ENDIAN is defined on all architectures so we have
+ * to exclude _MACHINE_ENDIAN_H_ and define the bulk of it here
+ */
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+/*
+ * Define the order of 32-bit words in 64-bit words.
+ */
+#define _QUAD_HIGHWORD 1
+#define _QUAD_LOWWORD 0
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#undef _LITTLE_ENDIAN
+/* LSB first: i386, vax */
+#define _LITTLE_ENDIAN 1234
+/* LSB first in word, MSW first in long */
+#define _PDP_ENDIAN 3412
+
+#define _BYTE_ORDER _LITTLE_ENDIAN
+
+/*
+ * Deprecated variants that don't have enough underscores to be useful in more
+ * strict namespaces.
+ */
+#if __BSD_VISIBLE
+#define LITTLE_ENDIAN _LITTLE_ENDIAN
+#define PDP_ENDIAN _PDP_ENDIAN
+#define BYTE_ORDER _BYTE_ORDER
+#endif
+
+#define __bswap16_gen(x) (__uint16_t)((x) << 8 | (x) >> 8)
+#define __bswap32_gen(x) \
+ (((__uint32_t)__bswap16((x) & 0xffff) << 16) | __bswap16((x) >> 16))
+#define __bswap64_gen(x) \
+ (((__uint64_t)__bswap32((x) & 0xffffffff) << 32) | __bswap32((x) >> 32))
+
+#ifdef __GNUCLIKE_BUILTIN_CONSTANT_P
+#define __bswap16(x) \
+ ((__uint16_t)(__builtin_constant_p(x) ? \
+ __bswap16_gen((__uint16_t)(x)) : __bswap16_var(x)))
+#define __bswap32(x) \
+ (__builtin_constant_p(x) ? \
+ __bswap32_gen((__uint32_t)(x)) : __bswap32_var(x))
+#define __bswap64(x) \
+ (__builtin_constant_p(x) ? \
+ __bswap64_gen((__uint64_t)(x)) : __bswap64_var(x))
+#else
+/* XXX these are broken for use in static initializers. */
+#define __bswap16(x) __bswap16_var(x)
+#define __bswap32(x) __bswap32_var(x)
+#define __bswap64(x) __bswap64_var(x)
+#endif
+
+/* These are defined as functions to avoid multiple evaluation of x. */
+
+static __inline __uint16_t
+__bswap16_var(__uint16_t _x)
+{
+
+ return (__bswap16_gen(_x));
+}
+
+static __inline __uint32_t
+__bswap32_var(__uint32_t _x)
+{
+
+#ifdef __GNUCLIKE_ASM
+ __asm("bswap %0" : "+r" (_x));
+ return (_x);
+#else
+ return (__bswap32_gen(_x));
+#endif
+}
+#define __htonl(x) __bswap32(x)
+#define __htons(x) __bswap16(x)
+#define __ntohl(x) __bswap32(x)
+#define __ntohs(x) __bswap16(x)
+
+#include <sys/isa_defs.h>
+#include <sys/int_types.h>
+
+#if defined(__GNUC__) && defined(_ASM_INLINES) && \
+ (defined(__i386) || defined(__amd64))
+#include <asm/byteorder.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * macros for conversion between host and (internet) network byte order
+ */
+
+#if defined(_BIG_ENDIAN) && !defined(ntohl) && !defined(__lint)
+/* big-endian */
+#if defined(_BIG_ENDIAN) && (defined(__amd64__) || defined(__amd64))
+#error "incompatible ENDIAN / ARCH combination"
+#endif
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
+
+#elif !defined(ntohl) /* little-endian */
+
+#ifndef _IN_PORT_T
+#define _IN_PORT_T
+typedef uint16_t in_port_t;
+#endif
+
+#ifndef _IN_ADDR_T
+#define _IN_ADDR_T
+typedef uint32_t in_addr_t;
+#endif
+
+#if !defined(_XPG4_2) || defined(__EXTENSIONS__) || defined(_XPG5)
+extern uint32_t htonl(uint32_t);
+extern uint16_t htons(uint16_t);
+extern uint32_t ntohl(uint32_t);
+extern uint16_t ntohs(uint16_t);
+#else
+extern in_addr_t htonl(in_addr_t);
+extern in_port_t htons(in_port_t);
+extern in_addr_t ntohl(in_addr_t);
+extern in_port_t ntohs(in_port_t);
+#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) || defined(_XPG5) */
+#endif
+
+#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
+
+/*
+ * Macros to reverse byte order
+ */
+#define BSWAP_8(x) ((x) & 0xff)
+#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
+#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
+#define BSWAP_64(x) ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32))
+
+#define BMASK_8(x) ((x) & 0xff)
+#define BMASK_16(x) ((x) & 0xffff)
+#define BMASK_32(x) ((x) & 0xffffffff)
+#define BMASK_64(x) (x)
+
+/*
+ * Macros to convert from a specific byte order to/from native byte order
+ */
+#ifdef _BIG_ENDIAN
+#define BE_8(x) BMASK_8(x)
+#define BE_16(x) BMASK_16(x)
+#define BE_32(x) BMASK_32(x)
+#define BE_64(x) BMASK_64(x)
+#define LE_8(x) BSWAP_8(x)
+#define LE_16(x) BSWAP_16(x)
+#define LE_32(x) BSWAP_32(x)
+#define LE_64(x) BSWAP_64(x)
+#else
+#define LE_8(x) BMASK_8(x)
+#define LE_16(x) BMASK_16(x)
+#define LE_32(x) BMASK_32(x)
+#define LE_64(x) BMASK_64(x)
+#define BE_8(x) BSWAP_8(x)
+#define BE_16(x) BSWAP_16(x)
+#define BE_32(x) BSWAP_32(x)
+#define BE_64(x) BSWAP_64(x)
+#endif
+
+#ifdef _BIG_ENDIAN
+static __inline__ uint64_t
+htonll(uint64_t n)
+{
+ return (n);
+}
+
+static __inline__ uint64_t
+ntohll(uint64_t n)
+{
+ return (n);
+}
+#else
+static __inline__ uint64_t
+htonll(uint64_t n)
+{
+ return ((((uint64_t)htonl(n)) << 32) + htonl(n >> 32));
+}
+
+static __inline__ uint64_t
+ntohll(uint64_t n)
+{
+ return ((((uint64_t)ntohl(n)) << 32) + ntohl(n >> 32));
+}
+#endif
+
+/*
+ * Macros to read unaligned values from a specific byte order to
+ * native byte order
+ */
+
+#define BE_IN8(xa) \
+ *((uint8_t *)(xa))
+
+#define BE_IN16(xa) \
+ (((uint16_t)BE_IN8(xa) << 8) | BE_IN8((uint8_t *)(xa)+1))
+
+#define BE_IN32(xa) \
+ (((uint32_t)BE_IN16(xa) << 16) | BE_IN16((uint8_t *)(xa)+2))
+
+#define BE_IN64(xa) \
+ (((uint64_t)BE_IN32(xa) << 32) | BE_IN32((uint8_t *)(xa)+4))
+
+#define LE_IN8(xa) \
+ *((uint8_t *)(xa))
+
+#define LE_IN16(xa) \
+ (((uint16_t)LE_IN8((uint8_t *)(xa) + 1) << 8) | LE_IN8(xa))
+
+#define LE_IN32(xa) \
+ (((uint32_t)LE_IN16((uint8_t *)(xa) + 2) << 16) | LE_IN16(xa))
+
+#define LE_IN64(xa) \
+ (((uint64_t)LE_IN32((uint8_t *)(xa) + 4) << 32) | LE_IN32(xa))
+
+/*
+ * Macros to write unaligned values from native byte order to a specific byte
+ * order.
+ */
+
+#define BE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define BE_OUT16(xa, yv) \
+ BE_OUT8((uint8_t *)(xa) + 1, yv); \
+ BE_OUT8((uint8_t *)(xa), (yv) >> 8);
+
+#define BE_OUT32(xa, yv) \
+ BE_OUT16((uint8_t *)(xa) + 2, yv); \
+ BE_OUT16((uint8_t *)(xa), (yv) >> 16);
+
+#define BE_OUT64(xa, yv) \
+ BE_OUT32((uint8_t *)(xa) + 4, yv); \
+ BE_OUT32((uint8_t *)(xa), (yv) >> 32);
+
+#define LE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define LE_OUT16(xa, yv) \
+ LE_OUT8((uint8_t *)(xa), yv); \
+ LE_OUT8((uint8_t *)(xa) + 1, (yv) >> 8);
+
+#define LE_OUT32(xa, yv) \
+ LE_OUT16((uint8_t *)(xa), yv); \
+ LE_OUT16((uint8_t *)(xa) + 2, (yv) >> 16);
+
+#define LE_OUT64(xa, yv) \
+ LE_OUT32((uint8_t *)(xa), yv); \
+ LE_OUT32((uint8_t *)(xa) + 4, (yv) >> 32);
+
+#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_BYTEORDER_H */
diff --git a/lib/libspl/include/os/freebsd/sys/file.h b/lib/libspl/include/os/freebsd/sys/file.h
new file mode 100644
index 000000000..27fd2888f
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/file.h
@@ -0,0 +1,42 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_FILE_H
+#define _LIBSPL_SYS_FILE_H
+
+#include_next <sys/file.h>
+
+#define FCREAT O_CREAT
+#define FTRUNC O_TRUNC
+#define FSYNC O_SYNC
+#define FDSYNC O_DSYNC
+#define FEXCL O_EXCL
+
+#define FNODSYNC 0x10000 /* fsync pseudo flag */
+#define FNOFOLLOW 0x20000 /* don't follow symlinks */
+#define FIGNORECASE 0x80000 /* request case-insensitive lookups */
+
+#endif
diff --git a/lib/libspl/include/os/freebsd/sys/mnttab.h b/lib/libspl/include/os/freebsd/sys/mnttab.h
new file mode 100644
index 000000000..eb6ea2433
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/mnttab.h
@@ -0,0 +1,85 @@
+/*
+ * 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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright 2006 Ricardo Correia */
+
+#ifndef _SYS_MNTTAB_H
+#define _SYS_MNTTAB_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef MNTTAB
+#undef MNTTAB
+#endif /* MNTTAB */
+
+#include <paths.h>
+#include <sys/mount.h>
+#define MNTTAB _PATH_DEVZERO
+#define MS_NOMNTTAB 0x0
+#define MS_RDONLY 0x1
+#define umount2(p, f) unmount(p, f)
+#define MNT_LINE_MAX 4096
+
+#define MNT_TOOLONG 1 /* entry exceeds MNT_LINE_MAX */
+#define MNT_TOOMANY 2 /* too many fields in line */
+#define MNT_TOOFEW 3 /* too few fields in line */
+
+struct mnttab {
+ char *mnt_special;
+ char *mnt_mountp;
+ char *mnt_fstype;
+ char *mnt_mntopts;
+};
+
+/*
+ * NOTE: fields in extmnttab should match struct mnttab till new fields
+ * are encountered, this allows hasmntopt to work properly when its arg is
+ * a pointer to an extmnttab struct cast to a mnttab struct pointer.
+ */
+
+struct extmnttab {
+ char *mnt_special;
+ char *mnt_mountp;
+ char *mnt_fstype;
+ char *mnt_mntopts;
+ uint_t mnt_major;
+ uint_t mnt_minor;
+};
+
+struct stat64;
+struct statfs;
+
+extern int getmntany(FILE *fp, struct mnttab *mp, struct mnttab *mpref);
+extern int _sol_getmntent(FILE *fp, struct mnttab *mp);
+extern int getextmntent(const char *path, struct extmnttab *entry,
+ struct stat64 *statbuf);
+extern void statfs2mnttab(struct statfs *sfs, struct mnttab *mp);
+char *hasmntopt(struct mnttab *mnt, char *opt);
+int getmntent(FILE *fp, struct mnttab *mp);
+
+#endif
diff --git a/lib/libspl/include/os/freebsd/sys/mount.h b/lib/libspl/include/os/freebsd/sys/mount.h
new file mode 100644
index 000000000..b40239100
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/mount.h
@@ -0,0 +1,108 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _LIBSPL_SYS_MOUNT_H
+#define _LIBSPL_SYS_MOUNT_H
+
+#undef _SYS_MOUNT_H_
+#include_next <sys/mount.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Some old glibc headers don't define BLKGETSIZE64
+ * and we don't want to require the kernel headers
+ */
+#if !defined(BLKGETSIZE64)
+#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
+#endif
+
+/*
+ * Some old glibc headers don't correctly define MS_DIRSYNC and
+ * instead use the enum name S_WRITE. When using these older
+ * headers define MS_DIRSYNC to be S_WRITE.
+ */
+#if !defined(MS_DIRSYNC)
+#define MS_DIRSYNC S_WRITE
+#endif
+
+/*
+ * Some old glibc headers don't correctly define MS_POSIXACL and
+ * instead leave it undefined. When using these older headers define
+ * MS_POSIXACL to the reserved value of (1<<16).
+ */
+#if !defined(MS_POSIXACL)
+#define MS_POSIXACL (1<<16)
+#endif
+
+#define MS_NOSUID MNT_NOSUID
+#define MS_NOEXEC MNT_NOEXEC
+#define MS_NODEV 0
+#define S_WRITE 0
+#define MS_BIND 0
+#define MS_REMOUNT 0
+#define MS_SYNCHRONOUS MNT_SYNCHRONOUS
+
+#define MS_USERS (MS_NOEXEC|MS_NOSUID|MS_NODEV)
+#define MS_OWNER (MS_NOSUID|MS_NODEV)
+#define MS_GROUP (MS_NOSUID|MS_NODEV)
+#define MS_COMMENT 0
+
+/*
+ * Older glibc <sys/mount.h> headers did not define all the available
+ * umount2(2) flags. Both MNT_FORCE and MNT_DETACH are supported in the
+ * kernel back to 2.4.11 so we define them correctly if they are missing.
+ */
+#ifdef MNT_FORCE
+#define MS_FORCE MNT_FORCE
+#else
+#define MS_FORCE 0x00000001
+#endif /* MNT_FORCE */
+
+#ifdef MNT_DETACH
+#define MS_DETACH MNT_DETACH
+#else
+#define MS_DETACH 0x00000002
+#endif /* MNT_DETACH */
+
+/*
+ * Overlay mount is default in Linux, but for solaris/zfs
+ * compatibility, MS_OVERLAY is defined to explicitly have the user
+ * provide a flag (-O) to mount over a non empty directory.
+ */
+#define MS_OVERLAY 0x00000004
+
+/*
+ * MS_CRYPT indicates that encryption keys should be loaded if they are not
+ * already available. This is not defined in glibc, but it is never seen by
+ * the kernel so it will not cause any problems.
+ */
+#define MS_CRYPT 0x00000008
+
+#endif /* _LIBSPL_SYS_MOUNT_H */
diff --git a/lib/libspl/include/os/freebsd/sys/param.h b/lib/libspl/include/os/freebsd/sys/param.h
new file mode 100644
index 000000000..c0ad8d679
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/param.h
@@ -0,0 +1,70 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_PARAM_H
+#define _LIBSPL_SYS_PARAM_H
+
+#include_next <sys/param.h>
+#include <unistd.h>
+
+/*
+ * File system parameters and macros.
+ *
+ * The file system is made out of blocks of at most MAXBSIZE units,
+ * with smaller units (fragments) only in the last direct block.
+ * MAXBSIZE primarily determines the size of buffers in the buffer
+ * pool. It may be made larger without any effect on existing
+ * file systems; however making it smaller may make some file
+ * systems unmountable.
+ *
+ * Note that the blocked devices are assumed to have DEV_BSIZE
+ * "sectors" and that fragments must be some multiple of this size.
+ */
+#define MAXNAMELEN 256
+
+#define UID_NOBODY 60001 /* user ID no body */
+#define GID_NOBODY UID_NOBODY
+#define UID_NOACCESS 60002 /* user ID no access */
+
+#define MAXUID UINT32_MAX /* max user id */
+#define MAXPROJID MAXUID /* max project id */
+
+#ifdef PAGESIZE
+#undef PAGESIZE
+#endif /* PAGESIZE */
+
+extern size_t spl_pagesize(void);
+#define PAGESIZE (spl_pagesize())
+
+extern int execvpe(const char *name, char * const argv[], char * const envp[]);
+
+struct zfs_handle;
+/*
+ * Attach/detach the given filesystem to/from the given jail.
+ */
+extern int zfs_jail(struct zfs_handle *zhp, int jailid, int attach);
+
+#endif
diff --git a/lib/libspl/include/os/freebsd/sys/stat.h b/lib/libspl/include/os/freebsd/sys/stat.h
new file mode 100644
index 000000000..82c86262f
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/stat.h
@@ -0,0 +1,71 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _LIBSPL_SYS_STAT_H
+#define _LIBSPL_SYS_STAT_H
+
+#include_next <sys/stat.h>
+
+#include <sys/mount.h> /* for BLKGETSIZE64 */
+
+#define stat64 stat
+
+#define MAXOFFSET_T OFF_MAX
+
+#ifndef _KERNEL
+#include <sys/disk.h>
+
+static __inline int
+fstat64(int fd, struct stat *sb)
+{
+ int ret;
+
+ ret = fstat(fd, sb);
+ if (ret == 0) {
+ if (S_ISCHR(sb->st_mode))
+ (void) ioctl(fd, DIOCGMEDIASIZE, &sb->st_size);
+ }
+ return (ret);
+}
+#endif
+
+/*
+ * Emulate Solaris' behavior of returning the block device size in fstat64().
+ */
+static inline int
+fstat64_blk(int fd, struct stat64 *st)
+{
+ if (fstat64(fd, st) == -1)
+ return (-1);
+
+ /* In Linux we need to use an ioctl to get the size of a block device */
+ if (S_ISBLK(st->st_mode)) {
+ if (ioctl(fd, BLKGETSIZE64, &st->st_size) != 0)
+ return (-1);
+ }
+
+ return (0);
+}
+#endif /* _LIBSPL_SYS_STAT_H */
diff --git a/lib/libspl/include/os/freebsd/sys/sysmacros.h b/lib/libspl/include/os/freebsd/sys/sysmacros.h
new file mode 100644
index 000000000..d9639d27b
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/sysmacros.h
@@ -0,0 +1 @@
+/* keep me */
diff --git a/lib/libspl/include/os/freebsd/sys/uio.h b/lib/libspl/include/os/freebsd/sys/uio.h
new file mode 100644
index 000000000..d978b6ad0
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/uio.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef _LIBSPL_SYS_UIO_H
+#define _LIBSPL_SYS_UIO_H
+
+#include_next <sys/uio.h>
+
+typedef struct iovec iovec_t;
+typedef enum uio_seg uio_seg_t;
+
+typedef struct uio {
+ struct iovec *uio_iov; /* pointer to array of iovecs */
+ int uio_iovcnt; /* number of iovecs */
+ offset_t uio_loffset; /* file offset */
+ uio_seg_t uio_segflg; /* address space (kernel or user) */
+ uint16_t uio_fmode; /* file mode flags */
+ uint16_t uio_extflg; /* extended flags */
+ offset_t uio_limit; /* u-limit (maximum byte offset) */
+ ssize_t uio_resid; /* residual count */
+} uio_t;
+
+typedef enum xuio_type {
+ UIOTYPE_ASYNCIO,
+ UIOTYPE_ZEROCOPY,
+} xuio_type_t;
+
+#define UIOA_IOV_MAX 16
+
+typedef struct uioa_page_s { /* locked uio_iov state */
+ int uioa_pfncnt; /* count of pfn_t(s) in *uioa_ppp */
+ void **uioa_ppp; /* page_t or pfn_t array */
+ caddr_t uioa_base; /* address base */
+ size_t uioa_len; /* span length */
+} uioa_page_t;
+
+typedef struct xuio {
+ uio_t xu_uio; /* embedded UIO structure */
+
+ /* Extended uio fields */
+ enum xuio_type xu_type; /* uio type */
+ union {
+ struct {
+ uint32_t xu_a_state; /* state of async i/o */
+ ssize_t xu_a_mbytes; /* bytes moved */
+ uioa_page_t *xu_a_lcur; /* uioa_locked[] pointer */
+ void **xu_a_lppp; /* lcur->uioa_pppp[] pointer */
+ void *xu_a_hwst[4]; /* opaque hardware state */
+ uioa_page_t xu_a_locked[UIOA_IOV_MAX];
+ } xu_aio;
+
+ struct {
+ int xu_zc_rw; /* read or write buffer */
+ void *xu_zc_priv; /* fs specific */
+ } xu_zc;
+ } xu_ext;
+} xuio_t;
+
+#define XUIO_XUZC_PRIV(xuio) xuio->xu_ext.xu_zc.xu_zc_priv
+#define XUIO_XUZC_RW(xuio) xuio->xu_ext.xu_zc.xu_zc_rw
+
+#endif /* _SYS_UIO_H */
diff --git a/lib/libspl/include/os/freebsd/sys/vfs.h b/lib/libspl/include/os/freebsd/sys/vfs.h
new file mode 100644
index 000000000..55eb3c23b
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/vfs.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 iXsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ZFS_SYS_VFS_H_
+#define ZFS_SYS_VFS_H_
+
+#include_next <sys/statvfs.h>
+
+int fsshare(const char *, const char *, const char *);
+int fsunshare(const char *, const char *);
+
+#endif /* !ZFS_SYS_VFS_H_ */
diff --git a/lib/libspl/include/os/freebsd/sys/zfs_context_os.h b/lib/libspl/include/os/freebsd/sys/zfs_context_os.h
new file mode 100644
index 000000000..25b5a47df
--- /dev/null
+++ b/lib/libspl/include/os/freebsd/sys/zfs_context_os.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 iXsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ZFS_CONTEXT_OS_H_
+#define ZFS_CONTEXT_OS_H_
+
+#if BYTE_ORDER != BIG_ENDIAN
+#undef _BIG_ENDIAN
+#endif
+
+#define ZFS_EXPORTS_PATH "/etc/zfs/exports"
+
+#endif
diff --git a/lib/libspl/os/freebsd/getexecname.c b/lib/libspl/os/freebsd/getexecname.c
new file mode 100644
index 000000000..13e50d324
--- /dev/null
+++ b/lib/libspl/os/freebsd/getexecname.c
@@ -0,0 +1,70 @@
+/*
+ * 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
+ */
+
+
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <errno.h>
+
+const char *
+getexecname(void)
+{
+ static char execname[PATH_MAX + 1] = "";
+ static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+ char *ptr = NULL;
+ ssize_t rc;
+
+ (void) pthread_mutex_lock(&mtx);
+
+ if (strlen(execname) == 0) {
+ int error, name[4];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_PATHNAME;
+ name[3] = -1;
+ len = PATH_MAX;
+ error = sysctl(name, nitems(name), execname, &len, NULL, 0);
+ if (error != 0) {
+ rc = -1;
+ } else {
+ rc = len;
+ }
+ if (rc == -1) {
+ execname[0] = '\0';
+ } else {
+ execname[rc] = '\0';
+ ptr = execname;
+ }
+ } else {
+ ptr = execname;
+ }
+
+ (void) pthread_mutex_unlock(&mtx);
+ return (ptr);
+}
diff --git a/lib/libspl/os/freebsd/gethostid.c b/lib/libspl/os/freebsd/gethostid.c
new file mode 100644
index 000000000..7bd567fe6
--- /dev/null
+++ b/lib/libspl/os/freebsd/gethostid.c
@@ -0,0 +1,36 @@
+/*
+ * 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) 2017, Lawrence Livermore National Security, LLC.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+
+unsigned long
+get_system_hostid(void)
+{
+ return (gethostid());
+}
diff --git a/lib/libspl/os/freebsd/getmntany.c b/lib/libspl/os/freebsd/getmntany.c
new file mode 100644
index 000000000..b41e763ce
--- /dev/null
+++ b/lib/libspl/os/freebsd/getmntany.c
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ * Copyright 2006 Ricardo Correia. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/mnttab.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define BUFSIZE (MNT_LINE_MAX + 2)
+
+__thread char buf[BUFSIZE];
+
+int
+getextmntent(const char *path, struct extmnttab *entry, struct stat64 *statbuf)
+{
+ struct statfs sfs;
+
+ if (strlen(path) >= MAXPATHLEN) {
+ (void) fprintf(stderr, "invalid object; pathname too long\n");
+ return (-1);
+ }
+
+ if (stat64(path, statbuf) != 0) {
+ (void) fprintf(stderr, "cannot open '%s': %s\n",
+ path, strerror(errno));
+ return (-1);
+ }
+
+ if (statfs(path, &sfs) != 0) {
+ (void) fprintf(stderr, "%s: %s\n", path,
+ strerror(errno));
+ return (-1);
+ }
+ statfs2mnttab(&sfs, (struct mnttab *)entry);
+ return (0);
+}
diff --git a/lib/libspl/os/freebsd/mnttab.c b/lib/libspl/os/freebsd/mnttab.c
new file mode 100644
index 000000000..5b9e6429d
--- /dev/null
+++ b/lib/libspl/os/freebsd/mnttab.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2006 Pawel Jakub Dawidek <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This file implements Solaris compatible getmntany() and hasmntopt()
+ * functions.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *
+mntopt(char **p)
+{
+ char *cp = *p;
+ char *retstr;
+
+ while (*cp && isspace(*cp))
+ cp++;
+
+ retstr = cp;
+ while (*cp && *cp != ',')
+ cp++;
+
+ if (*cp) {
+ *cp = '\0';
+ cp++;
+ }
+
+ *p = cp;
+ return (retstr);
+}
+
+char *
+hasmntopt(struct mnttab *mnt, char *opt)
+{
+ char tmpopts[MNT_LINE_MAX];
+ char *f, *opts = tmpopts;
+
+ if (mnt->mnt_mntopts == NULL)
+ return (NULL);
+ (void) strcpy(opts, mnt->mnt_mntopts);
+ f = mntopt(&opts);
+ for (; *f; f = mntopt(&opts)) {
+ if (strncmp(opt, f, strlen(opt)) == 0)
+ return (f - tmpopts + mnt->mnt_mntopts);
+ }
+ return (NULL);
+}
+
+static void
+optadd(char *mntopts, size_t size, const char *opt)
+{
+
+ if (mntopts[0] != '\0')
+ strlcat(mntopts, ",", size);
+ strlcat(mntopts, opt, size);
+}
+
+void
+statfs2mnttab(struct statfs *sfs, struct mnttab *mp)
+{
+ static char mntopts[MNTMAXSTR];
+ long flags;
+
+ mntopts[0] = '\0';
+
+ flags = sfs->f_flags;
+#define OPTADD(opt) optadd(mntopts, sizeof (mntopts), (opt))
+ if (flags & MNT_RDONLY)
+ OPTADD(MNTOPT_RO);
+ else
+ OPTADD(MNTOPT_RW);
+ if (flags & MNT_NOSUID)
+ OPTADD(MNTOPT_NOSETUID);
+ else
+ OPTADD(MNTOPT_SETUID);
+ if (flags & MNT_UPDATE)
+ OPTADD(MNTOPT_REMOUNT);
+ if (flags & MNT_NOATIME)
+ OPTADD(MNTOPT_NOATIME);
+ else
+ OPTADD(MNTOPT_ATIME);
+ OPTADD(MNTOPT_NOXATTR);
+ if (flags & MNT_NOEXEC)
+ OPTADD(MNTOPT_NOEXEC);
+ else
+ OPTADD(MNTOPT_EXEC);
+#undef OPTADD
+ mp->mnt_special = strdup(sfs->f_mntfromname);
+ mp->mnt_mountp = strdup(sfs->f_mntonname);
+ mp->mnt_fstype = strdup(sfs->f_fstypename);
+ mp->mnt_mntopts = strdup(mntopts);
+}
+
+static struct statfs *gsfs = NULL;
+static int allfs = 0;
+
+static int
+statfs_init(void)
+{
+ struct statfs *sfs;
+ int error;
+
+ if (gsfs != NULL) {
+ free(gsfs);
+ gsfs = NULL;
+ }
+ allfs = getfsstat(NULL, 0, MNT_WAIT);
+ if (allfs == -1)
+ goto fail;
+ gsfs = malloc(sizeof (gsfs[0]) * allfs * 2);
+ if (gsfs == NULL)
+ goto fail;
+ allfs = getfsstat(gsfs, (long)(sizeof (gsfs[0]) * allfs * 2),
+ MNT_WAIT);
+ if (allfs == -1)
+ goto fail;
+ sfs = realloc(gsfs, allfs * sizeof (gsfs[0]));
+ if (sfs != NULL)
+ gsfs = sfs;
+ return (0);
+fail:
+ error = errno;
+ if (gsfs != NULL)
+ free(gsfs);
+ gsfs = NULL;
+ allfs = 0;
+ return (error);
+}
+
+int
+getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
+{
+ // struct statfs *sfs;
+ int i, error;
+
+ error = statfs_init();
+ if (error != 0)
+ return (error);
+
+ for (i = 0; i < allfs; i++) {
+ if (mrefp->mnt_special != NULL &&
+ strcmp(mrefp->mnt_special, gsfs[i].f_mntfromname) != 0) {
+ continue;
+ }
+ if (mrefp->mnt_mountp != NULL &&
+ strcmp(mrefp->mnt_mountp, gsfs[i].f_mntonname) != 0) {
+ continue;
+ }
+ if (mrefp->mnt_fstype != NULL &&
+ strcmp(mrefp->mnt_fstype, gsfs[i].f_fstypename) != 0) {
+ continue;
+ }
+ statfs2mnttab(&gsfs[i], mgetp);
+ return (0);
+ }
+ return (-1);
+}
+
+int
+getmntent(FILE *fp, struct mnttab *mp)
+{
+ // struct statfs *sfs;
+ int error, nfs;
+
+ nfs = (int)lseek(fileno(fp), 0, SEEK_CUR);
+ if (nfs == -1)
+ return (errno);
+ /* If nfs is 0, we want to refresh out cache. */
+ if (nfs == 0 || gsfs == NULL) {
+ error = statfs_init();
+ if (error != 0)
+ return (error);
+ }
+ if (nfs >= allfs)
+ return (-1);
+ statfs2mnttab(&gsfs[nfs], mp);
+ if (lseek(fileno(fp), 1, SEEK_CUR) == -1)
+ return (errno);
+ return (0);
+}
diff --git a/lib/libuutil/Makefile.am b/lib/libuutil/Makefile.am
index c61b66fce..9eb81f090 100644
--- a/lib/libuutil/Makefile.am
+++ b/lib/libuutil/Makefile.am
@@ -19,6 +19,10 @@ libuutil_la_LIBADD = \
$(top_builddir)/lib/libavl/libavl.la \
$(top_builddir)/lib/libspl/libspl.la
+if BUILD_FREEBSD
+libuutil_la_LDFLAGS = -pthread -version-info 3:0:0
+else
libuutil_la_LDFLAGS = -pthread -version-info 1:1:0
+endif
EXTRA_DIST = $(USER_C)
diff --git a/lib/libzfs/Makefile.am b/lib/libzfs/Makefile.am
index 2747a7e9b..0e1e0a53e 100644
--- a/lib/libzfs/Makefile.am
+++ b/lib/libzfs/Makefile.am
@@ -27,6 +27,15 @@ USER_C = \
libzfs_status.c \
libzfs_util.c
+
+if BUILD_FREEBSD
+USER_C += \
+ os/freebsd/libzfs_fsshare.c \
+ os/freebsd/libzfs_compat.c \
+ os/freebsd/libzfs_ioctl_compat.c \
+ os/freebsd/libzfs_zmount.c
+endif
+
if BUILD_LINUX
USER_C += \
os/linux/libzfs_mount_os.c \
@@ -35,7 +44,6 @@ USER_C += \
os/linux/libzfs_util_os.c
endif
-
KERNEL_C = \
algs/sha2/sha2.c \
cityhash.c \
@@ -70,7 +78,12 @@ libzfs_la_LIBADD += \
$(top_builddir)/lib/libshare/libshare.la
endif
+if BUILD_FREEBSD
+libzfs_la_LIBADD += -lutil -lgeom
+libzfs_la_LDFLAGS = -version-info 4:0:0
+else
libzfs_la_LDFLAGS = -version-info 2:0:0
+endif
libzfs_la_LIBADD += -lm $(LIBSSL)
diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c
index c6debd576..71ac72ee1 100644
--- a/lib/libzfs/libzfs_util.c
+++ b/lib/libzfs/libzfs_util.c
@@ -881,7 +881,7 @@ libzfs_init(void)
return (NULL);
}
- if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
+ if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR|O_EXCL)) < 0) {
free(hdl);
return (NULL);
}
diff --git a/lib/libzfs/os/freebsd/libzfs_compat.c b/lib/libzfs/os/freebsd/libzfs_compat.c
new file mode 100644
index 000000000..e1c6ef93d
--- /dev/null
+++ b/lib/libzfs/os/freebsd/libzfs_compat.c
@@ -0,0 +1,323 @@
+/*
+ * 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 <[email protected]>. All rights reserved.
+ */
+#include <os/freebsd/zfs/sys/zfs_ioctl_compat.h>
+#include <libzfs_impl.h>
+#include <libzfs.h>
+#include <libzutil.h>
+#include <sys/sysctl.h>
+#include <libintl.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
+// static int zfs_spa_version = -1;
+
+void
+libzfs_set_pipe_max(int infd)
+{
+ /* FreeBSD automatically resizes */
+}
+
+static int
+execvPe(const char *name, const char *path, char * const *argv,
+ char * const *envp)
+{
+ const char **memp;
+ size_t cnt, lp, ln;
+ int eacces, save_errno;
+ char *cur, buf[MAXPATHLEN];
+ const char *p, *bp;
+ struct stat sb;
+
+ eacces = 0;
+
+ /* If it's an absolute or relative path name, it's easy. */
+ if (strchr(name, '/')) {
+ bp = name;
+ cur = NULL;
+ goto retry;
+ }
+ bp = buf;
+
+ /* If it's an empty path name, fail in the usual POSIX way. */
+ if (*name == '\0') {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ cur = alloca(strlen(path) + 1);
+ if (cur == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ strcpy(cur, path);
+ while ((p = strsep(&cur, ":")) != NULL) {
+ /*
+ * It's a SHELL path -- double, leading and trailing colons
+ * mean the current directory.
+ */
+ if (*p == '\0') {
+ p = ".";
+ lp = 1;
+ } else
+ lp = strlen(p);
+ ln = strlen(name);
+
+ /*
+ * If the path is too long complain. This is a possible
+ * security issue; given a way to make the path too long
+ * the user may execute the wrong program.
+ */
+ if (lp + ln + 2 > sizeof (buf)) {
+ (void) write(STDERR_FILENO, "execvP: ", 8);
+ (void) write(STDERR_FILENO, p, lp);
+ (void) write(STDERR_FILENO, ": path too long\n",
+ 16);
+ continue;
+ }
+ bcopy(p, buf, lp);
+ buf[lp] = '/';
+ bcopy(name, buf + lp + 1, ln);
+ buf[lp + ln + 1] = '\0';
+
+retry: (void) execve(bp, argv, envp);
+ switch (errno) {
+ case E2BIG:
+ goto done;
+ case ELOOP:
+ case ENAMETOOLONG:
+ case ENOENT:
+ break;
+ case ENOEXEC:
+ for (cnt = 0; argv[cnt]; ++cnt)
+ ;
+ memp = alloca((cnt + 2) * sizeof (char *));
+ if (memp == NULL) {
+ /* errno = ENOMEM; XXX override ENOEXEC? */
+ goto done;
+ }
+ memp[0] = "sh";
+ memp[1] = bp;
+ bcopy(argv + 1, memp + 2, cnt * sizeof (char *));
+ execve(_PATH_BSHELL, __DECONST(char **, memp), envp);
+ goto done;
+ case ENOMEM:
+ goto done;
+ case ENOTDIR:
+ break;
+ case ETXTBSY:
+ /*
+ * We used to retry here, but sh(1) doesn't.
+ */
+ goto done;
+ default:
+ /*
+ * EACCES may be for an inaccessible directory or
+ * a non-executable file. Call stat() to decide
+ * which. This also handles ambiguities for EFAULT
+ * and EIO, and undocumented errors like ESTALE.
+ * We hope that the race for a stat() is unimportant.
+ */
+ save_errno = errno;
+ if (stat(bp, &sb) != 0)
+ break;
+ if (save_errno == EACCES) {
+ eacces = 1;
+ continue;
+ }
+ errno = save_errno;
+ goto done;
+ }
+ }
+ if (eacces)
+ errno = EACCES;
+ else
+ errno = ENOENT;
+done:
+ return (-1);
+}
+
+int
+execvpe(const char *name, char * const argv[], char * const envp[])
+{
+ const char *path;
+
+ /* Get the path we're searching. */
+ if ((path = getenv("PATH")) == NULL)
+ path = _PATH_DEFPATH;
+
+ return (execvPe(name, path, argv, envp));
+}
+
+#if 0
+/*
+ * 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);
+}
+#endif
+
+/*
+ * 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);
+}
+
+const char *
+libzfs_error_init(int error)
+{
+
+ return (strerror(error));
+}
+
+int
+zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
+{
+ return (zfs_ioctl_fd(hdl->libzfs_fd, request, zc));
+}
+
+/*
+ * Verify the required ZFS_DEV device is available and optionally attempt
+ * to load the ZFS modules. Under normal circumstances the modules
+ * should already have been loaded by some external mechanism.
+ *
+ * Environment variables:
+ * - ZFS_MODULE_LOADING="YES|yes|ON|on" - Attempt to load modules.
+ * - ZFS_MODULE_TIMEOUT="<seconds>" - Seconds to wait for ZFS_DEV
+ */
+int
+libzfs_load_module(void)
+{
+ /* XXX: modname is "zfs" but file is named "openzfs". */
+ if (modfind("zfs") < 0) {
+ /* Not present in kernel, try loading it. */
+ if (kldload("openzfs") < 0 && errno != EEXIST) {
+ return (errno);
+ }
+ }
+ return (0);
+}
+
+int
+zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg)
+{
+ return (0);
+}
+
+int
+zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name)
+{
+ return (0);
+}
+
+int
+find_shares_object(differ_info_t *di)
+{
+ return (0);
+}
+
+/*
+ * 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));
+ case ZFS_TYPE_BOOKMARK:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "bookmarks can not be jailed"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ case ZFS_TYPE_POOL:
+ case ZFS_TYPE_FILESYSTEM:
+ /* OK */
+ ;
+ }
+ 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_zoneid = 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);
+}
+
+/*
+ * Fill given version buffer with zfs kernel version.
+ * Returns 0 on success, and -1 on error (with errno set)
+ */
+int
+zfs_version_kernel(char *version, int len)
+{
+ size_t l = len;
+
+ return (sysctlbyname("vfs.zfs.version.module",
+ version, &l, NULL, 0));
+}
diff --git a/lib/libzfs/os/freebsd/libzfs_fsshare.c b/lib/libzfs/os/freebsd/libzfs_fsshare.c
new file mode 100644
index 000000000..0fd75bf2c
--- /dev/null
+++ b/lib/libzfs/os/freebsd/libzfs_fsshare.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2007 Pawel Jakub Dawidek <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/vfs.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+
+#include "libzfs_impl.h"
+
+#define _PATH_MOUNTDPID "/var/run/mountd.pid"
+#define FILE_HEADER "# !!! DO NOT EDIT THIS FILE MANUALLY !!!\n\n"
+#define OPTSSIZE 1024
+#define MAXLINESIZE (PATH_MAX + OPTSSIZE)
+
+
+void
+sa_fini(sa_handle_t handle)
+{
+}
+
+int
+sa_parse_legacy_options(sa_group_t group, char *options, char *proto)
+{
+ return (SA_OK);
+}
+
+
+int
+zfs_init_libshare(libzfs_handle_t *zhandle, int service)
+{
+ return (SA_OK);
+}
+
+/*
+ * Share the given filesystem according to the options in the specified
+ * protocol specific properties (sharenfs, sharesmb). We rely
+ * on "libshare" to do the dirty work for us.
+ */
+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 err, ret;
+
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL, 0))
+ 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;
+
+ ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API);
+ if (ret != SA_OK) {
+ (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+ dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
+ zfs_get_name(zhp), sa_errorstr(ret));
+ return (-1);
+ }
+
+ /*
+ * 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;
+
+ if (*curr_proto != PROTO_NFS) {
+ fprintf(stderr, "Unsupported share protocol: %d.\n",
+ *curr_proto);
+ continue;
+ }
+
+ if (strcmp(shareopts, "on") == 0)
+ err = fsshare(ZFS_EXPORTS_PATH, mountpoint, "");
+ else
+ err = fsshare(ZFS_EXPORTS_PATH, mountpoint, shareopts);
+ if (err != 0) {
+ (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);
+}
+
+/*
+ * Unshare a filesystem by mountpoint.
+ */
+int
+unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
+ zfs_share_proto_t proto)
+{
+ 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));
+ }
+ return (0);
+}
+
+zfs_share_type_t
+is_shared_impl(libzfs_handle_t *hdl, const char *mountpoint,
+ zfs_share_proto_t proto)
+{
+ char buf[MAXPATHLEN], *tab;
+
+ 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) {
+ if (proto == PROTO_NFS)
+ return (SHARED_NFS);
+ }
+ }
+
+ return (SHARED_NOT_SHARED);
+}
+
+static void
+restart_mountd(void)
+{
+ struct pidfh *pfh;
+ pid_t mountdpid;
+
+ pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &mountdpid);
+ if (pfh != NULL) {
+ /* Mountd is not running. */
+ pidfile_remove(pfh);
+ return;
+ }
+ if (errno != EEXIST) {
+ /* Cannot open pidfile for some reason. */
+ return;
+ }
+ /* We have mountd(8) PID in mountdpid varible. */
+ kill(mountdpid, SIGHUP);
+}
+
+/*
+ * Read one line from a file. Skip comments, empty lines and a line with a
+ * mountpoint specified in the 'skip' argument.
+ */
+static char *
+zgetline(FILE *fd, const char *skip)
+{
+ static char line[MAXLINESIZE];
+ size_t len, skiplen = 0;
+ char *s, last;
+
+ if (skip != NULL)
+ skiplen = strlen(skip);
+ for (;;) {
+ s = fgets(line, sizeof (line), fd);
+ if (s == NULL)
+ return (NULL);
+ /* Skip empty lines and comments. */
+ if (line[0] == '\n' || line[0] == '#')
+ continue;
+ len = strlen(line);
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ last = line[skiplen];
+ /* Skip the given mountpoint. */
+ if (skip != NULL && strncmp(skip, line, skiplen) == 0 &&
+ (last == '\t' || last == ' ' || last == '\0')) {
+ continue;
+ }
+ break;
+ }
+ return (line);
+}
+/* BEGIN CSTYLED */
+/*
+ * Function translate options to a format acceptable by exports(5), eg.
+ *
+ * -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org 69.147.83.54
+ *
+ * Accepted input formats:
+ *
+ * ro,network=192.168.0.0,mask=255.255.255.0,maproot=0,freefall.freebsd.org
+ * ro network=192.168.0.0 mask=255.255.255.0 maproot=0 freefall.freebsd.org
+ * -ro,-network=192.168.0.0,-mask=255.255.255.0,-maproot=0,freefall.freebsd.org
+ * -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org
+ *
+ * Recognized keywords:
+ *
+ * ro, maproot, mapall, mask, network, sec, alldirs, public, webnfs, index, quiet
+ *
+ */
+/* END CSTYLED */
+
+static const char *known_opts[] = { "ro", "maproot", "mapall", "mask",
+ "network", "sec", "alldirs", "public", "webnfs", "index", "quiet",
+ NULL };
+static char *
+translate_opts(const char *shareopts)
+{
+ static char newopts[OPTSSIZE];
+ char oldopts[OPTSSIZE];
+ char *o, *s = NULL;
+ unsigned int i;
+ size_t len;
+
+ strlcpy(oldopts, shareopts, sizeof (oldopts));
+ newopts[0] = '\0';
+ s = oldopts;
+ while ((o = strsep(&s, "-, ")) != NULL) {
+ if (o[0] == '\0')
+ continue;
+ for (i = 0; known_opts[i] != NULL; i++) {
+ len = strlen(known_opts[i]);
+ if (strncmp(known_opts[i], o, len) == 0 &&
+ (o[len] == '\0' || o[len] == '=')) {
+ strlcat(newopts, "-", sizeof (newopts));
+ break;
+ }
+ }
+ strlcat(newopts, o, sizeof (newopts));
+ strlcat(newopts, " ", sizeof (newopts));
+ }
+ return (newopts);
+}
+
+static int
+fsshare_main(const char *file, const char *mountpoint, const char *shareopts,
+ int share)
+{
+ char tmpfile[PATH_MAX];
+ char *line;
+ FILE *newfd, *oldfd;
+ int fd, error;
+
+ newfd = oldfd = NULL;
+ error = 0;
+
+ /*
+ * Create temporary file in the same directory, so we can atomically
+ * rename it.
+ */
+ if (strlcpy(tmpfile, file, sizeof (tmpfile)) >= sizeof (tmpfile))
+ return (ENAMETOOLONG);
+ if (strlcat(tmpfile, ".XXXXXXXX", sizeof (tmpfile)) >= sizeof (tmpfile))
+ return (ENAMETOOLONG);
+ fd = mkstemp(tmpfile);
+ if (fd == -1)
+ return (errno);
+ /*
+ * File name is random, so we don't really need file lock now, but it
+ * will be needed after rename(2).
+ */
+ error = flock(fd, LOCK_EX);
+ assert(error == 0 || (error == -1 && errno == EOPNOTSUPP));
+ newfd = fdopen(fd, "r+");
+ assert(newfd != NULL);
+ /* Open old exports file. */
+ oldfd = fopen(file, "r");
+ if (oldfd == NULL) {
+ if (share) {
+ if (errno != ENOENT) {
+ error = errno;
+ goto out;
+ }
+ } else {
+ /* If there is no exports file, ignore the error. */
+ if (errno == ENOENT)
+ errno = 0;
+ error = errno;
+ goto out;
+ }
+ } else {
+ error = flock(fileno(oldfd), LOCK_EX);
+ assert(error == 0 || (error == -1 && errno == EOPNOTSUPP));
+ error = 0;
+ }
+
+ /* Place big, fat warning at the begining of the file. */
+ fprintf(newfd, "%s", FILE_HEADER);
+ while (oldfd != NULL && (line = zgetline(oldfd, mountpoint)) != NULL)
+ fprintf(newfd, "%s\n", line);
+ if (oldfd != NULL && ferror(oldfd) != 0) {
+ error = ferror(oldfd);
+ goto out;
+ }
+ if (ferror(newfd) != 0) {
+ error = ferror(newfd);
+ goto out;
+ }
+ if (share) {
+ fprintf(newfd, "%s\t%s\n", mountpoint,
+ translate_opts(shareopts));
+ }
+
+out:
+ if (error != 0)
+ unlink(tmpfile);
+ else {
+ if (rename(tmpfile, file) == -1) {
+ error = errno;
+ unlink(tmpfile);
+ } else {
+ fflush(newfd);
+ /*
+ * Send SIGHUP to mountd, but unlock exports file later.
+ */
+ restart_mountd();
+ }
+ }
+ if (oldfd != NULL) {
+ flock(fileno(oldfd), LOCK_UN);
+ fclose(oldfd);
+ }
+ if (newfd != NULL) {
+ flock(fileno(newfd), LOCK_UN);
+ fclose(newfd);
+ }
+ return (error);
+}
+
+/*
+ * Add the given mountpoint to the given exports file.
+ */
+int
+fsshare(const char *file, const char *mountpoint, const char *shareopts)
+{
+
+ return (fsshare_main(file, mountpoint, shareopts, 1));
+}
+
+/*
+ * Remove the given mountpoint from the given exports file.
+ */
+int
+fsunshare(const char *file, const char *mountpoint)
+{
+
+ return (fsshare_main(file, mountpoint, NULL, 0));
+}
diff --git a/lib/libzfs/os/freebsd/libzfs_ioctl_compat.c b/lib/libzfs/os/freebsd/libzfs_ioctl_compat.c
new file mode 100644
index 000000000..18b93fe27
--- /dev/null
+++ b/lib/libzfs/os/freebsd/libzfs_ioctl_compat.c
@@ -0,0 +1,432 @@
+/*
+ * 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 2013 Xin Li <[email protected]>. All rights reserved.
+ * Copyright 2013 Martin Matuska <[email protected]>. All rights reserved.
+ * Portions Copyright 2005, 2010, Oracle and/or its affiliates.
+ * All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/cred.h>
+#include <sys/dmu.h>
+#include <sys/zio.h>
+#include <sys/nvpair.h>
+#include <sys/dsl_deleg.h>
+#include <sys/zfs_ioctl.h>
+#include "zfs_namecheck.h"
+#include <os/freebsd/zfs/sys/zfs_ioctl_compat.h>
+
+/*
+ * FreeBSD zfs_cmd compatibility with older binaries
+ * appropriately remap/extend the zfs_cmd_t structure
+ */
+void
+zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
+{
+
+}
+#if 0
+static int
+zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
+ nvlist_t **nvp)
+{
+ char *packed;
+ int error;
+ nvlist_t *list = NULL;
+
+ /*
+ * Read in and unpack the user-supplied nvlist.
+ */
+ if (size == 0)
+ return (EINVAL);
+
+#ifdef _KERNEL
+ packed = kmem_alloc(size, KM_SLEEP);
+ if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
+ iflag)) != 0) {
+ kmem_free(packed, size);
+ return (error);
+ }
+#else
+ packed = (void *)(uintptr_t)nvl;
+#endif
+
+ error = nvlist_unpack(packed, size, &list, 0);
+
+#ifdef _KERNEL
+ kmem_free(packed, size);
+#endif
+
+ if (error != 0)
+ return (error);
+
+ *nvp = list;
+ return (0);
+}
+
+static int
+zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
+{
+ char *packed = NULL;
+ int error = 0;
+ size_t size;
+
+ VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
+
+#ifdef _KERNEL
+ packed = kmem_alloc(size, KM_SLEEP);
+ VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
+ KM_SLEEP) == 0);
+
+ if (ddi_copyout(packed,
+ (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
+ error = EFAULT;
+ kmem_free(packed, size);
+#else
+ packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
+ VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
+ 0) == 0);
+#endif
+
+ zc->zc_nvlist_dst_size = size;
+ return (error);
+}
+
+static void
+zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
+{
+ nvlist_t **child;
+ nvlist_t *nvroot = NULL;
+ vdev_stat_t *vs;
+ uint_t c, children, nelem;
+
+ if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ zfs_ioctl_compat_fix_stats_nvlist(child[c]);
+ }
+ }
+
+ if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0)
+ zfs_ioctl_compat_fix_stats_nvlist(nvroot);
+ if ((nvlist_lookup_uint64_array(nvl, "stats",
+ (uint64_t **)&vs, &nelem) == 0)) {
+ nvlist_add_uint64_array(nvl,
+ ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t *)vs, nelem);
+ nvlist_remove(nvl, "stats",
+ DATA_TYPE_UINT64_ARRAY);
+ }
+}
+
+
+static int
+zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
+{
+ nvlist_t *nv, *nvp = NULL;
+ nvpair_t *elem;
+ int error;
+
+ if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
+ zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
+ return (error);
+
+ if (nc == 5) { /* ZFS_IOC_POOL_STATS */
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
+ if (nvpair_value_nvlist(elem, &nvp) == 0)
+ zfs_ioctl_compat_fix_stats_nvlist(nvp);
+ }
+ elem = NULL;
+ } else
+ zfs_ioctl_compat_fix_stats_nvlist(nv);
+
+ error = zfs_ioctl_compat_put_nvlist(zc, nv);
+
+ nvlist_free(nv);
+
+ return (error);
+}
+
+static int
+zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
+{
+ nvlist_t *nv, *nva = NULL;
+ int error;
+
+ if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
+ zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
+ return (error);
+
+ if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
+ nvlist_add_nvlist(nv, "allocated", nva);
+ nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
+ }
+
+ if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
+ nvlist_add_nvlist(nv, "free", nva);
+ nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
+ }
+
+ error = zfs_ioctl_compat_put_nvlist(zc, nv);
+
+ nvlist_free(nv);
+
+ return (error);
+}
+#endif
+
+#ifdef _KERNEL
+int
+zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
+{
+ int error = 0;
+
+ /* are we creating a clone? */
+ if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
+ *vec = ZFS_IOC_CLONE;
+
+ if (cflag == ZFS_CMD_COMPAT_V15) {
+ switch (*vec) {
+
+ case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
+ zc->zc_cookie = POOL_SCAN_SCRUB;
+ break;
+ }
+ }
+
+ return (error);
+}
+
+void
+zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
+{
+ if (cflag == ZFS_CMD_COMPAT_V15) {
+ switch (vec) {
+ case ZFS_IOC_POOL_CONFIGS:
+ case ZFS_IOC_POOL_STATS:
+ case ZFS_IOC_POOL_TRYIMPORT:
+ zfs_ioctl_compat_fix_stats(zc, vec);
+ break;
+ case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
+ zfs_ioctl_compat_pool_get_props(zc);
+ break;
+ }
+ }
+}
+
+nvlist_t *
+zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t *innvl, const int vec,
+ const int cflag)
+{
+ nvlist_t *nvl, *tmpnvl, *hnvl;
+ nvpair_t *elem;
+ char *poolname, *snapname;
+ int err;
+
+ if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
+ cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP ||
+ cflag == ZFS_CMD_COMPAT_RESUME || cflag == ZFS_CMD_COMPAT_INLANES)
+ goto out;
+
+ switch (vec) {
+ case ZFS_IOC_CREATE:
+ nvl = fnvlist_alloc();
+ fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
+ if (innvl != NULL) {
+ fnvlist_add_nvlist(nvl, "props", innvl);
+ nvlist_free(innvl);
+ }
+ return (nvl);
+ break;
+ case ZFS_IOC_CLONE:
+ nvl = fnvlist_alloc();
+ fnvlist_add_string(nvl, "origin", zc->zc_value);
+ if (innvl != NULL) {
+ fnvlist_add_nvlist(nvl, "props", innvl);
+ nvlist_free(innvl);
+ }
+ return (nvl);
+ break;
+ case ZFS_IOC_SNAPSHOT:
+ if (innvl == NULL)
+ goto out;
+ nvl = fnvlist_alloc();
+ fnvlist_add_nvlist(nvl, "props", innvl);
+ tmpnvl = fnvlist_alloc();
+ snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
+ fnvlist_add_boolean(tmpnvl, snapname);
+ kmem_free(snapname, strlen(snapname + 1));
+ /* check if we are doing a recursive snapshot */
+ if (zc->zc_cookie)
+ dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
+ tmpnvl);
+ fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
+ fnvlist_free(tmpnvl);
+ nvlist_free(innvl);
+ /* strip dataset part from zc->zc_name */
+ zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
+ return (nvl);
+ break;
+ case ZFS_IOC_SPACE_SNAPS:
+ nvl = fnvlist_alloc();
+ fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
+ if (innvl != NULL)
+ nvlist_free(innvl);
+ return (nvl);
+ break;
+ case ZFS_IOC_DESTROY_SNAPS:
+ if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
+ goto out;
+ nvl = fnvlist_alloc();
+ if (innvl != NULL) {
+ fnvlist_add_nvlist(nvl, "snaps", innvl);
+ } else {
+ /*
+ * We are probably called by even older binaries,
+ * allocate and populate nvlist with recursive
+ * snapshots
+ */
+ if (zfs_component_namecheck(zc->zc_value, NULL,
+ NULL) == 0) {
+ tmpnvl = fnvlist_alloc();
+ if (dmu_get_recursive_snaps_nvl(zc->zc_name,
+ zc->zc_value, tmpnvl) == 0)
+ fnvlist_add_nvlist(nvl, "snaps",
+ tmpnvl);
+ nvlist_free(tmpnvl);
+ }
+ }
+ if (innvl != NULL)
+ nvlist_free(innvl);
+ /* strip dataset part from zc->zc_name */
+ zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
+ return (nvl);
+ break;
+ case ZFS_IOC_HOLD:
+ nvl = fnvlist_alloc();
+ tmpnvl = fnvlist_alloc();
+ if (zc->zc_cleanup_fd != -1)
+ fnvlist_add_int32(nvl, "cleanup_fd",
+ (int32_t)zc->zc_cleanup_fd);
+ if (zc->zc_cookie) {
+ hnvl = fnvlist_alloc();
+ if (dmu_get_recursive_snaps_nvl(zc->zc_name,
+ zc->zc_value, hnvl) == 0) {
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(hnvl,
+ elem)) != NULL) {
+ nvlist_add_string(tmpnvl,
+ nvpair_name(elem), zc->zc_string);
+ }
+ }
+ nvlist_free(hnvl);
+ } else {
+ snapname = kmem_asprintf("%s@%s", zc->zc_name,
+ zc->zc_value);
+ nvlist_add_string(tmpnvl, snapname, zc->zc_string);
+ kmem_free(snapname, strlen(snapname + 1));
+ }
+ fnvlist_add_nvlist(nvl, "holds", tmpnvl);
+ nvlist_free(tmpnvl);
+ if (innvl != NULL)
+ nvlist_free(innvl);
+ /* strip dataset part from zc->zc_name */
+ zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
+ return (nvl);
+ break;
+ case ZFS_IOC_RELEASE:
+ nvl = fnvlist_alloc();
+ tmpnvl = fnvlist_alloc();
+ if (zc->zc_cookie) {
+ hnvl = fnvlist_alloc();
+ if (dmu_get_recursive_snaps_nvl(zc->zc_name,
+ zc->zc_value, hnvl) == 0) {
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(hnvl,
+ elem)) != NULL) {
+ fnvlist_add_boolean(tmpnvl,
+ zc->zc_string);
+ fnvlist_add_nvlist(nvl,
+ nvpair_name(elem), tmpnvl);
+ }
+ }
+ nvlist_free(hnvl);
+ } else {
+ snapname = kmem_asprintf("%s@%s", zc->zc_name,
+ zc->zc_value);
+ fnvlist_add_boolean(tmpnvl, zc->zc_string);
+ fnvlist_add_nvlist(nvl, snapname, tmpnvl);
+ kmem_free(snapname, strlen(snapname + 1));
+ }
+ nvlist_free(tmpnvl);
+ if (innvl != NULL)
+ nvlist_free(innvl);
+ /* strip dataset part from zc->zc_name */
+ zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
+ return (nvl);
+ break;
+ }
+out:
+ return (innvl);
+}
+
+nvlist_t *
+zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t *outnvl, const int vec,
+ const int cflag)
+{
+ nvlist_t *tmpnvl;
+
+ if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
+ cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP ||
+ cflag == ZFS_CMD_COMPAT_RESUME || cflag == ZFS_CMD_COMPAT_INLANES)
+ return (outnvl);
+
+ switch (vec) {
+ case ZFS_IOC_SPACE_SNAPS:
+ (void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
+ (void) nvlist_lookup_uint64(outnvl, "compressed",
+ &zc->zc_objset_type);
+ (void) nvlist_lookup_uint64(outnvl, "uncompressed",
+ &zc->zc_perm_action);
+ nvlist_free(outnvl);
+ /* return empty outnvl */
+ tmpnvl = fnvlist_alloc();
+ return (tmpnvl);
+ break;
+ case ZFS_IOC_CREATE:
+ case ZFS_IOC_CLONE:
+ case ZFS_IOC_HOLD:
+ case ZFS_IOC_RELEASE:
+ nvlist_free(outnvl);
+ /* return empty outnvl */
+ tmpnvl = fnvlist_alloc();
+ return (tmpnvl);
+ break;
+ }
+
+ return (outnvl);
+}
+#endif /* KERNEL */
diff --git a/lib/libzfs/os/freebsd/libzfs_zmount.c b/lib/libzfs/os/freebsd/libzfs_zmount.c
new file mode 100644
index 000000000..8ff24f446
--- /dev/null
+++ b/lib/libzfs/os/freebsd/libzfs_zmount.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2006 Pawel Jakub Dawidek <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This file implements Solaris compatible zmount() function.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/mntent.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mnttab.h>
+#include <sys/errno.h>
+
+static void
+build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
+ size_t len)
+{
+ int i;
+
+ if (*iovlen < 0)
+ return;
+ i = *iovlen;
+ *iov = realloc(*iov, sizeof (**iov) * (i + 2));
+ if (*iov == NULL) {
+ *iovlen = -1;
+ return;
+ }
+ (*iov)[i].iov_base = strdup(name);
+ (*iov)[i].iov_len = strlen(name) + 1;
+ i++;
+ (*iov)[i].iov_base = val;
+ if (len == (size_t)-1) {
+ if (val != NULL)
+ len = strlen(val) + 1;
+ else
+ len = 0;
+ }
+ (*iov)[i].iov_len = (int)len;
+ *iovlen = ++i;
+}
+
+static int
+do_mount_(const char *spec, const char *dir, int mflag, char *fstype,
+ char *dataptr, int datalen, char *optptr, int optlen)
+{
+ struct iovec *iov;
+ char *optstr, *p, *tofree;
+ int iovlen, rv;
+
+ assert(spec != NULL);
+ assert(dir != NULL);
+ assert(fstype != NULL);
+ assert(strcmp(fstype, MNTTYPE_ZFS) == 0);
+ assert(dataptr == NULL);
+ assert(datalen == 0);
+ assert(optptr != NULL);
+ assert(optlen > 0);
+
+ tofree = optstr = strdup(optptr);
+ assert(optstr != NULL);
+
+ iov = NULL;
+ iovlen = 0;
+ if (strstr(optstr, MNTOPT_REMOUNT) != NULL)
+ build_iovec(&iov, &iovlen, "update", NULL, 0);
+ if (strstr(optstr, MNTOPT_NOXATTR) == NULL &&
+ strstr(optstr, MNTOPT_XATTR) == NULL &&
+ strstr(optstr, MNTOPT_SAXATTR) == NULL &&
+ strstr(optstr, MNTOPT_DIRXATTR) == NULL)
+ build_iovec(&iov, &iovlen, "xattr", NULL, 0);
+ if (mflag & MS_RDONLY)
+ build_iovec(&iov, &iovlen, "ro", NULL, 0);
+ build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, dir),
+ (size_t)-1);
+ build_iovec(&iov, &iovlen, "from", __DECONST(char *, spec), (size_t)-1);
+ while ((p = strsep(&optstr, ",/")) != NULL)
+ build_iovec(&iov, &iovlen, p, NULL, (size_t)-1);
+ rv = nmount(iov, iovlen, 0);
+ free(tofree);
+ if (rv < 0)
+ return (errno);
+ return (rv);
+}
+
+int
+do_mount(const char *src, const char *mntpt, char *opts, int flags)
+{
+
+ return (do_mount_(src, mntpt, flags, MNTTYPE_ZFS, NULL, 0, opts,
+ sizeof (mntpt)));
+}
+
+int
+do_unmount(const char *mntpt, int flags)
+{
+
+ return (unmount(mntpt, flags));
+}
+
+int
+zfs_mount_delegation_check(void)
+{
+ return (0);
+}
+
+/*
+ * Check if we are doing an overlay mount.
+ * Returns B_TRUE if the mount would overlay, otherwise B_FALSE.
+ */
+boolean_t
+zfs_mount_overlay_check(const char *mountpoint)
+{
+ /* FreeBSD always allows overlay mounts. */
+ return (B_FALSE);
+}
diff --git a/lib/libzfs_core/Makefile.am b/lib/libzfs_core/Makefile.am
index dca81e01a..617b1cf32 100644
--- a/lib/libzfs_core/Makefile.am
+++ b/lib/libzfs_core/Makefile.am
@@ -12,6 +12,10 @@ libzfs_core_la_LIBADD = \
$(top_builddir)/lib/libuutil/libuutil.la \
$(top_builddir)/lib/libzutil/libzutil.la
+if BUILD_FREEBSD
+libzfs_core_la_LDFLAGS = -version-info 3:0:0
+libzfs_core_la_LIBADD += -lutil -lgeom
+else
libzfs_core_la_LDFLAGS = -version-info 1:0:0
-
+endif
EXTRA_DIST = $(USER_C)
diff --git a/lib/libzfs_core/libzfs_core_compat.h b/lib/libzfs_core/libzfs_core_compat.h
new file mode 100644
index 000000000..6527c4b25
--- /dev/null
+++ b/lib/libzfs_core/libzfs_core_compat.h
@@ -0,0 +1,47 @@
+/*
+ * 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) 2013 by Martin Matuska <[email protected]>. All rights reserved.
+ */
+
+#ifndef _LIBZFS_CORE_COMPAT_H
+#define _LIBZFS_CORE_COMPAT_H
+
+#include <libnvpair.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int lzc_compat_pre(zfs_cmd_t *, zfs_ioc_t *, nvlist_t **);
+void lzc_compat_post(zfs_cmd_t *, const zfs_ioc_t);
+int lzc_compat_outnvl(zfs_cmd_t *, const zfs_ioc_t, nvlist_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_CORE_COMPAT_H */
diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am
index 4225246b9..a9396105b 100644
--- a/lib/libzpool/Makefile.am
+++ b/lib/libzpool/Makefile.am
@@ -199,8 +199,13 @@ libzpool_la_LIBADD = \
$(top_builddir)/lib/libunicode/libunicode.la \
$(top_builddir)/lib/libzutil/libzutil.la
+if BUILD_FREEBSD
+libzpool_la_LIBADD += $(ZLIB) -ldl -lgeom
+libzpool_la_LDFLAGS = -pthread -version-info 4:0:0
+else
libzpool_la_LIBADD += $(ZLIB) -ldl
libzpool_la_LDFLAGS = -pthread -version-info 2:0:0
+endif
EXTRA_DIST = $(USER_C)
diff --git a/lib/libzutil/Makefile.am b/lib/libzutil/Makefile.am
index e5c6a340d..092312e0d 100644
--- a/lib/libzutil/Makefile.am
+++ b/lib/libzutil/Makefile.am
@@ -21,13 +21,24 @@ USER_C += \
os/linux/zutil_compat.c
endif
+if BUILD_FREEBSD
+USER_C += \
+ os/freebsd/zutil_device_path_os.c \
+ os/freebsd/zutil_import_os.c \
+ os/freebsd/zutil_compat.c
+endif
+
nodist_libzutil_la_SOURCES = $(USER_C)
libzutil_la_LIBADD = \
$(top_builddir)/lib/libavl/libavl.la \
- $(top_builddir)/lib/libefi/libefi.la \
$(top_builddir)/lib/libtpool/libtpool.la
+if BUILD_LINUX
+libzutil_la_LIBADD += \
+ $(top_builddir)/lib/libefi/libefi.la
+endif
+
libzutil_la_LIBADD += -lm $(LIBBLKID) $(LIBUDEV)
EXTRA_DIST = $(USER_C)
diff --git a/lib/libzutil/os/freebsd/zutil_compat.c b/lib/libzutil/os/freebsd/zutil_compat.c
new file mode 100644
index 000000000..5b0fe8548
--- /dev/null
+++ b/lib/libzutil/os/freebsd/zutil_compat.c
@@ -0,0 +1,74 @@
+/*
+ * 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
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/zfs_ioctl.h>
+#include <os/freebsd/zfs/sys/zfs_ioctl_compat.h>
+#include <libzutil.h>
+
+static int
+zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag)
+{
+ int ret;
+ void *zc_c;
+ unsigned long ncmd;
+ zfs_iocparm_t zp;
+
+ switch (cflag) {
+ case ZFS_CMD_COMPAT_NONE:
+ ncmd = _IOWR('Z', request, zfs_iocparm_t);
+ zp.zfs_cmd = (uint64_t)zc;
+ zp.zfs_cmd_size = sizeof (zfs_cmd_t);
+ zp.zfs_ioctl_version = ZFS_IOCVER_ZOF;
+ return (ioctl(fd, ncmd, &zp));
+ default:
+ abort();
+ return (EINVAL);
+ }
+
+ ret = ioctl(fd, ncmd, zc_c);
+ zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
+ free(zc_c);
+
+ return (ret);
+}
+
+/*
+ * 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
+zfs_ioctl_fd(int fd, unsigned long request, zfs_cmd_t *zc)
+{
+ size_t oldsize;
+ int ret, cflag = ZFS_CMD_COMPAT_NONE;
+
+ 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/lib/libzutil/os/freebsd/zutil_device_path_os.c b/lib/libzutil/os/freebsd/zutil_device_path_os.c
new file mode 100644
index 000000000..71c936005
--- /dev/null
+++ b/lib/libzutil/os/freebsd/zutil_device_path_os.c
@@ -0,0 +1,132 @@
+/*
+ * 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
+ */
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/stat.h>
+
+#include <libgeom.h>
+
+#include <libzutil.h>
+
+/*
+ * We don't strip/append partitions on FreeBSD.
+ */
+
+/*
+ * Note: The caller must free the returned string.
+ */
+char *
+zfs_strip_partition(char *dev)
+{
+ return (strdup(dev));
+}
+
+int
+zfs_append_partition(char *path, size_t max_len)
+{
+ return (strnlen(path, max_len));
+}
+
+/*
+ * Strip the path from a device name.
+ * On FreeBSD we only want to remove "/dev/" from the beginning of
+ * paths if present.
+ */
+char *
+zfs_strip_path(char *path)
+{
+ if (strncmp(path, _PATH_DEV, sizeof (_PATH_DEV) - 1) == 0)
+ return (path + sizeof (_PATH_DEV) - 1);
+ else
+ return (path);
+}
+
+char *
+zfs_get_underlying_path(const char *dev_name)
+{
+
+ if (dev_name == NULL)
+ return (NULL);
+
+ return (realpath(dev_name, NULL));
+}
+
+boolean_t
+zfs_dev_is_whole_disk(const char *dev_name)
+{
+ int fd;
+
+ fd = g_open(dev_name, 0);
+ if (fd >= 0) {
+ g_close(fd);
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Wait up to timeout_ms for udev to set up the device node. The device is
+ * considered ready when libudev determines it has been initialized, all of
+ * the device links have been verified to exist, and it has been allowed to
+ * settle. At this point the device the device can be accessed reliably.
+ * Depending on the complexity of the udev rules this process could take
+ * several seconds.
+ */
+int
+zpool_label_disk_wait(const char *path, int timeout_ms)
+{
+ int settle_ms = 50;
+ long sleep_ms = 10;
+ hrtime_t start, settle;
+ struct stat64 statbuf;
+
+ start = gethrtime();
+ settle = 0;
+
+ do {
+ errno = 0;
+ if ((stat64(path, &statbuf) == 0) && (errno == 0)) {
+ if (settle == 0)
+ settle = gethrtime();
+ else if (NSEC2MSEC(gethrtime() - settle) >= settle_ms)
+ return (0);
+ } else if (errno != ENOENT) {
+ return (errno);
+ }
+
+ usleep(sleep_ms * MILLISEC);
+ } while (NSEC2MSEC(gethrtime() - start) < timeout_ms);
+
+ return (ENODEV);
+}
+
+/* ARGSUSED */
+boolean_t
+is_mpath_whole_disk(const char *path)
+{
+ return (B_FALSE);
+}
diff --git a/lib/libzutil/os/freebsd/zutil_import_os.c b/lib/libzutil/os/freebsd/zutil_import_os.c
new file mode 100644
index 000000000..7272a1e0e
--- /dev/null
+++ b/lib/libzutil/os/freebsd/zutil_import_os.c
@@ -0,0 +1,239 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <libintl.h>
+#include <libgen.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/disk.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/efi_partition.h>
+#include <thread_pool.h>
+#include <libgeom.h>
+
+#include <sys/vdev_impl.h>
+
+#include <libzutil.h>
+
+#include "zutil_import.h"
+
+/*
+ * Update a leaf vdev's persistent device strings
+ *
+ * - only applies for a dedicated leaf vdev (aka whole disk)
+ * - updated during pool create|add|attach|import
+ * - used for matching device matching during auto-{online,expand,replace}
+ * - stored in a leaf disk config label (i.e. alongside 'path' NVP)
+ * - these strings are currently not used in kernel (i.e. for vdev_disk_open)
+ *
+ * On FreeBSD we currently just strip devid and phys_path to avoid confusion.
+ */
+void
+update_vdev_config_dev_strs(nvlist_t *nv)
+{
+ (void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
+ (void) nvlist_remove_all(nv, ZPOOL_CONFIG_PHYS_PATH);
+}
+
+/*
+ * Do not even look at these devices.
+ */
+static const char * const blacklist_devs[] = {
+ "nfslock",
+ "sequencer",
+ "zfs",
+};
+#define BLACKLIST_DIR "/dev/"
+#define BLACKLIST_DIR_LEN 5
+
+void
+zpool_open_func(void *arg)
+{
+ rdsk_node_t *rn = arg;
+ struct stat64 statbuf;
+ nvlist_t *config;
+ size_t i;
+ int num_labels;
+ int fd;
+ off_t mediasize = 0;
+
+ /*
+ * Do not even look at blacklisted devices.
+ */
+ if (strncmp(rn->rn_name, BLACKLIST_DIR, BLACKLIST_DIR_LEN) == 0) {
+ char *name = rn->rn_name + BLACKLIST_DIR_LEN;
+ for (i = 0; i < nitems(blacklist_devs); ++i) {
+ const char *badname = blacklist_devs[i];
+ size_t len = strlen(badname);
+ if (strncmp(name, badname, len) == 0) {
+ return;
+ }
+ }
+ }
+
+ /*
+ * O_NONBLOCK so we don't hang trying to open things like serial ports.
+ */
+ if ((fd = open(rn->rn_name, O_RDONLY|O_NONBLOCK)) < 0)
+ return;
+
+ /*
+ * Ignore failed stats.
+ */
+ if (fstat64(fd, &statbuf) != 0)
+ goto out;
+ /*
+ * We only want regular files, character devs and block devs.
+ */
+ if (S_ISREG(statbuf.st_mode)) {
+ /* Check if this file is too small to hold a zpool. */
+ if (statbuf.st_size < SPA_MINDEVSIZE) {
+ goto out;
+ }
+ } else if (S_ISCHR(statbuf.st_mode) || S_ISBLK(statbuf.st_mode)) {
+ /* Check if this device is too small to hold a zpool. */
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0 ||
+ mediasize < SPA_MINDEVSIZE) {
+ goto out;
+ }
+ } else {
+ goto out;
+ }
+
+ if (zpool_read_label(fd, &config, &num_labels) != 0)
+ goto out;
+ if (num_labels == 0) {
+ nvlist_free(config);
+ goto out;
+ }
+
+ rn->rn_config = config;
+ rn->rn_num_labels = num_labels;
+
+ /* TODO: Reuse labelpaths logic from Linux? */
+out:
+ (void) close(fd);
+}
+
+static const char *
+zpool_default_import_path[] = {
+ "/dev"
+};
+
+const char * const *
+zpool_default_search_paths(size_t *count)
+{
+ *count = nitems(zpool_default_import_path);
+ return (zpool_default_import_path);
+}
+
+int
+zpool_find_import_blkid(libpc_handle_t *hdl, pthread_mutex_t *lock,
+ avl_tree_t **slice_cache)
+{
+ char *end, path[MAXPATHLEN];
+ rdsk_node_t *slice;
+ struct gmesh mesh;
+ struct gclass *mp;
+ struct ggeom *gp;
+ struct gprovider *pp;
+ avl_index_t where;
+ size_t pathleft;
+ int error;
+
+ end = stpcpy(path, "/dev/");
+ pathleft = &path[sizeof (path)] - end;
+
+ error = geom_gettree(&mesh);
+ if (error != 0)
+ return (error);
+
+ *slice_cache = zutil_alloc(hdl, sizeof (avl_tree_t));
+ avl_create(*slice_cache, slice_cache_compare, sizeof (rdsk_node_t),
+ offsetof(rdsk_node_t, rn_node));
+
+ LIST_FOREACH(mp, &mesh.lg_class, lg_class) {
+ LIST_FOREACH(gp, &mp->lg_geom, lg_geom) {
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ strlcpy(end, pp->lg_name, pathleft);
+ slice = zutil_alloc(hdl, sizeof (rdsk_node_t));
+ slice->rn_name = zutil_strdup(hdl, path);
+ slice->rn_vdev_guid = 0;
+ slice->rn_lock = lock;
+ slice->rn_avl = *slice_cache;
+ slice->rn_hdl = hdl;
+ slice->rn_labelpaths = B_FALSE;
+ slice->rn_order = IMPORT_ORDER_DEFAULT;
+
+ pthread_mutex_lock(lock);
+ if (avl_find(*slice_cache, slice, &where)) {
+ free(slice->rn_name);
+ free(slice);
+ } else {
+ avl_insert(*slice_cache, slice, where);
+ }
+ pthread_mutex_unlock(lock);
+ }
+ }
+ }
+
+ geom_deletetree(&mesh);
+
+ return (0);
+}
+
+int
+zfs_dev_flush(int fd __unused)
+{
+ return (0);
+}