diff --git a/include/Makefile.am b/include/Makefile.am index 17286ecbb7fd..4da43afd850d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,34 +1,33 @@ SUBDIRS = sys os COMMON_H = \ cityhash.h \ zfeature_common.h \ zfs_comutil.h \ zfs_deleg.h \ zfs_fletcher.h \ zfs_namecheck.h \ zfs_prop.h USER_H = \ libnvpair.h \ libuutil_common.h \ libuutil.h \ libuutil_impl.h \ libzfs.h \ libzfsbootenv.h \ libzfs_core.h \ - libzfs_impl.h \ libzutil.h \ thread_pool.h if CONFIG_USER libzfsdir = $(includedir)/libzfs libzfs_HEADERS = $(COMMON_H) $(USER_H) endif if CONFIG_KERNEL if BUILD_LINUX kerneldir = @prefix@/src/zfs-$(VERSION)/include kernel_HEADERS = $(COMMON_H) endif endif diff --git a/lib/libshare/libshare.c b/lib/libshare/libshare.c index d32a282a36e3..a228645fbf8f 100644 --- a/lib/libshare/libshare.c +++ b/lib/libshare/libshare.c @@ -1,366 +1,365 @@ /* * 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) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 Gunnar Beutner * Copyright (c) 2018, 2020 by Delphix. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include -#include "libzfs_impl.h" #include "libshare_impl.h" #include "nfs.h" #include "smb.h" static sa_share_impl_t alloc_share(const char *zfsname, const char *path); static void free_share(sa_share_impl_t share); static int fstypes_count; static sa_fstype_t *fstypes; sa_fstype_t * register_fstype(const char *name, const sa_share_ops_t *ops) { sa_fstype_t *fstype; fstype = calloc(1, sizeof (sa_fstype_t)); if (fstype == NULL) return (NULL); fstype->name = name; fstype->ops = ops; fstype->fsinfo_index = fstypes_count; fstypes_count++; fstype->next = fstypes; fstypes = fstype; return (fstype); } __attribute__((constructor)) static void libshare_init(void) { libshare_nfs_init(); libshare_smb_init(); } int sa_enable_share(const char *zfsname, const char *mountpoint, const char *shareopts, char *protocol) { int rc, ret = SA_OK; boolean_t found_protocol = B_FALSE; sa_fstype_t *fstype; sa_share_impl_t impl_share = alloc_share(zfsname, mountpoint); if (impl_share == NULL) return (SA_NO_MEMORY); fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) { rc = fstype->ops->update_shareopts(impl_share, shareopts); if (rc != SA_OK) break; rc = fstype->ops->enable_share(impl_share); if (rc != SA_OK) ret = rc; found_protocol = B_TRUE; } fstype = fstype->next; } free_share(impl_share); return (found_protocol ? ret : SA_INVALID_PROTOCOL); } int sa_disable_share(const char *mountpoint, char *protocol) { int rc, ret = SA_OK; boolean_t found_protocol = B_FALSE; sa_fstype_t *fstype; sa_share_impl_t impl_share = alloc_share(NULL, mountpoint); if (impl_share == NULL) return (SA_NO_MEMORY); fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) { rc = fstype->ops->disable_share(impl_share); if (rc != SA_OK) ret = rc; found_protocol = B_TRUE; } fstype = fstype->next; } free_share(impl_share); return (found_protocol ? ret : SA_INVALID_PROTOCOL); } boolean_t sa_is_shared(const char *mountpoint, char *protocol) { sa_fstype_t *fstype; boolean_t ret = B_FALSE; /* guid value is not used */ sa_share_impl_t impl_share = alloc_share(NULL, mountpoint); if (impl_share == NULL) return (B_FALSE); fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) { ret = fstype->ops->is_shared(impl_share); } fstype = fstype->next; } free_share(impl_share); return (ret); } void sa_commit_shares(const char *protocol) { sa_fstype_t *fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) fstype->ops->commit_shares(); fstype = fstype->next; } } /* * sa_errorstr(err) * * convert an error value to an error string */ char * sa_errorstr(int err) { static char errstr[32]; char *ret = NULL; switch (err) { case SA_OK: ret = dgettext(TEXT_DOMAIN, "ok"); break; case SA_NO_SUCH_PATH: ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); break; case SA_NO_MEMORY: ret = dgettext(TEXT_DOMAIN, "no memory"); break; case SA_DUPLICATE_NAME: ret = dgettext(TEXT_DOMAIN, "name in use"); break; case SA_BAD_PATH: ret = dgettext(TEXT_DOMAIN, "bad path"); break; case SA_NO_SUCH_GROUP: ret = dgettext(TEXT_DOMAIN, "no such group"); break; case SA_CONFIG_ERR: ret = dgettext(TEXT_DOMAIN, "configuration error"); break; case SA_SYSTEM_ERR: ret = dgettext(TEXT_DOMAIN, "system error"); break; case SA_SYNTAX_ERR: ret = dgettext(TEXT_DOMAIN, "syntax error"); break; case SA_NO_PERMISSION: ret = dgettext(TEXT_DOMAIN, "no permission"); break; case SA_BUSY: ret = dgettext(TEXT_DOMAIN, "busy"); break; case SA_NO_SUCH_PROP: ret = dgettext(TEXT_DOMAIN, "no such property"); break; case SA_INVALID_NAME: ret = dgettext(TEXT_DOMAIN, "invalid name"); break; case SA_INVALID_PROTOCOL: ret = dgettext(TEXT_DOMAIN, "invalid protocol"); break; case SA_NOT_ALLOWED: ret = dgettext(TEXT_DOMAIN, "operation not allowed"); break; case SA_BAD_VALUE: ret = dgettext(TEXT_DOMAIN, "bad property value"); break; case SA_INVALID_SECURITY: ret = dgettext(TEXT_DOMAIN, "invalid security type"); break; case SA_NO_SUCH_SECURITY: ret = dgettext(TEXT_DOMAIN, "security type not found"); break; case SA_VALUE_CONFLICT: ret = dgettext(TEXT_DOMAIN, "property value conflict"); break; case SA_NOT_IMPLEMENTED: ret = dgettext(TEXT_DOMAIN, "not implemented"); break; case SA_INVALID_PATH: ret = dgettext(TEXT_DOMAIN, "invalid path"); break; case SA_NOT_SUPPORTED: ret = dgettext(TEXT_DOMAIN, "operation not supported"); break; case SA_PROP_SHARE_ONLY: ret = dgettext(TEXT_DOMAIN, "property not valid for group"); break; case SA_NOT_SHARED: ret = dgettext(TEXT_DOMAIN, "not shared"); break; case SA_NO_SUCH_RESOURCE: ret = dgettext(TEXT_DOMAIN, "no such resource"); break; case SA_RESOURCE_REQUIRED: ret = dgettext(TEXT_DOMAIN, "resource name required"); break; case SA_MULTIPLE_ERROR: ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); break; case SA_PATH_IS_SUBDIR: ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); break; case SA_PATH_IS_PARENTDIR: ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); break; case SA_NO_SECTION: ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); break; case SA_NO_PROPERTIES: ret = dgettext(TEXT_DOMAIN, "properties not found"); break; case SA_NO_SUCH_SECTION: ret = dgettext(TEXT_DOMAIN, "section not found"); break; case SA_PASSWORD_ENC: ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); break; case SA_SHARE_EXISTS: ret = dgettext(TEXT_DOMAIN, "path or file is already shared"); break; default: (void) snprintf(errstr, sizeof (errstr), dgettext(TEXT_DOMAIN, "unknown %d"), err); ret = errstr; } return (ret); } int sa_validate_shareopts(char *options, char *proto) { sa_fstype_t *fstype; fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, proto) != 0) { fstype = fstype->next; continue; } return (fstype->ops->validate_shareopts(options)); } return (SA_INVALID_PROTOCOL); } static sa_share_impl_t alloc_share(const char *zfsname, const char *mountpoint) { sa_share_impl_t impl_share; impl_share = calloc(1, sizeof (struct sa_share_impl)); if (impl_share == NULL) return (NULL); if (mountpoint != NULL && ((impl_share->sa_mountpoint = strdup(mountpoint)) == NULL)) { free(impl_share); return (NULL); } if (zfsname != NULL && ((impl_share->sa_zfsname = strdup(zfsname)) == NULL)) { free(impl_share->sa_mountpoint); free(impl_share); return (NULL); } impl_share->sa_fsinfo = calloc(fstypes_count, sizeof (sa_share_fsinfo_t)); if (impl_share->sa_fsinfo == NULL) { free(impl_share->sa_mountpoint); free(impl_share->sa_zfsname); free(impl_share); return (NULL); } return (impl_share); } static void free_share(sa_share_impl_t impl_share) { sa_fstype_t *fstype; fstype = fstypes; while (fstype != NULL) { fstype->ops->clear_shareopts(impl_share); fstype = fstype->next; } free(impl_share->sa_mountpoint); free(impl_share->sa_zfsname); free(impl_share->sa_fsinfo); free(impl_share); } diff --git a/lib/libshare/os/freebsd/nfs.c b/lib/libshare/os/freebsd/nfs.c index 323c9269f188..b82491f2ebe8 100644 --- a/lib/libshare/os/freebsd/nfs.c +++ b/lib/libshare/os/freebsd/nfs.c @@ -1,342 +1,342 @@ /* * Copyright (c) 2007 Pawel Jakub Dawidek * 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. * * Copyright (c) 2020 by Delphix. All rights reserved. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include -#include "libzfs_impl.h" +#include #include "libshare_impl.h" #include "nfs.h" #define _PATH_MOUNTDPID "/var/run/mountd.pid" #define OPTSSIZE 1024 #define MAXLINESIZE (PATH_MAX + OPTSSIZE) #define ZFS_EXPORTS_FILE "/etc/zfs/exports" #define ZFS_EXPORTS_LOCK ZFS_EXPORTS_FILE".lock" static sa_fstype_t *nfs_fstype; /* * Read one line from a file. Skip comments, empty lines and a line with a * mountpoint specified in the 'skip' argument. * * NOTE: This function returns a static buffer and thus is not thread-safe. */ 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); } /* * This function translate options to a format acceptable by exports(5), eg. * * -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 \ * zfs.freebsd.org 69.147.83.54 * * Accepted input formats: * * ro,network=192.168.0.0,mask=255.255.255.0,maproot=0,zfs.freebsd.org * ro network=192.168.0.0 mask=255.255.255.0 maproot=0 zfs.freebsd.org * -ro,-network=192.168.0.0,-mask=255.255.255.0,-maproot=0,zfs.freebsd.org * -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 \ * zfs.freebsd.org * * Recognized keywords: * * ro, maproot, mapall, mask, network, sec, alldirs, public, webnfs, * index, quiet * * NOTE: This function returns a static buffer and thus is not thread-safe. */ static char * translate_opts(const char *shareopts) { static const char *known_opts[] = { "ro", "maproot", "mapall", "mask", "network", "sec", "alldirs", "public", "webnfs", "index", "quiet", NULL }; 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); } /* * This function copies all entries from the exports file to "filename", * omitting any entries for the specified mountpoint. */ __attribute__((visibility("hidden"))) int nfs_copy_entries(char *filename, const char *mountpoint) { int error = SA_OK; char *line; FILE *oldfp = fopen(ZFS_EXPORTS_FILE, "re"); FILE *newfp = fopen(filename, "w+e"); if (newfp == NULL) { fprintf(stderr, "failed to open %s file: %s", filename, strerror(errno)); fclose(oldfp); return (SA_SYSTEM_ERR); } fputs(FILE_HEADER, newfp); /* * The ZFS_EXPORTS_FILE may not exist yet. If that's the * case then just write out the new file. */ if (oldfp != NULL) { while ((line = zgetline(oldfp, mountpoint)) != NULL) fprintf(newfp, "%s\n", line); if (ferror(oldfp) != 0) { error = ferror(oldfp); } if (fclose(oldfp) != 0) { fprintf(stderr, "Unable to close file %s: %s\n", filename, strerror(errno)); error = error != 0 ? error : SA_SYSTEM_ERR; } } if (error == 0 && ferror(newfp) != 0) { error = ferror(newfp); } if (fclose(newfp) != 0) { fprintf(stderr, "Unable to close file %s: %s\n", filename, strerror(errno)); error = error != 0 ? error : SA_SYSTEM_ERR; } return (error); } static int nfs_enable_share_impl(sa_share_impl_t impl_share, char *filename) { FILE *fp = fopen(filename, "a+e"); if (fp == NULL) { fprintf(stderr, "failed to open %s file: %s", filename, strerror(errno)); return (SA_SYSTEM_ERR); } char *shareopts = FSINFO(impl_share, nfs_fstype)->shareopts; if (strcmp(shareopts, "on") == 0) shareopts = ""; if (fprintf(fp, "%s\t%s\n", impl_share->sa_mountpoint, translate_opts(shareopts)) < 0) { fprintf(stderr, "failed to write to %s\n", filename); fclose(fp); return (SA_SYSTEM_ERR); } if (fclose(fp) != 0) { fprintf(stderr, "Unable to close file %s: %s\n", filename, strerror(errno)); return (SA_SYSTEM_ERR); } return (SA_OK); } static int nfs_enable_share(sa_share_impl_t impl_share) { return (nfs_toggle_share( ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE, NULL, impl_share, nfs_enable_share_impl)); } static int nfs_disable_share_impl(sa_share_impl_t impl_share, char *filename) { return (SA_OK); } static int nfs_disable_share(sa_share_impl_t impl_share) { return (nfs_toggle_share( ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE, NULL, impl_share, nfs_disable_share_impl)); } static boolean_t nfs_is_shared(sa_share_impl_t impl_share) { char *s, last, line[MAXLINESIZE]; size_t len; char *mntpoint = impl_share->sa_mountpoint; size_t mntlen = strlen(mntpoint); FILE *fp = fopen(ZFS_EXPORTS_FILE, "re"); if (fp == NULL) return (B_FALSE); for (;;) { s = fgets(line, sizeof (line), fp); if (s == NULL) return (B_FALSE); /* 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[mntlen]; /* Skip the given mountpoint. */ if (strncmp(mntpoint, line, mntlen) == 0 && (last == '\t' || last == ' ' || last == '\0')) { fclose(fp); return (B_TRUE); } } fclose(fp); return (B_FALSE); } static int nfs_validate_shareopts(const char *shareopts) { return (SA_OK); } static int nfs_update_shareopts(sa_share_impl_t impl_share, const char *shareopts) { FSINFO(impl_share, nfs_fstype)->shareopts = (char *)shareopts; return (SA_OK); } static void nfs_clear_shareopts(sa_share_impl_t impl_share) { FSINFO(impl_share, nfs_fstype)->shareopts = NULL; } /* * Commit the shares by restarting mountd. */ static int nfs_commit_shares(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 (SA_OK); } if (errno != EEXIST) { /* Cannot open pidfile for some reason. */ return (SA_SYSTEM_ERR); } /* We have mountd(8) PID in mountdpid variable. */ kill(mountdpid, SIGHUP); return (SA_OK); } static const sa_share_ops_t nfs_shareops = { .enable_share = nfs_enable_share, .disable_share = nfs_disable_share, .is_shared = nfs_is_shared, .validate_shareopts = nfs_validate_shareopts, .update_shareopts = nfs_update_shareopts, .clear_shareopts = nfs_clear_shareopts, .commit_shares = nfs_commit_shares, }; /* * Initializes the NFS functionality of libshare. */ void libshare_nfs_init(void) { nfs_fstype = register_fstype("nfs", &nfs_shareops); } diff --git a/lib/libzfs/Makefile.am b/lib/libzfs/Makefile.am index 31267fd9a5e9..9385eb1aadbb 100644 --- a/lib/libzfs/Makefile.am +++ b/lib/libzfs/Makefile.am @@ -1,98 +1,99 @@ include $(top_srcdir)/config/Rules.am VPATH = \ $(top_srcdir)/module/icp \ $(top_srcdir)/module/zcommon \ $(top_srcdir)/lib/libzfs # Suppress unused but set variable warnings often due to ASSERTs AM_CFLAGS += $(NO_UNUSED_BUT_SET_VARIABLE) AM_CFLAGS += $(LIBCRYPTO_CFLAGS) $(ZLIB_CFLAGS) pkgconfig_DATA = libzfs.pc lib_LTLIBRARIES = libzfs.la include $(top_srcdir)/config/Abigail.am USER_C = \ + libzfs_impl.h \ libzfs_changelist.c \ libzfs_config.c \ libzfs_crypto.c \ libzfs_dataset.c \ libzfs_diff.c \ libzfs_import.c \ libzfs_iter.c \ libzfs_mount.c \ libzfs_pool.c \ libzfs_sendrecv.c \ libzfs_status.c \ libzfs_util.c if BUILD_FREEBSD USER_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 \ os/linux/libzfs_pool_os.c \ os/linux/libzfs_sendrecv_os.c \ os/linux/libzfs_util_os.c endif KERNEL_C = \ algs/sha2/sha2.c \ cityhash.c \ zfeature_common.c \ zfs_comutil.c \ zfs_deleg.c \ zfs_fletcher.c \ zfs_fletcher_aarch64_neon.c \ zfs_fletcher_avx512.c \ zfs_fletcher_intel.c \ zfs_fletcher_sse.c \ zfs_fletcher_superscalar.c \ zfs_fletcher_superscalar4.c \ zfs_namecheck.c \ zfs_prop.c \ zpool_prop.c \ zprop_common.c dist_libzfs_la_SOURCES = \ $(USER_C) nodist_libzfs_la_SOURCES = \ $(KERNEL_C) libzfs_la_LIBADD = \ $(abs_top_builddir)/lib/libshare/libshare.la \ $(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \ $(abs_top_builddir)/lib/libnvpair/libnvpair.la \ $(abs_top_builddir)/lib/libuutil/libuutil.la libzfs_la_LIBADD += -lm $(LIBCRYPTO_LIBS) $(ZLIB_LIBS) $(LIBFETCH_LIBS) $(LTLIBINTL) libzfs_la_LDFLAGS = -pthread if !ASAN_ENABLED libzfs_la_LDFLAGS += -Wl,-z,defs endif if BUILD_FREEBSD libzfs_la_LIBADD += -lutil -lgeom endif libzfs_la_LDFLAGS += -version-info 5:0:1 include $(top_srcdir)/config/CppCheck.am # Library ABI EXTRA_DIST = libzfs.abi libzfs.suppr # Licensing data EXTRA_DIST += THIRDPARTYLICENSE.openssl THIRDPARTYLICENSE.openssl.descrip diff --git a/include/libzfs_impl.h b/lib/libzfs/libzfs_impl.h similarity index 100% rename from include/libzfs_impl.h rename to lib/libzfs/libzfs_impl.h diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c index 64fa31c67d0f..0d375b355166 100644 --- a/lib/libzfs/libzfs_import.c +++ b/lib/libzfs/libzfs_import.c @@ -1,471 +1,471 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved. * Copyright 2015 RackTop Systems. * Copyright (c) 2016, Intel Corporation. */ #include #include #include #include #include #include #include #include #include #include -#include +#include "libzfs_impl.h" #include #include /* * Returns true if the named pool matches the given GUID. */ static int pool_active(libzfs_handle_t *hdl, const char *name, uint64_t guid, boolean_t *isactive) { zpool_handle_t *zhp; uint64_t theguid; if (zpool_open_silent(hdl, name, &zhp) != 0) return (-1); if (zhp == NULL) { *isactive = B_FALSE; return (0); } verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID, &theguid) == 0); zpool_close(zhp); *isactive = (theguid == guid); return (0); } static nvlist_t * refresh_config(libzfs_handle_t *hdl, nvlist_t *config) { nvlist_t *nvl; zfs_cmd_t zc = {"\0"}; int err, dstbuf_size; if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) return (NULL); dstbuf_size = MAX(CONFIG_BUF_MINSIZE, zc.zc_nvlist_conf_size * 32); if (zcmd_alloc_dst_nvlist(hdl, &zc, dstbuf_size) != 0) { zcmd_free_nvlists(&zc); return (NULL); } while ((err = zfs_ioctl(hdl, ZFS_IOC_POOL_TRYIMPORT, &zc)) != 0 && errno == ENOMEM) { if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { zcmd_free_nvlists(&zc); return (NULL); } } if (err) { zcmd_free_nvlists(&zc); return (NULL); } if (zcmd_read_dst_nvlist(hdl, &zc, &nvl) != 0) { zcmd_free_nvlists(&zc); return (NULL); } zcmd_free_nvlists(&zc); return (nvl); } static nvlist_t * refresh_config_libzfs(void *handle, nvlist_t *tryconfig) { return (refresh_config((libzfs_handle_t *)handle, tryconfig)); } static int pool_active_libzfs(void *handle, const char *name, uint64_t guid, boolean_t *isactive) { return (pool_active((libzfs_handle_t *)handle, name, guid, isactive)); } const pool_config_ops_t libzfs_config_ops = { .pco_refresh_config = refresh_config_libzfs, .pco_pool_active = pool_active_libzfs, }; /* * Return the offset of the given label. */ static uint64_t label_offset(uint64_t size, int l) { ASSERT(P2PHASE_TYPED(size, sizeof (vdev_label_t), uint64_t) == 0); return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ? 0 : size - VDEV_LABELS * sizeof (vdev_label_t))); } /* * Given a file descriptor, clear (zero) the label information. This function * is used in the appliance stack as part of the ZFS sysevent module and * to implement the "zpool labelclear" command. */ int zpool_clear_label(int fd) { struct stat64 statbuf; int l; vdev_label_t *label; l2arc_dev_hdr_phys_t *l2dhdr; uint64_t size; int labels_cleared = 0, header_cleared = 0; boolean_t clear_l2arc_header = B_FALSE; if (fstat64_blk(fd, &statbuf) == -1) return (0); size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t); if ((label = calloc(1, sizeof (vdev_label_t))) == NULL) return (-1); if ((l2dhdr = calloc(1, sizeof (l2arc_dev_hdr_phys_t))) == NULL) { free(label); return (-1); } for (l = 0; l < VDEV_LABELS; l++) { uint64_t state, guid, l2cache; nvlist_t *config; if (pread64(fd, label, sizeof (vdev_label_t), label_offset(size, l)) != sizeof (vdev_label_t)) { continue; } if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist, sizeof (label->vl_vdev_phys.vp_nvlist), &config, 0) != 0) { continue; } /* Skip labels which do not have a valid guid. */ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &guid) != 0 || guid == 0) { nvlist_free(config); continue; } /* Skip labels which are not in a known valid state. */ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &state) != 0 || state > POOL_STATE_L2CACHE) { nvlist_free(config); continue; } /* If the device is a cache device clear the header. */ if (!clear_l2arc_header) { if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &l2cache) == 0 && l2cache == POOL_STATE_L2CACHE) { clear_l2arc_header = B_TRUE; } } nvlist_free(config); /* * A valid label was found, overwrite this label's nvlist * and uberblocks with zeros on disk. This is done to prevent * system utilities, like blkid, from incorrectly detecting a * partial label. The leading pad space is left untouched. */ memset(label, 0, sizeof (vdev_label_t)); size_t label_size = sizeof (vdev_label_t) - (2 * VDEV_PAD_SIZE); if (pwrite64(fd, label, label_size, label_offset(size, l) + (2 * VDEV_PAD_SIZE)) == label_size) { labels_cleared++; } } /* Clear the L2ARC header. */ if (clear_l2arc_header) { memset(l2dhdr, 0, sizeof (l2arc_dev_hdr_phys_t)); if (pwrite64(fd, l2dhdr, sizeof (l2arc_dev_hdr_phys_t), VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t)) { header_cleared++; } } free(label); free(l2dhdr); if (labels_cleared == 0) return (-1); return (0); } static boolean_t find_guid(nvlist_t *nv, uint64_t guid) { uint64_t tmp; nvlist_t **child; uint_t c, children; verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &tmp) == 0); if (tmp == guid) return (B_TRUE); if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, &children) == 0) { for (c = 0; c < children; c++) if (find_guid(child[c], guid)) return (B_TRUE); } return (B_FALSE); } typedef struct aux_cbdata { const char *cb_type; uint64_t cb_guid; zpool_handle_t *cb_zhp; } aux_cbdata_t; static int find_aux(zpool_handle_t *zhp, void *data) { aux_cbdata_t *cbp = data; nvlist_t **list; uint_t i, count; uint64_t guid; nvlist_t *nvroot; verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); if (nvlist_lookup_nvlist_array(nvroot, cbp->cb_type, &list, &count) == 0) { for (i = 0; i < count; i++) { verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, &guid) == 0); if (guid == cbp->cb_guid) { cbp->cb_zhp = zhp; return (1); } } } zpool_close(zhp); return (0); } /* * Determines if the pool is in use. If so, it returns true and the state of * the pool as well as the name of the pool. Name string is allocated and * must be freed by the caller. */ int zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr, boolean_t *inuse) { nvlist_t *config; char *name; boolean_t ret; uint64_t guid, vdev_guid; zpool_handle_t *zhp; nvlist_t *pool_config; uint64_t stateval, isspare; aux_cbdata_t cb = { 0 }; boolean_t isactive; *inuse = B_FALSE; if (zpool_read_label(fd, &config, NULL) != 0) { (void) no_memory(hdl); return (-1); } if (config == NULL) return (0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &stateval) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0); if (stateval != POOL_STATE_SPARE && stateval != POOL_STATE_L2CACHE) { verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &name) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) == 0); } switch (stateval) { case POOL_STATE_EXPORTED: /* * A pool with an exported state may in fact be imported * read-only, so check the in-core state to see if it's * active and imported read-only. If it is, set * its state to active. */ if (pool_active(hdl, name, guid, &isactive) == 0 && isactive && (zhp = zpool_open_canfail(hdl, name)) != NULL) { if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL)) stateval = POOL_STATE_ACTIVE; /* * All we needed the zpool handle for is the * readonly prop check. */ zpool_close(zhp); } ret = B_TRUE; break; case POOL_STATE_ACTIVE: /* * For an active pool, we have to determine if it's really part * of a currently active pool (in which case the pool will exist * and the guid will be the same), or whether it's part of an * active pool that was disconnected without being explicitly * exported. */ if (pool_active(hdl, name, guid, &isactive) != 0) { nvlist_free(config); return (-1); } if (isactive) { /* * Because the device may have been removed while * offlined, we only report it as active if the vdev is * still present in the config. Otherwise, pretend like * it's not in use. */ if ((zhp = zpool_open_canfail(hdl, name)) != NULL && (pool_config = zpool_get_config(zhp, NULL)) != NULL) { nvlist_t *nvroot; verify(nvlist_lookup_nvlist(pool_config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); ret = find_guid(nvroot, vdev_guid); } else { ret = B_FALSE; } /* * If this is an active spare within another pool, we * treat it like an unused hot spare. This allows the * user to create a pool with a hot spare that currently * in use within another pool. Since we return B_TRUE, * libdiskmgt will continue to prevent generic consumers * from using the device. */ if (ret && nvlist_lookup_uint64(config, ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare) stateval = POOL_STATE_SPARE; if (zhp != NULL) zpool_close(zhp); } else { stateval = POOL_STATE_POTENTIALLY_ACTIVE; ret = B_TRUE; } break; case POOL_STATE_SPARE: /* * For a hot spare, it can be either definitively in use, or * potentially active. To determine if it's in use, we iterate * over all pools in the system and search for one with a spare * with a matching guid. * * Due to the shared nature of spares, we don't actually report * the potentially active case as in use. This means the user * can freely create pools on the hot spares of exported pools, * but to do otherwise makes the resulting code complicated, and * we end up having to deal with this case anyway. */ cb.cb_zhp = NULL; cb.cb_guid = vdev_guid; cb.cb_type = ZPOOL_CONFIG_SPARES; if (zpool_iter(hdl, find_aux, &cb) == 1) { name = (char *)zpool_get_name(cb.cb_zhp); ret = B_TRUE; } else { ret = B_FALSE; } break; case POOL_STATE_L2CACHE: /* * Check if any pool is currently using this l2cache device. */ cb.cb_zhp = NULL; cb.cb_guid = vdev_guid; cb.cb_type = ZPOOL_CONFIG_L2CACHE; if (zpool_iter(hdl, find_aux, &cb) == 1) { name = (char *)zpool_get_name(cb.cb_zhp); ret = B_TRUE; } else { ret = B_FALSE; } break; default: ret = B_FALSE; } if (ret) { if ((*namestr = zfs_strdup(hdl, name)) == NULL) { if (cb.cb_zhp) zpool_close(cb.cb_zhp); nvlist_free(config); return (-1); } *state = (pool_state_t)stateval; } if (cb.cb_zhp) zpool_close(cb.cb_zhp); nvlist_free(config); *inuse = ret; return (0); } diff --git a/lib/libzfs/os/freebsd/libzfs_compat.c b/lib/libzfs/os/freebsd/libzfs_compat.c index 3c5f684c6889..4d7421df8d3b 100644 --- a/lib/libzfs/os/freebsd/libzfs_compat.c +++ b/lib/libzfs/os/freebsd/libzfs_compat.c @@ -1,355 +1,355 @@ /* * 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 Martin Matuska . All rights reserved. */ #include -#include +#include "../../libzfs_impl.h" #include #include #include #include #include #include #include #include #ifdef IN_BASE #define ZFS_KMOD "zfs" #else #define ZFS_KMOD "openzfs" #endif 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 buf[MAXPATHLEN]; const char *bp, *np, *op, *p; struct stat sb; eacces = 0; /* If it's an absolute or relative path name, it's easy. */ if (strchr(name, '/')) { bp = name; op = 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); } op = path; ln = strlen(name); while (op != NULL) { np = strchrnul(op, ':'); /* * It's a SHELL path -- double, leading and trailing colons * mean the current directory. */ if (np == op) { /* Empty component. */ p = "."; lp = 1; } else { /* Non-empty component. */ p = op; lp = np - op; } /* Advance to the next component or terminate after this. */ if (*np == '\0') op = NULL; else op = np + 1; /* * 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) ; /* * cnt may be 0 above; always allocate at least * 3 entries so that we can at least fit "sh", bp, and * the NULL terminator. We can rely on cnt to take into * account the NULL terminator in all other scenarios, * as we drop argv[0]. */ memp = alloca(MAX(3, cnt + 2) * sizeof (char *)); if (memp == NULL) { /* errno = ENOMEM; XXX override ENOEXEC? */ goto done; } if (cnt > 0) { memp[0] = argv[0]; memp[1] = bp; bcopy(argv + 1, memp + 2, cnt * sizeof (char *)); } else { memp[0] = "sh"; memp[1] = bp; memp[2] = NULL; } (void) 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)); } #define ERRBUFLEN 256 static __thread char errbuf[ERRBUFLEN]; const char * libzfs_error_init(int error) { char *msg = errbuf; size_t len, msglen = ERRBUFLEN; if (modfind("zfs") < 0) { len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN, "Failed to load %s module: "), ZFS_KMOD); msg += len; msglen -= len; } (void) snprintf(msg, msglen, "%s", strerror(error)); return (errbuf); } 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. */ int libzfs_load_module(void) { /* * XXX: kldfind(ZFS_KMOD) would be nice here, but we retain * modfind("zfs") so out-of-base openzfs userland works with the * in-base module. */ if (modfind("zfs") < 0) { /* Not present in kernel, try loading it. */ if (kldload(ZFS_KMOD) < 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, const 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 = zfs_ioctl(hdl, cmd, &zc)) != 0) zfs_standard_error(hdl, errno, errbuf); return (ret); } /* * Set loader options for next boot. */ int zpool_nextboot(libzfs_handle_t *hdl, uint64_t pool_guid, uint64_t dev_guid, const char *command) { zfs_cmd_t zc = {"\0"}; nvlist_t *args; int error; args = fnvlist_alloc(); fnvlist_add_uint64(args, ZPOOL_CONFIG_POOL_GUID, pool_guid); fnvlist_add_uint64(args, ZPOOL_CONFIG_GUID, dev_guid); fnvlist_add_string(args, "command", command); error = zcmd_write_src_nvlist(hdl, &zc, args); if (error == 0) error = zfs_ioctl(hdl, ZFS_IOC_NEXTBOOT, &zc); zcmd_free_nvlists(&zc); nvlist_free(args); return (error); } /* * 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_zmount.c b/lib/libzfs/os/freebsd/libzfs_zmount.c index 699d330ebdb4..e1febe6a2d91 100644 --- a/lib/libzfs/os/freebsd/libzfs_zmount.c +++ b/lib/libzfs/os/freebsd/libzfs_zmount.c @@ -1,135 +1,135 @@ /* * Copyright (c) 2006 Pawel Jakub Dawidek * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include -#include "libzfs_impl.h" +#include "../../libzfs_impl.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 (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(zfs_handle_t *zhp, const char *mntpt, char *opts, int flags) { return (do_mount_(zfs_get_name(zhp), mntpt, flags, MNTTYPE_ZFS, NULL, 0, opts, sizeof (mntpt))); } int do_unmount(const char *mntpt, int flags) { if (unmount(mntpt, flags) < 0) return (errno); return (0); } int zfs_mount_delegation_check(void) { return (0); } diff --git a/lib/libzfs/os/linux/libzfs_mount_os.c b/lib/libzfs/os/linux/libzfs_mount_os.c index 21d64053862e..547895d7e370 100644 --- a/lib/libzfs/os/linux/libzfs_mount_os.c +++ b/lib/libzfs/os/linux/libzfs_mount_os.c @@ -1,413 +1,413 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021 by Delphix. All rights reserved. * Copyright 2016 Igor Kozhukhov * Copyright 2017 RackTop Systems. * Copyright (c) 2018 Datto Inc. * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include "libzfs_impl.h" +#include "../../libzfs_impl.h" #include #define ZS_COMMENT 0x00000000 /* comment */ #define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */ typedef struct option_map { const char *name; unsigned long mntmask; unsigned long zfsmask; } option_map_t; static const option_map_t option_map[] = { /* Canonicalized filesystem independent options from mount(8) */ { MNTOPT_NOAUTO, MS_COMMENT, ZS_COMMENT }, { MNTOPT_DEFAULTS, MS_COMMENT, ZS_COMMENT }, { MNTOPT_NODEVICES, MS_NODEV, ZS_COMMENT }, { MNTOPT_DEVICES, MS_COMMENT, ZS_COMMENT }, { MNTOPT_DIRSYNC, MS_DIRSYNC, ZS_COMMENT }, { MNTOPT_NOEXEC, MS_NOEXEC, ZS_COMMENT }, { MNTOPT_EXEC, MS_COMMENT, ZS_COMMENT }, { MNTOPT_GROUP, MS_GROUP, ZS_COMMENT }, { MNTOPT_NETDEV, MS_COMMENT, ZS_COMMENT }, { MNTOPT_NOFAIL, MS_COMMENT, ZS_COMMENT }, { MNTOPT_NOSUID, MS_NOSUID, ZS_COMMENT }, { MNTOPT_SUID, MS_COMMENT, ZS_COMMENT }, { MNTOPT_OWNER, MS_OWNER, ZS_COMMENT }, { MNTOPT_REMOUNT, MS_REMOUNT, ZS_COMMENT }, { MNTOPT_RO, MS_RDONLY, ZS_COMMENT }, { MNTOPT_RW, MS_COMMENT, ZS_COMMENT }, { MNTOPT_SYNC, MS_SYNCHRONOUS, ZS_COMMENT }, { MNTOPT_USER, MS_USERS, ZS_COMMENT }, { MNTOPT_USERS, MS_USERS, ZS_COMMENT }, /* acl flags passed with util-linux-2.24 mount command */ { MNTOPT_ACL, MS_POSIXACL, ZS_COMMENT }, { MNTOPT_NOACL, MS_COMMENT, ZS_COMMENT }, { MNTOPT_POSIXACL, MS_POSIXACL, ZS_COMMENT }, #ifdef MS_NOATIME { MNTOPT_NOATIME, MS_NOATIME, ZS_COMMENT }, { MNTOPT_ATIME, MS_COMMENT, ZS_COMMENT }, #endif #ifdef MS_NODIRATIME { MNTOPT_NODIRATIME, MS_NODIRATIME, ZS_COMMENT }, { MNTOPT_DIRATIME, MS_COMMENT, ZS_COMMENT }, #endif #ifdef MS_RELATIME { MNTOPT_RELATIME, MS_RELATIME, ZS_COMMENT }, { MNTOPT_NORELATIME, MS_COMMENT, ZS_COMMENT }, #endif #ifdef MS_STRICTATIME { MNTOPT_STRICTATIME, MS_STRICTATIME, ZS_COMMENT }, { MNTOPT_NOSTRICTATIME, MS_COMMENT, ZS_COMMENT }, #endif #ifdef MS_LAZYTIME { MNTOPT_LAZYTIME, MS_LAZYTIME, ZS_COMMENT }, #endif { MNTOPT_CONTEXT, MS_COMMENT, ZS_COMMENT }, { MNTOPT_FSCONTEXT, MS_COMMENT, ZS_COMMENT }, { MNTOPT_DEFCONTEXT, MS_COMMENT, ZS_COMMENT }, { MNTOPT_ROOTCONTEXT, MS_COMMENT, ZS_COMMENT }, #ifdef MS_I_VERSION { MNTOPT_IVERSION, MS_I_VERSION, ZS_COMMENT }, #endif #ifdef MS_MANDLOCK { MNTOPT_NBMAND, MS_MANDLOCK, ZS_COMMENT }, { MNTOPT_NONBMAND, MS_COMMENT, ZS_COMMENT }, #endif /* Valid options not found in mount(8) */ { MNTOPT_BIND, MS_BIND, ZS_COMMENT }, #ifdef MS_REC { MNTOPT_RBIND, MS_BIND|MS_REC, ZS_COMMENT }, #endif { MNTOPT_COMMENT, MS_COMMENT, ZS_COMMENT }, #ifdef MS_NOSUB { MNTOPT_NOSUB, MS_NOSUB, ZS_COMMENT }, #endif #ifdef MS_SILENT { MNTOPT_QUIET, MS_SILENT, ZS_COMMENT }, #endif /* Custom zfs options */ { MNTOPT_XATTR, MS_COMMENT, ZS_COMMENT }, { MNTOPT_NOXATTR, MS_COMMENT, ZS_COMMENT }, { MNTOPT_ZFSUTIL, MS_COMMENT, ZS_ZFSUTIL }, { NULL, 0, 0 } }; /* * Break the mount option in to a name/value pair. The name is * validated against the option map and mount flags set accordingly. */ static int parse_option(char *mntopt, unsigned long *mntflags, unsigned long *zfsflags, int sloppy) { const option_map_t *opt; char *ptr, *name, *value = NULL; int error = 0; name = strdup(mntopt); if (name == NULL) return (ENOMEM); for (ptr = name; ptr && *ptr; ptr++) { if (*ptr == '=') { *ptr = '\0'; value = ptr+1; VERIFY3P(value, !=, NULL); break; } } for (opt = option_map; opt->name != NULL; opt++) { if (strncmp(name, opt->name, strlen(name)) == 0) { *mntflags |= opt->mntmask; *zfsflags |= opt->zfsmask; error = 0; goto out; } } if (!sloppy) error = ENOENT; out: /* If required further process on the value may be done here */ free(name); return (error); } /* * Translate the mount option string in to MS_* mount flags for the * kernel vfs. When sloppy is non-zero unknown options will be ignored * otherwise they are considered fatal are copied in to badopt. */ int zfs_parse_mount_options(char *mntopts, unsigned long *mntflags, unsigned long *zfsflags, int sloppy, char *badopt, char *mtabopt) { int error = 0, quote = 0, flag = 0, count = 0; char *ptr, *opt, *opts; opts = strdup(mntopts); if (opts == NULL) return (ENOMEM); *mntflags = 0; opt = NULL; /* * Scan through all mount options which must be comma delimited. * We must be careful to notice regions which are double quoted * and skip commas in these regions. Each option is then checked * to determine if it is a known option. */ for (ptr = opts; ptr && !flag; ptr++) { if (opt == NULL) opt = ptr; if (*ptr == '"') quote = !quote; if (quote) continue; if (*ptr == '\0') flag = 1; if ((*ptr == ',') || (*ptr == '\0')) { *ptr = '\0'; error = parse_option(opt, mntflags, zfsflags, sloppy); if (error) { strcpy(badopt, opt); goto out; } if (!(*mntflags & MS_REMOUNT) && !(*zfsflags & ZS_ZFSUTIL) && mtabopt != NULL) { if (count > 0) strlcat(mtabopt, ",", MNT_LINE_MAX); strlcat(mtabopt, opt, MNT_LINE_MAX); count++; } opt = NULL; } } out: free(opts); return (error); } static void append_mntopt(const char *name, const char *val, char *mntopts, char *mtabopt, boolean_t quote) { char tmp[MNT_LINE_MAX]; snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val); if (mntopts) strlcat(mntopts, tmp, MNT_LINE_MAX); if (mtabopt) strlcat(mtabopt, tmp, MNT_LINE_MAX); } static void zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name, char *mntopts, char *mtabopt) { char context[ZFS_MAXPROPLEN]; if (zfs_prop_get(zhp, zpt, context, sizeof (context), NULL, NULL, 0, B_FALSE) == 0) { if (strcmp(context, "none") != 0) append_mntopt(name, context, mntopts, mtabopt, B_TRUE); } } void zfs_adjust_mount_options(zfs_handle_t *zhp, const char *mntpoint, char *mntopts, char *mtabopt) { char prop[ZFS_MAXPROPLEN]; /* * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists * if it does, create a tmp variable in case it's needed * checks to see if the selinux context is set to the default * if it is, allow the setting of the other context properties * this is needed because the 'context' property overrides others * if it is not the default, set the 'context' property */ if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop), NULL, NULL, 0, B_FALSE) == 0) { if (strcmp(prop, "none") == 0) { zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT, MNTOPT_FSCONTEXT, mntopts, mtabopt); zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT, MNTOPT_DEFCONTEXT, mntopts, mtabopt); zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT, mntopts, mtabopt); } else { append_mntopt(MNTOPT_CONTEXT, prop, mntopts, mtabopt, B_TRUE); } } /* A hint used to determine an auto-mounted snapshot mount point */ append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE); } /* * By default the filesystem by preparing the mount options (i.e. parsing * some flags from the "opts" parameter into the "flags" parameter) and then * directly calling the system call mount(2). We don't need the mount utility * or update /etc/mtab, because this is a symlink on all modern systems. * * If the environment variable ZFS_MOUNT_HELPER is set, we fall back to the * previous behavior: * The filesystem is mounted by invoking the system mount utility rather * than by the system call mount(2). This ensures that the /etc/mtab * file is correctly locked for the update. Performing our own locking * and /etc/mtab update requires making an unsafe assumption about how * the mount utility performs its locking. Unfortunately, this also means * in the case of a mount failure we do not have the exact errno. We must * make due with return value from the mount process. */ int do_mount(zfs_handle_t *zhp, const char *mntpt, char *opts, int flags) { const char *src = zfs_get_name(zhp); int error = 0; if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) { char badopt[MNT_LINE_MAX] = {0}; unsigned long mntflags = flags, zfsflags; char myopts[MNT_LINE_MAX] = {0}; if (zfs_parse_mount_options(opts, &mntflags, &zfsflags, 0, badopt, NULL)) { return (EINVAL); } strlcat(myopts, opts, MNT_LINE_MAX); zfs_adjust_mount_options(zhp, mntpt, myopts, NULL); if (mount(src, mntpt, MNTTYPE_ZFS, mntflags, myopts)) { return (errno); } } else { char *argv[9] = { "/bin/mount", "--no-canonicalize", "-t", MNTTYPE_ZFS, "-o", opts, (char *)src, (char *)mntpt, (char *)NULL }; /* Return only the most critical mount error */ error = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE); if (error) { if (error & MOUNT_FILEIO) { error = EIO; } else if (error & MOUNT_USER) { error = EINTR; } else if (error & MOUNT_SOFTWARE) { error = EPIPE; } else if (error & MOUNT_BUSY) { error = EBUSY; } else if (error & MOUNT_SYSERR) { error = EAGAIN; } else if (error & MOUNT_USAGE) { error = EINVAL; } else error = ENXIO; /* Generic error */ } } return (error); } int do_unmount(const char *mntpt, int flags) { if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) { int rv = umount2(mntpt, flags); return (rv < 0 ? errno : 0); } char force_opt[] = "-f"; char lazy_opt[] = "-l"; char *argv[7] = { "/bin/umount", "-t", MNTTYPE_ZFS, NULL, NULL, NULL, NULL }; int rc, count = 3; if (flags & MS_FORCE) { argv[count] = force_opt; count++; } if (flags & MS_DETACH) { argv[count] = lazy_opt; count++; } argv[count] = (char *)mntpt; rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE); return (rc ? EINVAL : 0); } int zfs_mount_delegation_check(void) { return ((geteuid() != 0) ? EACCES : 0); } diff --git a/lib/libzfs/os/linux/libzfs_pool_os.c b/lib/libzfs/os/linux/libzfs_pool_os.c index 747b5652f7c0..90eb8db50790 100644 --- a/lib/libzfs/os/linux/libzfs_pool_os.c +++ b/lib/libzfs/os/linux/libzfs_pool_os.c @@ -1,342 +1,342 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2018 by Delphix. All rights reserved. * Copyright 2016 Igor Kozhukhov * Copyright (c) 2018 Datto Inc. * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2018, loli10K */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "zfs_namecheck.h" #include "zfs_prop.h" -#include "libzfs_impl.h" +#include "../../libzfs_impl.h" #include "zfs_comutil.h" #include "zfeature_common.h" /* * If the device has being dynamically expanded then we need to relabel * the disk to use the new unallocated space. */ int zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg) { int fd, error; if ((fd = open(path, O_RDWR|O_DIRECT|O_CLOEXEC)) < 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " "relabel '%s': unable to open device: %d"), path, errno); return (zfs_error(hdl, EZFS_OPENFAILED, msg)); } /* * It's possible that we might encounter an error if the device * does not have any unallocated space left. If so, we simply * ignore that error and continue on. */ error = efi_use_whole_disk(fd); /* Flush the buffers to disk and invalidate the page cache. */ (void) fsync(fd); (void) ioctl(fd, BLKFLSBUF); (void) close(fd); if (error && error != VT_ENOSPC) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " "relabel '%s': unable to read disk capacity"), path); return (zfs_error(hdl, EZFS_NOCAP, msg)); } return (0); } /* * Read the EFI label from the config, if a label does not exist then * pass back the error to the caller. If the caller has passed a non-NULL * diskaddr argument then we set it to the starting address of the EFI * partition. */ static int read_efi_label(nvlist_t *config, diskaddr_t *sb) { char *path; int fd; char diskname[MAXPATHLEN]; int err = -1; if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) return (err); (void) snprintf(diskname, sizeof (diskname), "%s%s", DISK_ROOT, strrchr(path, '/')); if ((fd = open(diskname, O_RDONLY|O_DIRECT|O_CLOEXEC)) >= 0) { struct dk_gpt *vtoc; if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { if (sb != NULL) *sb = vtoc->efi_parts[0].p_start; efi_free(vtoc); } (void) close(fd); } return (err); } /* * determine where a partition starts on a disk in the current * configuration */ static diskaddr_t find_start_block(nvlist_t *config) { nvlist_t **child; uint_t c, children; diskaddr_t sb = MAXOFFSET_T; uint64_t wholedisk; if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk) != 0 || !wholedisk) { return (MAXOFFSET_T); } if (read_efi_label(config, &sb) < 0) sb = MAXOFFSET_T; return (sb); } for (c = 0; c < children; c++) { sb = find_start_block(child[c]); if (sb != MAXOFFSET_T) { return (sb); } } return (MAXOFFSET_T); } static int zpool_label_disk_check(char *path) { struct dk_gpt *vtoc; int fd, err; if ((fd = open(path, O_RDONLY|O_DIRECT|O_CLOEXEC)) < 0) return (errno); if ((err = efi_alloc_and_read(fd, &vtoc)) != 0) { (void) close(fd); return (err); } if (vtoc->efi_flags & EFI_GPT_PRIMARY_CORRUPT) { efi_free(vtoc); (void) close(fd); return (EIDRM); } efi_free(vtoc); (void) close(fd); return (0); } /* * Generate a unique partition name for the ZFS member. Partitions must * have unique names to ensure udev will be able to create symlinks under * /dev/disk/by-partlabel/ for all pool members. The partition names are * of the form -. */ static void zpool_label_name(char *label_name, int label_size) { uint64_t id = 0; int fd; fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); if (fd >= 0) { if (read(fd, &id, sizeof (id)) != sizeof (id)) id = 0; close(fd); } if (id == 0) id = (((uint64_t)rand()) << 32) | (uint64_t)rand(); snprintf(label_name, label_size, "zfs-%016llx", (u_longlong_t)id); } /* * Label an individual disk. The name provided is the short name, * stripped of any leading /dev path. */ int zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name) { char path[MAXPATHLEN]; struct dk_gpt *vtoc; int rval, fd; size_t resv = EFI_MIN_RESV_SIZE; uint64_t slice_size; diskaddr_t start_block; char errbuf[1024]; /* prepare an error message just in case */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); if (zhp) { nvlist_t *nvroot; verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); if (zhp->zpool_start_block == 0) start_block = find_start_block(nvroot); else start_block = zhp->zpool_start_block; zhp->zpool_start_block = start_block; } else { /* new pool */ start_block = NEW_START_BLOCK; } (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name); if ((fd = open(path, O_RDWR|O_DIRECT|O_EXCL|O_CLOEXEC)) < 0) { /* * This shouldn't happen. We've long since verified that this * is a valid device. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " "label '%s': unable to open device: %d"), path, errno); return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); } if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { /* * The only way this can fail is if we run out of memory, or we * were unable to read the disk's capacity */ if (errno == ENOMEM) (void) no_memory(hdl); (void) close(fd); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " "label '%s': unable to read disk capacity"), path); return (zfs_error(hdl, EZFS_NOCAP, errbuf)); } slice_size = vtoc->efi_last_u_lba + 1; slice_size -= EFI_MIN_RESV_SIZE; if (start_block == MAXOFFSET_T) start_block = NEW_START_BLOCK; slice_size -= start_block; slice_size = P2ALIGN(slice_size, PARTITION_END_ALIGNMENT); vtoc->efi_parts[0].p_start = start_block; vtoc->efi_parts[0].p_size = slice_size; /* * Why we use V_USR: V_BACKUP confuses users, and is considered * disposable by some EFI utilities (since EFI doesn't have a backup * slice). V_UNASSIGNED is supposed to be used only for zero size * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, * etc. were all pretty specific. V_USR is as close to reality as we * can get, in the absence of V_OTHER. */ vtoc->efi_parts[0].p_tag = V_USR; zpool_label_name(vtoc->efi_parts[0].p_name, EFI_PART_NAME_LEN); vtoc->efi_parts[8].p_start = slice_size + start_block; vtoc->efi_parts[8].p_size = resv; vtoc->efi_parts[8].p_tag = V_RESERVED; rval = efi_write(fd, vtoc); /* Flush the buffers to disk and invalidate the page cache. */ (void) fsync(fd); (void) ioctl(fd, BLKFLSBUF); if (rval == 0) rval = efi_rescan(fd); /* * Some block drivers (like pcata) may not support EFI GPT labels. * Print out a helpful error message directing the user to manually * label the disk and give a specific slice. */ if (rval != 0) { (void) close(fd); efi_free(vtoc); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "try using " "parted(8) and then provide a specific slice: %d"), rval); return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); } (void) close(fd); efi_free(vtoc); (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name); (void) zfs_append_partition(path, MAXPATHLEN); /* Wait to udev to signal use the device has settled. */ rval = zpool_label_disk_wait(path, DISK_LABEL_WAIT); if (rval) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to " "detect device partitions on '%s': %d"), path, rval); return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); } /* We can't be to paranoid. Read the label back and verify it. */ (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name); rval = zpool_label_disk_check(path); if (rval) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "freshly written " "EFI label on '%s' is damaged. Ensure\nthis device " "is not in use, and is functioning properly: %d"), path, rval); return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); } return (0); } diff --git a/lib/libzfs/os/linux/libzfs_sendrecv_os.c b/lib/libzfs/os/linux/libzfs_sendrecv_os.c index ac7ab95a39b6..593c38ec62df 100644 --- a/lib/libzfs/os/linux/libzfs_sendrecv_os.c +++ b/lib/libzfs/os/linux/libzfs_sendrecv_os.c @@ -1,52 +1,52 @@ /* * 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 -#include "libzfs_impl.h" +#include "../../libzfs_impl.h" #ifndef F_SETPIPE_SZ #define F_SETPIPE_SZ (F_SETLEASE + 7) #endif /* F_SETPIPE_SZ */ #ifndef F_GETPIPE_SZ #define F_GETPIPE_SZ (F_GETLEASE + 7) #endif /* F_GETPIPE_SZ */ void libzfs_set_pipe_max(int infd) { FILE *procf = fopen("/proc/sys/fs/pipe-max-size", "re"); if (procf != NULL) { unsigned long max_psize; long cur_psize; if (fscanf(procf, "%lu", &max_psize) > 0) { cur_psize = fcntl(infd, F_GETPIPE_SZ); if (cur_psize > 0 && max_psize > (unsigned long) cur_psize) fcntl(infd, F_SETPIPE_SZ, max_psize); } fclose(procf); } } diff --git a/lib/libzfs/os/linux/libzfs_util_os.c b/lib/libzfs/os/linux/libzfs_util_os.c index e2482c57135a..b116f92d97af 100644 --- a/lib/libzfs/os/linux/libzfs_util_os.c +++ b/lib/libzfs/os/linux/libzfs_util_os.c @@ -1,215 +1,215 @@ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include "libzfs_impl.h" +#include "../../libzfs_impl.h" #include "zfs_prop.h" #include #include #define ZDIFF_SHARESDIR "/.zfs/shares/" int zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc) { return (ioctl(hdl->libzfs_fd, request, zc)); } const char * libzfs_error_init(int error) { switch (error) { case ENXIO: return (dgettext(TEXT_DOMAIN, "The ZFS modules are not " "loaded.\nTry running '/sbin/modprobe zfs' as root " "to load them.")); case ENOENT: return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts " "are required.\nTry running 'udevadm trigger' and 'mount " "-t proc proc /proc' as root.")); case ENOEXEC: return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be " "auto-loaded.\nTry running '/sbin/modprobe zfs' as " "root to manually load them.")); case EACCES: return (dgettext(TEXT_DOMAIN, "Permission denied the " "ZFS utilities must be run as root.")); default: return (dgettext(TEXT_DOMAIN, "Failed to initialize the " "libzfs library.")); } } static int libzfs_module_loaded(const char *module) { const char path_prefix[] = "/sys/module/"; char path[256]; memcpy(path, path_prefix, sizeof (path_prefix) - 1); strcpy(path + sizeof (path_prefix) - 1, module); return (access(path, F_OK) == 0); } /* * 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 to wait for ZFS_DEV */ static int libzfs_load_module_impl(const char *module) { char *argv[4] = {"/sbin/modprobe", "-q", (char *)module, (char *)0}; char *load_str, *timeout_str; long timeout = 10; /* seconds */ long busy_timeout = 10; /* milliseconds */ int load = 0, fd; hrtime_t start; /* Optionally request module loading */ if (!libzfs_module_loaded(module)) { load_str = getenv("ZFS_MODULE_LOADING"); if (load_str) { if (!strncasecmp(load_str, "YES", strlen("YES")) || !strncasecmp(load_str, "ON", strlen("ON"))) load = 1; else load = 0; } if (load) { if (libzfs_run_process("/sbin/modprobe", argv, 0)) return (ENOEXEC); } if (!libzfs_module_loaded(module)) return (ENXIO); } /* * Device creation by udev is asynchronous and waiting may be * required. Busy wait for 10ms and then fall back to polling every * 10ms for the allowed timeout (default 10s, max 10m). This is * done to optimize for the common case where the device is * immediately available and to avoid penalizing the possible * case where udev is slow or unable to create the device. */ timeout_str = getenv("ZFS_MODULE_TIMEOUT"); if (timeout_str) { timeout = strtol(timeout_str, NULL, 0); timeout = MAX(MIN(timeout, (10 * 60)), 0); /* 0 <= N <= 600 */ } start = gethrtime(); do { fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC); if (fd >= 0) { (void) close(fd); return (0); } else if (errno != ENOENT) { return (errno); } else if (NSEC2MSEC(gethrtime() - start) < busy_timeout) { sched_yield(); } else { usleep(10 * MILLISEC); } } while (NSEC2MSEC(gethrtime() - start) < (timeout * MILLISEC)); return (ENOENT); } int libzfs_load_module(void) { return (libzfs_load_module_impl(ZFS_DRIVER)); } int find_shares_object(differ_info_t *di) { char fullpath[MAXPATHLEN]; struct stat64 sb = { 0 }; (void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN); (void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN); if (stat64(fullpath, &sb) != 0) { (void) snprintf(di->errbuf, sizeof (di->errbuf), dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath); return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf)); } di->shares = (uint64_t)sb.st_ino; return (0); } /* * Fill given version buffer with zfs kernel version read from ZFS_SYSFS_DIR * Returns 0 on success, and -1 on error (with errno set) */ int zfs_version_kernel(char *version, int len) { int _errno; int fd; int rlen; if ((fd = open(ZFS_SYSFS_DIR "/version", O_RDONLY | O_CLOEXEC)) == -1) return (-1); if ((rlen = read(fd, version, len)) == -1) { version[0] = '\0'; _errno = errno; (void) close(fd); errno = _errno; return (-1); } version[rlen-1] = '\0'; /* discard '\n' */ if (close(fd) == -1) return (-1); return (0); }