summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authoreschrock <none@none>2006-05-30 15:47:16 -0700
committereschrock <none@none>2006-05-30 15:47:16 -0700
commit99653d4ee642c6528e88224f12409a5f23060994 (patch)
tree5cbcc540b8ed86b6a008f1084f9ca031368d926f /usr/src/lib
parent354a1801a85aa6b61ff4d5e290ab708ba57e56a3 (diff)
downloadillumos-joyent-99653d4ee642c6528e88224f12409a5f23060994.tar.gz
PSARC 2006/223 ZFS Hot Spares
PSARC 2006/303 ZFS Clone Promotion 6276916 support for "clone swap" 6288488 du reports misleading size on RAID-Z 6393490 libzfs should be a real library 6397148 fbufs debug code should be removed from buf_hash_insert() 6405966 Hot Spare support in ZFS 6409302 passing a non-root vdev via zpool_create() panics system 6415739 assertion failed: !(zio->io_flags & 0x00040) 6416759 ::dbufs does not find bonus buffers anymore 6417978 double parity RAID-Z a.k.a. RAID6 6424554 full block re-writes need not read data in 6425111 detaching an offline device can result in import confusion
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/libdiskmgt/common/entry.c9
-rw-r--r--usr/src/lib/libdiskmgt/common/inuse_zpool.c36
-rw-r--r--usr/src/lib/libdiskmgt/common/libdiskmgt.h6
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h127
-rw-r--r--usr/src/lib/libzfs/common/libzfs_changelist.c70
-rw-r--r--usr/src/lib/libzfs/common/libzfs_config.c165
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c1644
-rw-r--r--usr/src/lib/libzfs/common/libzfs_graph.c198
-rw-r--r--usr/src/lib/libzfs/common/libzfs_impl.h49
-rw-r--r--usr/src/lib/libzfs/common/libzfs_import.c507
-rw-r--r--usr/src/lib/libzfs/common/libzfs_mount.c193
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c978
-rw-r--r--usr/src/lib/libzfs/common/libzfs_status.c16
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c429
-rw-r--r--usr/src/lib/libzfs/spec/libzfs.spec53
-rw-r--r--usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c18
-rw-r--r--usr/src/lib/libzfs_jni/common/libzfs_jni_main.c24
-rw-r--r--usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c3
-rw-r--r--usr/src/lib/libzfs_jni/common/libzfs_jni_util.h3
-rw-r--r--usr/src/lib/libzpool/common/util.c10
20 files changed, 2490 insertions, 2048 deletions
diff --git a/usr/src/lib/libdiskmgt/common/entry.c b/usr/src/lib/libdiskmgt/common/entry.c
index 860801b41d..61bc9d60d4 100644
--- a/usr/src/lib/libdiskmgt/common/entry.c
+++ b/usr/src/lib/libdiskmgt/common/entry.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -966,6 +965,10 @@ dm_get_usage_string(char *what, char *how, char **usage_string)
*usage_string = dgettext(TEXT_DOMAIN,
"%s is part of active ZFS pool %s. Please see zpool(1M)."
"\n");
+ } else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) {
+ *usage_string = dgettext(TEXT_DOMAIN,
+ "%s is reserved as a hot spare for ZFS pool %s. Please "
+ "see zpool(1M).\n");
}
}
void
diff --git a/usr/src/lib/libdiskmgt/common/inuse_zpool.c b/usr/src/lib/libdiskmgt/common/inuse_zpool.c
index 1637ace92d..a7cf203a2f 100644
--- a/usr/src/lib/libdiskmgt/common/inuse_zpool.c
+++ b/usr/src/lib/libdiskmgt/common/inuse_zpool.c
@@ -46,17 +46,21 @@
#include <ctype.h>
#include <sys/fs/zfs.h>
+#include <libzfs.h>
#include "libdiskmgt.h"
#include "disks_private.h"
/*
* Pointers to libzfs.so functions that we dynamically resolve.
*/
-static int (*zfsdl_zpool_in_use)(int fd, pool_state_t *state, char **name);
+static int (*zfsdl_zpool_in_use)(libzfs_handle_t *hdl, int fd,
+ pool_state_t *state, char **name, boolean_t *);
+static libzfs_handle_t *(*zfsdl_libzfs_init)(boolean_t);
static mutex_t init_lock = DEFAULTMUTEX;
static rwlock_t zpool_lock = DEFAULTRWLOCK;
-static int initialized = 0;
+static boolean_t initialized;
+static libzfs_handle_t *zfs_hdl;
static void *init_zpool();
@@ -67,6 +71,7 @@ inuse_zpool_common(char *slice, nvlist_t *attrs, int *errp, char *type)
char *name;
int fd;
pool_state_t state;
+ boolean_t used;
*errp = 0;
if (slice == NULL) {
@@ -83,15 +88,21 @@ inuse_zpool_common(char *slice, nvlist_t *attrs, int *errp, char *type)
(void) mutex_unlock(&init_lock);
return (found);
}
- initialized = 1;
+ initialized = B_TRUE;
}
(void) mutex_unlock(&init_lock);
(void) rw_rdlock(&zpool_lock);
if ((fd = open(slice, O_RDONLY)) > 0) {
- if (zfsdl_zpool_in_use(fd, &state, &name)) {
+ name = NULL;
+ if (zfsdl_zpool_in_use(zfs_hdl, fd, &state,
+ &name, &used) == 0 && used) {
if (strcmp(type, DM_USE_ACTIVE_ZPOOL) == 0) {
- if (state == POOL_STATE_ACTIVE)
+ if (state == POOL_STATE_ACTIVE) {
found = 1;
+ } else if (state == POOL_STATE_SPARE) {
+ found = 1;
+ type = DM_USE_SPARE_ZPOOL;
+ }
} else {
found = 1;
}
@@ -100,9 +111,11 @@ inuse_zpool_common(char *slice, nvlist_t *attrs, int *errp, char *type)
libdiskmgt_add_str(attrs, DM_USED_BY,
type, errp);
libdiskmgt_add_str(attrs, DM_USED_NAME,
- name, errp);
+ name, errp);
}
}
+ if (name)
+ free(name);
(void) close(fd);
}
(void) rw_unlock(&zpool_lock);
@@ -133,15 +146,24 @@ init_zpool()
if ((lh = dlopen("libzfs.so", RTLD_NOW)) == NULL) {
return (lh);
}
+
/*
* Instantiate the functions needed to get zpool configuration
* data
*/
- if ((zfsdl_zpool_in_use = (int (*)(int, pool_state_t *, char **))
+ if ((zfsdl_libzfs_init = (libzfs_handle_t *(*)(boolean_t))
+ dlsym(lh, "libzfs_init")) == NULL ||
+ (zfsdl_zpool_in_use = (int (*)(libzfs_handle_t *, int,
+ pool_state_t *, char **, boolean_t *))
dlsym(lh, "zpool_in_use")) == NULL) {
(void) dlclose(lh);
return (NULL);
}
+ if ((zfs_hdl = (*zfsdl_libzfs_init)(B_FALSE)) == NULL) {
+ (void) dlclose(lh);
+ return (NULL);
+ }
+
return (lh);
}
diff --git a/usr/src/lib/libdiskmgt/common/libdiskmgt.h b/usr/src/lib/libdiskmgt/common/libdiskmgt.h
index aa6df0967e..7d6fef46d4 100644
--- a/usr/src/lib/libdiskmgt/common/libdiskmgt.h
+++ b/usr/src/lib/libdiskmgt/common/libdiskmgt.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -215,6 +214,7 @@ typedef enum {
#define DM_USE_VFSTAB "vfstab"
#define DM_USE_EXPORTED_ZPOOL "exported_zpool"
#define DM_USE_ACTIVE_ZPOOL "active_zpool"
+#define DM_USE_SPARE_ZPOOL "spare_zpool"
/* event */
#define DM_EV_NAME "name"
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 0044ccd7c9..bf4b2874ad 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -47,16 +47,78 @@ extern "C" {
#define ZFS_MAXPROPLEN MAXPATHLEN
/*
+ * libzfs errors
+ */
+enum {
+ EZFS_NOMEM = 2000, /* out of memory */
+ EZFS_BADPROP, /* invalid property value */
+ EZFS_PROPREADONLY, /* cannot set readonly property */
+ EZFS_PROPTYPE, /* property does not apply to dataset type */
+ EZFS_PROPNONINHERIT, /* property is not inheritable */
+ EZFS_PROPSPACE, /* bad quota or reservation */
+ EZFS_BADTYPE, /* dataset is not of appropriate type */
+ EZFS_BUSY, /* pool or dataset is busy */
+ EZFS_EXISTS, /* pool or dataset already exists */
+ EZFS_NOENT, /* no such pool or dataset */
+ EZFS_BADSTREAM, /* bad backup stream */
+ EZFS_DSREADONLY, /* dataset is readonly */
+ EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */
+ EZFS_VOLHASDATA, /* volume already contains data */
+ EZFS_INVALIDNAME, /* invalid dataset name */
+ EZFS_BADRESTORE, /* unable to restore to destination */
+ EZFS_BADBACKUP, /* backup failed */
+ EZFS_BADTARGET, /* bad attach/detach/replace target */
+ EZFS_NODEVICE, /* no such device in pool */
+ EZFS_BADDEV, /* invalid device to add */
+ EZFS_NOREPLICAS, /* no valid replicas */
+ EZFS_RESILVERING, /* currently resilvering */
+ EZFS_BADVERSION, /* unsupported version */
+ EZFS_POOLUNAVAIL, /* pool is currently unavailable */
+ EZFS_DEVOVERFLOW, /* too many devices in one vdev */
+ EZFS_BADPATH, /* must be an absolute path */
+ EZFS_CROSSTARGET, /* rename or clone across pool or dataset */
+ EZFS_ZONED, /* used improperly in local zone */
+ EZFS_MOUNTFAILED, /* failed to mount dataset */
+ EZFS_UMOUNTFAILED, /* failed to unmount dataset */
+ EZFS_UNSHAREFAILED, /* unshare(1M) failed */
+ EZFS_SHAREFAILED, /* share(1M) failed */
+ EZFS_DEVLINKS, /* failed to create zvol links */
+ EZFS_PERM, /* permission denied */
+ EZFS_NOSPC, /* out of space */
+ EZFS_IO, /* I/O error */
+ EZFS_INTR, /* signal received */
+ EZFS_ISSPARE, /* device is a hot spare */
+ EZFS_INVALCONFIG, /* invalid vdev configuration */
+ EZFS_UNKNOWN /* unknown error */
+};
+
+/*
* Basic handle types
*/
typedef struct zfs_handle zfs_handle_t;
typedef struct zpool_handle zpool_handle_t;
+typedef struct libzfs_handle libzfs_handle_t;
+
+/*
+ * Library initialization
+ */
+extern libzfs_handle_t *libzfs_init(void);
+extern void libzfs_fini(libzfs_handle_t *);
+
+extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
+extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
+
+extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
+
+extern int libzfs_errno(libzfs_handle_t *);
+extern const char *libzfs_error_action(libzfs_handle_t *);
+extern const char *libzfs_error_description(libzfs_handle_t *);
/*
* Basic handle functions
*/
-extern zpool_handle_t *zpool_open(const char *);
-extern zpool_handle_t *zpool_open_canfail(const char *);
+extern zpool_handle_t *zpool_open(libzfs_handle_t *, const char *);
+extern zpool_handle_t *zpool_open_canfail(libzfs_handle_t *, const char *);
extern void zpool_close(zpool_handle_t *);
extern const char *zpool_get_name(zpool_handle_t *);
extern uint64_t zpool_get_guid(zpool_handle_t *);
@@ -64,17 +126,19 @@ extern uint64_t zpool_get_space_used(zpool_handle_t *);
extern uint64_t zpool_get_space_total(zpool_handle_t *);
extern int zpool_get_root(zpool_handle_t *, char *, size_t);
extern int zpool_get_state(zpool_handle_t *);
+extern uint64_t zpool_get_version(zpool_handle_t *);
/*
* Iterate over all active pools in the system.
*/
typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
-extern int zpool_iter(zpool_iter_f, void *);
+extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
/*
* Functions to create and destroy pools
*/
-extern int zpool_create(const char *, nvlist_t *, const char *);
+extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
+ const char *);
extern int zpool_destroy(zpool_handle_t *);
extern int zpool_add(zpool_handle_t *, nvlist_t *);
@@ -88,8 +152,9 @@ extern int zpool_vdev_offline(zpool_handle_t *, const char *, int);
extern int zpool_vdev_attach(zpool_handle_t *, const char *, const char *,
nvlist_t *, int);
extern int zpool_vdev_detach(zpool_handle_t *, const char *);
+extern int zpool_vdev_remove(zpool_handle_t *, const char *);
extern int zpool_clear(zpool_handle_t *, const char *);
-extern uint64_t zpool_vdev_to_guid(zpool_handle_t *, const char *);
+extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *);
/*
* Pool health statistics.
@@ -143,24 +208,25 @@ extern int zpool_get_errlog(zpool_handle_t *, nvlist_t ***, size_t *);
* Import and export functions
*/
extern int zpool_export(zpool_handle_t *);
-extern int zpool_import(nvlist_t *, const char *, const char *);
+extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
+ const char *);
/*
* Search for pools to import
*/
-extern nvlist_t *zpool_find_import(int, char **);
+extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
/*
* Miscellaneous pool functions
*/
-extern char *zpool_vdev_name(zpool_handle_t *, nvlist_t *);
+extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *);
extern int zpool_upgrade(zpool_handle_t *);
/*
* Basic handle manipulations. These functions do not create or destroy the
* underlying datasets, only the references to them.
*/
-extern zfs_handle_t *zfs_open(const char *, int);
+extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
extern void zfs_close(zfs_handle_t *);
extern zfs_type_t zfs_get_type(const zfs_handle_t *);
extern const char *zfs_get_name(const zfs_handle_t *);
@@ -182,11 +248,11 @@ typedef enum {
const char *zfs_prop_to_name(zfs_prop_t);
int zfs_prop_set(zfs_handle_t *, zfs_prop_t, const char *);
int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t, zfs_source_t *,
- char *, size_t, int);
+ char *, size_t, boolean_t);
int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *, zfs_source_t *,
char *, size_t);
uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
-int zfs_prop_validate(zfs_prop_t, const char *, uint64_t *);
+int zfs_prop_validate(libzfs_handle_t *, zfs_prop_t, const char *, uint64_t *);
int zfs_prop_inheritable(zfs_prop_t);
int zfs_prop_inherit(zfs_handle_t *, zfs_prop_t);
const char *zfs_prop_values(zfs_prop_t);
@@ -206,7 +272,7 @@ int zfs_get_proplist(char *fields, zfs_prop_t *proplist, int max, int *count,
* Iterator functions.
*/
typedef int (*zfs_iter_f)(zfs_handle_t *, void *);
-extern int zfs_iter_root(zfs_iter_f, void *);
+extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_dependents(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
@@ -215,14 +281,16 @@ extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
/*
* Functions to create and destroy datasets.
*/
-extern int zfs_create(const char *, zfs_type_t, const char *, const char *);
+extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
+ const char *, const char *);
extern int zfs_destroy(zfs_handle_t *);
extern int zfs_clone(zfs_handle_t *, const char *);
-extern int zfs_snapshot(const char *);
+extern int zfs_snapshot(libzfs_handle_t *, const char *);
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, int);
extern int zfs_rename(zfs_handle_t *, const char *);
extern int zfs_send(zfs_handle_t *, zfs_handle_t *);
-extern int zfs_receive(const char *, int, int, int);
+extern int zfs_receive(libzfs_handle_t *, const char *, int, int, int);
+extern int zfs_promote(zfs_handle_t *);
/*
* Miscellaneous functions.
@@ -234,7 +302,7 @@ extern int zfs_name_valid(const char *, zfs_type_t);
/*
* Mount support functions.
*/
-extern int zfs_is_mounted(zfs_handle_t *, char **);
+extern boolean_t zfs_is_mounted(zfs_handle_t *, char **);
extern int zfs_mount(zfs_handle_t *, const char *, int);
extern int zfs_unmount(zfs_handle_t *, const char *, int);
extern int zfs_unmountall(zfs_handle_t *, int);
@@ -242,17 +310,12 @@ extern int zfs_unmountall(zfs_handle_t *, int);
/*
* Share support functions.
*/
-extern int zfs_is_shared(zfs_handle_t *, char **);
+extern boolean_t zfs_is_shared(zfs_handle_t *, char **);
extern int zfs_share(zfs_handle_t *);
extern int zfs_unshare(zfs_handle_t *, const char *);
extern int zfs_unshareall(zfs_handle_t *);
/*
- * For clients that need to capture error output.
- */
-extern void zfs_set_error_handler(void (*)(const char *, va_list));
-
-/*
* When dealing with nvlists, verify() is extremely useful
*/
#ifdef NDEBUG
@@ -276,12 +339,13 @@ extern int zfs_remove_link(zfs_handle_t *);
/*
* Given a device or file, determine if it is part of a pool.
*/
-extern int zpool_in_use(int fd, pool_state_t *state, char **name);
+extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
+ boolean_t *);
/*
* ftyp special. Read the label from a given device.
*/
-extern nvlist_t *zpool_read_label(int fd);
+extern int zpool_read_label(int, nvlist_t **);
/*
* Create and remove zvol /dev links
@@ -289,21 +353,6 @@ extern nvlist_t *zpool_read_label(int fd);
extern int zpool_create_zvol_links(zpool_handle_t *);
extern int zpool_remove_zvol_links(zpool_handle_t *);
-/*
- * zoneadmd hack
- */
-extern void zfs_init(void);
-
-/*
- * Useful defines
- */
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c
index 57fcc1497c..04270dfe51 100644
--- a/usr/src/lib/libzfs/common/libzfs_changelist.c
+++ b/usr/src/lib/libzfs/common/libzfs_changelist.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -73,11 +72,11 @@ struct prop_changelist {
zfs_prop_t cl_realprop;
uu_list_pool_t *cl_pool;
uu_list_t *cl_list;
- int cl_waslegacy;
- int cl_allchildren;
- int cl_alldependents;
+ boolean_t cl_waslegacy;
+ boolean_t cl_allchildren;
+ boolean_t cl_alldependents;
int cl_flags;
- int cl_haszonedchild;
+ boolean_t cl_haszonedchild;
};
/*
@@ -109,7 +108,8 @@ changelist_prefix(prop_changelist_t *clp)
*/
if (cn->cn_handle->zfs_volblocksize &&
clp->cl_realprop == ZFS_PROP_NAME) {
- if (zvol_remove_link(cn->cn_handle->zfs_name) != 0)
+ if (zvol_remove_link(cn->cn_handle->zfs_hdl,
+ cn->cn_handle->zfs_name) != 0)
ret = -1;
} else if (zfs_unmount(cn->cn_handle, NULL, clp->cl_flags) != 0)
ret = -1;
@@ -167,7 +167,8 @@ changelist_postfix(prop_changelist_t *clp)
*/
if (cn->cn_handle->zfs_volblocksize &&
clp->cl_realprop == ZFS_PROP_NAME) {
- if (zvol_create_link(cn->cn_handle->zfs_name) != 0)
+ if (zvol_create_link(cn->cn_handle->zfs_hdl,
+ cn->cn_handle->zfs_name) != 0)
ret = -1;
continue;
}
@@ -186,7 +187,7 @@ changelist_postfix(prop_changelist_t *clp)
char shareopts[ZFS_MAXPROPLEN];
if (zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
shareopts, sizeof (shareopts), NULL, NULL, 0,
- FALSE) == 0 && strcmp(shareopts, "off") == 0)
+ B_FALSE) == 0 && strcmp(shareopts, "off") == 0)
ret = zfs_unshare(cn->cn_handle, NULL);
else
ret = zfs_share(cn->cn_handle);
@@ -199,22 +200,22 @@ changelist_postfix(prop_changelist_t *clp)
/*
* Is this "dataset" a child of "parent"?
*/
-static int
+static boolean_t
isa_child_of(char *dataset, const char *parent)
{
int len;
/* snapshot does not have a child */
if (strchr(parent, '@'))
- return (FALSE);
+ return (B_FALSE);
len = strlen(parent);
if (strncmp(dataset, parent, len) == 0 &&
(dataset[len] == '/' || dataset[len] == '\0'))
- return (TRUE);
+ return (B_TRUE);
else
- return (FALSE);
+ return (B_FALSE);
}
@@ -326,6 +327,9 @@ changelist_free(prop_changelist_t *clp)
free(cn);
}
+ uu_list_walk_end(walk);
+
+ uu_list_destroy(clp->cl_list);
uu_list_pool_destroy(clp->cl_pool);
free(clp);
@@ -353,12 +357,18 @@ change_one(zfs_handle_t *zhp, void *data)
if (!(zhp->zfs_volblocksize && clp->cl_realprop == ZFS_PROP_NAME) &&
zfs_prop_get(zhp, clp->cl_prop, property,
sizeof (property), &sourcetype, where, sizeof (where),
- FALSE) != 0)
+ B_FALSE) != 0) {
+ zfs_close(zhp);
return (0);
+ }
if (clp->cl_alldependents || clp->cl_allchildren ||
sourcetype == ZFS_SRC_DEFAULT || sourcetype == ZFS_SRC_INHERITED) {
- cn = zfs_malloc(sizeof (prop_changenode_t));
+ if ((cn = zfs_alloc(zfs_get_handle(zhp),
+ sizeof (prop_changenode_t))) == NULL) {
+ zfs_close(zhp);
+ return (-1);
+ }
cn->cn_handle = zhp;
cn->cn_mounted = zfs_is_mounted(zhp, NULL);
@@ -367,7 +377,7 @@ change_one(zfs_handle_t *zhp, void *data)
/* indicate if any child is exported to a local zone */
if ((getzoneid() == GLOBAL_ZONEID) && cn->cn_zoned)
- clp->cl_haszonedchild = TRUE;
+ clp->cl_haszonedchild = B_TRUE;
uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
@@ -399,11 +409,14 @@ change_one(zfs_handle_t *zhp, void *data)
prop_changelist_t *
changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
{
- prop_changelist_t *clp = zfs_malloc(sizeof (prop_changelist_t));
+ prop_changelist_t *clp;
prop_changenode_t *cn;
zfs_handle_t *temp;
char property[ZFS_MAXPROPLEN];
+ if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
+ return (NULL);
+
clp->cl_pool = uu_list_pool_create("changelist_pool",
sizeof (prop_changenode_t),
offsetof(prop_changenode_t, cn_listnode),
@@ -423,10 +436,10 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
*/
if (prop == ZFS_PROP_NAME) {
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
- clp->cl_alldependents = TRUE;
+ clp->cl_alldependents = B_TRUE;
} else if (prop == ZFS_PROP_ZONED) {
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
- clp->cl_allchildren = TRUE;
+ clp->cl_allchildren = B_TRUE;
} else {
clp->cl_prop = prop;
}
@@ -450,8 +463,9 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
* We have to re-open ourselves because we auto-close all the handles
* and can't tell the difference.
*/
- if ((temp = zfs_open(zfs_get_name(zhp), ZFS_TYPE_ANY)) == NULL) {
- free(clp);
+ if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
+ ZFS_TYPE_ANY)) == NULL) {
+ changelist_free(clp);
return (NULL);
}
@@ -459,7 +473,13 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
* Always add ourself to the list. We add ourselves to the end so that
* we're the last to be unmounted.
*/
- cn = zfs_malloc(sizeof (prop_changenode_t));
+ if ((cn = zfs_alloc(zhp->zfs_hdl,
+ sizeof (prop_changenode_t))) == NULL) {
+ zfs_close(temp);
+ changelist_free(clp);
+ return (NULL);
+ }
+
cn->cn_handle = temp;
cn->cn_mounted = zfs_is_mounted(temp, NULL);
cn->cn_shared = zfs_is_shared(temp, NULL);
@@ -474,10 +494,10 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
* as the behavior of changelist_postfix() will be different.
*/
if (zfs_prop_get(zhp, prop, property, sizeof (property),
- NULL, NULL, 0, FALSE) == 0 &&
+ NULL, NULL, 0, B_FALSE) == 0 &&
(strcmp(property, "legacy") == 0 || strcmp(property, "none") == 0 ||
strcmp(property, "off") == 0))
- clp->cl_waslegacy = TRUE;
+ clp->cl_waslegacy = B_TRUE;
return (clp);
}
diff --git a/usr/src/lib/libzfs/common/libzfs_config.c b/usr/src/lib/libzfs/common/libzfs_config.c
index 71801d5cba..be691f0ced 100644
--- a/usr/src/lib/libzfs/common/libzfs_config.c
+++ b/usr/src/lib/libzfs/common/libzfs_config.c
@@ -45,9 +45,6 @@
#include "libzfs_impl.h"
-static uu_avl_t *namespace_avl;
-static uint64_t namespace_generation;
-
typedef struct config_node {
char *cn_name;
nvlist_t *cn_config;
@@ -73,11 +70,41 @@ config_node_compare(const void *a, const void *b, void *unused)
return (0);
}
+void
+namespace_clear(libzfs_handle_t *hdl)
+{
+ if (hdl->libzfs_ns_avl) {
+ uu_avl_walk_t *walk;
+ config_node_t *cn;
+
+ if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl,
+ UU_WALK_ROBUST)) == NULL)
+ return;
+
+ while ((cn = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_remove(hdl->libzfs_ns_avl, cn);
+ nvlist_free(cn->cn_config);
+ free(cn->cn_name);
+ free(cn);
+ }
+
+ uu_avl_walk_end(walk);
+
+ uu_avl_destroy(hdl->libzfs_ns_avl);
+ hdl->libzfs_ns_avl = NULL;
+ }
+
+ if (hdl->libzfs_ns_avlpool) {
+ uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
+ hdl->libzfs_ns_avlpool = NULL;
+ }
+}
+
/*
* Loads the pool namespace, or re-loads it if the cache has changed.
*/
-static void
-namespace_reload()
+static int
+namespace_reload(libzfs_handle_t *hdl)
{
nvlist_t *config;
config_node_t *cn;
@@ -85,23 +112,21 @@ namespace_reload()
zfs_cmd_t zc = { 0 };
uu_avl_walk_t *walk;
- if (namespace_generation == 0) {
+ if (hdl->libzfs_ns_gen == 0) {
/*
* This is the first time we've accessed the configuration
* cache. Initialize the AVL tree and then fall through to the
* common code.
*/
- uu_avl_pool_t *pool;
-
- if ((pool = uu_avl_pool_create("config_pool",
+ if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
sizeof (config_node_t),
offsetof(config_node_t, cn_avl),
config_node_compare, UU_DEFAULT)) == NULL)
- no_memory();
+ return (no_memory(hdl));
- if ((namespace_avl = uu_avl_create(pool, NULL,
- UU_DEFAULT)) == NULL)
- no_memory();
+ if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
+ NULL, UU_DEFAULT)) == NULL)
+ return (no_memory(hdl));
}
/*
@@ -114,68 +139,92 @@ namespace_reload()
* been modified to tell us how much to allocate.
*/
zc.zc_config_dst_size = 1024;
- zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_malloc(zc.zc_config_dst_size);
+ if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL)
+ return (-1);
for (;;) {
- zc.zc_cookie = namespace_generation;
- if (zfs_ioctl(ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
+ zc.zc_cookie = hdl->libzfs_ns_gen;
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
switch (errno) {
case EEXIST:
/*
* The namespace hasn't changed.
*/
free((void *)(uintptr_t)zc.zc_config_dst);
- return;
+ return (0);
case ENOMEM:
free((void *)(uintptr_t)zc.zc_config_dst);
- zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_malloc(zc.zc_config_dst_size);
+ if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(hdl, zc.zc_config_dst_size))
+ == NULL)
+ return (-1);
break;
default:
- zfs_baderror(errno);
+ return (zfs_standard_error(hdl, errno,
+ dgettext(TEXT_DOMAIN, "failed to read "
+ "pool configuration")));
}
} else {
- namespace_generation = zc.zc_cookie;
+ hdl->libzfs_ns_gen = zc.zc_cookie;
break;
}
}
- verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
- zc.zc_config_dst_size, &config, 0) == 0);
+ if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
+ zc.zc_config_dst_size, &config, 0) != 0)
+ return (no_memory(hdl));
free((void *)(uintptr_t)zc.zc_config_dst);
/*
* Clear out any existing configuration information.
*/
- if ((walk = uu_avl_walk_start(namespace_avl, UU_WALK_ROBUST)) == NULL)
- no_memory();
+ if ((walk = uu_avl_walk_start(hdl->libzfs_ns_avl,
+ UU_WALK_ROBUST)) == NULL) {
+ nvlist_free(config);
+ return (no_memory(hdl));
+ }
while ((cn = uu_avl_walk_next(walk)) != NULL) {
- uu_avl_remove(namespace_avl, cn);
+ uu_avl_remove(hdl->libzfs_ns_avl, cn);
nvlist_free(cn->cn_config);
free(cn->cn_name);
free(cn);
}
+ uu_avl_walk_end(walk);
+
elem = NULL;
while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
nvlist_t *child;
uu_avl_index_t where;
- cn = zfs_malloc(sizeof (config_node_t));
- cn->cn_name = zfs_strdup(nvpair_name(elem));
+ if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
+ nvlist_free(config);
+ return (-1);
+ }
+
+ if ((cn->cn_name = zfs_strdup(hdl,
+ nvpair_name(elem))) == NULL) {
+ free(cn);
+ return (-1);
+ }
verify(nvpair_value_nvlist(elem, &child) == 0);
- verify(nvlist_dup(child, &cn->cn_config, 0) == 0);
- verify(uu_avl_find(namespace_avl, cn, NULL, &where) == NULL);
+ if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
+ nvlist_free(config);
+ return (no_memory(hdl));
+ }
+ verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
+ == NULL);
- uu_avl_insert(namespace_avl, cn, where);
+ uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
}
nvlist_free(config);
+ return (0);
}
/*
@@ -209,35 +258,43 @@ zpool_refresh_stats(zpool_handle_t *zhp)
zhp->zpool_config_size = 1 << 16;
zc.zc_config_dst_size = zhp->zpool_config_size;
- zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_malloc(zc.zc_config_dst_size);
+ if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(zhp->zpool_hdl, zc.zc_config_dst_size)) == NULL)
+ return (-1);
for (;;) {
- if (zfs_ioctl(ZFS_IOC_POOL_STATS, &zc) == 0) {
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
+ &zc) == 0) {
/*
* The real error is returned in the zc_cookie field.
*/
- error = zc.zc_cookie;
+ error = errno = zc.zc_cookie;
break;
}
if (errno == ENOMEM) {
free((void *)(uintptr_t)zc.zc_config_dst);
- zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_malloc(zc.zc_config_dst_size);
+ if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(zhp->zpool_hdl,
+ zc.zc_config_dst_size)) == NULL)
+ return (-1);
} else {
free((void *)(uintptr_t)zc.zc_config_dst);
- return (errno);
+ return (-1);
}
}
- verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
- zc.zc_config_dst_size, &config, 0) == 0);
+ if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
+ zc.zc_config_dst_size, &config, 0) != 0) {
+ free((void *)(uintptr_t)zc.zc_config_dst);
+ return (no_memory(zhp->zpool_hdl));
+ }
zhp->zpool_config_size = zc.zc_config_dst_size;
free((void *)(uintptr_t)zc.zc_config_dst);
- set_pool_health(config);
+ if (set_pool_health(config) != 0)
+ return (no_memory(zhp->zpool_hdl));
if (zhp->zpool_config != NULL) {
uint64_t oldtxg, newtxg;
@@ -260,25 +317,26 @@ zpool_refresh_stats(zpool_handle_t *zhp)
zhp->zpool_config = config;
- return (error);
+ return (error ? -1 : 0);
}
/*
* Iterate over all pools in the system.
*/
int
-zpool_iter(zpool_iter_f func, void *data)
+zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
{
config_node_t *cn;
zpool_handle_t *zhp;
int ret;
- namespace_reload();
+ if (namespace_reload(hdl) != 0)
+ return (-1);
- for (cn = uu_avl_first(namespace_avl); cn != NULL;
- cn = uu_avl_next(namespace_avl, cn)) {
+ for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
+ cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
- if ((zhp = zpool_open_silent(cn->cn_name)) == NULL)
+ if ((zhp = zpool_open_silent(hdl, cn->cn_name)) == NULL)
continue;
if ((ret = func(zhp, data)) != 0)
@@ -293,18 +351,19 @@ zpool_iter(zpool_iter_f func, void *data)
* handle passed each time must be explicitly closed by the callback.
*/
int
-zfs_iter_root(zfs_iter_f func, void *data)
+zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
{
config_node_t *cn;
zfs_handle_t *zhp;
int ret;
- namespace_reload();
+ if (namespace_reload(hdl) != 0)
+ return (-1);
- for (cn = uu_avl_first(namespace_avl); cn != NULL;
- cn = uu_avl_next(namespace_avl, cn)) {
+ for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
+ cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
- if ((zhp = make_dataset_handle(cn->cn_name)) == NULL)
+ if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
continue;
if ((ret = func(zhp, data)) != 0)
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index f23136c8aa..14ba6112ed 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -36,6 +36,7 @@
#include <strings.h>
#include <unistd.h>
#include <zone.h>
+#include <fcntl.h>
#include <sys/mntent.h>
#include <sys/mnttab.h>
#include <sys/mount.h>
@@ -64,7 +65,6 @@ zfs_type_to_name(zfs_type_t type)
return (dgettext(TEXT_DOMAIN, "volume"));
}
- zfs_baderror(type);
return (NULL);
}
@@ -118,43 +118,43 @@ path_to_str(const char *path, int types)
* 'buf' detailing exactly why the name was not valid.
*/
static int
-zfs_validate_name(const char *path, int type, char *buf, size_t buflen)
+zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type)
{
namecheck_err_t why;
char what;
if (dataset_namecheck(path, &why, &what) != 0) {
- if (buf != NULL) {
+ if (hdl != NULL) {
switch (why) {
case NAME_ERR_TOOLONG:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "name is too long"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "name is too long"));
break;
case NAME_ERR_LEADING_SLASH:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "leading slash"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "leading slash in name"));
break;
case NAME_ERR_EMPTY_COMPONENT:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "empty component"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "empty component in name"));
break;
case NAME_ERR_TRAILING_SLASH:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "trailing slash"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "trailing slash in name"));
break;
case NAME_ERR_INVALCHAR:
- (void) snprintf(buf, buflen,
+ zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "invalid character "
- "'%c'"), what);
+ "'%c' in name"), what);
break;
case NAME_ERR_MULTIPLE_AT:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "multiple '@' delimiters"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "multiple '@' delimiters in name"));
break;
}
}
@@ -163,20 +163,19 @@ zfs_validate_name(const char *path, int type, char *buf, size_t buflen)
}
if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
- if (buf != NULL)
- (void) strlcpy(buf,
- dgettext(TEXT_DOMAIN,
- "snapshot delimiter '@'"), buflen);
+ if (hdl != NULL)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snapshot delimiter '@' in filesystem name"));
return (0);
}
- return (1);
+ return (-1);
}
int
zfs_name_valid(const char *name, zfs_type_t type)
{
- return (zfs_validate_name(name, type, NULL, NULL));
+ return (zfs_validate_name(NULL, name, type));
}
/*
@@ -189,13 +188,16 @@ get_stats(zfs_handle_t *zhp)
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- zc.zc_config_src = (uint64_t)(uintptr_t)zfs_malloc(1024);
+ if ((zc.zc_config_src = (uint64_t)(uintptr_t)malloc(1024)) == NULL)
+ return (-1);
zc.zc_config_src_size = 1024;
- while (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+ while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
if (errno == ENOMEM) {
- zc.zc_config_src = (uint64_t)(uintptr_t)
- zfs_malloc(zc.zc_config_src_size);
+ free((void *)(uintptr_t)zc.zc_config_src);
+ if ((zc.zc_config_src = (uint64_t)(uintptr_t)
+ malloc(zc.zc_config_src_size)) == NULL)
+ return (-1);
} else {
free((void *)(uintptr_t)zc.zc_config_src);
return (-1);
@@ -207,12 +209,22 @@ get_stats(zfs_handle_t *zhp)
(void) strcpy(zhp->zfs_root, zc.zc_root);
- verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_src,
- zc.zc_config_src_size, &zhp->zfs_props, 0) == 0);
+ if (zhp->zfs_props) {
+ nvlist_free(zhp->zfs_props);
+ zhp->zfs_props = NULL;
+ }
+
+ if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_src,
+ zc.zc_config_src_size, &zhp->zfs_props, 0) != 0) {
+ free((void *)(uintptr_t)zc.zc_config_src);
+ return (-1);
+ }
zhp->zfs_volsize = zc.zc_volsize;
zhp->zfs_volblocksize = zc.zc_volblocksize;
+ free((void *)(uintptr_t)zc.zc_config_src);
+
return (0);
}
@@ -230,9 +242,14 @@ zfs_refresh_properties(zfs_handle_t *zhp)
* zfs_iter_* to create child handles on the fly.
*/
zfs_handle_t *
-make_dataset_handle(const char *path)
+make_dataset_handle(libzfs_handle_t *hdl, const char *path)
{
- zfs_handle_t *zhp = zfs_malloc(sizeof (zfs_handle_t));
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ zhp->zfs_hdl = hdl;
top:
(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
@@ -263,20 +280,20 @@ top:
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
- (void) zvol_remove_link(zhp->zfs_name);
+ (void) zvol_remove_link(hdl, zhp->zfs_name);
zc.zc_objset_type = DMU_OST_ZVOL;
} else {
zc.zc_objset_type = DMU_OST_ZFS;
}
/* If we can successfully roll it back, reget the stats */
- if (zfs_ioctl(ZFS_IOC_ROLLBACK, &zc) == 0)
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0)
goto top;
/*
* If we can sucessfully destroy it, pretend that it
* never existed.
*/
- if (zfs_ioctl(ZFS_IOC_DESTROY, &zc) == 0) {
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) {
free(zhp);
errno = ENOENT;
return (NULL);
@@ -294,8 +311,7 @@ top:
else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
else
- /* we should never see any other dataset types */
- zfs_baderror(zhp->zfs_dmustats.dds_type);
+ abort(); /* we should never see any other types */
return (zhp);
}
@@ -306,18 +322,21 @@ top:
* appropriate error message and return NULL if it can't be opened.
*/
zfs_handle_t *
-zfs_open(const char *path, int types)
+zfs_open(libzfs_handle_t *hdl, const char *path, int types)
{
zfs_handle_t *zhp;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
/*
- * Validate the name before we even try to open it. We don't care about
- * the verbose invalid messages here; just report a generic error.
+ * Validate the name before we even try to open it.
*/
- if (!zfs_validate_name(path, types, NULL, 0)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': invalid %s name"), path,
- path_to_str(path, types));
+ if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid dataset name"));
+ (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
return (NULL);
}
@@ -325,48 +344,13 @@ zfs_open(const char *path, int types)
* Try to get stats for the dataset, which will tell us if it exists.
*/
errno = 0;
- if ((zhp = make_dataset_handle(path)) == NULL) {
- switch (errno) {
- case ENOENT:
- /*
- * The dataset doesn't exist.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': no such %s"), path,
- path_to_str(path, types));
- break;
-
- case EBUSY:
- /*
- * We were able to open the dataset but couldn't
- * get the stats.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': %s is busy"), path,
- path_to_str(path, types));
- break;
-
- case ENXIO:
- case EIO:
- /*
- * I/O error from the underlying pool.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': I/O error"), path,
- path_to_str(path, types));
- break;
-
- default:
- zfs_baderror(errno);
-
- }
+ if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
+ (void) zfs_standard_error(hdl, errno, errbuf, path);
return (NULL);
}
if (!(types & zhp->zfs_type)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': operation "
- "not supported for %ss"), path,
- zfs_type_to_name(zhp->zfs_type));
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
free(zhp);
return (NULL);
}
@@ -382,6 +366,8 @@ zfs_close(zfs_handle_t *zhp)
{
if (zhp->zfs_mntopts)
free(zhp->zfs_mntopts);
+ if (zhp->zfs_props)
+ nvlist_free(zhp->zfs_props);
free(zhp);
}
@@ -443,7 +429,7 @@ struct {
* resulting value must be shifted.
*/
static int
-str2shift(const char *buf, char *reason, size_t len)
+str2shift(libzfs_handle_t *hdl, const char *buf)
{
const char *ends = "BKMGTPEZ";
int i;
@@ -455,8 +441,8 @@ str2shift(const char *buf, char *reason, size_t len)
break;
}
if (i == strlen(ends)) {
- (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid "
- "numeric suffix '%s'"), buf);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid numeric suffix '%s'"), buf);
return (-1);
}
@@ -465,12 +451,11 @@ str2shift(const char *buf, char *reason, size_t len)
* allow 'BB' - that's just weird.
*/
if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
- toupper(buf[0]) != 'B')) {
+ toupper(buf[0]) != 'B'))
return (10*i);
- }
- (void) snprintf(reason, len, dgettext(TEXT_DOMAIN, "invalid numeric "
- "suffix '%s'"), buf);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid numeric suffix '%s'"), buf);
return (-1);
}
@@ -480,7 +465,7 @@ str2shift(const char *buf, char *reason, size_t len)
* message for the caller to use.
*/
static int
-nicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen)
+nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
{
char *end;
int shift;
@@ -489,8 +474,9 @@ nicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen)
/* Check to see if this looks like a number. */
if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "must be a numeric value"), buflen);
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "bad numeric value '%s'"), value);
return (-1);
}
@@ -503,8 +489,9 @@ nicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen)
* in a 64-bit value.
*/
if (errno == ERANGE) {
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "value is too large"), buflen);
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "numeric value is too large"));
return (-1);
}
@@ -515,26 +502,28 @@ nicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen)
if (*end == '.') {
double fval = strtod(value, &end);
- if ((shift = str2shift(end, buf, buflen)) == -1)
+ if ((shift = str2shift(hdl, end)) == -1)
return (-1);
fval *= pow(2, shift);
if (fval > UINT64_MAX) {
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "value is too large"), buflen);
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "numeric value is too large"));
return (-1);
}
*num = (uint64_t)fval;
} else {
- if ((shift = str2shift(end, buf, buflen)) == -1)
+ if ((shift = str2shift(hdl, end)) == -1)
return (-1);
/* Check for overflow */
if (shift >= 64 || (*num << shift) >> shift != *num) {
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "value is too large"), buflen);
+ if (hdl)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "numeric value is too large"));
return (-1);
}
@@ -547,9 +536,7 @@ nicestrtonum(const char *value, uint64_t *num, char *buf, size_t buflen)
int
zfs_nicestrtonum(const char *str, uint64_t *val)
{
- char buf[1];
-
- return (nicestrtonum(str, val, buf, sizeof (buf)));
+ return (nicestrtonum(NULL, str, val));
}
/*
@@ -557,28 +544,28 @@ zfs_nicestrtonum(const char *str, uint64_t *val)
* by zfs_prop_set() and some libzfs consumers.
*/
int
-zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
+zfs_prop_validate(libzfs_handle_t *hdl, zfs_prop_t prop, const char *value,
+ uint64_t *intval)
{
const char *propname = zfs_prop_to_name(prop);
uint64_t number;
- char reason[64];
+ char errbuf[1024];
int i;
/*
* Check to see if this a read-only property.
*/
- if (zfs_prop_readonly(prop)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s property: read-only property"), propname);
- return (-1);
- }
+ if (zfs_prop_readonly(prop))
+ return (zfs_error(hdl, EZFS_PROPREADONLY,
+ dgettext(TEXT_DOMAIN, "cannot set %s property"), propname));
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "bad %s value '%s'"), propname, value);
/* See if the property value is too long */
if (strlen(value) >= ZFS_MAXPROPLEN) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': value is too long"), propname,
- value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "value is too long"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
/* Perform basic checking based on property type */
@@ -589,10 +576,9 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
} else if (strcmp(value, "off") == 0) {
number = 0;
} else {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': must be 'on' or 'off'"),
- propname, value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be 'on' or 'off'"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
break;
@@ -603,21 +589,15 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
break;
}
- if (nicestrtonum(value, &number, reason,
- sizeof (reason)) != 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': %s"), propname, value,
- reason);
- return (-1);
- }
+ if (nicestrtonum(hdl, value, &number) != 0)
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
/* don't allow 0 for quota, use 'none' instead */
if (prop == ZFS_PROP_QUOTA && number == 0 &&
strcmp(value, "none") != 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': use '%s=none' to disable"),
- propname, value, propname);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "use 'quota=none' to disable"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
/* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
@@ -625,13 +605,11 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
prop == ZFS_PROP_VOLBLOCKSIZE) {
if (number < SPA_MINBLOCKSIZE ||
number > SPA_MAXBLOCKSIZE || !ISP2(number)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': "
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"must be power of 2 from %u to %uk"),
- propname, value,
(uint_t)SPA_MINBLOCKSIZE,
(uint_t)SPA_MAXBLOCKSIZE >> 10);
- return (-1);
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
}
@@ -652,11 +630,10 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
break;
if (value[0] != '/') {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': must be an absolute "
- "path, 'none', or 'legacy'"),
- propname, value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be an absolute path, 'none', or "
+ "'legacy'"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
break;
@@ -670,11 +647,10 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
}
if (checksum_table[i].name == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': must be 'on', 'off', "
- "'fletcher2', 'fletcher4', or 'sha256'"),
- propname, value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be 'on', 'off', 'fletcher2', "
+ "'fletcher4', or 'sha256'"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
break;
@@ -688,11 +664,9 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
}
if (compress_table[i].name == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': must be 'on', 'off', "
- "or 'lzjb'"),
- propname, value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be 'on', 'off', or 'lzjb'"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
break;
@@ -705,11 +679,9 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
}
if (snapdir_table[i].name == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': must be 'hidden' "
- "or 'visible'"),
- propname, value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be 'hidden' or 'visible'"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
break;
@@ -723,11 +695,10 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
}
if (acl_mode_table[i].name == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': must be 'discard', "
- "'groupmask' or 'passthrough'"),
- propname, value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be 'disacard', 'groupmask', or "
+ "'passthrough'"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
break;
@@ -741,11 +712,10 @@ zfs_prop_validate(zfs_prop_t prop, const char *value, uint64_t *intval)
}
if (acl_inherit_table[i].name == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad %s value '%s': must be 'discard', "
- "'noallow', 'secure' or 'passthrough'"),
- propname, value);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be 'discard, 'noallow', 'secure', "
+ "or 'passthrough'"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
break;
@@ -775,19 +745,22 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
zfs_cmd_t zc = { 0 };
int ret;
prop_changelist_t *cl;
+ char errbuf[1024];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
- if (zfs_prop_validate(prop, propval, &number) != 0)
+ if (zfs_prop_validate(zhp->zfs_hdl, prop, propval, &number) != 0)
return (-1);
+
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot set %s for '%s'"), propname,
+ zhp->zfs_name);
+
/*
* Check to see if the value applies to this type
*/
- if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': property does not apply to %ss"),
- propname, zhp->zfs_name, zfs_type_to_name(zhp->zfs_type));
- return (-1);
- }
+ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
+ return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
/*
* For the mountpoint and sharenfs properties, check if it can be set
@@ -804,29 +777,24 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
if (getzoneid() == GLOBAL_ZONEID) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': "
- "dataset is used in a non-global zone"),
- propname, zhp->zfs_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is used in a non-global zone"));
+ return (zfs_error(hdl, EZFS_ZONED, errbuf));
} else if (prop == ZFS_PROP_SHARENFS) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': filesystems "
- "cannot be shared in a non-global zone"),
- propname, zhp->zfs_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "filesystems cannot be shared in a "
+ "non-global zone"));
+ return (zfs_error(hdl, EZFS_ZONED, errbuf));
}
} else if (getzoneid() != GLOBAL_ZONEID) {
/*
* If zoned property is 'off', this must be in
* a globle zone. If not, something is wrong.
*/
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': dataset is "
- "used in a non-global zone, but 'zoned' "
- "property is not set"),
- propname, zhp->zfs_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is used in a non-global zone, but "
+ "'zoned' property is not set"));
+ return (zfs_error(hdl, EZFS_ZONED, errbuf));
}
}
@@ -834,11 +802,10 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
return (-1);
if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s for '%s', "
- "child dataset with inherited mountpoint is used "
- "in a non-global zone"),
- propname, zhp->zfs_name);
- ret = -1;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "child dataset with inherited mountpoint is used "
+ "in a non-global zone"));
+ ret = zfs_error(hdl, EZFS_ZONED, errbuf);
goto error;
}
@@ -853,11 +820,12 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
switch (prop) {
case ZFS_PROP_QUOTA:
zc.zc_cookie = number;
- ret = zfs_ioctl(ZFS_IOC_SET_QUOTA, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_QUOTA, &zc);
break;
case ZFS_PROP_RESERVATION:
zc.zc_cookie = number;
- ret = zfs_ioctl(ZFS_IOC_SET_RESERVATION, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_RESERVATION,
+ &zc);
break;
case ZFS_PROP_MOUNTPOINT:
case ZFS_PROP_SHARENFS:
@@ -870,15 +838,16 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
sizeof (zc.zc_prop_value));
zc.zc_intsz = 1;
zc.zc_numints = strlen(propval) + 1;
- ret = zfs_ioctl(ZFS_IOC_SET_PROP, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
break;
case ZFS_PROP_VOLSIZE:
zc.zc_volsize = number;
- ret = zfs_ioctl(ZFS_IOC_SET_VOLSIZE, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLSIZE, &zc);
break;
case ZFS_PROP_VOLBLOCKSIZE:
zc.zc_volblocksize = number;
- ret = zfs_ioctl(ZFS_IOC_SET_VOLBLOCKSIZE, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLBLOCKSIZE,
+ &zc);
break;
default:
(void) strlcpy(zc.zc_prop_name, propname,
@@ -887,25 +856,13 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
*(uint64_t *)zc.zc_prop_value = number;
zc.zc_intsz = 8;
zc.zc_numints = 1;
- ret = zfs_ioctl(ZFS_IOC_SET_PROP, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
break;
}
if (ret != 0) {
switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': permission "
- "denied"), propname, zhp->zfs_name);
- break;
-
- case ENOENT:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': no such %s"), zhp->zfs_name,
- zfs_type_to_name(zhp->zfs_type));
- break;
-
case ENOSPC:
/*
* For quotas and reservations, ENOSPC indicates
@@ -914,41 +871,33 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
*/
switch (prop) {
case ZFS_PROP_QUOTA:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s "
- "for '%s': size is less than current "
- "used or reserved space"), propname,
- zhp->zfs_name);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "size is less than current used or "
+ "reserved space"));
+ (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
break;
case ZFS_PROP_RESERVATION:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s "
- "for '%s': size is greater than available "
- "space"), propname, zhp->zfs_name);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "size is greater than available space"));
+ (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
break;
default:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': out of space"),
- propname, zhp->zfs_name);
+ (void) zfs_standard_error(hdl, errno, errbuf);
break;
}
break;
case EBUSY:
- if (prop == ZFS_PROP_VOLBLOCKSIZE) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': "
- "volume already contains data"),
- propname, zhp->zfs_name);
- } else {
- zfs_baderror(errno);
- }
+ if (prop == ZFS_PROP_VOLBLOCKSIZE)
+ (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf);
+ else
+ return (zfs_standard_error(hdl, EBUSY, errbuf));
break;
case EROFS:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot set %s for "
- "'%s': read only %s"), propname, zhp->zfs_name,
- zfs_type_to_name(zhp->zfs_type));
+ (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
break;
case EOVERFLOW:
@@ -957,16 +906,13 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
*/
#ifdef _ILP32
if (prop == ZFS_PROP_VOLSIZE) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot set %s for '%s': "
- "max volume size is 1TB on 32-bit systems"),
- propname, zhp->zfs_name);
+ (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
break;
}
#endif
- zfs_baderror(errno);
+ /* FALLTHROUGH */
default:
- zfs_baderror(errno);
+ (void) zfs_standard_error(hdl, errno, errbuf);
}
} else {
/*
@@ -994,44 +940,35 @@ zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop)
zfs_cmd_t zc = { 0 };
int ret;
prop_changelist_t *cl;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
/*
* Verify that this property is inheritable.
*/
- if (zfs_prop_readonly(prop)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot inherit %s for '%s': property is read-only"),
- propname, zhp->zfs_name);
- return (-1);
- }
+ if (zfs_prop_readonly(prop))
+ return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
- if (!zfs_prop_inheritable(prop)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot inherit %s for '%s': property is not inheritable"),
- propname, zhp->zfs_name);
- return (-1);
- }
+ if (!zfs_prop_inheritable(prop))
+ return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
/*
* Check to see if the value applies to this type
*/
- if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot inherit %s for '%s': property does "
- "not apply to %ss"), propname, zhp->zfs_name,
- zfs_type_to_name(zhp->zfs_type));
- return (-1);
- }
+ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
+ return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_prop_name, propname, sizeof (zc.zc_prop_name));
if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', "
- "dataset is used in a non-global zone"), propname,
- zhp->zfs_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is used in a non-global zone"));
+ return (zfs_error(hdl, EZFS_ZONED, errbuf));
}
/*
@@ -1041,11 +978,10 @@ zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop)
return (-1);
if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s', "
- "child dataset with inherited mountpoint is "
- "used in a non-global zone"),
- propname, zhp->zfs_name);
- ret = -1;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "child dataset with inherited mountpoint is used "
+ "in a non-global zone"));
+ ret = zfs_error(hdl, EZFS_ZONED, errbuf);
goto error;
}
@@ -1054,27 +990,9 @@ zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop)
zc.zc_numints = 0;
- if ((ret = zfs_ioctl(ZFS_IOC_SET_PROP, &zc)) != 0) {
- switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot inherit %s for '%s': permission "
- "denied"), propname, zhp->zfs_name);
- break;
- case ENOENT:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': no such %s"), zhp->zfs_name,
- zfs_type_to_name(zhp->zfs_type));
- break;
- case ENOSPC:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot inherit %s for '%s': "
- "out of space"), propname, zhp->zfs_name);
- break;
- default:
- zfs_baderror(errno);
- }
-
+ if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd,
+ ZFS_IOC_SET_PROP, &zc)) != 0) {
+ return (zfs_standard_error(hdl, errno, errbuf));
} else {
if ((ret = changelist_postfix(cl)) != 0)
@@ -1151,11 +1069,10 @@ getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
* If they differ from the on-disk values, report the current values and mark
* the source "temporary".
*/
-static uint64_t
+static int
get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
- char **source)
+ char **source, uint64_t *val)
{
- uint64_t val;
struct mnttab mnt;
*source = NULL;
@@ -1167,86 +1084,90 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
switch (prop) {
case ZFS_PROP_ATIME:
- val = getprop_uint64(zhp, prop, source);
+ *val = getprop_uint64(zhp, prop, source);
- if (hasmntopt(&mnt, MNTOPT_ATIME) && !val) {
- val = TRUE;
+ if (hasmntopt(&mnt, MNTOPT_ATIME) && !*val) {
+ *val = B_TRUE;
if (src)
*src = ZFS_SRC_TEMPORARY;
- } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && val) {
- val = FALSE;
+ } else if (hasmntopt(&mnt, MNTOPT_NOATIME) && *val) {
+ *val = B_FALSE;
if (src)
*src = ZFS_SRC_TEMPORARY;
}
- return (val);
+ break;
case ZFS_PROP_AVAILABLE:
- return (zhp->zfs_dmustats.dds_available);
+ *val = zhp->zfs_dmustats.dds_available;
+ break;
case ZFS_PROP_DEVICES:
- val = getprop_uint64(zhp, prop, source);
+ *val = getprop_uint64(zhp, prop, source);
- if (hasmntopt(&mnt, MNTOPT_DEVICES) && !val) {
- val = TRUE;
+ if (hasmntopt(&mnt, MNTOPT_DEVICES) && !*val) {
+ *val = B_TRUE;
if (src)
*src = ZFS_SRC_TEMPORARY;
- } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && val) {
- val = FALSE;
+ } else if (hasmntopt(&mnt, MNTOPT_NODEVICES) && *val) {
+ *val = B_FALSE;
if (src)
*src = ZFS_SRC_TEMPORARY;
}
- return (val);
+ break;
case ZFS_PROP_EXEC:
- val = getprop_uint64(zhp, prop, source);
+ *val = getprop_uint64(zhp, prop, source);
- if (hasmntopt(&mnt, MNTOPT_EXEC) && !val) {
- val = TRUE;
+ if (hasmntopt(&mnt, MNTOPT_EXEC) && !*val) {
+ *val = B_TRUE;
if (src)
*src = ZFS_SRC_TEMPORARY;
- } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && val) {
- val = FALSE;
+ } else if (hasmntopt(&mnt, MNTOPT_NOEXEC) && *val) {
+ *val = B_FALSE;
if (src)
*src = ZFS_SRC_TEMPORARY;
}
- return (val);
+ break;
case ZFS_PROP_RECORDSIZE:
case ZFS_PROP_COMPRESSION:
case ZFS_PROP_ZONED:
- val = getprop_uint64(zhp, prop, source);
- return (val);
+ *val = getprop_uint64(zhp, prop, source);
+ break;
case ZFS_PROP_READONLY:
- val = getprop_uint64(zhp, prop, source);
+ *val = getprop_uint64(zhp, prop, source);
- if (hasmntopt(&mnt, MNTOPT_RO) && !val) {
- val = TRUE;
+ if (hasmntopt(&mnt, MNTOPT_RO) && !*val) {
+ *val = B_TRUE;
if (src)
*src = ZFS_SRC_TEMPORARY;
- } else if (hasmntopt(&mnt, MNTOPT_RW) && val) {
- val = FALSE;
+ } else if (hasmntopt(&mnt, MNTOPT_RW) && *val) {
+ *val = B_FALSE;
if (src)
*src = ZFS_SRC_TEMPORARY;
}
- return (val);
+ break;
case ZFS_PROP_CREATION:
- return (zhp->zfs_dmustats.dds_creation_time);
+ *val = zhp->zfs_dmustats.dds_creation_time;
+ break;
case ZFS_PROP_QUOTA:
if (zhp->zfs_dmustats.dds_quota == 0)
*source = ""; /* default */
else
*source = zhp->zfs_name;
- return (zhp->zfs_dmustats.dds_quota);
+ *val = zhp->zfs_dmustats.dds_quota;
+ break;
case ZFS_PROP_RESERVATION:
if (zhp->zfs_dmustats.dds_reserved == 0)
*source = ""; /* default */
else
*source = zhp->zfs_name;
- return (zhp->zfs_dmustats.dds_reserved);
+ *val = zhp->zfs_dmustats.dds_reserved;
+ break;
case ZFS_PROP_COMPRESSRATIO:
/*
@@ -1255,43 +1176,50 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
* 100, so '2.5x' would be returned as 250.
*/
if (zhp->zfs_dmustats.dds_compressed_bytes == 0)
- return (100ULL);
+ *val = 100ULL;
else
- return (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 /
+ *val =
+ (zhp->zfs_dmustats.dds_uncompressed_bytes * 100 /
zhp->zfs_dmustats.dds_compressed_bytes);
+ break;
case ZFS_PROP_REFERENCED:
/*
* 'referenced' refers to the amount of physical space
* referenced (possibly shared) by this object.
*/
- return (zhp->zfs_dmustats.dds_space_refd);
+ *val = zhp->zfs_dmustats.dds_space_refd;
+ break;
case ZFS_PROP_SETUID:
- val = getprop_uint64(zhp, prop, source);
+ *val = getprop_uint64(zhp, prop, source);
- if (hasmntopt(&mnt, MNTOPT_SETUID) && !val) {
- val = TRUE;
+ if (hasmntopt(&mnt, MNTOPT_SETUID) && !*val) {
+ *val = B_TRUE;
if (src)
*src = ZFS_SRC_TEMPORARY;
- } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && val) {
- val = FALSE;
+ } else if (hasmntopt(&mnt, MNTOPT_NOSETUID) && *val) {
+ *val = B_FALSE;
if (src)
*src = ZFS_SRC_TEMPORARY;
}
- return (val);
+ break;
case ZFS_PROP_VOLSIZE:
- return (zhp->zfs_volsize);
+ *val = zhp->zfs_volsize;
+ break;
case ZFS_PROP_VOLBLOCKSIZE:
- return (zhp->zfs_volblocksize);
+ *val = zhp->zfs_volblocksize;
+ break;
case ZFS_PROP_USED:
- return (zhp->zfs_dmustats.dds_space_used);
+ *val = zhp->zfs_dmustats.dds_space_used;
+ break;
case ZFS_PROP_CREATETXG:
- return (zhp->zfs_dmustats.dds_creation_txg);
+ *val = zhp->zfs_dmustats.dds_creation_txg;
+ break;
case ZFS_PROP_MOUNTED:
/*
@@ -1306,16 +1234,22 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
search.mnt_special = (char *)zhp->zfs_name;
search.mnt_fstype = MNTTYPE_ZFS;
- rewind(zfs_mnttab());
+ rewind(zhp->zfs_hdl->libzfs_mnttab);
- if (getmntany(zfs_mnttab(), &entry, &search) == 0)
- zhp->zfs_mntopts =
- zfs_strdup(entry.mnt_mntopts);
+ if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry,
+ &search) == 0 && (zhp->zfs_mntopts =
+ zfs_strdup(zhp->zfs_hdl,
+ entry.mnt_mntopts)) == NULL)
+ return (-1);
}
- return (zhp->zfs_mntopts != NULL);
+ *val = (zhp->zfs_mntopts != NULL);
+ break;
default:
- zfs_baderror(EINVAL);
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "cannot get non-numeric property"));
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "internal error")));
}
return (0);
@@ -1355,7 +1289,7 @@ get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source,
*/
int
zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
- zfs_source_t *src, char *statbuf, size_t statlen, int literal)
+ zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
{
char *source = NULL;
uint64_t val;
@@ -1383,8 +1317,9 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
* Basic boolean values are built on top of
* get_numeric_property().
*/
- nicebool(get_numeric_property(zhp, prop, src, &source),
- propbuf, proplen);
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
+ nicebool(val, propbuf, proplen);
break;
@@ -1399,7 +1334,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
* Basic numeric values are built on top of
* get_numeric_property().
*/
- val = get_numeric_property(zhp, prop, src, &source);
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
if (literal)
(void) snprintf(propbuf, proplen, "%llu", val);
else
@@ -1533,7 +1469,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
case ZFS_PROP_QUOTA:
case ZFS_PROP_RESERVATION:
- val = get_numeric_property(zhp, prop, src, &source);
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
/*
* If quota or reservation is 0, we translate this into 'none'
@@ -1555,7 +1492,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break;
case ZFS_PROP_COMPRESSRATIO:
- val = get_numeric_property(zhp, prop, src, &source);
+ if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+ return (-1);
(void) snprintf(propbuf, proplen, "%lld.%02lldx", val / 100,
val % 100);
break;
@@ -1572,7 +1510,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
str = "snapshot";
break;
default:
- zfs_baderror(zhp->zfs_type);
+ abort();
}
(void) snprintf(propbuf, proplen, "%s", str);
break;
@@ -1584,7 +1522,10 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
* it's a boolean value, the typical values of "on" and "off"
* don't make sense, so we translate to "yes" and "no".
*/
- if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, src, &source))
+ if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
+ src, &source, &val) != 0)
+ return (-1);
+ if (val)
(void) strlcpy(propbuf, "yes", proplen);
else
(void) strlcpy(propbuf, "no", proplen);
@@ -1600,7 +1541,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break;
default:
- zfs_baderror(EINVAL);
+ abort();
}
get_source(zhp, src, source, statbuf, statlen);
@@ -1618,8 +1559,11 @@ zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
{
char *source;
zfs_source_t sourcetype = ZFS_SRC_NONE;
+ uint64_t val;
+
+ (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val);
- return (get_numeric_property(zhp, prop, &sourcetype, &source));
+ return (val);
}
/*
@@ -1635,12 +1579,15 @@ zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
* Check to see if this property applies to our object
*/
if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
- return (-1);
+ return (zfs_error(zhp->zfs_hdl, EZFS_PROPTYPE,
+ dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
+ zfs_prop_to_name(prop)));
if (src)
*src = ZFS_SRC_NONE;
- *value = get_numeric_property(zhp, prop, src, &source);
+ if (get_numeric_property(zhp, prop, src, &source, value) != 0)
+ return (-1);
get_source(zhp, src, source, statbuf, statlen);
@@ -1676,7 +1623,7 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
int ret;
for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- zfs_ioctl(ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
+ ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
/*
* Ignore private dataset names.
@@ -1688,7 +1635,8 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
* Silently ignore errors, as the only plausible explanation is
* that the pool has since been removed.
*/
- if ((nzhp = make_dataset_handle(zc.zc_name)) == NULL)
+ if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
+ zc.zc_name)) == NULL)
continue;
if ((ret = func(nzhp, data)) != 0)
@@ -1701,7 +1649,8 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
* obtained the handle.
*/
if (errno != ESRCH && errno != ENOENT)
- zfs_baderror(errno);
+ return (zfs_standard_error(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
return (0);
}
@@ -1717,10 +1666,12 @@ zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
int ret;
for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- zfs_ioctl(ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
+ ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT,
+ &zc) == 0;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
- if ((nzhp = make_dataset_handle(zc.zc_name)) == NULL)
+ if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
+ zc.zc_name)) == NULL)
continue;
if ((ret = func(nzhp, data)) != 0)
@@ -1733,7 +1684,8 @@ zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
* obtained the handle. Silently ignore this case, and return success.
*/
if (errno != ESRCH && errno != ENOENT)
- zfs_baderror(errno);
+ return (zfs_standard_error(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
return (0);
}
@@ -1774,21 +1726,22 @@ parent_name(const char *path, char *buf, size_t buflen)
* Checks to make sure that the given path has a parent, and that it exists.
*/
static int
-check_parents(const char *path, zfs_type_t type)
+check_parents(libzfs_handle_t *hdl, const char *path)
{
zfs_cmd_t zc = { 0 };
char parent[ZFS_MAXNAMELEN];
char *slash;
zfs_handle_t *zhp;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'",
+ path);
/* get parent, and check to see if this is just a pool */
if (parent_name(path, parent, sizeof (parent)) != 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': missing dataset name"),
- path, zfs_type_to_name(type));
- zfs_error(dgettext(TEXT_DOMAIN,
- "use 'zpool create' to create a storage pool"));
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing dataset name"));
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
}
/* check to see if the pool exists */
@@ -1796,40 +1749,39 @@ check_parents(const char *path, zfs_type_t type)
slash = parent + strlen(parent);
(void) strncpy(zc.zc_name, parent, slash - parent);
zc.zc_name[slash - parent] = '\0';
- if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
errno == ENOENT) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': no such pool '%s'"), path, zc.zc_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no such pool '%s'"), zc.zc_name);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
}
/* check to see if the parent dataset exists */
- if ((zhp = make_dataset_handle(parent)) == NULL) {
+ if ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
switch (errno) {
case ENOENT:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': parent does not exist"), path);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "parent does not exist"));
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
default:
- zfs_baderror(errno);
+ return (zfs_standard_error(hdl, errno, errbuf));
}
}
/* we are in a non-global zone, but parent is in the global zone */
if (getzoneid() != GLOBAL_ZONEID &&
!zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': permission denied"), path);
+ (void) zfs_standard_error(hdl, EPERM, errbuf);
zfs_close(zhp);
return (-1);
}
/* make sure parent is a filesystem */
if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': parent is not a filesystem"),
- path);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "parent is not a filesystem"));
+ (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
zfs_close(zhp);
return (-1);
}
@@ -1843,44 +1795,35 @@ check_parents(const char *path, zfs_type_t type)
* only for volumes, and indicate the size and blocksize of the volume.
*/
int
-zfs_create(const char *path, zfs_type_t type,
+zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
const char *sizestr, const char *blocksizestr)
{
- char reason[64];
zfs_cmd_t zc = { 0 };
int ret;
uint64_t size = 0;
uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
+ char errbuf[1024];
/* convert sizestr into integer size */
- if (sizestr != NULL && nicestrtonum(sizestr, &size,
- reason, sizeof (reason)) != 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad volume size '%s': %s"), sizestr, reason);
- return (-1);
- }
+ if (sizestr != NULL && nicestrtonum(hdl, sizestr, &size) != 0)
+ return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
+ "bad volume size '%s'"), sizestr));
/* convert blocksizestr into integer blocksize */
- if (blocksizestr != NULL && nicestrtonum(blocksizestr, &blocksize,
- reason, sizeof (reason)) != 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad volume blocksize '%s': %s"), blocksizestr, reason);
- return (-1);
- }
+ if (blocksizestr != NULL && nicestrtonum(hdl, blocksizestr,
+ &blocksize) != 0)
+ return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
+ "bad volume blocksize '%s'"), blocksizestr));
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot create '%s'"), path);
/* validate the path, taking care to note the extended error message */
- if (!zfs_validate_name(path, type, reason, sizeof (reason))) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': %s in %s name"), path, reason,
- zfs_type_to_name(type));
- if (strstr(reason, "snapshot") != NULL)
- zfs_error(dgettext(TEXT_DOMAIN,
- "use 'zfs snapshot' to create a snapshot"));
- return (-1);
- }
+ if (!zfs_validate_name(hdl, path, type))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
/* validate parents exist */
- if (check_parents(path, type) != 0)
+ if (check_parents(hdl, path) != 0)
return (-1);
/*
@@ -1891,10 +1834,10 @@ zfs_create(const char *path, zfs_type_t type,
* first try to see if the dataset exists.
*/
(void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
- if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) == 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': dataset exists"), path);
- return (-1);
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset already exists"));
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
}
if (type == ZFS_TYPE_VOLUME)
@@ -1911,30 +1854,30 @@ zfs_create(const char *path, zfs_type_t type,
* zero.
*/
if (size == 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad volume size '%s': cannot be zero"), sizestr);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot be zero"));
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "bad volume size '%s'"),
+ sizestr));
}
if (blocksize < SPA_MINBLOCKSIZE ||
blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad volume block size '%s': "
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"must be power of 2 from %u to %uk"),
- blocksizestr,
(uint_t)SPA_MINBLOCKSIZE,
(uint_t)SPA_MAXBLOCKSIZE >> 10);
- return (-1);
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN,
+ "bad volume block size '%s'"), blocksizestr));
}
if (size % blocksize != 0) {
- char buf[64];
- zfs_nicenum(blocksize, buf, sizeof (buf));
- zfs_error(dgettext(TEXT_DOMAIN,
- "bad volume size '%s': "
- "must be multiple of volume block size (%s)"),
- sizestr, buf);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "must be a multiple of volume block size"));
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "bad volume size '%s'"),
+ sizestr));
}
zc.zc_volsize = size;
@@ -1942,10 +1885,10 @@ zfs_create(const char *path, zfs_type_t type,
}
/* create the dataset */
- ret = zfs_ioctl(ZFS_IOC_CREATE, &zc);
+ ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
if (ret == 0 && type == ZFS_TYPE_VOLUME)
- ret = zvol_create_link(path);
+ ret = zvol_create_link(hdl, path);
/* check for failure */
if (ret != 0) {
@@ -1954,81 +1897,38 @@ zfs_create(const char *path, zfs_type_t type,
switch (errno) {
case ENOENT:
- /*
- * The parent dataset has been deleted since our
- * previous check.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': no such parent '%s'"),
- path, parent);
- break;
-
- case EPERM:
- /*
- * The user doesn't have permission to create a new
- * dataset here.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': permission denied"), path);
- break;
-
- case EDQUOT:
- case ENOSPC:
- /*
- * The parent dataset does not have enough free space
- * to create a new dataset.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': not enough space in '%s'"),
- path, parent);
- break;
-
- case EEXIST:
- /*
- * The target dataset already exists. We should have
- * caught this above, but there may be some unexplained
- * race condition.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': dataset exists"), path);
- break;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no such parent '%s'"), parent);
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
case EINVAL:
- /*
- * The target dataset does not support children.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': children unsupported in '%s'"),
- path, parent);
- break;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "parent '%s' is not a filesysem"), parent);
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
case EDOM:
- zfs_error(dgettext(TEXT_DOMAIN, "bad %s value '%s': "
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"must be power of 2 from %u to %uk"),
- zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
- blocksizestr ? blocksizestr : "<unknown>",
(uint_t)SPA_MINBLOCKSIZE,
(uint_t)SPA_MAXBLOCKSIZE >> 10);
- break;
+
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "bad block size '%s'"),
+ blocksizestr ? blocksizestr : "<unknown>"));
+
#ifdef _ILP32
case EOVERFLOW:
/*
* This platform can't address a volume this big.
*/
- if (type == ZFS_TYPE_VOLUME) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': "
- "max volume size is 1TB on 32-bit systems"),
- path);
- break;
- }
+ if (type == ZFS_TYPE_VOLUME)
+ return (zfs_error(hdl, EZFS_VOLTOOBIG,
+ errbuf));
#endif
-
+ /* FALLTHROUGH */
default:
- zfs_baderror(errno);
+ return (zfs_standard_error(hdl, errno, errbuf));
}
-
- return (-1);
}
return (0);
@@ -2043,6 +1943,7 @@ zfs_destroy(zfs_handle_t *zhp)
{
zfs_cmd_t zc = { 0 };
int ret;
+ char errbuf[1024];
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
@@ -2051,7 +1952,7 @@ zfs_destroy(zfs_handle_t *zhp)
* so that we do the right thing for snapshots of volumes.
*/
if (zhp->zfs_volblocksize != 0) {
- if (zvol_remove_link(zhp->zfs_name) != 0)
+ if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
return (-1);
zc.zc_objset_type = DMU_OST_ZVOL;
@@ -2059,63 +1960,15 @@ zfs_destroy(zfs_handle_t *zhp)
zc.zc_objset_type = DMU_OST_ZFS;
}
- ret = zfs_ioctl(ZFS_IOC_DESTROY, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc);
- if (ret != 0) {
- switch (errno) {
-
- case EPERM:
- /*
- * We don't have permission to destroy this dataset.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': permission denied"),
- zhp->zfs_name);
- break;
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot destroy '%s'"), zhp->zfs_name);
- case EIO:
- /*
- * I/O error.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': I/O error"),
- zhp->zfs_name);
- break;
-
- case ENOENT:
- /*
- * We've hit a race condition where the dataset has been
- * destroyed since we opened it.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': no such %s"),
- zhp->zfs_name, zfs_type_to_name(zhp->zfs_type));
- break;
-
- case EBUSY:
- /*
- * Even if we destroy all children, there is a chance we
- * can hit this case if:
- *
- * - A child dataset has since been created
- * - A filesystem is mounted
- *
- * This error message is awful, but hopefully we've
- * already caught the common cases (and aborted more
- * appropriately) before calling this function. There's
- * nothing else we can do at this point.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': %s is busy"),
- zhp->zfs_name, zfs_type_to_name(zhp->zfs_type));
- break;
-
- default:
- zfs_baderror(errno);
- }
-
- return (-1);
- }
+ if (ret != 0)
+ return (zfs_standard_error(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+ zhp->zfs_name));
remove_mountpoint(zhp);
@@ -2128,24 +1981,23 @@ zfs_destroy(zfs_handle_t *zhp)
int
zfs_clone(zfs_handle_t *zhp, const char *target)
{
- char reason[64];
zfs_cmd_t zc = { 0 };
char parent[ZFS_MAXNAMELEN];
int ret;
+ char errbuf[1024];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot create '%s'"), target);
+
/* validate the target name */
- if (!zfs_validate_name(target, ZFS_TYPE_FILESYSTEM, reason,
- sizeof (reason))) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': %s in filesystem name"), target,
- reason, zfs_type_to_name(ZFS_TYPE_FILESYSTEM));
- return (-1);
- }
+ if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
/* validate parents exist */
- if (check_parents(target, zhp->zfs_type) != 0)
+ if (check_parents(zhp->zfs_hdl, target) != 0)
return (-1);
(void) parent_name(target, parent, sizeof (parent));
@@ -2158,18 +2010,10 @@ zfs_clone(zfs_handle_t *zhp, const char *target)
(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename));
- ret = zfs_ioctl(ZFS_IOC_CREATE, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
if (ret != 0) {
switch (errno) {
- case EPERM:
- /*
- * The user doesn't have permission to create the clone.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': permission denied"),
- target);
- break;
case ENOENT:
/*
@@ -2181,42 +2025,147 @@ zfs_clone(zfs_handle_t *zhp, const char *target)
* that doesn't exist anymore, or whether the target
* dataset doesn't exist.
*/
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': no such parent '%s'"),
- target, parent);
- break;
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "no such parent '%s'"), parent);
+ return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
- case EDQUOT:
- case ENOSPC:
- /*
- * There is not enough space in the target dataset
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': not enough space in '%s'"),
- target, parent);
- break;
+ case EXDEV:
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "source and target pools differ"));
+ return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
+ errbuf));
- case EEXIST:
- /*
- * The target already exists.
- */
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': dataset exists"), target);
- break;
+ default:
+ return (zfs_standard_error(zhp->zfs_hdl, errno,
+ errbuf));
+ }
+ } else if (zhp->zfs_volblocksize != 0) {
+ ret = zvol_create_link(zhp->zfs_hdl, target);
+ }
- case EXDEV:
+ return (ret);
+}
+
+typedef struct promote_data {
+ char cb_mountpoint[MAXPATHLEN];
+ const char *cb_target;
+ const char *cb_errbuf;
+ uint64_t cb_pivot_txg;
+} promote_data_t;
+
+static int
+promote_snap_cb(zfs_handle_t *zhp, void *data)
+{
+ promote_data_t *pd = data;
+ zfs_handle_t *szhp;
+ int err;
+ char snapname[MAXPATHLEN];
+ char *cp;
+
+ /* We don't care about snapshots after the pivot point */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg)
+ return (0);
+
+ /*
+ * Unmount it. We actually need to open it to provoke it to be
+ * mounted first, because if it is not mounted, umount2 will
+ * mount it!
+ */
+ (void) strcpy(snapname, pd->cb_mountpoint);
+ (void) strcat(snapname, "/.zfs/snapshot/");
+ cp = strchr(zhp->zfs_name, '@');
+ (void) strcat(snapname, cp+1);
+ err = open(snapname, O_RDONLY);
+ if (err != -1)
+ (void) close(err);
+ (void) umount2(snapname, MS_FORCE);
+
+ /* Check for conflicting names */
+ (void) strcpy(snapname, pd->cb_target);
+ (void) strcat(snapname, cp);
+ szhp = make_dataset_handle(zhp->zfs_hdl, snapname);
+ if (szhp != NULL) {
+ zfs_close(szhp);
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "snapshot name '%s' from origin \n"
+ "conflicts with '%s' from target"),
+ zhp->zfs_name, snapname);
+ return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf));
+ }
+ return (0);
+}
+
+/*
+ * Promotes the given clone fs to be the clone parent.
+ */
+int
+zfs_promote(zfs_handle_t *zhp)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zfs_cmd_t zc = { 0 };
+ char parent[MAXPATHLEN];
+ char *cp;
+ int ret;
+ zfs_handle_t *pzhp;
+ promote_data_t pd;
+ char errbuf[1024];
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot promote '%s'"), zhp->zfs_name);
+
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snapshots can not be promoted"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+
+ (void) strcpy(parent, zhp->zfs_dmustats.dds_clone_of);
+ if (parent[0] == '\0') {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not a cloned filesystem"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+ }
+ cp = strchr(parent, '@');
+ *cp = '\0';
+
+ /* Walk the snapshots we will be moving */
+ pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT);
+ if (pzhp == NULL)
+ return (-1);
+ pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG);
+ zfs_close(pzhp);
+ pd.cb_target = zhp->zfs_name;
+ pd.cb_errbuf = errbuf;
+ pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY);
+ if (pzhp == NULL)
+ return (-1);
+ (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint,
+ sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE);
+ ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd);
+ if (ret != 0)
+ return (-1);
+
+ /* issue the ioctl */
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc);
+
+ if (ret != 0) {
+ switch (errno) {
+
+ case EEXIST:
/*
- * The source and target pools differ.
+ * There is a conflicting snapshot name. We
+ * should have caught this above, but they could
+ * have renamed something in the mean time.
*/
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "source and target pools differ"), target);
- break;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "conflicting snapshot name from parent '%s'"),
+ parent);
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
default:
- zfs_baderror(errno);
+ return (zfs_standard_error(hdl, errno, errbuf));
}
- } else if (zhp->zfs_volblocksize != 0) {
- ret = zvol_create_link(target);
}
return (ret);
@@ -2226,40 +2175,36 @@ zfs_clone(zfs_handle_t *zhp, const char *target)
* Takes a snapshot of the given dataset
*/
int
-zfs_snapshot(const char *path)
+zfs_snapshot(libzfs_handle_t *hdl, const char *path)
{
- char reason[64];
const char *delim;
char *parent;
zfs_handle_t *zhp;
zfs_cmd_t zc = { 0 };
int ret;
+ char errbuf[1024];
- /* validate the snapshot name */
- if (!zfs_validate_name(path, ZFS_TYPE_SNAPSHOT, reason,
- sizeof (reason))) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot snapshot '%s': %s in snapshot name"), path,
- reason);
- return (-1);
- }
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot snapshot '%s'"), path);
+
+ /* validate the target name */
+ if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
/* make sure we have a snapshot */
if ((delim = strchr(path, '@')) == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot snapshot '%s': missing '@' delim in snapshot "
- "name"), path);
- zfs_error(dgettext(TEXT_DOMAIN,
- "use 'zfs create' to create a filesystem"));
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing '@' delimeter in snapshot name"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
}
/* make sure the parent exists and is of the appropriate type */
- parent = zfs_malloc(delim - path + 1);
+ if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL)
+ return (-1);
(void) strncpy(parent, path, delim - path);
parent[delim - path] = '\0';
- if ((zhp = zfs_open(parent, ZFS_TYPE_FILESYSTEM |
+ if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
ZFS_TYPE_VOLUME)) == NULL) {
free(parent);
return (-1);
@@ -2272,56 +2217,17 @@ zfs_snapshot(const char *path)
else
zc.zc_objset_type = DMU_OST_ZFS;
- ret = zfs_ioctl(ZFS_IOC_CREATE, &zc);
+ ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) {
- ret = zvol_create_link(path);
+ ret = zvol_create_link(zhp->zfs_hdl, path);
if (ret != 0)
- (void) zfs_ioctl(ZFS_IOC_DESTROY, &zc);
+ (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY,
+ &zc);
}
- if (ret != 0) {
- switch (errno) {
- case EPERM:
- /*
- * User doesn't have permission to create a snapshot
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "permission denied"), path);
- break;
-
- case EDQUOT:
- case ENOSPC:
- /*
- * Out of space in parent.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "not enough space in '%s'"), path, parent);
- break;
-
- case EEXIST:
- /*
- * Snapshot already exists.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "snapshot exists"), path);
- break;
-
- case ENOENT:
- /*
- * Shouldn't happen because we verified the parent
- * above. But there may be a race condition where it
- * has since been removed.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': "
- "no such %s"), parent,
- zfs_type_to_name(zhp->zfs_type));
- break;
-
- default:
- zfs_baderror(errno);
- }
- }
+ if (ret != 0)
+ (void) zfs_standard_error(hdl, errno, errbuf);
free(parent);
zfs_close(zhp);
@@ -2337,6 +2243,11 @@ zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from)
{
zfs_cmd_t zc = { 0 };
int ret;
+ char errbuf[1024];
+ libzfs_handle_t *hdl = zhp_to->zfs_hdl;
+
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot send '%s'"), zhp_to->zfs_name);
/* do the ioctl() */
(void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name));
@@ -2348,34 +2259,14 @@ zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from)
}
zc.zc_cookie = STDOUT_FILENO;
- ret = zfs_ioctl(ZFS_IOC_SENDBACKUP, &zc);
+ ret = ioctl(zhp_to->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc);
if (ret != 0) {
switch (errno) {
- case EPERM:
- /*
- * User doesn't have permission to do a send
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot send '%s': "
- "permission denied"), zhp_to->zfs_name);
- break;
case EXDEV:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot send incremental from %s:\n"
- "it is not an earlier snapshot from the "
- "same fs as %s"),
- zhp_from->zfs_name, zhp_to->zfs_name);
- break;
-
- case ENOENT:
- /*
- * Shouldn't happen because we verified the parent
- * above. But there may be a race condition where it
- * has since been removed.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot open: "
- "no such snapshot"));
- break;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not an ealier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
case EDQUOT:
case EFBIG:
@@ -2388,18 +2279,11 @@ zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from)
case ERANGE:
case EFAULT:
case EROFS:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot write stream: %s"),
- strerror(errno));
- break;
-
- case EINTR:
- zfs_error(dgettext(TEXT_DOMAIN,
- "send failed: signal received"));
- break;
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
default:
- zfs_baderror(errno);
+ return (zfs_standard_error(hdl, errno, errbuf));
}
}
@@ -2410,7 +2294,8 @@ zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from)
* Restores a backup of tosnap from stdin.
*/
int
-zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
+zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
+ int verbose, int dryrun)
{
zfs_cmd_t zc = { 0 };
time_t begin_time;
@@ -2418,9 +2303,13 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
char *cp;
dmu_replay_record_t drr;
struct drr_begin *drrb = &zc.zc_begin_record;
+ char errbuf[1024];
begin_time = time(NULL);
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot receive"));
+
/* trim off snapname, if any */
(void) strcpy(zc.zc_name, tosnap);
cp = strchr(zc.zc_name, '@');
@@ -2437,31 +2326,26 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
} while (size > 0);
if (size < 0 || bytes != sizeof (drr)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: invalid stream "
- "(couldn't read first record)"));
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+ "stream (failed to read first record)"));
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
}
zc.zc_begin_record = drr.drr_u.drr_begin;
if (drrb->drr_magic != DMU_BACKUP_MAGIC &&
drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: invalid stream "
- "(invalid magic number)"));
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+ "stream (bad magic number)"));
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
}
if (drrb->drr_version != DMU_BACKUP_VERSION &&
drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) {
- if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
- drrb->drr_version = BSWAP_64(drrb->drr_version);
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: only stream version 0x%llx is supported, "
- "stream is version %llx."),
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version "
+ "0x%llx is supported (stream is version 0x%llx)"),
DMU_BACKUP_VERSION, drrb->drr_version);
- return (-1);
+ return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
}
/*
@@ -2470,10 +2354,9 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
(void) strcpy(zc.zc_filename, tosnap);
if (isprefix) {
if (strchr(tosnap, '@') != NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: "
- "argument to -d must be a filesystem"));
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination must be a filesystem"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
}
cp = strchr(drr.drr_u.drr_begin.drr_toname, '/');
@@ -2490,11 +2373,8 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
* snapname from the backup.
*/
cp = strchr(drr.drr_u.drr_begin.drr_toname, '@');
- if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: invalid snapshot name"));
- return (-1);
- }
+ if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN)
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
(void) strcat(zc.zc_filename, cp);
}
@@ -2508,20 +2388,16 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
*cp = '\0';
/* make sure destination fs exists */
- h = zfs_open(zc.zc_name, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
- if (h == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive incrememtal stream: destination\n"
- "filesystem %s does not exist"),
- zc.zc_name);
+ h = zfs_open(hdl, zc.zc_name,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (h == NULL)
return (-1);
- }
if (!dryrun) {
/* unmount destination fs or remove device link. */
if (h->zfs_type == ZFS_TYPE_FILESYSTEM) {
(void) zfs_unmount(h, NULL, 0);
} else {
- (void) zvol_remove_link(h->zfs_name);
+ (void) zvol_remove_link(hdl, h->zfs_name);
}
}
zfs_close(h);
@@ -2535,24 +2411,18 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
cp = strchr(zc.zc_name, '@');
if (cp)
*cp = '\0';
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: destination fs %s already exists"),
- zc.zc_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination '%s' already exists"), zc.zc_name);
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
}
if (isprefix) {
zfs_handle_t *h;
/* make sure prefix exists */
- h = zfs_open(tosnap, ZFS_TYPE_FILESYSTEM);
- if (h == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: "
- "%s is an invalid destination"),
- tosnap);
+ h = zfs_open(hdl, tosnap, ZFS_TYPE_FILESYSTEM);
+ if (h == NULL)
return (-1);
- }
zfs_close(h);
/* create any necessary ancestors up to prefix */
@@ -2569,24 +2439,25 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
const char *opname;
*cp = '\0';
- opname = "create";
- if (zfs_create(zc.zc_name, ZFS_TYPE_FILESYSTEM,
- NULL, NULL) != 0) {
+ opname = dgettext(TEXT_DOMAIN, "create");
+ if (zfs_create(hdl, zc.zc_name,
+ ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0) {
if (errno == EEXIST)
continue;
goto ancestorerr;
}
- opname = "open";
- h = zfs_open(zc.zc_name, ZFS_TYPE_FILESYSTEM);
+ opname = dgettext(TEXT_DOMAIN, "open");
+ h = zfs_open(hdl, zc.zc_name,
+ ZFS_TYPE_FILESYSTEM);
if (h == NULL)
goto ancestorerr;
- opname = "mount";
+ opname = dgettext(TEXT_DOMAIN, "mount");
if (zfs_mount(h, NULL, 0) != 0)
goto ancestorerr;
- opname = "share";
+ opname = dgettext(TEXT_DOMAIN, "share");
if (zfs_share(h) != 0)
goto ancestorerr;
@@ -2594,22 +2465,21 @@ zfs_receive(const char *tosnap, int isprefix, int verbose, int dryrun)
continue;
ancestorerr:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: couldn't %s ancestor %s"),
- opname, zc.zc_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "failed to %s ancestor '%s'"), opname,
+ zc.zc_name);
+ return (zfs_error(hdl, EZFS_BADRESTORE,
+ errbuf));
}
}
/* Make sure destination fs does not exist */
cp = strchr(zc.zc_name, '@');
*cp = '\0';
- if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) == 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive full stream: "
- "destination filesystem %s already exists"),
- zc.zc_name);
- return (-1);
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination '%s' exists"), zc.zc_name);
+ return (zfs_error(hdl, EZFS_EXISTS, errbuf));
}
/* Do the recvbackup ioctl to the fs's parent. */
@@ -2630,21 +2500,20 @@ ancestorerr:
}
if (dryrun)
return (0);
- err = ioctl_err = zfs_ioctl(ZFS_IOC_RECVBACKUP, &zc);
+ err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc);
if (ioctl_err != 0) {
switch (errno) {
case ENODEV:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: "
- "most recent snapshot does not "
- "match incremental source"));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "most recent snapshot does not match incremental "
+ "source"));
+ (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
break;
case ETXTBSY:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: "
- "destination has been modified since "
- "most recent snapshot --\n"
- "use 'zfs rollback' to discard changes"));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination has been modified since most recent "
+ "snapshot"));
+ (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
break;
case EEXIST:
if (drrb->drr_fromguid == 0) {
@@ -2652,45 +2521,21 @@ ancestorerr:
cp = strchr(zc.zc_filename, '@');
*cp = '\0';
}
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive to %s: destination already exists"),
- zc.zc_filename);
- break;
- case ENOENT:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: destination does not exist"));
- break;
- case EBUSY:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: destination is in use"));
- break;
- case ENOSPC:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: out of space"));
- break;
- case EDQUOT:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: quota exceeded"));
- break;
- case EINTR:
- zfs_error(dgettext(TEXT_DOMAIN,
- "receive failed: signal received"));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "destination already exists"));
+ (void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN,
+ "cannot restore to %s"), zc.zc_filename);
break;
case EINVAL:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: invalid stream"));
+ (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
case ECKSUM:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: invalid stream "
- "(checksum mismatch)"));
- break;
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot receive: permission denied"));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid stream (checksum mismatch)"));
+ (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
default:
- zfs_baderror(errno);
+ (void) zfs_standard_error(hdl, errno, errbuf);
}
}
@@ -2705,16 +2550,17 @@ ancestorerr:
zfs_handle_t *h;
*cp = '\0';
- h = zfs_open(zc.zc_filename,
+ h = zfs_open(hdl, zc.zc_filename,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
*cp = '@';
if (h) {
if (h->zfs_type == ZFS_TYPE_FILESYSTEM) {
err = zfs_mount(h, NULL, 0);
} else {
- err = zvol_create_link(h->zfs_name);
+ err = zvol_create_link(hdl, h->zfs_name);
if (err == 0 && ioctl_err == 0)
- err = zvol_create_link(zc.zc_filename);
+ err = zvol_create_link(hdl,
+ zc.zc_filename);
}
zfs_close(h);
}
@@ -2750,7 +2596,7 @@ typedef struct rollback_data {
uint64_t cb_create; /* creation time reference */
prop_changelist_t *cb_clp; /* changelist pointer */
int cb_error;
- int cb_dependent;
+ boolean_t cb_dependent;
} rollback_data_t;
static int
@@ -2764,9 +2610,9 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
cbp->cb_create) {
- cbp->cb_dependent = TRUE;
+ cbp->cb_dependent = B_TRUE;
(void) zfs_iter_dependents(zhp, rollback_destroy, cbp);
- cbp->cb_dependent = FALSE;
+ cbp->cb_dependent = B_FALSE;
if (zfs_destroy(zhp) != 0)
cbp->cb_error = 1;
@@ -2797,7 +2643,7 @@ do_rollback(zfs_handle_t *zhp)
zhp->zfs_type == ZFS_TYPE_VOLUME);
if (zhp->zfs_type == ZFS_TYPE_VOLUME &&
- zvol_remove_link(zhp->zfs_name) != 0)
+ zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
return (-1);
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
@@ -2814,58 +2660,13 @@ do_rollback(zfs_handle_t *zhp)
* condition where the user has taken a snapshot since we verified that
* this was the most recent.
*/
- if ((ret = zfs_ioctl(ZFS_IOC_ROLLBACK, &zc)) != 0) {
- switch (errno) {
- case EPERM:
- /*
- * The user doesn't have permission to rollback the
- * given dataset.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': "
- "permission denied"), zhp->zfs_name);
- break;
-
- case EDQUOT:
- case ENOSPC:
- /*
- * The parent dataset doesn't have enough space to
- * rollback to the last snapshot.
- */
- {
- char parent[ZFS_MAXNAMELEN];
- (void) parent_name(zhp->zfs_name, parent,
- sizeof (parent));
- zfs_error(dgettext(TEXT_DOMAIN, "cannot "
- "rollback '%s': out of space"), parent);
- }
- break;
-
- case ENOENT:
- /*
- * The dataset doesn't exist. This shouldn't happen
- * except in race conditions.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': "
- "no such %s"), zhp->zfs_name,
- zfs_type_to_name(zhp->zfs_type));
- break;
-
- case EBUSY:
- /*
- * The filesystem is busy. This should have been caught
- * by the caller before getting here, but there may be
- * an unexpected problem.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rollback '%s': "
- "%s is busy"), zhp->zfs_name,
- zfs_type_to_name(zhp->zfs_type));
- break;
-
- default:
- zfs_baderror(errno);
- }
+ if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK,
+ &zc)) != 0) {
+ (void) zfs_standard_error(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
+ zhp->zfs_name);
} else if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
- ret = zvol_create_link(zhp->zfs_name);
+ ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
}
return (ret);
@@ -2946,9 +2747,10 @@ zfs_iter_dependents(zfs_handle_t *zhp, zfs_iter_f func, void *data)
zfs_handle_t *child;
int ret = 0;
- dependents = get_dependents(zhp->zfs_name, &count);
+ dependents = get_dependents(zhp->zfs_hdl, zhp->zfs_name, &count);
for (i = 0; i < count; i++) {
- if ((child = make_dataset_handle(dependents[i])) == NULL)
+ if ((child = make_dataset_handle(zhp->zfs_hdl,
+ dependents[i])) == NULL)
continue;
if ((ret = func(child, data)) != 0)
@@ -2970,10 +2772,11 @@ zfs_rename(zfs_handle_t *zhp, const char *target)
{
int ret;
zfs_cmd_t zc = { 0 };
- char reason[64];
char *delim;
prop_changelist_t *cl;
char parent[ZFS_MAXNAMELEN];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ char errbuf[1024];
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value));
@@ -2982,22 +2785,21 @@ zfs_rename(zfs_handle_t *zhp, const char *target)
if (strcmp(zhp->zfs_name, target) == 0)
return (0);
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "cannot rename to '%s'"), target);
+
/*
* Make sure the target name is valid
*/
- if (!zfs_validate_name(target, zhp->zfs_type, reason,
- sizeof (reason))) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create '%s': %s in %s name"), target, reason,
- zfs_type_to_name(zhp->zfs_type));
- return (-1);
- }
+ if (!zfs_validate_name(hdl, target, zhp->zfs_type))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+
if ((delim = strchr(target, '@')) == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot rename to '%s': not a snapshot"), target);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not a snapshot"));
+ return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
}
/*
@@ -3005,17 +2807,16 @@ zfs_rename(zfs_handle_t *zhp, const char *target)
*/
if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
zhp->zfs_name[delim - target] != '@') {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot rename to '%s': snapshots must be part "
- "of same dataset"), target);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snapshots must be part of same dataset"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
}
(void) strncpy(parent, target, delim - target);
parent[delim - target] = '\0';
} else {
/* validate parents */
- if (check_parents(target, zhp->zfs_type) != 0)
+ if (check_parents(hdl, target) != 0)
return (-1);
(void) parent_name(target, parent, sizeof (parent));
@@ -3024,28 +2825,30 @@ zfs_rename(zfs_handle_t *zhp, const char *target)
verify((delim = strchr(target, '/')) != NULL);
if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
zhp->zfs_name[delim - target] != '/') {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot rename to '%s': "
- "datasets must be within same pool"), target);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "datasets must be within same pool"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
}
}
+ (void) snprintf(errbuf, sizeof (errbuf),
+ dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
+
if (getzoneid() == GLOBAL_ZONEID &&
zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rename %s, "
- "dataset is used in a non-global zone"), zhp->zfs_name);
- return (-1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is used in a non-global zone"));
+ return (zfs_error(hdl, EZFS_ZONED, errbuf));
}
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL)
- return (1);
+ return (-1);
if (changelist_haszonedchild(cl)) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot rename '%s': child dataset with inherited "
- "mountpoint is used in a non-global zone"), zhp->zfs_name);
- ret = -1;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "child dataset with inherited mountpoint is used "
+ "in a non-global zone"));
+ ret = zfs_error(hdl, EZFS_ZONED, errbuf);
goto error;
}
@@ -3057,59 +2860,8 @@ zfs_rename(zfs_handle_t *zhp, const char *target)
else
zc.zc_objset_type = DMU_OST_ZFS;
- if ((ret = zfs_ioctl(ZFS_IOC_RENAME, &zc)) != 0) {
- switch (errno) {
- case EPERM:
- /*
- * The user doesn't have permission to rename the
- * given dataset.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': "
- "permission denied"), zhp->zfs_name);
- break;
-
- case EDQUOT:
- case ENOSPC:
- /*
- * Not enough space in the parent dataset.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot "
- "rename '%s': not enough space in '%s'"),
- zhp->zfs_name, parent);
- break;
-
- case ENOENT:
- /*
- * The destination doesn't exist.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' "
- "to '%s': destination doesn't exist"),
- zhp->zfs_name, target);
- break;
-
- case EEXIST:
- /*
- * The destination already exists.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s' "
- "to '%s': destination already exists"),
- zhp->zfs_name, target);
- break;
-
- case EBUSY:
- /*
- * The filesystem is busy. This should have been caught
- * by the caller before getting here, but there may be
- * an unexpected problem.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot rename '%s': "
- "%s is busy"), zhp->zfs_name,
- zfs_type_to_name(zhp->zfs_type));
- break;
-
- default:
- zfs_baderror(errno);
- }
+ if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) {
+ (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
/*
* On failure, we still want to remount any filesystems that
@@ -3132,24 +2884,18 @@ error:
* poke devfsadm to create the /dev link, and then wait for the link to appear.
*/
int
-zvol_create_link(const char *dataset)
+zvol_create_link(libzfs_handle_t *hdl, const char *dataset)
{
zfs_cmd_t zc = { 0 };
- di_devlink_handle_t hdl;
+ di_devlink_handle_t dhdl;
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
/*
* Issue the appropriate ioctl.
*/
- if (zfs_ioctl(ZFS_IOC_CREATE_MINOR, &zc) != 0) {
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) {
switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create "
- "device links for '%s': permission denied"),
- dataset);
- break;
-
case EEXIST:
/*
* Silently ignore the case where the link already
@@ -3159,22 +2905,24 @@ zvol_create_link(const char *dataset)
return (0);
default:
- zfs_baderror(errno);
+ return (zfs_standard_error(hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot create device links "
+ "for '%s'"), dataset));
}
-
- return (-1);
}
/*
* Call devfsadm and wait for the links to magically appear.
*/
- if ((hdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot create device links for '%s'"), dataset);
- (void) zfs_ioctl(ZFS_IOC_REMOVE_MINOR, &zc);
+ if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) {
+ zfs_error_aux(hdl, strerror(errno));
+ (void) zfs_error(hdl, EZFS_DEVLINKS,
+ dgettext(TEXT_DOMAIN, "cannot create device links "
+ "for '%s'"), dataset);
+ (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc);
return (-1);
} else {
- (void) di_devlink_fini(&hdl);
+ (void) di_devlink_fini(&dhdl);
}
return (0);
@@ -3184,26 +2932,14 @@ zvol_create_link(const char *dataset)
* Remove a minor node for the given zvol and the associated /dev links.
*/
int
-zvol_remove_link(const char *dataset)
+zvol_remove_link(libzfs_handle_t *hdl, const char *dataset)
{
zfs_cmd_t zc = { 0 };
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- if (zfs_ioctl(ZFS_IOC_REMOVE_MINOR, &zc) != 0) {
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) {
switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot remove "
- "device links for '%s': permission denied"),
- dataset);
- break;
-
- case EBUSY:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot remove "
- "device links for '%s': volume is in use"),
- dataset);
- break;
-
case ENXIO:
/*
* Silently ignore the case where the link no longer
@@ -3213,10 +2949,10 @@ zvol_remove_link(const char *dataset)
return (0);
default:
- zfs_baderror(errno);
+ return (zfs_standard_error(hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot remove device "
+ "links for '%s'"), dataset));
}
-
- return (-1);
}
return (0);
diff --git a/usr/src/lib/libzfs/common/libzfs_graph.c b/usr/src/lib/libzfs/common/libzfs_graph.c
index 4c7bb547ee..e86a6c9377 100644
--- a/usr/src/lib/libzfs/common/libzfs_graph.c
+++ b/usr/src/lib/libzfs/common/libzfs_graph.c
@@ -121,9 +121,12 @@ typedef struct zfs_graph {
* Allocate a new edge pointing to the target vertex.
*/
static zfs_edge_t *
-zfs_edge_create(zfs_vertex_t *dest)
+zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
{
- zfs_edge_t *zep = zfs_malloc(sizeof (zfs_edge_t));
+ zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
+
+ if (zep == NULL)
+ return (NULL);
zep->ze_dest = dest;
@@ -143,15 +146,23 @@ zfs_edge_destroy(zfs_edge_t *zep)
* Allocate a new vertex with the given name.
*/
static zfs_vertex_t *
-zfs_vertex_create(const char *dataset)
+zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
{
- zfs_vertex_t *zvp = zfs_malloc(sizeof (zfs_vertex_t));
+ zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
+
+ if (zvp == NULL)
+ return (NULL);
assert(strlen(dataset) < ZFS_MAXNAMELEN);
(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
- zvp->zv_edges = zfs_malloc(MIN_EDGECOUNT * sizeof (void *));
+ if ((zvp->zv_edges = zfs_alloc(hdl,
+ MIN_EDGECOUNT * sizeof (void *))) == NULL) {
+ free(zvp);
+ return (NULL);
+ }
+
zvp->zv_edgealloc = MIN_EDGECOUNT;
return (zvp);
@@ -175,15 +186,22 @@ zfs_vertex_destroy(zfs_vertex_t *zvp)
/*
* Given a vertex, add an edge to the destination vertex.
*/
-static void
-zfs_vertex_add_edge(zfs_vertex_t *zvp, zfs_vertex_t *dest)
+static int
+zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
+ zfs_vertex_t *dest)
{
- zfs_edge_t *zep = zfs_edge_create(dest);
+ zfs_edge_t *zep = zfs_edge_create(hdl, dest);
+
+ if (zep == NULL)
+ return (-1);
if (zvp->zv_edgecount == zvp->zv_edgealloc) {
- zfs_edge_t **newedges = zfs_malloc(zvp->zv_edgealloc * 2 *
+ zfs_edge_t **newedges = zfs_alloc(hdl, zvp->zv_edgealloc * 2 *
sizeof (void *));
+ if (newedges == NULL)
+ return (-1);
+
bcopy(zvp->zv_edges, newedges,
zvp->zv_edgealloc * sizeof (void *));
@@ -193,6 +211,8 @@ zfs_vertex_add_edge(zfs_vertex_t *zvp, zfs_vertex_t *dest)
}
zvp->zv_edges[zvp->zv_edgecount++] = zep;
+
+ return (0);
}
static int
@@ -227,12 +247,19 @@ zfs_vertex_sort_edges(zfs_vertex_t *zvp)
* datasets in the pool.
*/
static zfs_graph_t *
-zfs_graph_create(size_t size)
+zfs_graph_create(libzfs_handle_t *hdl, size_t size)
{
- zfs_graph_t *zgp = zfs_malloc(sizeof (zfs_graph_t));
+ zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
+
+ if (zgp == NULL)
+ return (NULL);
zgp->zg_size = size;
- zgp->zg_hash = zfs_malloc(size * sizeof (zfs_vertex_t *));
+ if ((zgp->zg_hash = zfs_alloc(hdl,
+ size * sizeof (zfs_vertex_t *))) == NULL) {
+ free(zgp);
+ return (NULL);
+ }
return (zgp);
}
@@ -280,7 +307,8 @@ zfs_graph_hash(zfs_graph_t *zgp, const char *str)
* Given a dataset name, finds the associated vertex, creating it if necessary.
*/
static zfs_vertex_t *
-zfs_graph_lookup(zfs_graph_t *zgp, const char *dataset, uint64_t txg)
+zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
+ uint64_t txg)
{
size_t idx = zfs_graph_hash(zgp, dataset);
zfs_vertex_t *zvp;
@@ -293,7 +321,9 @@ zfs_graph_lookup(zfs_graph_t *zgp, const char *dataset, uint64_t txg)
}
}
- zvp = zfs_vertex_create(dataset);
+ if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
+ return (NULL);
+
zvp->zv_next = zgp->zg_hash[idx];
zvp->zv_txg = txg;
zgp->zg_hash[idx] = zvp;
@@ -308,43 +338,52 @@ zfs_graph_lookup(zfs_graph_t *zgp, const char *dataset, uint64_t txg)
* created it as a destination of another edge. If 'dest' is NULL, then this
* is an individual vertex (i.e. the starting vertex), so don't add an edge.
*/
-static void
-zfs_graph_add(zfs_graph_t *zgp, const char *source, const char *dest,
- uint64_t txg)
+static int
+zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
+ const char *dest, uint64_t txg)
{
zfs_vertex_t *svp, *dvp;
- svp = zfs_graph_lookup(zgp, source, 0);
+ if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
+ return (-1);
svp->zv_visited = 1;
if (dest != NULL) {
- dvp = zfs_graph_lookup(zgp, dest, txg);
- zfs_vertex_add_edge(svp, dvp);
+ dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
+ if (dvp == NULL)
+ return (-1);
+ if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
+ return (-1);
}
+
+ return (0);
}
/*
* Iterate over all children of the given dataset, adding any vertices as
- * necessary. Returns 0 if no cloned snapshots were seen, 1 otherwise. This is
+ * necessary. Returns 0 if no cloned snapshots were seen, -1 if there was an
+ * error, or 1 otherwise. This is
* a simple recursive algorithm - the ZFS namespace typically is very flat. We
* manually invoke the necessary ioctl() calls to avoid the overhead and
* additional semantics of zfs_open().
*/
static int
-iterate_children(zfs_graph_t *zgp, const char *dataset)
+iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
{
zfs_cmd_t zc = { 0 };
- int ret = 0;
+ int ret = 0, err;
zfs_vertex_t *zvp;
/*
* Look up the source vertex, and avoid it if we've seen it before.
*/
- zvp = zfs_graph_lookup(zgp, dataset, 0);
+ zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
+ if (zvp == NULL)
+ return (-1);
if (zvp->zv_visited)
return (0);
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- zfs_ioctl(ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
+ ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
/*
@@ -358,32 +397,38 @@ iterate_children(zfs_graph_t *zgp, const char *dataset)
* dataset and clone statistics. If this fails, the dataset has
* since been removed, and we're pretty much screwed anyway.
*/
- if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) != 0)
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
continue;
/*
* Add an edge between the parent and the child.
*/
- zfs_graph_add(zgp, dataset, zc.zc_name,
- zc.zc_objset_stats.dds_creation_txg);
+ if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
+ zc.zc_objset_stats.dds_creation_txg) != 0)
+ return (-1);
/*
* If this dataset has a clone parent, add an appropriate edge.
*/
- if (zc.zc_objset_stats.dds_clone_of[0] != '\0')
- zfs_graph_add(zgp, zc.zc_objset_stats.dds_clone_of,
- zc.zc_name, zc.zc_objset_stats.dds_creation_txg);
+ if (zc.zc_objset_stats.dds_clone_of[0] != '\0' &&
+ zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_clone_of,
+ zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0)
+ return (-1);
/*
* Iterate over all children
*/
- ret |= iterate_children(zgp, zc.zc_name);
+ err = iterate_children(hdl, zgp, zc.zc_name);
+ if (err == -1)
+ return (-1);
+ else if (err == 1)
+ ret = 1;
/*
* Indicate if we found a dataset with a non-zero clone count.
*/
if (zc.zc_objset_stats.dds_num_clones != 0)
- ret |= 1;
+ ret = 1;
}
/*
@@ -392,7 +437,7 @@ iterate_children(zfs_graph_t *zgp, const char *dataset)
bzero(&zc, sizeof (zc));
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- zfs_ioctl(ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
+ ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
/*
@@ -400,20 +445,21 @@ iterate_children(zfs_graph_t *zgp, const char *dataset)
* dataset and clone statistics. If this fails, the dataset has
* since been removed, and we're pretty much screwed anyway.
*/
- if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) != 0)
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
continue;
/*
* Add an edge between the parent and the child.
*/
- zfs_graph_add(zgp, dataset, zc.zc_name,
- zc.zc_objset_stats.dds_creation_txg);
+ if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
+ zc.zc_objset_stats.dds_creation_txg) != 0)
+ return (-1);
/*
* Indicate if we found a dataset with a non-zero clone count.
*/
if (zc.zc_objset_stats.dds_num_clones != 0)
- ret |= 1;
+ ret = 1;
}
zvp->zv_visited = 1;
@@ -428,20 +474,24 @@ iterate_children(zfs_graph_t *zgp, const char *dataset)
* over all datasets.
*/
static zfs_graph_t *
-construct_graph(const char *dataset)
+construct_graph(libzfs_handle_t *hdl, const char *dataset)
{
- zfs_graph_t *zgp = zfs_graph_create(ZFS_GRAPH_SIZE);
+ zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE);
zfs_cmd_t zc = { 0 };
+ int ret = 0;
+
+ if (zgp == NULL)
+ return (zgp);
/*
* We need to explicitly check whether this dataset has clones or not,
* since iterate_children() only checks the children.
*/
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- (void) zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc);
+ (void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc);
if (zc.zc_objset_stats.dds_num_clones != 0 ||
- iterate_children(zgp, dataset) != 0) {
+ (ret = iterate_children(hdl, zgp, dataset)) != 0) {
/*
* Determine pool name and try again.
*/
@@ -449,17 +499,29 @@ construct_graph(const char *dataset)
if ((slash = strchr(dataset, '/')) != NULL ||
(slash = strchr(dataset, '@')) != NULL) {
- pool = zfs_malloc(slash - dataset + 1);
+ pool = zfs_alloc(hdl, slash - dataset + 1);
+ if (pool == NULL) {
+ zfs_graph_destroy(zgp);
+ return (NULL);
+ }
(void) strncpy(pool, dataset, slash - dataset);
pool[slash - dataset] = '\0';
- (void) iterate_children(zgp, pool);
- zfs_graph_add(zgp, pool, NULL, 0);
+ if (iterate_children(hdl, zgp, pool) == -1 ||
+ zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
+ free(pool);
+ zfs_graph_destroy(zgp);
+ return (NULL);
+ }
free(pool);
}
}
- zfs_graph_add(zgp, dataset, NULL, 0);
+
+ if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
+ zfs_graph_destroy(zgp);
+ return (NULL);
+ }
return (zgp);
}
@@ -469,27 +531,33 @@ construct_graph(const char *dataset)
* really just a depth first search, so that the deepest nodes appear first.
* hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
*/
-static void
-topo_sort(char **result, size_t *idx, zfs_vertex_t *zgv)
+static int
+topo_sort(libzfs_handle_t *hdl, char **result, size_t *idx, zfs_vertex_t *zgv)
{
int i;
/* avoid doing a search if we don't have to */
if (zgv->zv_visited == 2)
- return;
+ return (0);
zfs_vertex_sort_edges(zgv);
- for (i = 0; i < zgv->zv_edgecount; i++)
- topo_sort(result, idx, zgv->zv_edges[i]->ze_dest);
+ for (i = 0; i < zgv->zv_edgecount; i++) {
+ if (topo_sort(hdl, result, idx, zgv->zv_edges[i]->ze_dest) != 0)
+ return (-1);
+ }
/* we may have visited this in the course of the above */
if (zgv->zv_visited == 2)
- return;
+ return (0);
+
+ if ((result[*idx] = zfs_alloc(hdl,
+ strlen(zgv->zv_dataset) + 1)) == NULL)
+ return (-1);
- result[*idx] = zfs_malloc(strlen(zgv->zv_dataset) + 1);
(void) strcpy(result[*idx], zgv->zv_dataset);
*idx += 1;
zgv->zv_visited = 2;
+ return (0);
}
/*
@@ -498,19 +566,33 @@ topo_sort(char **result, size_t *idx, zfs_vertex_t *zgv)
* sort, and then return the array of strings to the caller.
*/
char **
-get_dependents(const char *dataset, size_t *count)
+get_dependents(libzfs_handle_t *hdl, const char *dataset, size_t *count)
{
char **result;
zfs_graph_t *zgp;
zfs_vertex_t *zvp;
- zgp = construct_graph(dataset);
- result = zfs_malloc(zgp->zg_nvertex * sizeof (char *));
+ if ((zgp = construct_graph(hdl, dataset)) == NULL)
+ return (NULL);
- zvp = zfs_graph_lookup(zgp, dataset, 0);
+ if ((result = zfs_alloc(hdl,
+ zgp->zg_nvertex * sizeof (char *))) == NULL) {
+ zfs_graph_destroy(zgp);
+ return (NULL);
+ }
+
+ if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
+ free(result);
+ zfs_graph_destroy(zgp);
+ return (NULL);
+ }
*count = 0;
- topo_sort(result, count, zvp);
+ if (topo_sort(hdl, result, count, zvp) != 0) {
+ free(result);
+ zfs_graph_destroy(zgp);
+ return (NULL);
+ }
/*
* Get rid of the last entry, which is our starting vertex and not
diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h
index 76bca21242..2c5e890767 100644
--- a/usr/src/lib/libzfs/common/libzfs_impl.h
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h
@@ -34,13 +34,29 @@
#include <sys/zfs_acl.h>
#include <sys/nvpair.h>
+#include <libuutil.h>
#include <libzfs.h>
#ifdef __cplusplus
extern "C" {
#endif
+struct libzfs_handle {
+ int libzfs_error;
+ int libzfs_fd;
+ FILE *libzfs_mnttab;
+ FILE *libzfs_sharetab;
+ uu_avl_pool_t *libzfs_ns_avlpool;
+ uu_avl_t *libzfs_ns_avl;
+ uint64_t libzfs_ns_gen;
+ int libzfs_desc_active;
+ char libzfs_action[1024];
+ char libzfs_desc[1024];
+ int libzfs_printerr;
+};
+
struct zfs_handle {
+ libzfs_handle_t *zfs_hdl;
char zfs_name[ZFS_MAXNAMELEN];
zfs_type_t zfs_type;
dmu_objset_stats_t zfs_dmustats;
@@ -52,6 +68,7 @@ struct zfs_handle {
};
struct zpool_handle {
+ libzfs_handle_t *zpool_hdl;
char zpool_name[ZPOOL_MAXNAMELEN];
int zpool_state;
size_t zpool_config_size;
@@ -61,18 +78,16 @@ struct zpool_handle {
size_t zpool_error_count;
};
-void zfs_error(const char *, ...);
-void zfs_fatal(const char *, ...);
-void *zfs_malloc(size_t);
-char *zfs_strdup(const char *);
-void no_memory(void);
+int zfs_error(libzfs_handle_t *, int, const char *, ...);
+void zfs_error_aux(libzfs_handle_t *, const char *, ...);
+void *zfs_alloc(libzfs_handle_t *, size_t);
+char *zfs_strdup(libzfs_handle_t *, const char *);
+int no_memory(libzfs_handle_t *);
-#define zfs_baderror(err) \
- (zfs_fatal(dgettext(TEXT_DOMAIN, \
- "internal error: unexpected error %d at line %d of %s"), \
- (err), (__LINE__), (__FILE__)))
+int zfs_standard_error(libzfs_handle_t *, int, const char *, ...);
+int zpool_standard_error(libzfs_handle_t *, int, const char *, ...);
-char **get_dependents(const char *, size_t *);
+char **get_dependents(libzfs_handle_t *, const char *, size_t *);
typedef struct prop_changelist prop_changelist_t;
@@ -87,17 +102,15 @@ int changelist_haszonedchild(prop_changelist_t *);
void remove_mountpoint(zfs_handle_t *);
-zfs_handle_t *make_dataset_handle(const char *);
-void set_pool_health(nvlist_t *);
+zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
+int set_pool_health(nvlist_t *);
-zpool_handle_t *zpool_open_silent(const char *);
+zpool_handle_t *zpool_open_silent(libzfs_handle_t *, const char *);
-int zvol_create_link(const char *);
-int zvol_remove_link(const char *);
+int zvol_create_link(libzfs_handle_t *, const char *);
+int zvol_remove_link(libzfs_handle_t *, const char *);
-int zfs_ioctl(int, zfs_cmd_t *);
-FILE *zfs_mnttab(void);
-FILE *zfs_sharetab(void);
+void namespace_clear(libzfs_handle_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
index 98519c3aae..ef34419146 100644
--- a/usr/src/lib/libzfs/common/libzfs_import.c
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
@@ -78,7 +78,7 @@ typedef struct pool_entry {
} pool_entry_t;
typedef struct name_entry {
- const char *ne_name;
+ char *ne_name;
uint64_t ne_guid;
struct name_entry *ne_next;
} name_entry_t;
@@ -117,7 +117,7 @@ get_devid(const char *path)
* Go through and fix up any path and/or devid information for the given vdev
* configuration.
*/
-static void
+static int
fix_paths(nvlist_t *nv, name_entry_t *names)
{
nvlist_t **child;
@@ -130,8 +130,9 @@ fix_paths(nvlist_t *nv, name_entry_t *names)
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) == 0) {
for (c = 0; c < children; c++)
- fix_paths(child[c], names);
- return;
+ if (fix_paths(child[c], names) != 0)
+ return (-1);
+ return (0);
}
/*
@@ -182,31 +183,56 @@ fix_paths(nvlist_t *nv, name_entry_t *names)
}
if (best == NULL)
- return;
+ return (0);
- verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) == 0);
+ if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) != 0)
+ return (-1);
if ((devid = get_devid(best->ne_name)) == NULL) {
(void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
} else {
- verify(nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) == 0);
+ if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0)
+ return (-1);
devid_str_free(devid);
}
+
+ return (0);
}
/*
* Add the given configuration to the list of known devices.
*/
-static void
-add_config(pool_list_t *pl, const char *path, nvlist_t *config)
+static int
+add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
+ nvlist_t *config)
{
- uint64_t pool_guid, vdev_guid, top_guid, txg;
+ uint64_t pool_guid, vdev_guid, top_guid, txg, state;
pool_entry_t *pe;
vdev_entry_t *ve;
config_entry_t *ce;
name_entry_t *ne;
/*
+ * If this is a hot spare not currently in use, add it to the list of
+ * names to translate, but don't do anything else.
+ */
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+ &state) == 0 && state == POOL_STATE_SPARE &&
+ nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0) {
+ if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL)
+ return (-1);
+
+ if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
+ free(ne);
+ return (-1);
+ }
+ ne->ne_guid = vdev_guid;
+ ne->ne_next = pl->names;
+ pl->names = ne;
+ return (0);
+ }
+
+ /*
* If we have a valid config but cannot read any of these fields, then
* it means we have a half-initialized label. In vdev_label_init()
* we write a label with txg == 0 so that we can identify the device
@@ -223,7 +249,7 @@ add_config(pool_list_t *pl, const char *path, nvlist_t *config)
nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
&txg) != 0 || txg == 0) {
nvlist_free(config);
- return;
+ return (0);
}
/*
@@ -236,7 +262,10 @@ add_config(pool_list_t *pl, const char *path, nvlist_t *config)
}
if (pe == NULL) {
- pe = zfs_malloc(sizeof (pool_entry_t));
+ if ((pe = zfs_alloc(hdl, sizeof (pool_entry_t))) == NULL) {
+ nvlist_free(config);
+ return (-1);
+ }
pe->pe_guid = pool_guid;
pe->pe_next = pl->pools;
pl->pools = pe;
@@ -252,7 +281,10 @@ add_config(pool_list_t *pl, const char *path, nvlist_t *config)
}
if (ve == NULL) {
- ve = zfs_malloc(sizeof (vdev_entry_t));
+ if ((ve = zfs_alloc(hdl, sizeof (vdev_entry_t))) == NULL) {
+ nvlist_free(config);
+ return (-1);
+ }
ve->ve_guid = top_guid;
ve->ve_next = pe->pe_vdevs;
pe->pe_vdevs = ve;
@@ -269,7 +301,10 @@ add_config(pool_list_t *pl, const char *path, nvlist_t *config)
}
if (ce == NULL) {
- ce = zfs_malloc(sizeof (config_entry_t));
+ if ((ce = zfs_alloc(hdl, sizeof (config_entry_t))) == NULL) {
+ nvlist_free(config);
+ return (-1);
+ }
ce->ce_txg = txg;
ce->ce_config = config;
ce->ce_next = ve->ve_configs;
@@ -284,24 +319,31 @@ add_config(pool_list_t *pl, const char *path, nvlist_t *config)
* mappings so that we can fix up the configuration as necessary before
* doing the import.
*/
- ne = zfs_malloc(sizeof (name_entry_t));
+ if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL)
+ return (-1);
+
+ if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
+ free(ne);
+ return (-1);
+ }
- ne->ne_name = zfs_strdup(path);
ne->ne_guid = vdev_guid;
ne->ne_next = pl->names;
pl->names = ne;
+
+ return (0);
}
/*
* Returns true if the named pool matches the given GUID.
*/
-boolean_t
-pool_active(const char *name, uint64_t guid)
+static boolean_t
+pool_active(libzfs_handle_t *hdl, const char *name, uint64_t guid)
{
zpool_handle_t *zhp;
uint64_t theguid;
- if ((zhp = zpool_open_silent(name)) == NULL)
+ if ((zhp = zpool_open_silent(hdl, name)) == NULL)
return (B_FALSE);
verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID,
@@ -320,41 +362,42 @@ pool_active(const char *name, uint64_t guid)
* return to the user.
*/
static nvlist_t *
-get_configs(pool_list_t *pl)
+get_configs(libzfs_handle_t *hdl, pool_list_t *pl)
{
- pool_entry_t *pe, *penext;
- vdev_entry_t *ve, *venext;
- config_entry_t *ce, *cenext;
- nvlist_t *ret, *config, *tmp, *nvtop, *nvroot;
- int config_seen;
+ pool_entry_t *pe;
+ vdev_entry_t *ve;
+ config_entry_t *ce;
+ nvlist_t *ret = NULL, *config = NULL, *tmp, *nvtop, *nvroot;
+ nvlist_t **spares;
+ uint_t i, nspares;
+ boolean_t config_seen;
uint64_t best_txg;
char *name;
zfs_cmd_t zc = { 0 };
- uint64_t guid;
+ uint64_t version, guid;
char *packed;
size_t len;
int err;
+ uint_t children = 0;
+ nvlist_t **child = NULL;
+ uint_t c;
- verify(nvlist_alloc(&ret, 0, 0) == 0);
+ if (nvlist_alloc(&ret, 0, 0) != 0)
+ goto nomem;
- for (pe = pl->pools; pe != NULL; pe = penext) {
- uint_t c;
- uint_t children = 0;
+ for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
uint64_t id;
- nvlist_t **child = NULL;
- penext = pe->pe_next;
-
- verify(nvlist_alloc(&config, NV_UNIQUE_NAME, 0) == 0);
- config_seen = FALSE;
+ if (nvlist_alloc(&config, NV_UNIQUE_NAME, 0) != 0)
+ goto nomem;
+ config_seen = B_FALSE;
/*
* Iterate over all toplevel vdevs. Grab the pool configuration
* from the first one we find, and then go through the rest and
* add them as necessary to the 'vdevs' member of the config.
*/
- for (ve = pe->pe_vdevs; ve != NULL; ve = venext) {
- venext = ve->ve_next;
+ for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
/*
* Determine the best configuration for this vdev by
@@ -365,8 +408,10 @@ get_configs(pool_list_t *pl)
for (ce = ve->ve_configs; ce != NULL;
ce = ce->ce_next) {
- if (ce->ce_txg > best_txg)
+ if (ce->ce_txg > best_txg) {
tmp = ce->ce_config;
+ best_txg = ce->ce_txg;
+ }
}
if (!config_seen) {
@@ -374,6 +419,7 @@ get_configs(pool_list_t *pl)
* Copy the relevant pieces of data to the pool
* configuration:
*
+ * version
* pool guid
* name
* pool state
@@ -381,19 +427,27 @@ get_configs(pool_list_t *pl)
uint64_t state;
verify(nvlist_lookup_uint64(tmp,
+ ZPOOL_CONFIG_VERSION, &version) == 0);
+ if (nvlist_add_uint64(config,
+ ZPOOL_CONFIG_VERSION, version) != 0)
+ goto nomem;
+ verify(nvlist_lookup_uint64(tmp,
ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
- verify(nvlist_add_uint64(config,
- ZPOOL_CONFIG_POOL_GUID, guid) == 0);
+ if (nvlist_add_uint64(config,
+ ZPOOL_CONFIG_POOL_GUID, guid) != 0)
+ goto nomem;
verify(nvlist_lookup_string(tmp,
ZPOOL_CONFIG_POOL_NAME, &name) == 0);
- verify(nvlist_add_string(config,
- ZPOOL_CONFIG_POOL_NAME, name) == 0);
+ if (nvlist_add_string(config,
+ ZPOOL_CONFIG_POOL_NAME, name) != 0)
+ goto nomem;
verify(nvlist_lookup_uint64(tmp,
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
- verify(nvlist_add_uint64(config,
- ZPOOL_CONFIG_POOL_STATE, state) == 0);
+ if (nvlist_add_uint64(config,
+ ZPOOL_CONFIG_POOL_STATE, state) != 0)
+ goto nomem;
- config_seen = TRUE;
+ config_seen = B_TRUE;
}
/*
@@ -406,8 +460,10 @@ get_configs(pool_list_t *pl)
if (id >= children) {
nvlist_t **newchild;
- newchild = zfs_malloc((id + 1) *
+ newchild = zfs_alloc(hdl, (id + 1) *
sizeof (nvlist_t *));
+ if (newchild == NULL)
+ goto nomem;
for (c = 0; c < children; c++)
newchild[c] = child[c];
@@ -416,23 +472,9 @@ get_configs(pool_list_t *pl)
child = newchild;
children = id + 1;
}
- verify(nvlist_dup(nvtop, &child[id], 0) == 0);
+ if (nvlist_dup(nvtop, &child[id], 0) != 0)
+ goto nomem;
- /*
- * Go through and free all config information.
- */
- for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
- cenext = ce->ce_next;
-
- nvlist_free(ce->ce_config);
- free(ce);
- }
-
- /*
- * Free this vdev entry, since it has now been merged
- * into the main config.
- */
- free(ve);
}
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
@@ -448,51 +490,63 @@ get_configs(pool_list_t *pl)
for (c = 0; c < children; c++)
if (child[c] == NULL) {
nvlist_t *missing;
- verify(nvlist_alloc(&missing, NV_UNIQUE_NAME,
- 0) == 0);
- verify(nvlist_add_string(missing,
- ZPOOL_CONFIG_TYPE, VDEV_TYPE_MISSING) == 0);
- verify(nvlist_add_uint64(missing,
- ZPOOL_CONFIG_ID, c) == 0);
- verify(nvlist_add_uint64(missing,
- ZPOOL_CONFIG_GUID, 0ULL) == 0);
+ if (nvlist_alloc(&missing, NV_UNIQUE_NAME,
+ 0) != 0)
+ goto nomem;
+ if (nvlist_add_string(missing,
+ ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_MISSING) != 0 ||
+ nvlist_add_uint64(missing,
+ ZPOOL_CONFIG_ID, c) != 0 ||
+ nvlist_add_uint64(missing,
+ ZPOOL_CONFIG_GUID, 0ULL) != 0) {
+ nvlist_free(missing);
+ goto nomem;
+ }
child[c] = missing;
}
/*
* Put all of this pool's top-level vdevs into a root vdev.
*/
- verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
- verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
- VDEV_TYPE_ROOT) == 0);
- verify(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) == 0);
- verify(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, guid) == 0);
- verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
- child, children) == 0);
+ if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0)
+ goto nomem;
+ if (nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
+ VDEV_TYPE_ROOT) != 0 ||
+ nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) != 0 ||
+ nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, guid) != 0 ||
+ nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ child, children) != 0) {
+ nvlist_free(nvroot);
+ goto nomem;
+ }
for (c = 0; c < children; c++)
nvlist_free(child[c]);
free(child);
+ children = 0;
+ child = NULL;
/*
* Go through and fix up any paths and/or devids based on our
* known list of vdev GUID -> path mappings.
*/
- fix_paths(nvroot, pl->names);
+ if (fix_paths(nvroot, pl->names) != 0) {
+ nvlist_free(nvroot);
+ goto nomem;
+ }
/*
* Add the root vdev to this pool's configuration.
*/
- verify(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
- nvroot) == 0);
+ if (nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ nvroot) != 0) {
+ nvlist_free(nvroot);
+ goto nomem;
+ }
nvlist_free(nvroot);
/*
- * Free this pool entry.
- */
- free(pe);
-
- /*
* Determine if this pool is currently active, in which case we
* can't actually import it.
*/
@@ -501,8 +555,9 @@ get_configs(pool_list_t *pl)
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
&guid) == 0);
- if (pool_active(name, guid)) {
+ if (pool_active(hdl, name, guid)) {
nvlist_free(config);
+ config = NULL;
continue;
}
@@ -510,13 +565,14 @@ get_configs(pool_list_t *pl)
* Try to do the import in order to get vdev state.
*/
if ((err = nvlist_size(config, &len, NV_ENCODE_NATIVE)) != 0)
- zfs_baderror(err);
+ goto nomem;
- packed = zfs_malloc(len);
+ if ((packed = zfs_alloc(hdl, len)) == NULL)
+ goto nomem;
if ((err = nvlist_pack(config, &packed, &len,
NV_ENCODE_NATIVE, 0)) != 0)
- zfs_baderror(err);
+ goto nomem;
nvlist_free(config);
config = NULL;
@@ -525,37 +581,76 @@ get_configs(pool_list_t *pl)
zc.zc_config_src = (uint64_t)(uintptr_t)packed;
zc.zc_config_dst_size = 2 * len;
- zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_malloc(zc.zc_config_dst_size);
+ if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL)
+ goto nomem;
- while ((err = zfs_ioctl(ZFS_IOC_POOL_TRYIMPORT,
+ while ((err = ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_TRYIMPORT,
&zc)) != 0 && errno == ENOMEM) {
free((void *)(uintptr_t)zc.zc_config_dst);
- zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_malloc(zc.zc_config_dst_size);
+ if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL)
+ goto nomem;
}
free(packed);
- if (err)
- zfs_baderror(errno);
+ if (err) {
+ (void) zpool_standard_error(hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot discover pools"));
+ free((void *)(uintptr_t)zc.zc_config_dst);
+ goto error;
+ }
- verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
- zc.zc_config_dst_size, &config, 0) == 0);
+ if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
+ zc.zc_config_dst_size, &config, 0) != 0) {
+ free((void *)(uintptr_t)zc.zc_config_dst);
+ goto nomem;
+ }
+ free((void *)(uintptr_t)zc.zc_config_dst);
- set_pool_health(config);
+ /*
+ * Go through and update the paths for spares, now that we have
+ * them.
+ */
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ for (i = 0; i < nspares; i++) {
+ if (fix_paths(spares[i], pl->names) != 0)
+ goto nomem;
+ }
+ }
+
+ if (set_pool_health(config) != 0)
+ goto nomem;
/*
* Add this pool to the list of configs.
*/
- verify(nvlist_add_nvlist(ret, name, config) == 0);
+ if (nvlist_add_nvlist(ret, name, config) != 0)
+ goto nomem;
nvlist_free(config);
-
- free((void *)(uintptr_t)zc.zc_config_dst);
+ config = NULL;
}
return (ret);
+
+nomem:
+ (void) no_memory(hdl);
+error:
+ if (config)
+ nvlist_free(config);
+ if (ret)
+ nvlist_free(ret);
+ for (c = 0; c < children; c++)
+ nvlist_free(child[c]);
+ if (child)
+ free(child);
+
+ return (NULL);
}
/*
@@ -572,19 +667,21 @@ label_offset(size_t size, int l)
* Given a file descriptor, read the label information and return an nvlist
* describing the configuration, if there is one.
*/
-nvlist_t *
-zpool_read_label(int fd)
+int
+zpool_read_label(int fd, nvlist_t **config)
{
struct stat64 statbuf;
int l;
vdev_label_t *label;
- nvlist_t *config;
uint64_t state, txg;
+ *config = NULL;
+
if (fstat64(fd, &statbuf) == -1)
- return (NULL);
+ return (0);
- label = zfs_malloc(sizeof (vdev_label_t));
+ if ((label = malloc(sizeof (vdev_label_t))) == NULL)
+ return (-1);
for (l = 0; l < VDEV_LABELS; l++) {
if (pread(fd, label, sizeof (vdev_label_t),
@@ -592,27 +689,29 @@ zpool_read_label(int fd)
continue;
if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist,
- sizeof (label->vl_vdev_phys.vp_nvlist), &config, 0) != 0)
+ sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0)
continue;
- if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
- &state) != 0 || state > POOL_STATE_DESTROYED) {
- nvlist_free(config);
+ if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE,
+ &state) != 0 || state > POOL_STATE_SPARE) {
+ nvlist_free(*config);
continue;
}
- if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
- &txg) != 0 || txg == 0) {
- nvlist_free(config);
+ if (state != POOL_STATE_SPARE &&
+ (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG,
+ &txg) != 0 || txg == 0)) {
+ nvlist_free(*config);
continue;
}
free(label);
- return (config);
+ return (0);
}
free(label);
- return (NULL);
+ *config = NULL;
+ return (0);
}
/*
@@ -621,17 +720,22 @@ zpool_read_label(int fd)
* given (argc is 0), then the default directory (/dev/dsk) is searched.
*/
nvlist_t *
-zpool_find_import(int argc, char **argv)
+zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv)
{
int i;
DIR *dirp;
struct dirent64 *dp;
char path[MAXPATHLEN];
struct stat64 statbuf;
- nvlist_t *ret, *config;
+ nvlist_t *ret = NULL, *config;
static char *default_dir = "/dev/dsk";
int fd;
pool_list_t pools = { 0 };
+ pool_entry_t *pe, *penext;
+ vdev_entry_t *ve, *venext;
+ config_entry_t *ce, *cenext;
+ name_entry_t *ne, *nenext;
+
if (argc == 0) {
argc = 1;
@@ -645,17 +749,18 @@ zpool_find_import(int argc, char **argv)
*/
for (i = 0; i < argc; i++) {
if (argv[i][0] != '/') {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': must be an absolute path"),
+ (void) zfs_error(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"),
argv[i]);
- return (NULL);
+ goto error;
}
if ((dirp = opendir(argv[i])) == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot open '%s': %s"), argv[i],
- strerror(errno));
- return (NULL);
+ zfs_error_aux(hdl, strerror(errno));
+ (void) zfs_error(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"),
+ argv[i]);
+ goto error;
}
/*
@@ -678,21 +783,49 @@ zpool_find_import(int argc, char **argv)
if ((fd = open64(path, O_RDONLY)) < 0)
continue;
- config = zpool_read_label(fd);
+ if ((zpool_read_label(fd, &config)) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
(void) close(fd);
if (config != NULL)
- add_config(&pools, path, config);
+ if (add_config(hdl, &pools, path, config) != 0)
+ goto error;
}
}
- ret = get_configs(&pools);
+ ret = get_configs(hdl, &pools);
+
+error:
+ for (pe = pools.pools; pe != NULL; pe = penext) {
+ penext = pe->pe_next;
+ for (ve = pe->pe_vdevs; ve != NULL; ve = venext) {
+ venext = ve->ve_next;
+ for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
+ cenext = ce->ce_next;
+ if (ce->ce_config)
+ nvlist_free(ce->ce_config);
+ free(ce);
+ }
+ free(ve);
+ }
+ free(pe);
+ }
+
+ for (ne = pools.names; ne != NULL; ne = nenext) {
+ nenext = ne->ne_next;
+ if (ne->ne_name)
+ free(ne->ne_name);
+ free(ne);
+ }
+
return (ret);
}
-int
+boolean_t
find_guid(nvlist_t *nv, uint64_t guid)
{
uint64_t tmp;
@@ -701,49 +834,94 @@ find_guid(nvlist_t *nv, uint64_t guid)
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &tmp) == 0);
if (tmp == guid)
- return (TRUE);
+ 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 (TRUE);
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+typedef struct spare_cbdata {
+ uint64_t cb_guid;
+ zpool_handle_t *cb_zhp;
+} spare_cbdata_t;
+
+static int
+find_spare(zpool_handle_t *zhp, void *data)
+{
+ spare_cbdata_t *cbp = data;
+ nvlist_t **spares;
+ uint_t i, nspares;
+ 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, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ for (i = 0; i < nspares; i++) {
+ verify(nvlist_lookup_uint64(spares[i],
+ ZPOOL_CONFIG_GUID, &guid) == 0);
+ if (guid == cbp->cb_guid) {
+ cbp->cb_zhp = zhp;
+ return (1);
+ }
+ }
}
- return (FALSE);
+ zpool_close(zhp);
+ return (0);
}
/*
- * Determines if the pool is in use. If so, it returns TRUE and the state of
+ * Determines if the pool is in use. If so, it returns true and the state of
* the pool as well as the name of the pool. Both strings are allocated and
* must be freed by the caller.
*/
int
-zpool_in_use(int fd, pool_state_t *state, char **namestr)
+zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,
+ boolean_t *inuse)
{
nvlist_t *config;
char *name;
- int ret;
+ boolean_t ret;
uint64_t guid, vdev_guid;
zpool_handle_t *zhp;
nvlist_t *pool_config;
uint64_t stateval;
+ spare_cbdata_t cb = { 0 };
+
+ *inuse = B_FALSE;
- if ((config = zpool_read_label(fd)) == NULL)
- return (FALSE);
+ if (zpool_read_label(fd, &config) != 0) {
+ (void) no_memory(hdl);
+ return (-1);
+ }
+
+ if (config == NULL)
+ return (0);
- verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
- &name) == 0);
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
&stateval) == 0);
- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
- &guid) == 0);
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
&vdev_guid) == 0);
+ if (stateval != POOL_STATE_SPARE) {
+ 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:
- ret = TRUE;
+ ret = B_TRUE;
break;
case POOL_STATE_ACTIVE:
@@ -754,14 +932,14 @@ zpool_in_use(int fd, pool_state_t *state, char **namestr)
* active pool that was disconnected without being explicitly
* exported.
*/
- if (pool_active(name, guid)) {
+ if (pool_active(hdl, name, guid)) {
/*
* 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(name)) != NULL &&
+ if ((zhp = zpool_open_canfail(hdl, name)) != NULL &&
(pool_config = zpool_get_config(zhp, NULL))
!= NULL) {
nvlist_t *nvroot;
@@ -770,24 +948,57 @@ zpool_in_use(int fd, pool_state_t *state, char **namestr)
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
ret = find_guid(nvroot, vdev_guid);
} else {
- ret = FALSE;
+ ret = B_FALSE;
}
+
+ 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;
+ if (zpool_iter(hdl, find_spare, &cb) == 1) {
+ name = (char *)zpool_get_name(cb.cb_zhp);
ret = TRUE;
+ } else {
+ ret = FALSE;
}
break;
default:
- ret = FALSE;
+ ret = B_FALSE;
}
if (ret) {
- *namestr = zfs_strdup(name);
+ if ((*namestr = zfs_strdup(hdl, name)) == NULL) {
+ nvlist_free(config);
+ return (-1);
+ }
*state = (pool_state_t)stateval;
}
+ if (cb.cb_zhp)
+ zpool_close(cb.cb_zhp);
+
nvlist_free(config);
- return (ret);
+ *inuse = ret;
+ return (0);
}
diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c
index ae4a9937a8..894bcc0d03 100644
--- a/usr/src/lib/libzfs/common/libzfs_mount.c
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c
@@ -63,44 +63,44 @@
#include "libzfs_impl.h"
/*
- * Search the sharetab for the given mountpoint, returning TRUE if it is found.
+ * Search the sharetab for the given mountpoint, returning true if it is found.
*/
-static int
-is_shared(const char *mountpoint)
+static boolean_t
+is_shared(libzfs_handle_t *hdl, const char *mountpoint)
{
char buf[MAXPATHLEN], *tab;
- if (zfs_sharetab() == NULL)
+ if (hdl->libzfs_sharetab == NULL)
return (0);
- (void) fseek(zfs_sharetab(), 0, SEEK_SET);
+ (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
- while (fgets(buf, sizeof (buf), zfs_sharetab()) != NULL) {
+ while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
/* the mountpoint is the first entry on each line */
if ((tab = strchr(buf, '\t')) != NULL) {
*tab = '\0';
if (strcmp(buf, mountpoint) == 0)
- return (1);
+ return (B_TRUE);
}
}
- return (0);
+ return (B_FALSE);
}
/*
- * Returns TRUE if the specified directory is empty. If we can't open the
- * directory at all, return TRUE so that the mount can fail with a more
+ * Returns true if the specified directory is empty. If we can't open the
+ * directory at all, return true so that the mount can fail with a more
* informative error message.
*/
-static int
+static boolean_t
dir_is_empty(const char *dirname)
{
DIR *dirp;
struct dirent64 *dp;
if ((dirp = opendir(dirname)) == NULL)
- return (TRUE);
+ return (B_TRUE);
while ((dp = readdir64(dirp)) != NULL) {
@@ -109,11 +109,11 @@ dir_is_empty(const char *dirname)
continue;
(void) closedir(dirp);
- return (FALSE);
+ return (B_FALSE);
}
(void) closedir(dirp);
- return (TRUE);
+ return (B_TRUE);
}
/*
@@ -121,7 +121,7 @@ dir_is_empty(const char *dirname)
* in 'where' with the current mountpoint, and return 1. Otherwise, we return
* 0.
*/
-int
+boolean_t
zfs_is_mounted(zfs_handle_t *zhp, char **where)
{
struct mnttab search = { 0 }, entry;
@@ -134,14 +134,14 @@ zfs_is_mounted(zfs_handle_t *zhp, char **where)
search.mnt_special = (char *)zfs_get_name(zhp);
search.mnt_fstype = MNTTYPE_ZFS;
- rewind(zfs_mnttab());
- if (getmntany(zfs_mnttab(), &entry, &search) != 0)
- return (FALSE);
+ rewind(zhp->zfs_hdl->libzfs_mnttab);
+ if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) != 0)
+ return (B_FALSE);
if (where != NULL)
- *where = zfs_strdup(entry.mnt_mountp);
+ *where = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
- return (TRUE);
+ return (B_TRUE);
}
/*
@@ -153,6 +153,7 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
struct stat buf;
char mountpoint[ZFS_MAXPROPLEN];
char mntopts[MNT_LINE_MAX];
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
if (options == NULL)
mntopts[0] = '\0';
@@ -161,7 +162,7 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
/* ignore non-filesystems */
if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
- sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0)
+ sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0)
return (0);
/* return success if there is no mountpoint set */
@@ -173,25 +174,18 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
* If the 'zoned' property is set, and we're in the global zone, simply
* return success.
*/
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
- char zonename[ZONENAME_MAX];
- if (getzonenamebyid(getzoneid(), zonename,
- sizeof (zonename)) < 0) {
- zfs_error(dgettext(TEXT_DOMAIN, "internal error: "
- "cannot determine current zone"));
- return (1);
- }
-
- if (strcmp(zonename, "global") == 0)
- return (0);
- }
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
+ getzoneid() == GLOBAL_ZONEID)
+ return (0);
/* Create the directory if it doesn't already exist */
if (lstat(mountpoint, &buf) != 0) {
if (mkdirp(mountpoint, 0755) != 0) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
- "unable to create mountpoint"), mountpoint);
- return (1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "failed to create mountpoint"));
+ return (zfs_error(hdl, EZFS_MOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+ mountpoint));
}
}
@@ -204,11 +198,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
if ((flags & MS_OVERLAY) == 0 &&
strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
!dir_is_empty(mountpoint)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
- "directory is not empty"), mountpoint);
- zfs_error(dgettext(TEXT_DOMAIN, "use legacy mountpoint to "
- "allow this behavior, or use the -O flag"));
- return (1);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "directory is not empty"));
+ return (zfs_error(hdl, EZFS_MOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
}
/* perform the mount */
@@ -219,24 +212,15 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
* from mount(), and they're well-understood. We pick a few
* common ones to improve upon.
*/
- switch (errno) {
- case EBUSY:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
- "mountpoint or dataset is busy"), zhp->zfs_name);
- break;
- case EPERM:
- case EACCES:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
- "permission denied"), zhp->zfs_name,
- mountpoint);
- break;
- default:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot mount '%s': %s"),
- mountpoint, strerror(errno));
- break;
- }
- return (1);
+ if (errno == EBUSY)
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "mountpoint or dataset is busy"));
+ else
+ zfs_error_aux(hdl, strerror(errno));
+
+ return (zfs_error(hdl, EZFS_MOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+ zhp->zfs_name));
}
return (0);
@@ -253,9 +237,9 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
/* check to see if need to unmount the filesystem */
search.mnt_special = (char *)zfs_get_name(zhp);
search.mnt_fstype = MNTTYPE_ZFS;
- rewind(zfs_mnttab());
+ rewind(zhp->zfs_hdl->libzfs_mnttab);
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
- getmntany(zfs_mnttab(), &entry, &search) == 0)) {
+ getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
if (mountpoint == NULL)
mountpoint = entry.mnt_mountp;
@@ -277,10 +261,10 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
* semantics from the kernel.
*/
if (umount2(mountpoint, flags) != 0) {
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot unmount '%s': %s"),
- mountpoint, strerror(errno));
- return (-1);
+ zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+ return (zfs_error(zhp->zfs_hdl, EZFS_UMOUNTFAILED,
+ dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
+ mountpoint));
}
/*
@@ -315,23 +299,23 @@ zfs_unmountall(zfs_handle_t *zhp, int flags)
/*
* Check to see if the filesystem is currently shared.
*/
-int
+boolean_t
zfs_is_shared(zfs_handle_t *zhp, char **where)
{
char *mountpoint;
if (!zfs_is_mounted(zhp, &mountpoint))
- return (FALSE);
+ return (B_FALSE);
- if (is_shared(mountpoint)) {
+ if (is_shared(zhp->zfs_hdl, mountpoint)) {
if (where != NULL)
*where = mountpoint;
else
free(mountpoint);
- return (TRUE);
+ return (B_TRUE);
} else {
free(mountpoint);
- return (FALSE);
+ return (B_FALSE);
}
}
@@ -346,6 +330,7 @@ zfs_share(zfs_handle_t *zhp)
char shareopts[ZFS_MAXPROPLEN];
char buf[MAXPATHLEN];
FILE *fp;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
/* ignore non-filesystems */
if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM)
@@ -353,14 +338,14 @@ zfs_share(zfs_handle_t *zhp)
/* return success if there is no mountpoint set */
if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
- mountpoint, sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0 ||
+ mountpoint, sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0 ||
strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0)
return (0);
/* return success if there are no share options */
if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
- NULL, NULL, 0, FALSE) != 0 ||
+ NULL, NULL, 0, B_FALSE) != 0 ||
strcmp(shareopts, "off") == 0)
return (0);
@@ -386,11 +371,10 @@ zfs_share(zfs_handle_t *zhp)
"-F nfs -o \"%s\" \"%s\" 2>&1", shareopts,
mountpoint);
- if ((fp = popen(buf, "r")) == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot share '%s': "
- "share(1M) failed"), zfs_get_name(zhp));
- return (-1);
- }
+ if ((fp = popen(buf, "r")) == NULL)
+ return (zfs_error(hdl, EZFS_SHAREFAILED,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+ zfs_get_name(zhp)));
/*
* share(1M) should only produce output if there is some kind
@@ -403,14 +387,11 @@ zfs_share(zfs_handle_t *zhp)
while (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
- if (colon == NULL)
- zfs_error(dgettext(TEXT_DOMAIN, "cannot share "
- "'%s': share(1M) failed"),
- zfs_get_name(zhp));
- else
- zfs_error(dgettext(TEXT_DOMAIN, "cannot share "
- "'%s': %s"), zfs_get_name(zhp),
- colon + 2);
+ if (colon != NULL)
+ zfs_error_aux(hdl, colon + 2);
+
+ (void) zfs_error(hdl, EZFS_SHAREFAILED,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"));
verify(pclose(fp) != 0);
return (-1);
@@ -429,30 +410,29 @@ zfs_unshare(zfs_handle_t *zhp, const char *mountpoint)
{
char buf[MAXPATHLEN];
struct mnttab search = { 0 }, entry;
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
/* check to see if need to unmount the filesystem */
search.mnt_special = (char *)zfs_get_name(zhp);
search.mnt_fstype = MNTTYPE_ZFS;
- rewind(zfs_mnttab());
+ rewind(zhp->zfs_hdl->libzfs_mnttab);
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
- getmntany(zfs_mnttab(), &entry, &search) == 0)) {
+ getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
if (mountpoint == NULL)
mountpoint = entry.mnt_mountp;
- if (is_shared(mountpoint)) {
+ if (is_shared(zhp->zfs_hdl, mountpoint)) {
FILE *fp;
(void) snprintf(buf, sizeof (buf),
"/usr/sbin/unshare \"%s\" 2>&1",
mountpoint);
- if ((fp = popen(buf, "r")) == NULL) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot "
- "unshare '%s': unshare(1M) failed"),
- zfs_get_name(zhp));
- return (-1);
- }
+ if ((fp = popen(buf, "r")) == NULL)
+ return (zfs_error(hdl, EZFS_UNSHAREFAILED,
+ dgettext(TEXT_DOMAIN,
+ "cannot unshare '%s'"), zfs_get_name(zhp)));
/*
* unshare(1M) should only produce output if there is
@@ -465,17 +445,14 @@ zfs_unshare(zfs_handle_t *zhp, const char *mountpoint)
while (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
- if (colon == NULL)
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot unshare '%s': unshare(1M) "
- "failed"), zfs_get_name(zhp));
- else
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot unshare '%s': %s"),
- zfs_get_name(zhp), colon + 2);
+ if (colon != NULL)
+ zfs_error_aux(hdl, colon + 2);
verify(pclose(fp) != 0);
- return (-1);
+
+ return (zfs_error(hdl, EZFS_UNSHAREFAILED,
+ dgettext(TEXT_DOMAIN,
+ "cannot unshare '%s'"), zfs_get_name(zhp)));
}
verify(pclose(fp) == 0);
@@ -521,24 +498,20 @@ remove_mountpoint(zfs_handle_t *zhp)
char mountpoint[ZFS_MAXPROPLEN];
char source[ZFS_MAXNAMELEN];
zfs_source_t sourcetype;
- char zonename[ZONENAME_MAX];
+ int zoneid = getzoneid();
/* ignore non-filesystems */
if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
sizeof (mountpoint), &sourcetype, source, sizeof (source),
- FALSE) != 0)
+ B_FALSE) != 0)
return;
- if (getzonenamebyid(getzoneid(), zonename, sizeof (zonename)) < 0)
- zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: "
- "cannot determine current zone"));
-
if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0 &&
strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
(sourcetype == ZFS_SRC_DEFAULT ||
sourcetype == ZFS_SRC_INHERITED) &&
(!zfs_prop_get_int(zhp, ZFS_PROP_ZONED) ||
- strcmp(zonename, "global") != 0)) {
+ zoneid != GLOBAL_ZONEID)) {
/*
* Try to remove the directory, silently ignoring any errors.
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index 1fe6fa2d27..37c82015b9 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -18,6 +18,7 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -45,8 +46,8 @@
* Validate the given pool name, optionally putting an extended error message in
* 'buf'.
*/
-static int
-zpool_name_valid(const char *pool, boolean_t isopen, char *buf, size_t buflen)
+static boolean_t
+zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
{
namecheck_err_t why;
char what;
@@ -64,53 +65,52 @@ zpool_name_valid(const char *pool, boolean_t isopen, char *buf, size_t buflen)
(strncmp(pool, "mirror", 6) == 0 ||
strncmp(pool, "raidz", 5) == 0 ||
strncmp(pool, "spare", 5) == 0)) {
- ret = -1;
- why = NAME_ERR_RESERVED;
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "name is reserved"));
+ return (B_FALSE);
}
if (ret != 0) {
- if (buf != NULL) {
+ if (hdl != NULL) {
switch (why) {
case NAME_ERR_TOOLONG:
- (void) snprintf(buf, buflen,
+ zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "name is too long"));
break;
case NAME_ERR_INVALCHAR:
- (void) snprintf(buf, buflen,
+ zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "invalid character "
"'%c' in pool name"), what);
break;
case NAME_ERR_NOLETTER:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "name must begin with a letter"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "name must begin with a letter"));
break;
case NAME_ERR_RESERVED:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "name is reserved\n"
- "pool name may have been omitted"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "name is reserved"));
break;
case NAME_ERR_DISKLIKE:
- (void) strlcpy(buf, dgettext(TEXT_DOMAIN,
- "pool name is reserved\n"
- "pool name may have been omitted"), buflen);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool name is reserved"));
break;
}
}
- return (FALSE);
+ return (B_FALSE);
}
- return (TRUE);
+ return (B_TRUE);
}
/*
* Set the pool-wide health based on the vdev state of the root vdev.
*/
-void
+int
set_pool_health(nvlist_t *config)
{
nvlist_t *nvroot;
@@ -140,11 +140,10 @@ set_pool_health(nvlist_t *config)
break;
default:
- zfs_baderror(vs->vs_state);
+ abort();
}
- verify(nvlist_add_string(config, ZPOOL_CONFIG_POOL_HEALTH,
- health) == 0);
+ return (nvlist_add_string(config, ZPOOL_CONFIG_POOL_HEALTH, health));
}
/*
@@ -152,28 +151,33 @@ set_pool_health(nvlist_t *config)
* state.
*/
zpool_handle_t *
-zpool_open_canfail(const char *pool)
+zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
{
zpool_handle_t *zhp;
- int error;
/*
* Make sure the pool name is valid.
*/
- if (!zpool_name_valid(pool, B_TRUE, NULL, 0)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': invalid "
- "pool name"), pool);
+ if (!zpool_name_valid(hdl, B_TRUE, pool)) {
+ (void) zfs_error(hdl, EZFS_INVALIDNAME,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"),
+ pool);
return (NULL);
}
- zhp = zfs_malloc(sizeof (zpool_handle_t));
+ if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
+ return (NULL);
+ zhp->zpool_hdl = hdl;
(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
- if ((error = zpool_refresh_stats(zhp)) != 0) {
- if (error == ENOENT || error == EINVAL) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': no "
- "such pool"), pool);
+ if (zpool_refresh_stats(zhp) != 0) {
+ if (errno == ENOENT || errno == EINVAL) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no such pool"));
+ (void) zfs_error(hdl, EZFS_NOENT,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"),
+ pool);
free(zhp);
return (NULL);
} else {
@@ -191,17 +195,18 @@ zpool_open_canfail(const char *pool)
* the configuration cache may be out of date).
*/
zpool_handle_t *
-zpool_open_silent(const char *pool)
+zpool_open_silent(libzfs_handle_t *hdl, const char *pool)
{
zpool_handle_t *zhp;
- int error;
- zhp = zfs_malloc(sizeof (zpool_handle_t));
+ if ((zhp = calloc(sizeof (zpool_handle_t), 1)) == NULL)
+ return (NULL);
+ zhp->zpool_hdl = hdl;
(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
- if ((error = zpool_refresh_stats(zhp)) != 0) {
- if (error == ENOENT || error == EINVAL) {
+ if (zpool_refresh_stats(zhp) != 0) {
+ if (errno == ENOENT || errno == EINVAL) {
free(zhp);
return (NULL);
} else {
@@ -219,18 +224,16 @@ zpool_open_silent(const char *pool)
* state.
*/
zpool_handle_t *
-zpool_open(const char *pool)
+zpool_open(libzfs_handle_t *hdl, const char *pool)
{
zpool_handle_t *zhp;
- if ((zhp = zpool_open_canfail(pool)) == NULL)
+ if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
return (NULL);
if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': pool is "
- "currently unavailable"), zhp->zpool_name);
- zfs_error(dgettext(TEXT_DOMAIN, "run 'zpool status %s' for "
- "detailed information"), zhp->zpool_name);
+ (void) zfs_error(hdl, EZFS_POOLUNAVAIL,
+ dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
zpool_close(zhp);
return (NULL);
}
@@ -251,7 +254,7 @@ zpool_close(zpool_handle_t *zhp)
if (zhp->zpool_error_log) {
int i;
for (i = 0; i < zhp->zpool_error_count; i++)
- free(zhp->zpool_error_log[i]);
+ nvlist_free(zhp->zpool_error_log[i]);
free(zhp->zpool_error_log);
}
free(zhp);
@@ -280,6 +283,20 @@ zpool_get_guid(zpool_handle_t *zhp)
}
/*
+ * Return the version of the pool.
+ */
+uint64_t
+zpool_get_version(zpool_handle_t *zhp)
+{
+ uint64_t version;
+
+ verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_VERSION,
+ &version) == 0);
+
+ return (version);
+}
+
+/*
* Return the amount of space currently consumed by the pool.
*/
uint64_t
@@ -324,7 +341,7 @@ zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen)
zfs_cmd_t zc = { 0 };
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (zfs_ioctl(ZFS_IOC_OBJSET_STATS, &zc) != 0 ||
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 ||
zc.zc_root[0] == '\0')
return (-1);
@@ -348,34 +365,35 @@ zpool_get_state(zpool_handle_t *zhp)
* don't have to worry about error semantics.
*/
int
-zpool_create(const char *pool, nvlist_t *nvroot, const char *altroot)
+zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
+ const char *altroot)
{
zfs_cmd_t zc = { 0 };
char *packed;
size_t len;
- int err;
- char reason[64];
+ char msg[1024];
- if (!zpool_name_valid(pool, B_FALSE, reason, sizeof (reason))) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': %s"),
- pool, reason);
- return (-1);
- }
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot create '%s'"), pool);
- if (altroot != NULL && altroot[0] != '/') {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': alternate "
- "root '%s' must be a complete path"), pool, altroot);
- return (-1);
- }
+ if (!zpool_name_valid(hdl, B_FALSE, pool))
+ return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
- if ((err = nvlist_size(nvroot, &len, NV_ENCODE_NATIVE)) != 0)
- zfs_baderror(err);
+ if (altroot != NULL && altroot[0] != '/')
+ return (zfs_error(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot));
- packed = zfs_malloc(len);
+ if (nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) != 0)
+ return (no_memory(hdl));
- if ((err = nvlist_pack(nvroot, &packed, &len,
- NV_ENCODE_NATIVE, 0)) != 0)
- zfs_baderror(err);
+ if ((packed = zfs_alloc(hdl, len)) == NULL)
+ return (-1);
+
+ if (nvlist_pack(nvroot, &packed, &len,
+ NV_ENCODE_NATIVE, 0) != 0) {
+ free(packed);
+ return (no_memory(hdl));
+ }
(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
zc.zc_config_src = (uint64_t)(uintptr_t)packed;
@@ -384,18 +402,10 @@ zpool_create(const char *pool, nvlist_t *nvroot, const char *altroot)
if (altroot != NULL)
(void) strlcpy(zc.zc_root, altroot, sizeof (zc.zc_root));
- if (zfs_ioctl(ZFS_IOC_POOL_CREATE, &zc) != 0) {
- switch (errno) {
- case EEXIST:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "pool exists"), pool);
- break;
-
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "permission denied"), pool);
- break;
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) {
+ free(packed);
+ switch (errno) {
case EBUSY:
/*
* This can happen if the user has specified the same
@@ -403,14 +413,13 @@ zpool_create(const char *pool, nvlist_t *nvroot, const char *altroot)
* until we try to add it and see we already have a
* label.
*/
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "one or more vdevs refer to the same device"),
- pool);
- break;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more vdevs refer to the same device"));
+ return (zfs_error(hdl, EZFS_BADDEV, msg));
case EOVERFLOW:
/*
- * This occurrs when one of the devices is below
+ * This occurs when one of the devices is below
* SPA_MINDEVSIZE. Unfortunately, we can't detect which
* device was the problem device since there's no
* reliable way to determine device size from userland.
@@ -420,53 +429,20 @@ zpool_create(const char *pool, nvlist_t *nvroot, const char *altroot)
zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
- zfs_error(dgettext(TEXT_DOMAIN, "cannot "
- "create '%s': one or more devices is less "
- "than the minimum size (%s)"), pool,
- buf);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is less than the "
+ "minimum size (%s)"), buf);
}
- break;
-
- case ENAMETOOLONG:
- /*
- * One of the vdevs has exceeded VDEV_SPEC_MAX length in
- * its plaintext representation.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "too many devices in a single vdev"), pool);
- break;
-
- case EIO:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "I/O error on one or more devices"), pool);
- break;
-
- case ENXIO:
- /*
- * This is unlikely to happen since we've verified that
- * all the devices can be opened from userland, but it's
- * still possible in some circumstances.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "one or more devices is unavailable"), pool);
- break;
+ return (zfs_error(hdl, EZFS_BADDEV, msg));
case ENOSPC:
- /*
- * This can occur if we were incapable of writing to a
- * file vdev because the underlying filesystem is out of
- * space. This is very similar to EOVERFLOW, but we'll
- * produce a slightly different message.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': "
- "one or more devices is out of space"), pool);
- break;
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is out of space"));
+ return (zfs_error(hdl, EZFS_BADDEV, msg));
default:
- zfs_baderror(errno);
+ return (zpool_standard_error(hdl, errno, msg));
}
-
- return (-1);
}
free(packed);
@@ -478,7 +454,7 @@ zpool_create(const char *pool, nvlist_t *nvroot, const char *altroot)
if (altroot != NULL) {
zfs_handle_t *zhp;
- verify((zhp = zfs_open(pool, ZFS_TYPE_ANY)) != NULL);
+ verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL);
verify(zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, "/") == 0);
zfs_close(zhp);
@@ -496,9 +472,12 @@ zpool_destroy(zpool_handle_t *zhp)
{
zfs_cmd_t zc = { 0 };
zfs_handle_t *zfp = NULL;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ char msg[1024];
if (zhp->zpool_state == POOL_STATE_ACTIVE &&
- (zfp = zfs_open(zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL)
+ (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
+ ZFS_TYPE_FILESYSTEM)) == NULL)
return (-1);
if (zpool_remove_zvol_links(zhp) != NULL)
@@ -506,35 +485,16 @@ zpool_destroy(zpool_handle_t *zhp)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (zfs_ioctl(ZFS_IOC_POOL_DESTROY, &zc) != 0) {
- switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': permission denied"),
- zhp->zpool_name);
- break;
-
- case EBUSY:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': pool busy"),
- zhp->zpool_name);
- break;
-
- case ENOENT:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': no such pool"),
- zhp->zpool_name);
- break;
-
- case EROFS:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot destroy '%s': one or more devices is "
- "read only, or '/' is mounted read only"),
- zhp->zpool_name);
- break;
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot destroy '%s'"), zhp->zpool_name);
- default:
- zfs_baderror(errno);
+ if (errno == EROFS) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is read only"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ } else {
+ (void) zpool_standard_error(hdl, errno, msg);
}
if (zfp)
@@ -560,10 +520,27 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
char *packed;
size_t len;
zfs_cmd_t zc;
+ int ret;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ char msg[1024];
+ nvlist_t **spares;
+ uint_t nspares;
+
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot add to '%s'"), zhp->zpool_name);
+
+ if (zpool_get_version(zhp) < ZFS_VERSION_SPARES &&
+ nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
+ "upgraded to add hot spares"));
+ return (zfs_error(hdl, EZFS_BADVERSION, msg));
+ }
verify(nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) == 0);
- packed = zfs_malloc(len);
+ if ((packed = zfs_alloc(zhp->zpool_hdl, len)) == NULL)
+ return (-1);
verify(nvlist_pack(nvroot, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
@@ -571,13 +548,8 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
zc.zc_config_src = (uint64_t)(uintptr_t)packed;
zc.zc_config_src_size = len;
- if (zfs_ioctl(ZFS_IOC_VDEV_ADD, &zc) != 0) {
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) {
switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot add to '%s': "
- "permission denied"), zhp->zpool_name);
- break;
-
case EBUSY:
/*
* This can happen if the user has specified the same
@@ -585,30 +557,9 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
* until we try to add it and see we already have a
* label.
*/
- zfs_error(dgettext(TEXT_DOMAIN, "cannot add to '%s': "
- "one or more vdevs refer to the same device"),
- zhp->zpool_name);
- break;
-
- case ENAMETOOLONG:
- /*
- * One of the vdevs has exceeded VDEV_SPEC_MAX length in
- * its plaintext representation.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot add to '%s': "
- "too many devices in a single vdev"),
- zhp->zpool_name);
- break;
-
- case ENXIO:
- /*
- * This is unlikely to happen since we've verified that
- * all the devices can be opened from userland, but it's
- * still possible in some circumstances.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "cannot add to '%s': "
- "one or more devices is unavailable"),
- zhp->zpool_name);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more vdevs refer to the same device"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
break;
case EOVERFLOW:
@@ -623,23 +574,31 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
- zfs_error(dgettext(TEXT_DOMAIN, "cannot "
- "add to '%s': one or more devices is less "
- "than the minimum size (%s)"),
- zhp->zpool_name, buf);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "device is less than the minimum "
+ "size (%s)"), buf);
}
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
+ break;
+
+ case ENOTSUP:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool must be upgraded to add raidz2 vdevs"));
+ (void) zfs_error(hdl, EZFS_BADVERSION, msg);
break;
default:
- zfs_baderror(errno);
+ (void) zpool_standard_error(hdl, errno, msg);
}
- return (-1);
+ ret = -1;
+ } else {
+ ret = 0;
}
free(packed);
- return (0);
+ return (ret);
}
/*
@@ -656,32 +615,10 @@ zpool_export(zpool_handle_t *zhp)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (zfs_ioctl(ZFS_IOC_POOL_EXPORT, &zc) != 0) {
- switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot export '%s': permission denied"),
- zhp->zpool_name);
- break;
-
- case EBUSY:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot export '%s': pool is in use"),
- zhp->zpool_name);
- break;
-
- case ENOENT:
- zfs_error(dgettext(TEXT_DOMAIN,
- "cannot export '%s': no such pool"),
- zhp->zpool_name);
- break;
-
- default:
- zfs_baderror(errno);
- }
-
- return (-1);
- }
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_EXPORT, &zc) != 0)
+ return (zpool_standard_error(zhp->zpool_hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot export '%s'"),
+ zhp->zpool_name));
return (0);
}
@@ -693,7 +630,8 @@ zpool_export(zpool_handle_t *zhp)
* an alternate root, respectively.
*/
int
-zpool_import(nvlist_t *config, const char *newname, const char *altroot)
+zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
+ const char *altroot)
{
zfs_cmd_t zc;
char *packed;
@@ -706,22 +644,19 @@ zpool_import(nvlist_t *config, const char *newname, const char *altroot)
&origname) == 0);
if (newname != NULL) {
- if (!zpool_name_valid(newname, B_FALSE, NULL, 0)) {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot import '%s': "
- "invalid pool name"), newname);
- return (-1);
- }
+ if (!zpool_name_valid(hdl, B_FALSE, newname))
+ return (zfs_error(hdl, EZFS_INVALIDNAME,
+ dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+ newname));
thename = (char *)newname;
} else {
thename = origname;
}
- if (altroot != NULL && altroot[0] != '/') {
- zfs_error(dgettext(TEXT_DOMAIN, "cannot import '%s': alternate "
- "root '%s' must be a complete path"), thename,
- altroot);
- return (-1);
- }
+ if (altroot != NULL && altroot[0] != '/')
+ return (zfs_error(hdl, EZFS_BADPATH,
+ dgettext(TEXT_DOMAIN, "bad alternate root '%s'"),
+ altroot));
(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
@@ -735,7 +670,8 @@ zpool_import(nvlist_t *config, const char *newname, const char *altroot)
verify(nvlist_size(config, &len, NV_ENCODE_NATIVE) == 0);
- packed = zfs_malloc(len);
+ if ((packed = zfs_alloc(hdl, len)) == NULL)
+ return (-1);
verify(nvlist_pack(config, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
@@ -743,7 +679,7 @@ zpool_import(nvlist_t *config, const char *newname, const char *altroot)
zc.zc_config_src_size = len;
ret = 0;
- if (zfs_ioctl(ZFS_IOC_POOL_IMPORT, &zc) != 0) {
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
char desc[1024];
if (newname == NULL)
(void) snprintf(desc, sizeof (desc),
@@ -755,42 +691,15 @@ zpool_import(nvlist_t *config, const char *newname, const char *altroot)
origname, thename);
switch (errno) {
- case EEXIST:
- /*
- * A pool with that name already exists.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: pool exists"),
- desc);
- break;
-
- case EPERM:
- /*
- * The user doesn't have permission to create pools.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: permission "
- "denied"), desc);
- break;
-
- case ENXIO:
- case EDOM:
- /*
- * Device is unavailable, or vdev sum didn't match.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: one or more "
- "devices is unavailable"),
- desc);
- break;
-
case ENOTSUP:
/*
* Unsupported version.
*/
- zfs_error(dgettext(TEXT_DOMAIN,
- "%s: unsupported version"), desc);
+ (void) zfs_error(hdl, EZFS_BADVERSION, desc);
break;
default:
- zfs_baderror(errno);
+ (void) zpool_standard_error(hdl, errno, desc);
}
ret = -1;
@@ -799,7 +708,7 @@ zpool_import(nvlist_t *config, const char *newname, const char *altroot)
/*
* This should never fail, but play it safe anyway.
*/
- if ((zhp = zpool_open_silent(thename)) != NULL) {
+ if ((zhp = zpool_open_silent(hdl, thename)) != NULL) {
ret = zpool_create_zvol_links(zhp);
zpool_close(zhp);
}
@@ -817,48 +726,35 @@ zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_cookie = type;
- if (zfs_ioctl(ZFS_IOC_POOL_SCRUB, &zc) == 0)
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SCRUB, &zc) == 0)
return (0);
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
- switch (errno) {
- case EPERM:
- /*
- * No permission to scrub this pool.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: permission denied"), msg);
- break;
-
- case EBUSY:
- /*
- * Resilver in progress.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: currently resilvering"),
- msg);
- break;
-
- default:
- zfs_baderror(errno);
- }
- return (-1);
+ if (errno == EBUSY)
+ return (zfs_error(hdl, EZFS_RESILVERING, msg));
+ else
+ return (zpool_standard_error(hdl, errno, msg));
}
-static uint64_t
-vdev_to_guid(nvlist_t *nv, const char *search, uint64_t guid)
+static nvlist_t *
+vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
+ boolean_t *isspare)
{
uint_t c, children;
nvlist_t **child;
- uint64_t ret, present;
+ uint64_t theguid, present;
char *path;
uint64_t wholedisk = 0;
+ nvlist_t *ret;
- verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &ret) == 0);
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0);
if (search == NULL &&
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) {
@@ -866,8 +762,8 @@ vdev_to_guid(nvlist_t *nv, const char *search, uint64_t guid)
* If the device has never been present since import, the only
* reliable way to match the vdev is by GUID.
*/
- if (ret == guid)
- return (ret);
+ if (theguid == guid)
+ return (nv);
} else if (search != NULL &&
nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
@@ -879,28 +775,37 @@ vdev_to_guid(nvlist_t *nv, const char *search, uint64_t guid)
*/
if (strlen(search) == strlen(path) - 2 &&
strncmp(search, path, strlen(search)) == 0)
- return (ret);
+ return (nv);
} else if (strcmp(search, path) == 0) {
- return (ret);
+ return (nv);
}
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) != 0)
- return (0);
+ return (NULL);
for (c = 0; c < children; c++)
- if ((ret = vdev_to_guid(child[c], search, guid)) != 0)
+ if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
+ isspare)) != NULL)
return (ret);
- return (0);
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++) {
+ if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
+ isspare)) != NULL) {
+ *isspare = B_TRUE;
+ return (ret);
+ }
+ }
+ }
+
+ return (NULL);
}
-/*
- * Given a string describing a vdev, returns the matching GUID, or 0 if none.
- */
-uint64_t
-zpool_vdev_to_guid(zpool_handle_t *zhp, const char *path)
+nvlist_t *
+zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *isspare)
{
char buf[MAXPATHLEN];
const char *search;
@@ -921,7 +826,8 @@ zpool_vdev_to_guid(zpool_handle_t *zhp, const char *path)
verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0);
- return (vdev_to_guid(nvroot, search, guid));
+ *isspare = B_FALSE;
+ return (vdev_to_nvlist_iter(nvroot, search, guid, isspare));
}
/*
@@ -932,39 +838,26 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
+ nvlist_t *tgt;
+ boolean_t isspare;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot online %s"), path);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if ((zc.zc_guid = zpool_vdev_to_guid(zhp, path)) == 0) {
- zfs_error(dgettext(TEXT_DOMAIN, "%s: no such device in pool"),
- msg);
- return (-1);
- }
+ if ((tgt = zpool_find_vdev(zhp, path, &isspare)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
- if (zfs_ioctl(ZFS_IOC_VDEV_ONLINE, &zc) == 0)
- return (0);
+ if (isspare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
- switch (errno) {
- case ENODEV:
- /*
- * Device doesn't exist
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: device not in pool"), msg);
- break;
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
- case EPERM:
- /*
- * No permission to bring this vdev online.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: permission denied"), msg);
- break;
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ONLINE, &zc) == 0)
+ return (0);
- default:
- zfs_baderror(errno);
- }
- return (-1);
+ return (zpool_standard_error(hdl, errno, msg));
}
/*
@@ -975,48 +868,66 @@ zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
+ nvlist_t *tgt;
+ boolean_t isspare;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if ((zc.zc_guid = zpool_vdev_to_guid(zhp, path)) == 0) {
- zfs_error(dgettext(TEXT_DOMAIN, "%s: no such device in pool"),
- msg);
- return (-1);
- }
+ if ((tgt = zpool_find_vdev(zhp, path, &isspare)) == NULL)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ if (isspare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
zc.zc_cookie = istmp;
- if (zfs_ioctl(ZFS_IOC_VDEV_OFFLINE, &zc) == 0)
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_OFFLINE, &zc) == 0)
return (0);
switch (errno) {
- case ENODEV:
- /*
- * Device doesn't exist
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: device not in pool"), msg);
- break;
-
- case EPERM:
- /*
- * No permission to take this vdev offline.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: permission denied"), msg);
- break;
+ case EBUSY:
- case EBUSY:
/*
* There are no other replicas of this device.
*/
- zfs_error(dgettext(TEXT_DOMAIN, "%s: no valid replicas"), msg);
- break;
+ return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
- default:
- zfs_baderror(errno);
+ default:
+ return (zpool_standard_error(hdl, errno, msg));
}
- return (-1);
+}
+
+/*
+ * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
+ * a hot spare.
+ */
+static boolean_t
+is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
+{
+ nvlist_t **child;
+ uint_t c, children;
+ char *type;
+
+ if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
+ &children) == 0) {
+ verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
+ &type) == 0);
+
+ if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
+ children == 2 && child[which] == tgt)
+ return (B_TRUE);
+
+ for (c = 0; c < children; c++)
+ if (is_replacing_spare(child[c], tgt, which))
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
}
/*
@@ -1032,6 +943,14 @@ zpool_vdev_attach(zpool_handle_t *zhp,
char *packed;
int ret;
size_t len;
+ nvlist_t *tgt;
+ boolean_t isspare;
+ uint64_t val;
+ char *path;
+ nvlist_t **child;
+ uint_t children;
+ nvlist_t *config_root;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
if (replacing)
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
@@ -1041,23 +960,63 @@ zpool_vdev_attach(zpool_handle_t *zhp,
"cannot attach %s to %s"), new_disk, old_disk);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if ((zc.zc_guid = zpool_vdev_to_guid(zhp, old_disk)) == 0) {
- zfs_error(dgettext(TEXT_DOMAIN, "%s: no such device in pool"),
- msg);
- return (-1);
- }
+ if ((tgt = zpool_find_vdev(zhp, old_disk, &isspare)) == 0)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ if (isspare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
zc.zc_cookie = replacing;
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0 || children != 1) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "new device must be a single disk"));
+ return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
+ }
+
+ verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
+ ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
+
+ /*
+ * If the target is a hot spare that has been swapped in, we can only
+ * replace it with another hot spare.
+ */
+ if (replacing &&
+ nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
+ nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
+ (zpool_find_vdev(zhp, path, &isspare) == NULL || !isspare) &&
+ is_replacing_spare(config_root, tgt, 1)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "can only be replaced by another hot spare"));
+ return (zfs_error(hdl, EZFS_BADTARGET, msg));
+ }
+
+ /*
+ * If we are attempting to replace a spare, it canot be applied to an
+ * already spared device.
+ */
+ if (replacing &&
+ nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
+ zpool_find_vdev(zhp, path, &isspare) != NULL && isspare &&
+ is_replacing_spare(config_root, tgt, 0)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "device has already been replaced with a spare"));
+ return (zfs_error(hdl, EZFS_BADTARGET, msg));
+ }
+
verify(nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) == 0);
- packed = zfs_malloc(len);
+ if ((packed = zfs_alloc(zhp->zpool_hdl, len)) == NULL)
+ return (-1);
verify(nvlist_pack(nvroot, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
zc.zc_config_src = (uint64_t)(uintptr_t)packed;
zc.zc_config_src_size = len;
- ret = zfs_ioctl(ZFS_IOC_VDEV_ATTACH, &zc);
+ ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc);
free(packed);
@@ -1065,87 +1024,65 @@ zpool_vdev_attach(zpool_handle_t *zhp,
return (0);
switch (errno) {
- case EPERM:
- /*
- * No permission to mess with the config.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: permission denied"), msg);
- break;
-
- case ENODEV:
- /*
- * Device doesn't exist.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: %s not in pool"),
- msg, old_disk);
- break;
-
case ENOTSUP:
/*
* Can't attach to or replace this type of vdev.
*/
if (replacing)
- zfs_error(dgettext(TEXT_DOMAIN,
- "%s: cannot replace a replacing device"), msg);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "cannot replace a replacing device"));
else
- zfs_error(dgettext(TEXT_DOMAIN,
- "%s: attach is only applicable to mirrors"), msg);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "can only attach to mirrors and top-level "
+ "disks"));
+ (void) zfs_error(hdl, EZFS_BADTARGET, msg);
break;
case EINVAL:
/*
* The new device must be a single disk.
*/
- zfs_error(dgettext(TEXT_DOMAIN,
- "%s: <new_device> must be a single disk"), msg);
- break;
-
- case ENXIO:
- /*
- * This is unlikely to happen since we've verified that
- * all the devices can be opened from userland, but it's
- * still possible in some circumstances.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: %s is unavailable"),
- msg, new_disk);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "new device must be a single disk"));
+ (void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
break;
case EBUSY:
- /*
- * The new device is is use.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: %s busy"), msg, new_disk);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
+ new_disk);
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
break;
case EOVERFLOW:
/*
* The new device is too small.
*/
- zfs_error(dgettext(TEXT_DOMAIN, "%s: %s is too small"),
- msg, new_disk);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "device is too small"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
break;
case EDOM:
/*
* The new device has a different alignment requirement.
*/
- zfs_error(dgettext(TEXT_DOMAIN,
- "%s: devices have different sector alignment"), msg);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "devices have different sector alignment"));
+ (void) zfs_error(hdl, EZFS_BADDEV, msg);
break;
case ENAMETOOLONG:
/*
* The resulting top-level vdev spec won't fit in the label.
*/
- zfs_error(dgettext(TEXT_DOMAIN,
- "%s: too many devices in a single vdev"), msg);
+ (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
break;
default:
- zfs_baderror(errno);
+ (void) zpool_standard_error(hdl, errno, msg);
}
- return (1);
+ return (-1);
}
/*
@@ -1156,55 +1093,81 @@ zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
+ nvlist_t *tgt;
+ boolean_t isspare;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if ((zc.zc_guid = zpool_vdev_to_guid(zhp, path)) == 0) {
- zfs_error(dgettext(TEXT_DOMAIN, "%s: no such device in pool"),
- msg);
- return (-1);
- }
+ if ((tgt = zpool_find_vdev(zhp, path, &isspare)) == 0)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
- if (zfs_ioctl(ZFS_IOC_VDEV_DETACH, &zc) == 0)
+ if (isspare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_DETACH, &zc) == 0)
return (0);
switch (errno) {
- case EPERM:
- /*
- * No permission to mess with the config.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: permission denied"), msg);
- break;
-
- case ENODEV:
- /*
- * Device doesn't exist.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: device not in pool"), msg);
- break;
case ENOTSUP:
/*
* Can't detach from this type of vdev.
*/
- zfs_error(dgettext(TEXT_DOMAIN,
- "%s: only applicable to mirror and replacing vdevs"), msg);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
+ "applicable to mirror and replacing vdevs"));
+ (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg);
break;
case EBUSY:
/*
* There are no other replicas of this device.
*/
- zfs_error(dgettext(TEXT_DOMAIN, "%s: no valid replicas"), msg);
+ (void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
break;
default:
- zfs_baderror(errno);
+ (void) zpool_standard_error(hdl, errno, msg);
}
- return (1);
+ return (-1);
+}
+
+/*
+ * Remove the given device. Currently, this is supported only for hot spares.
+ */
+int
+zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
+{
+ zfs_cmd_t zc = { 0 };
+ char msg[1024];
+ nvlist_t *tgt;
+ boolean_t isspare;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if ((tgt = zpool_find_vdev(zhp, path, &isspare)) == 0)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+ if (!isspare) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "only hot spares can be removed"));
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
+ }
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
}
/*
@@ -1215,6 +1178,9 @@ zpool_clear(zpool_handle_t *zhp, const char *path)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
+ nvlist_t *tgt;
+ boolean_t isspare;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
if (path)
(void) snprintf(msg, sizeof (msg),
@@ -1226,35 +1192,21 @@ zpool_clear(zpool_handle_t *zhp, const char *path)
zhp->zpool_name);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (path && (zc.zc_guid = zpool_vdev_to_guid(zhp, path)) == 0) {
- zfs_error(dgettext(TEXT_DOMAIN, "%s: no such device in pool"),
- msg);
- return (-1);
- }
+ if (path) {
+ if ((tgt = zpool_find_vdev(zhp, path, &isspare)) == 0)
+ return (zfs_error(hdl, EZFS_NODEVICE, msg));
- if (zfs_ioctl(ZFS_IOC_CLEAR, &zc) == 0)
- return (0);
+ if (isspare)
+ return (zfs_error(hdl, EZFS_ISSPARE, msg));
- switch (errno) {
- case EPERM:
- /*
- * No permission to mess with the config.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: permission denied"), msg);
- break;
-
- case ENODEV:
- /*
- * Device doesn't exist.
- */
- zfs_error(dgettext(TEXT_DOMAIN, "%s: device not in pool"), msg);
- break;
-
- default:
- zfs_baderror(errno);
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
+ &zc.zc_guid) == 0);
}
- return (1);
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
}
static int
@@ -1269,9 +1221,9 @@ do_zvol(zfs_handle_t *zhp, void *data)
*/
if (zhp->zfs_volblocksize != 0) {
if (linktype)
- ret = zvol_create_link(zhp->zfs_name);
+ ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
else
- ret = zvol_remove_link(zhp->zfs_name);
+ ret = zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name);
}
ret = zfs_iter_children(zhp, do_zvol, data);
@@ -1292,10 +1244,11 @@ zpool_create_zvol_links(zpool_handle_t *zhp)
/*
* If the pool is unavailable, just return success.
*/
- if ((zfp = make_dataset_handle(zhp->zpool_name)) == NULL)
+ if ((zfp = make_dataset_handle(zhp->zpool_hdl,
+ zhp->zpool_name)) == NULL)
return (0);
- ret = zfs_iter_children(zfp, do_zvol, (void *)TRUE);
+ ret = zfs_iter_children(zfp, do_zvol, (void *)B_TRUE);
zfs_close(zfp);
return (ret);
@@ -1313,10 +1266,11 @@ zpool_remove_zvol_links(zpool_handle_t *zhp)
/*
* If the pool is unavailable, just return success.
*/
- if ((zfp = make_dataset_handle(zhp->zpool_name)) == NULL)
+ if ((zfp = make_dataset_handle(zhp->zpool_hdl,
+ zhp->zpool_name)) == NULL)
return (0);
- ret = zfs_iter_children(zfp, do_zvol, (void *)FALSE);
+ ret = zfs_iter_children(zfp, do_zvol, (void *)B_FALSE);
zfs_close(zfp);
return (ret);
@@ -1345,7 +1299,9 @@ devid_to_path(char *devid_str)
if (ret != 0)
return (NULL);
- path = zfs_strdup(list[0].devname);
+ if ((path = strdup(list[0].devname)) == NULL)
+ return (NULL);
+
devid_free_nmlist(list);
return (path);
@@ -1393,7 +1349,7 @@ set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
&zc.zc_guid) == 0);
- (void) zfs_ioctl(ZFS_IOC_VDEV_SETPATH, &zc);
+ (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
}
/*
@@ -1412,7 +1368,7 @@ set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
* of these checks.
*/
char *
-zpool_vdev_name(zpool_handle_t *zhp, nvlist_t *nv)
+zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv)
{
char *path, *devid;
uint64_t value;
@@ -1442,17 +1398,17 @@ zpool_vdev_name(zpool_handle_t *zhp, nvlist_t *nv)
* Update the path appropriately.
*/
set_path(zhp, nv, newpath);
- verify(nvlist_add_string(nv,
- ZPOOL_CONFIG_PATH, newpath) == 0);
+ if (nvlist_add_string(nv,
+ ZPOOL_CONFIG_PATH, newpath) == 0)
+ verify(nvlist_lookup_string(nv,
+ ZPOOL_CONFIG_PATH,
+ &path) == 0);
free(newpath);
- verify(nvlist_lookup_string(nv,
- ZPOOL_CONFIG_PATH, &path) == 0);
}
-
- if (newdevid)
- devid_str_free(newdevid);
}
+ if (newdevid)
+ devid_str_free(newdevid);
}
if (strncmp(path, "/dev/dsk/", 9) == 0)
@@ -1460,15 +1416,28 @@ zpool_vdev_name(zpool_handle_t *zhp, nvlist_t *nv)
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
&value) == 0 && value) {
- char *tmp = zfs_strdup(path);
+ char *tmp = zfs_strdup(hdl, path);
+ if (tmp == NULL)
+ return (NULL);
tmp[strlen(path) - 2] = '\0';
return (tmp);
}
} else {
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
+
+ /*
+ * If it's a raidz device, we need to stick in the parity level.
+ */
+ if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
+ verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
+ &value) == 0);
+ (void) snprintf(buf, sizeof (buf), "%s%llu", path,
+ value);
+ path = buf;
+ }
}
- return (zfs_strdup(path));
+ return (zfs_strdup(hdl, path));
}
static int
@@ -1502,15 +1471,20 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
*/
verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
&count) == 0);
- zc.zc_config_dst = (uintptr_t)zfs_malloc(count * sizeof (zbookmark_t));
+ if ((zc.zc_config_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
+ count * sizeof (zbookmark_t))) == NULL)
+ return (-1);
zc.zc_config_dst_size = count;
(void) strcpy(zc.zc_name, zhp->zpool_name);
for (;;) {
- if (zfs_ioctl(ZFS_IOC_ERROR_LOG, &zc) != 0) {
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
+ &zc) != 0) {
+ free((void *)(uintptr_t)zc.zc_config_dst);
if (errno == ENOMEM) {
- free((void *)(uintptr_t)zc.zc_config_dst);
- zc.zc_config_dst = (uintptr_t)
- zfs_malloc(zc.zc_config_dst_size);
+ if ((zc.zc_config_dst = (uintptr_t)
+ zfs_alloc(zhp->zpool_hdl,
+ zc.zc_config_dst_size)) == NULL)
+ return (-1);
} else {
return (-1);
}
@@ -1549,6 +1523,7 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
*/
if (list == NULL) {
*nelem = j;
+ free((void *)(uintptr_t)zc.zc_config_dst);
return (0);
}
@@ -1557,7 +1532,11 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
/*
* Allocate an array of nvlists to hold the results
*/
- zhp->zpool_error_log = zfs_malloc(j * sizeof (nvlist_t *));
+ if ((zhp->zpool_error_log = zfs_alloc(zhp->zpool_hdl,
+ j * sizeof (nvlist_t *))) == NULL) {
+ free((void *)(uintptr_t)zc.zc_config_dst);
+ return (-1);
+ }
/*
* Fill in the results with names from the kernel.
@@ -1571,31 +1550,37 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
sizeof (zbookmark_t)) == 0)
continue;
- verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
- 0) == 0);
+ if (nvlist_alloc(&nv, NV_UNIQUE_NAME,
+ 0) != 0)
+ goto nomem;
zhp->zpool_error_log[j] = nv;
zc.zc_bookmark = zb[i];
- if (zfs_ioctl(ZFS_IOC_BOOKMARK_NAME, &zc) == 0) {
- verify(nvlist_add_string(nv, ZPOOL_ERR_DATASET,
- zc.zc_prop_name) == 0);
- verify(nvlist_add_string(nv, ZPOOL_ERR_OBJECT,
- zc.zc_prop_value) == 0);
- verify(nvlist_add_string(nv, ZPOOL_ERR_RANGE,
- zc.zc_filename) == 0);
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_BOOKMARK_NAME,
+ &zc) == 0) {
+ if (nvlist_add_string(nv, ZPOOL_ERR_DATASET,
+ zc.zc_prop_name) != 0 ||
+ nvlist_add_string(nv, ZPOOL_ERR_OBJECT,
+ zc.zc_prop_value) != 0 ||
+ nvlist_add_string(nv, ZPOOL_ERR_RANGE,
+ zc.zc_filename) != 0)
+ goto nomem;
} else {
(void) snprintf(buf, sizeof (buf), "%llx",
zb[i].zb_objset);
- verify(nvlist_add_string(nv,
- ZPOOL_ERR_DATASET, buf) == 0);
+ if (nvlist_add_string(nv,
+ ZPOOL_ERR_DATASET, buf) != 0)
+ goto nomem;
(void) snprintf(buf, sizeof (buf), "%llx",
zb[i].zb_object);
- verify(nvlist_add_string(nv, ZPOOL_ERR_OBJECT,
- buf) == 0);
+ if (nvlist_add_string(nv, ZPOOL_ERR_OBJECT,
+ buf) != 0)
+ goto nomem;
(void) snprintf(buf, sizeof (buf), "lvl=%u blkid=%llu",
(int)zb[i].zb_level, (long long)zb[i].zb_blkid);
- verify(nvlist_add_string(nv, ZPOOL_ERR_RANGE,
- buf) == 0);
+ if (nvlist_add_string(nv, ZPOOL_ERR_RANGE,
+ buf) != 0)
+ goto nomem;
}
j++;
@@ -1607,6 +1592,16 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
free((void *)(uintptr_t)zc.zc_config_dst);
return (0);
+
+nomem:
+ free((void *)(uintptr_t)zc.zc_config_dst);
+ for (i = 0; i < zhp->zpool_error_count; i++) {
+ if (zhp->zpool_error_log[i])
+ free(zhp->zpool_error_log[i]);
+ }
+ free(zhp->zpool_error_log);
+ zhp->zpool_error_log = NULL;
+ return (no_memory(zhp->zpool_hdl));
}
/*
@@ -1616,20 +1611,13 @@ int
zpool_upgrade(zpool_handle_t *zhp)
{
zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) strcpy(zc.zc_name, zhp->zpool_name);
- if (zfs_ioctl(ZFS_IOC_POOL_UPGRADE, &zc) != 0) {
- switch (errno) {
- case EPERM:
- zfs_error(dgettext(TEXT_DOMAIN, "cannot upgrade '%s': "
- "permission denied"), zhp->zpool_name);
- break;
- default:
- zfs_baderror(errno);
- }
-
- return (-1);
- }
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
+ return (zpool_standard_error(hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
+ zhp->zpool_name));
return (0);
}
diff --git a/usr/src/lib/libzfs/common/libzfs_status.c b/usr/src/lib/libzfs/common/libzfs_status.c
index 258b2e2f7d..2a4164964d 100644
--- a/usr/src/lib/libzfs/common/libzfs_status.c
+++ b/usr/src/lib/libzfs/common/libzfs_status.c
@@ -116,7 +116,7 @@ vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
/*
* Detect if any leaf devices that have seen errors or could not be opened.
*/
-static int
+static boolean_t
find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
{
nvlist_t **child;
@@ -132,13 +132,13 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
*/
verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
- return (FALSE);
+ return (B_FALSE);
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
&children) == 0) {
for (c = 0; c < children; c++)
if (find_vdev_problem(child[c], func))
- return (TRUE);
+ return (B_TRUE);
} else {
verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_STATS,
(uint64_t **)&vs, &c) == 0);
@@ -147,10 +147,10 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
vs->vs_read_errors +
vs->vs_write_errors +
vs->vs_checksum_errors))
- return (TRUE);
+ return (B_TRUE);
}
- return (FALSE);
+ return (B_FALSE);
}
/*
@@ -171,7 +171,7 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
* only picks the most damaging of all the current errors to report.
*/
static zpool_status_t
-check_status(nvlist_t *config, int isimport)
+check_status(nvlist_t *config, boolean_t isimport)
{
nvlist_t *nvroot;
vdev_stat_t *vs;
@@ -265,7 +265,7 @@ check_status(nvlist_t *config, int isimport)
zpool_status_t
zpool_get_status(zpool_handle_t *zhp, char **msgid)
{
- zpool_status_t ret = check_status(zhp->zpool_config, FALSE);
+ zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE);
if (ret >= NMSGID)
*msgid = NULL;
@@ -278,7 +278,7 @@ zpool_get_status(zpool_handle_t *zhp, char **msgid)
zpool_status_t
zpool_import_status(nvlist_t *config, char **msgid)
{
- zpool_status_t ret = check_status(config, TRUE);
+ zpool_status_t ret = check_status(config, B_TRUE);
if (ret >= NMSGID)
*msgid = NULL;
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index c7f7528491..29e99dc5b1 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -43,90 +43,320 @@
#include "libzfs_impl.h"
-static int zfs_fd = -1;
-static FILE *mnttab_file;
-static FILE *sharetab_file;
-static int sharetab_opened;
+int
+libzfs_errno(libzfs_handle_t *hdl)
+{
+ return (hdl->libzfs_error);
+}
-void (*error_func)(const char *, va_list);
+const char *
+libzfs_error_action(libzfs_handle_t *hdl)
+{
+ return (hdl->libzfs_action);
+}
-/*
- * All error handling is kept within libzfs where we have the most information
- * immediately available. While this may not be suitable for a general purpose
- * library, it greatly simplifies our commands. This command name is used to
- * prefix all error messages appropriately.
- */
+const char *
+libzfs_error_description(libzfs_handle_t *hdl)
+{
+ if (hdl->libzfs_desc[0] != '\0')
+ return (hdl->libzfs_desc);
+
+ switch (hdl->libzfs_error) {
+ case EZFS_NOMEM:
+ return (dgettext(TEXT_DOMAIN, "out of memory"));
+ case EZFS_BADPROP:
+ return (dgettext(TEXT_DOMAIN, "invalid property value"));
+ case EZFS_PROPREADONLY:
+ return (dgettext(TEXT_DOMAIN, "read only property"));
+ case EZFS_PROPTYPE:
+ return (dgettext(TEXT_DOMAIN, "property doesn't apply to "
+ "datasets of this type"));
+ case EZFS_PROPNONINHERIT:
+ return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));
+ case EZFS_PROPSPACE:
+ return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));
+ case EZFS_BADTYPE:
+ return (dgettext(TEXT_DOMAIN, "operation not applicable to "
+ "datasets of this type"));
+ case EZFS_BUSY:
+ return (dgettext(TEXT_DOMAIN, "pool or dataset is busy"));
+ case EZFS_EXISTS:
+ return (dgettext(TEXT_DOMAIN, "pool or dataset exists"));
+ case EZFS_NOENT:
+ return (dgettext(TEXT_DOMAIN, "no such pool or dataset"));
+ case EZFS_BADSTREAM:
+ return (dgettext(TEXT_DOMAIN, "invalid backup stream"));
+ case EZFS_DSREADONLY:
+ return (dgettext(TEXT_DOMAIN, "dataset is read only"));
+ case EZFS_VOLTOOBIG:
+ return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
+ "this system"));
+ case EZFS_VOLHASDATA:
+ return (dgettext(TEXT_DOMAIN, "volume has data"));
+ case EZFS_INVALIDNAME:
+ return (dgettext(TEXT_DOMAIN, "invalid name"));
+ case EZFS_BADRESTORE:
+ return (dgettext(TEXT_DOMAIN, "unable to restore to "
+ "destination"));
+ case EZFS_BADBACKUP:
+ return (dgettext(TEXT_DOMAIN, "backup failed"));
+ case EZFS_BADTARGET:
+ return (dgettext(TEXT_DOMAIN, "invalid target vdev"));
+ case EZFS_NODEVICE:
+ return (dgettext(TEXT_DOMAIN, "no such device in pool"));
+ case EZFS_BADDEV:
+ return (dgettext(TEXT_DOMAIN, "invalid device"));
+ case EZFS_NOREPLICAS:
+ return (dgettext(TEXT_DOMAIN, "no valid replicas"));
+ case EZFS_RESILVERING:
+ return (dgettext(TEXT_DOMAIN, "currently resilvering"));
+ case EZFS_BADVERSION:
+ return (dgettext(TEXT_DOMAIN, "unsupported version"));
+ case EZFS_POOLUNAVAIL:
+ return (dgettext(TEXT_DOMAIN, "pool is unavailable"));
+ case EZFS_DEVOVERFLOW:
+ return (dgettext(TEXT_DOMAIN, "too many devices in one vdev"));
+ case EZFS_BADPATH:
+ return (dgettext(TEXT_DOMAIN, "must be an absolute path"));
+ case EZFS_CROSSTARGET:
+ return (dgettext(TEXT_DOMAIN, "operation crosses datasets or "
+ "pools"));
+ case EZFS_ZONED:
+ return (dgettext(TEXT_DOMAIN, "dataset in use by local zone"));
+ case EZFS_MOUNTFAILED:
+ return (dgettext(TEXT_DOMAIN, "mount failed"));
+ case EZFS_UMOUNTFAILED:
+ return (dgettext(TEXT_DOMAIN, "umount failed"));
+ case EZFS_UNSHAREFAILED:
+ return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
+ case EZFS_SHAREFAILED:
+ return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
+ case EZFS_DEVLINKS:
+ return (dgettext(TEXT_DOMAIN, "failed to create /dev links"));
+ case EZFS_PERM:
+ return (dgettext(TEXT_DOMAIN, "permission denied"));
+ case EZFS_NOSPC:
+ return (dgettext(TEXT_DOMAIN, "out of space"));
+ case EZFS_IO:
+ return (dgettext(TEXT_DOMAIN, "I/O error"));
+ case EZFS_INTR:
+ return (dgettext(TEXT_DOMAIN, "signal received"));
+ case EZFS_ISSPARE:
+ return (dgettext(TEXT_DOMAIN, "device is reserved as a hot "
+ "spare"));
+ case EZFS_INVALCONFIG:
+ return (dgettext(TEXT_DOMAIN, "invalid vdev configuration"));
+ case EZFS_UNKNOWN:
+ return (dgettext(TEXT_DOMAIN, "unknown error"));
+ default:
+ abort();
+ }
+
+ /* NOTREACHED */
+}
+
+/*PRINTFLIKE2*/
void
-zfs_error(const char *fmt, ...)
+zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- if (error_func != NULL) {
- error_func(fmt, ap);
- } else {
- (void) vfprintf(stderr, fmt, ap);
- (void) fprintf(stderr, "\n");
+ (void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc),
+ fmt, ap);
+ hdl->libzfs_desc_active = 1;
+
+ va_end(ap);
+}
+
+static void
+zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap)
+{
+ (void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action),
+ fmt, ap);
+ hdl->libzfs_error = error;
+
+ if (hdl->libzfs_desc_active)
+ hdl->libzfs_desc_active = 0;
+ else
+ hdl->libzfs_desc[0] = '\0';
+
+ if (hdl->libzfs_printerr) {
+ if (error == EZFS_UNKNOWN) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal "
+ "error: %s\n"), libzfs_error_description(hdl));
+ abort();
+ }
+
+ (void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action,
+ libzfs_error_description(hdl));
+ if (error == EZFS_NOMEM)
+ exit(1);
}
+}
+
+/*PRINTFLIKE3*/
+int
+zfs_error(libzfs_handle_t *hdl, int error, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ zfs_verror(hdl, error, fmt, ap);
va_end(ap);
+
+ return (-1);
}
-/*
- * An internal error is something that we cannot recover from, and should never
- * happen (such as running out of memory). It should only be used in
- * exceptional circumstances.
- */
-void
-zfs_fatal(const char *fmt, ...)
+static int
+zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
+ va_list ap)
+{
+ switch (error) {
+ case EPERM:
+ case EACCES:
+ zfs_verror(hdl, EZFS_PERM, fmt, ap);
+ return (-1);
+
+ case EIO:
+ zfs_verror(hdl, EZFS_IO, fmt, ap);
+ return (-1);
+
+ case EINTR:
+ zfs_verror(hdl, EZFS_INTR, fmt, ap);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*PRINTFLIKE3*/
+int
+zfs_standard_error(libzfs_handle_t *hdl, int error, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- if (error_func != NULL) {
- error_func(fmt, ap);
- } else {
- (void) vfprintf(stderr, fmt, ap);
- (void) fprintf(stderr, "\n");
+ if (zfs_common_error(hdl, error, fmt, ap) != 0) {
+ va_end(ap);
+ return (-1);
}
- va_end(ap);
- exit(1);
+ switch (error) {
+ case ENXIO:
+ zfs_verror(hdl, EZFS_IO, fmt, ap);
+ break;
+
+ case ENOENT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset does not exist"));
+ zfs_verror(hdl, EZFS_NOENT, fmt, ap);
+ break;
+
+ case ENOSPC:
+ case EDQUOT:
+ zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+ return (-1);
+
+ case EEXIST:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset already exists"));
+ zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
+ break;
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "dataset is busy"));
+ zfs_verror(hdl, EZFS_BUSY, fmt, ap);
+ break;
+
+ default:
+ zfs_error_aux(hdl, strerror(errno));
+ zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
+ break;
+ }
+
+ va_end(ap);
+ return (-1);
}
-/*
- * Consumers (such as the JNI interface) that need to capture error output can
- * override the default error handler using this function.
- */
-void
-zfs_set_error_handler(void (*func)(const char *, va_list))
+/*PRINTFLIKE3*/
+int
+zpool_standard_error(libzfs_handle_t *hdl, int error, const char *fmt, ...)
{
- error_func = func;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (zfs_common_error(hdl, error, fmt, ap) != 0) {
+ va_end(ap);
+ return (-1);
+ }
+
+ switch (error) {
+ case ENODEV:
+ zfs_verror(hdl, EZFS_NODEVICE, fmt, ap);
+ break;
+
+ case ENOENT:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
+ zfs_verror(hdl, EZFS_NOENT, fmt, ap);
+ break;
+
+ case EEXIST:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "pool already exists"));
+ zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
+ break;
+
+ case EBUSY:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
+ zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
+ break;
+
+ case ENXIO:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "one or more devices is currently unavailable"));
+ zfs_verror(hdl, EZFS_BADDEV, fmt, ap);
+ break;
+
+ case ENAMETOOLONG:
+ zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap);
+ break;
+
+ default:
+ zfs_error_aux(hdl, strerror(error));
+ zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
+ }
+
+ va_end(ap);
+ return (-1);
}
/*
* Display an out of memory error message and abort the current program.
*/
-void
-no_memory(void)
+int
+no_memory(libzfs_handle_t *hdl)
{
- assert(errno == ENOMEM);
- zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: out of memory\n"));
+ return (zfs_error(hdl, EZFS_NOMEM, "internal error"));
}
/*
* A safe form of malloc() which will die if the allocation fails.
*/
void *
-zfs_malloc(size_t size)
+zfs_alloc(libzfs_handle_t *hdl, size_t size)
{
void *data;
if ((data = calloc(1, size)) == NULL)
- no_memory();
+ (void) no_memory(hdl);
return (data);
}
@@ -135,69 +365,17 @@ zfs_malloc(size_t size)
* A safe form of strdup() which will die if the allocation fails.
*/
char *
-zfs_strdup(const char *str)
+zfs_strdup(libzfs_handle_t *hdl, const char *str)
{
char *ret;
if ((ret = strdup(str)) == NULL)
- no_memory();
+ (void) no_memory(hdl);
return (ret);
}
/*
- * Utility functions around common used files - /dev/zfs, /etc/mnttab, and
- * /etc/dfs/sharetab.
- */
-int
-zfs_ioctl(int cmd, zfs_cmd_t *zc)
-{
- if (zfs_fd == -1 &&
- (zfs_fd = open(ZFS_DEV, O_RDWR)) < 0)
- zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: unable to "
- "open ZFS device\n"), MNTTAB);
-
- return (ioctl(zfs_fd, cmd, zc));
-}
-
-FILE *
-zfs_mnttab(void)
-{
- if (mnttab_file == NULL &&
- (mnttab_file = fopen(MNTTAB, "r")) == NULL)
- zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: unable to "
- "open %s\n"), MNTTAB);
-
- return (mnttab_file);
-}
-
-FILE *
-zfs_sharetab(void)
-{
- if (sharetab_opened)
- return (sharetab_file);
-
- sharetab_opened = TRUE;
- return (sharetab_file = fopen("/etc/dfs/sharetab", "r"));
-}
-
-/*
- * Cleanup function for library. Close any file descriptors that were
- * opened as part of the above functions.
- */
-#pragma fini(zfs_fini)
-void
-zfs_fini(void)
-{
- if (zfs_fd != -1)
- (void) close(zfs_fd);
- if (sharetab_file)
- (void) fclose(sharetab_file);
- if (mnttab_file)
- (void) fclose(mnttab_file);
-}
-
-/*
* Convert a number to an appropriately human-readable output.
*/
void
@@ -241,3 +419,58 @@ zfs_nicenum(uint64_t num, char *buf, size_t buflen)
}
}
}
+
+void
+libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)
+{
+ hdl->libzfs_printerr = printerr;
+}
+
+libzfs_handle_t *
+libzfs_init(void)
+{
+ libzfs_handle_t *hdl;
+
+ if ((hdl = calloc(sizeof (libzfs_handle_t), 1)) == NULL) {
+ return (NULL);
+ }
+
+ if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) == NULL) {
+ free(hdl);
+ return (NULL);
+ }
+
+ if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
+ (void) close(hdl->libzfs_fd);
+ free(hdl);
+ return (NULL);
+ }
+
+ hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "r");
+
+ return (hdl);
+}
+
+void
+libzfs_fini(libzfs_handle_t *hdl)
+{
+ (void) close(hdl->libzfs_fd);
+ if (hdl->libzfs_mnttab)
+ (void) fclose(hdl->libzfs_mnttab);
+ if (hdl->libzfs_sharetab)
+ (void) fclose(hdl->libzfs_sharetab);
+ namespace_clear(hdl);
+ free(hdl);
+}
+
+libzfs_handle_t *
+zpool_get_handle(zpool_handle_t *zhp)
+{
+ return (zhp->zpool_hdl);
+}
+
+libzfs_handle_t *
+zfs_get_handle(zfs_handle_t *zhp)
+{
+ return (zhp->zfs_hdl);
+}
diff --git a/usr/src/lib/libzfs/spec/libzfs.spec b/usr/src/lib/libzfs/spec/libzfs.spec
index 1789122711..6120603e18 100644
--- a/usr/src/lib/libzfs/spec/libzfs.spec
+++ b/usr/src/lib/libzfs/spec/libzfs.spec
@@ -24,6 +24,30 @@
#
#ident "%Z%%M% %I% %E% SMI"
+function libzfs_fini
+version SUNWprivate_1.1
+end
+
+function libzfs_init
+version SUNWprivate_1.1
+end
+
+function libzfs_errno
+version SUNWprivate_1.1
+end
+
+function libzfs_error_action
+version SUNWprivate_1.1
+end
+
+function libzfs_error_description
+version SUNWprivate_1.1
+end
+
+function libzfs_print_on_error
+version SUNWprivate_1.1
+end
+
function zfs_clone
version SUNWprivate_1.1
end
@@ -40,6 +64,10 @@ function zfs_destroy
version SUNWprivate_1.1
end
+function zfs_get_handle
+version SUNWprivate_1.1
+end
+
function zfs_get_name
version SUNWprivate_1.1
end
@@ -104,6 +132,10 @@ function zfs_open
version SUNWprivate_1.1
end
+function zfs_promote
+version SUNWprivate_1.1
+end
+
function zfs_prop_column_name
version SUNWprivate_1.1
end
@@ -188,10 +220,6 @@ function zfs_send
version SUNWprivate_1.1
end
-function zfs_set_error_handler
-version SUNWprivate_1.1
-end
-
function zfs_share
version SUNWprivate_1.1
end
@@ -248,6 +276,10 @@ function zpool_export
version SUNWprivate_1.1
end
+function zpool_find_vdev
+version SUNWprivate_1.1
+end
+
function zpool_find_import
version SUNWprivate_1.1
end
@@ -264,6 +296,10 @@ function zpool_get_guid
version SUNWprivate_1.1
end
+function zpool_get_handle
+version SUNWprivate_1.1
+end
+
function zpool_get_name
version SUNWprivate_1.1
end
@@ -288,6 +324,10 @@ function zpool_get_status
version SUNWprivate_1.1
end
+function zpool_get_version
+version SUNWprivate_1.1
+end
+
function zpool_import
version SUNWprivate_1.1
end
@@ -352,6 +392,7 @@ function zpool_vdev_name
version SUNWprivate_1.1
end
-function zpool_vdev_to_guid
-version SUNWprivate_1.1
+function zpool_vdev_remove
+version SUNWprivate_1.1
end
+
diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c b/usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c
index 64270f2cd7..2daeca32e2 100644
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c
@@ -574,7 +574,7 @@ is_fs_snapshot(zfs_handle_t *zhp)
zjni_get_dataset_from_snapshot(
zfs_get_name(zhp), parent, sizeof (parent));
- parent_zhp = zfs_open(parent, ZFS_TYPE_ANY);
+ parent_zhp = zfs_open(g_zfs, parent, ZFS_TYPE_ANY);
if (parent_zhp == NULL) {
return (-1);
}
@@ -606,7 +606,8 @@ zjni_create_add_Pool(zpool_handle_t *zphp, void *data)
zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
/* Get root fs for this pool -- may be NULL if pool is faulted */
- zfs_handle_t *zhp = zfs_open(zpool_get_name(zphp), ZFS_TYPE_FILESYSTEM);
+ zfs_handle_t *zhp = zfs_open(g_zfs, zpool_get_name(zphp),
+ ZFS_TYPE_FILESYSTEM);
jobject bean = create_PoolBean(env, zphp, zhp);
@@ -682,7 +683,7 @@ zjni_get_Datasets_below(JNIEnv *env, jstring parentUTF,
zjni_new_DatasetSet(env, list);
/* Retrieve parent dataset */
- zhp = zfs_open(name, parent_typemask);
+ zhp = zfs_open(g_zfs, name, parent_typemask);
if (zhp != NULL) {
zjni_DatasetArrayCallbackData_t data = {0};
@@ -703,7 +704,7 @@ zjni_get_Datasets_below(JNIEnv *env, jstring parentUTF,
/* Parent is not a dataset -- see if it's a faulted pool */
if ((parent_typemask & ZFS_TYPE_FILESYSTEM) &&
is_pool_name(name)) {
- zpool_handle_t *zphp = zpool_open_canfail(name);
+ zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
if (zphp != NULL) {
/* A faulted pool has no datasets */
@@ -750,7 +751,7 @@ zjni_get_Datasets_dependents(JNIEnv *env, jobjectArray paths)
const char *path =
(*env)->GetStringUTFChars(env, pathUTF, NULL);
- zfs_handle_t *zhp = zfs_open(path, ZFS_TYPE_ANY);
+ zfs_handle_t *zhp = zfs_open(g_zfs, path, ZFS_TYPE_ANY);
if (zhp != NULL) {
/* Add all dependents of this Dataset to list */
(void) zfs_iter_dependents(zhp,
@@ -762,7 +763,8 @@ zjni_get_Datasets_dependents(JNIEnv *env, jobjectArray paths)
/* Path is not a dataset - see if it's a faulted pool */
if (is_pool_name(path)) {
- zpool_handle_t *zphp = zpool_open_canfail(path);
+ zpool_handle_t *zphp = zpool_open_canfail(g_zfs,
+ path);
if (zphp != NULL) {
/*
@@ -795,10 +797,10 @@ zjni_get_Dataset(JNIEnv *env, jstring nameUTF, zfs_type_t typemask)
{
jobject device = NULL;
const char *name = (*env)->GetStringUTFChars(env, nameUTF, NULL);
- zfs_handle_t *zhp = zfs_open(name, typemask);
+ zfs_handle_t *zhp = zfs_open(g_zfs, name, typemask);
if ((typemask & ZFS_TYPE_FILESYSTEM) && is_pool_name(name)) {
- zpool_handle_t *zphp = zpool_open_canfail(name);
+ zpool_handle_t *zphp = zpool_open_canfail(g_zfs, name);
if (zphp != NULL) {
device = create_PoolBean(env, zphp, zhp);
diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c b/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c
index 34500684d3..a699ecd7ce 100644
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c
@@ -35,6 +35,8 @@
#include "libzfs_jni_diskmgt.h"
#include "libzfs_jni_disk.h"
+libzfs_handle_t *g_zfs;
+
/*
* Function prototypes
*/
@@ -46,14 +48,14 @@ static void init();
* Static functions
*/
-char libzfs_err[1024];
+char libdskmgt_err[1024];
static void
handle_error(const char *fmt, va_list ap)
{
/* Save the error message in case it's needed */
- (void) vsnprintf(libzfs_err, sizeof (libzfs_err), fmt, ap);
+ (void) vsnprintf(libdskmgt_err, sizeof (libdskmgt_err), fmt, ap);
#ifdef DEBUG
- (void) fprintf(stderr, "caught error: %s\n", libzfs_err);
+ (void) fprintf(stderr, "caught error: %s\n", libdskmgt_err);
#endif
}
@@ -64,10 +66,8 @@ handle_error(const char *fmt, va_list ap)
static void
init()
{
- libzfs_err[0] = '\0';
-
- /* libzfs error handler */
- zfs_set_error_handler(handle_error);
+ if ((g_zfs = libzfs_init()) == NULL)
+ abort();
/* diskmgt.o error handler */
dmgt_set_error_handler(handle_error);
@@ -151,7 +151,7 @@ Java_com_sun_zfs_common_model_SystemDataModel_getPools(JNIEnv *env, jobject obj)
data.env = env;
data.list = (zjni_Collection_t *)list;
- result = zpool_iter(zjni_create_add_Pool, &data);
+ result = zpool_iter(g_zfs, zjni_create_add_Pool, &data);
if (result && (*env)->ExceptionOccurred(env) != NULL) {
/* Must not call any more Java methods to preserve exception */
return (NULL);
@@ -334,7 +334,7 @@ Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevice(JNIEnv *env,
if (poolUTF != NULL) {
const char *pool = (*env)->GetStringUTFChars(env, poolUTF,
NULL);
- zpool_handle_t *zhp = zpool_open_canfail(pool);
+ zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
if (zhp != NULL) {
@@ -371,7 +371,7 @@ Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevices__Ljava_lang_Stri
if (poolUTF != NULL) {
const char *pool = (*env)->GetStringUTFChars(env, poolUTF,
NULL);
- zpool_handle_t *zhp = zpool_open_canfail(pool);
+ zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
/* Is the pool valid? */
@@ -408,7 +408,7 @@ Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevices__Ljava_lang_Stri
if (poolUTF != NULL) {
const char *pool = (*env)->GetStringUTFChars(env,
poolUTF, NULL);
- zpool_handle_t *zhp = zpool_open_canfail(pool);
+ zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
/* Is the pool valid? */
@@ -446,7 +446,7 @@ Java_com_sun_zfs_common_model_SystemDataModel_getAvailableDisks(JNIEnv *env,
error = dmgt_avail_disk_iter(zjni_create_add_DiskDevice, &data);
if (error) {
- zjni_throw_exception(env, "%s", libzfs_err);
+ zjni_throw_exception(env, "%s", libdskmgt_err);
} else {
array = zjni_Collection_to_array(
env, (zjni_Collection_t *)list,
diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c b/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c
index d9d09804ec..0e228460dc 100644
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c
@@ -26,6 +26,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
+#include "libzfs_jni_util.h"
#include "libzfs_jni_pool.h"
#include <strings.h>
@@ -1110,7 +1111,7 @@ zjni_pool_status_to_obj(JNIEnv *env, zpool_status_t status)
int
zjni_ipool_iter(int argc, char **argv, zjni_ipool_iter_f func, void *data)
{
- nvlist_t *pools = zpool_find_import(argc, argv);
+ nvlist_t *pools = zpool_find_import(g_zfs, argc, argv);
if (pools != NULL) {
nvpair_t *elem = NULL;
diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_util.h b/usr/src/lib/libzfs_jni/common/libzfs_jni_util.h
index 1b878a4977..b6989239ac 100644
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_util.h
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_util.h
@@ -32,6 +32,7 @@
#include <jni.h>
#include <regex.h>
#include <libnvpair.h>
+#include <libzfs.h>
#ifdef __cplusplus
extern "C" {
@@ -105,6 +106,8 @@ int zjni_count_elements(void **);
nvpair_t *zjni_nvlist_walk_nvpair(
nvlist_t *, const char *, data_type_t, nvpair_t *);
+extern libzfs_handle_t *g_zfs;
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libzpool/common/util.c b/usr/src/lib/libzpool/common/util.c
index 094c8b6c6f..df49adbc7a 100644
--- a/usr/src/lib/libzpool/common/util.c
+++ b/usr/src/lib/libzpool/common/util.c
@@ -111,11 +111,17 @@ show_vdev_stats(const char *desc, nvlist_t *nv, int indent)
for (c = 0; c < children; c++) {
nvlist_t *cnv = child[c];
- char *cname;
+ char *cname, *tname;
+ uint64_t np;
if (nvlist_lookup_string(cnv, ZPOOL_CONFIG_PATH, &cname) &&
nvlist_lookup_string(cnv, ZPOOL_CONFIG_TYPE, &cname))
cname = "<unknown>";
- show_vdev_stats(cname, cnv, indent + 2);
+ tname = calloc(1, strlen(cname) + 2);
+ (void) strcpy(tname, cname);
+ if (nvlist_lookup_uint64(cnv, ZPOOL_CONFIG_NPARITY, &np) == 0)
+ tname[strlen(tname)] = '0' + np;
+ show_vdev_stats(tname, cnv, indent + 2);
+ free(tname);
}
}