Пример #1
0
Файл: zinject.c Проект: RJVB/zfs
static int
iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
    void *data)
{
	zfs_cmd_t zc = { 0 };
	int ret;
#ifdef __APPLE__
	libzfs_handle_t hdl;
	hdl.libzfs_fd = zfs_fd;

	while (zfs_ioctl(&hdl, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
#else
	while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
#endif
		if ((ret = func((int)zc.zc_guid, zc.zc_name,
		    &zc.zc_inject_record, data)) != 0)
			return (ret);

	if (errno != ENOENT) {
		(void) fprintf(stderr, "Unable to list handlers: %s\n",
		    strerror(errno));
		return (-1);
	}

	return (0);
}
Пример #2
0
int
zfs_key_unload(zfs_handle_t *zhp, boolean_t force)
{
	zfs_cmd_t zc = { { 0 }};
	int ret = 0;
	int terrno;
	int type = zfs_get_type(zhp);
	char errbuf[1024];

	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
	    "cannot unload key for '%s'"), zfs_get_name(zhp));

	if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) == ZIO_CRYPT_OFF) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "no key to unload when encryption=off."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}
	if (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) !=
	    ZFS_CRYPT_KEY_AVAILABLE) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "key not present."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	/*
	 * We need to be sure that all the data has been written to
	 * disk before we unload the key so we first have to attempt
	 * an unmount, if that fails we don't continue with the key unload
	 * and instead return the error from zfs_umount.
	 */
	if (type == ZFS_TYPE_FILESYSTEM) {
		if (zfs_is_mounted(zhp, NULL)) {
			ret = zfs_unmountall(zhp, force ? MS_FORCE : 0);
			if (ret) {
				zfs_error_aux(zhp->zfs_hdl,
				    dgettext(TEXT_DOMAIN,
				    "failed to unload key: unmount failed"));
				return (zfs_error(zhp->zfs_hdl,
				    EZFS_KEYERR, errbuf));
			}
		}
	}

	(void) strlcpy(zc.zc_name, zfs_get_name(zhp), sizeof (zc.zc_name));

	errno = 0;
	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_UNLOAD, &zc);
	terrno = errno;
	if (ret != 0) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "failed to unload key: %s"), strerror(terrno));
		errno = terrno;	/* make sure it is the zfs_ioctl errno */
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}
	zfs_refresh_properties(zhp);

	return (0);
}
Пример #3
0
int
zfs_key_new(zfs_handle_t *zhp)
{
	char errbuf[1024];
	zfs_cmd_t zc = { { 0 } };

	(void) strlcpy(zc.zc_name, zfs_get_name(zhp), sizeof (zc.zc_name));

	if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_NEW, &zc) != 0) {
		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
		    "cannot create new key for '%s'"), zc.zc_name);
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}
	return (0);
}
Пример #4
0
static int
zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc)
{
	int rc;
	uint64_t	orig_cookie;

	orig_cookie = zc->zc_cookie;
top:
	(void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
	rc = zfs_ioctl(zhp->zfs_hdl, arg, zc);

	if (rc == -1) {
		switch (errno) {
		case ENOMEM:
			/* expand nvlist memory and try again */
			if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
				zcmd_free_nvlists(zc);
				return (-1);
			}
			zc->zc_cookie = orig_cookie;
			goto top;
		/*
		 * An errno value of ESRCH indicates normal completion.
		 * If ENOENT is returned, then the underlying dataset
		 * has been removed since we obtained the handle.
		 */
		case ESRCH:
		case ENOENT:
			rc = 1;
			break;
		default:
			rc = zfs_standard_error(zhp->zfs_hdl, errno,
			    dgettext(TEXT_DOMAIN,
			    "cannot iterate filesystems"));
			break;
		}
	}
	return (rc);
}
Пример #5
0
static nvlist_t *
refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
{
	nvlist_t *nvl;
	zfs_cmd_t zc = {"\0"};
	int err;

	if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0)
		return (NULL);

	if (zcmd_alloc_dst_nvlist(hdl, &zc,
	    zc.zc_nvlist_conf_size * 2) != 0) {
		zcmd_free_nvlists(&zc);
		return (NULL);
	}

	while ((err = zfs_ioctl(hdl, ZFS_IOC_POOL_TRYIMPORT,
	    &zc)) != 0 && errno == ENOMEM) {
		if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
			zcmd_free_nvlists(&zc);
			return (NULL);
		}
	}

	if (err) {
		zcmd_free_nvlists(&zc);
		return (NULL);
	}

	if (zcmd_read_dst_nvlist(hdl, &zc, &nvl) != 0) {
		zcmd_free_nvlists(&zc);
		return (NULL);
	}

	zcmd_free_nvlists(&zc);
	return (nvl);
}
Пример #6
0
/*
 * Given a {dsname, object id}, get the object path
 */
static int
get_stats_for_obj(differ_info_t *di, const char *dsname, uint64_t obj,
    char *pn, int maxlen, zfs_stat_t *sb)
{
	zfs_cmd_t zc = {"\0"};
	int error;

	(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
	zc.zc_obj = obj;

	errno = 0;
	error = zfs_ioctl(di->zhp->zfs_hdl, ZFS_IOC_OBJ_TO_STATS, &zc);
	di->zerr = errno;

	/* we can get stats even if we failed to get a path */
	(void) memcpy(sb, &zc.zc_stat, sizeof (zfs_stat_t));
	if (error == 0) {
		ASSERT(di->zerr == 0);
		(void) strlcpy(pn, zc.zc_value, maxlen);
		return (0);
	}

	if (di->zerr == EPERM) {
		(void) snprintf(di->errbuf, sizeof (di->errbuf),
		    dgettext(TEXT_DOMAIN,
		    "The sys_config privilege or diff delegated permission "
		    "is needed\nto discover path names"));
		return (-1);
	} else {
		(void) snprintf(di->errbuf, sizeof (di->errbuf),
		    dgettext(TEXT_DOMAIN,
		    "Unable to determine path or stats for "
		    "object %lld in %s"), (longlong_t)obj, dsname);
		return (-1);
	}
}
Пример #7
0
/*
 * Refresh the vdev statistics associated with the given pool.  This is used in
 * iostat to show configuration changes and determine the delta from the last
 * time the function was called.  This function can fail, in case the pool has
 * been destroyed.
 */
int
zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
{
	zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
	int error;
	nvlist_t *config;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	*missing = B_FALSE;
	(void) strcpy(zc.zc_name, zhp->zpool_name);

	if (zhp->zpool_config_size == 0)
		zhp->zpool_config_size = 1 << 16;

	if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
		return (-1);

	for (;;) {
		//if (zfs_ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
		if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_STATS,
		    &zc) == 0) {
			/*
			 * The real error is returned in the zc_cookie field.
			 */
            printf("ioctl(POOL_STATS) returned error\n");
			error = zc.zc_cookie;
			break;
		}

		if (errno == ENOMEM) {
			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
				zcmd_free_nvlists(&zc);
				return (-1);
			}
		} else {
			zcmd_free_nvlists(&zc);
			if (errno == ENOENT || errno == EINVAL)
				*missing = B_TRUE;
			zhp->zpool_state = POOL_STATE_UNAVAIL;
			return (0);
		}
	}

	if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
		zcmd_free_nvlists(&zc);
		return (-1);
	}

	zcmd_free_nvlists(&zc);

	zhp->zpool_config_size = zc.zc_nvlist_dst_size;

	if (zhp->zpool_config != NULL) {
		uint64_t oldtxg, newtxg;

		verify(nvlist_lookup_uint64(zhp->zpool_config,
		    ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0);
		verify(nvlist_lookup_uint64(config,
		    ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);

		if (zhp->zpool_old_config != NULL)
			nvlist_free(zhp->zpool_old_config);

		if (oldtxg != newtxg) {
			nvlist_free(zhp->zpool_config);
			zhp->zpool_old_config = NULL;
		} else {
			zhp->zpool_old_config = zhp->zpool_config;
		}
	}

	zhp->zpool_config = config;
	if (error)
		zhp->zpool_state = POOL_STATE_UNAVAIL;
	else
		zhp->zpool_state = POOL_STATE_ACTIVE;

	return (0);
}
Пример #8
0
/*
 * Loads the pool namespace, or re-loads it if the cache has changed.
 */
static int
namespace_reload(libzfs_handle_t *hdl)
{
	nvlist_t *config;
	config_node_t *cn;
	nvpair_t *elem;
	zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
	void *cookie;

	if (hdl->libzfs_ns_gen == 0) {
		/*
		 * This is the first time we've accessed the configuration
		 * cache.  Initialize the AVL tree and then fall through to the
		 * common code.
		 */
		if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
		    sizeof (config_node_t),
		    offsetof(config_node_t, cn_avl),
		    config_node_compare, UU_DEFAULT)) == NULL)
			return (no_memory(hdl));

		if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
		    NULL, UU_DEFAULT)) == NULL)
			return (no_memory(hdl));
	}

	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
		return (-1);

	for (;;) {
		zc.zc_cookie = hdl->libzfs_ns_gen;
		//if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
		if (zfs_ioctl(hdl, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
			switch (errno) {
			case EEXIST:
				/*
				 * The namespace hasn't changed.
				 */
				zcmd_free_nvlists(&zc);
				return (0);

			case ENOMEM:
				if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
					zcmd_free_nvlists(&zc);
					return (-1);
				}
				break;

			default:
				zcmd_free_nvlists(&zc);
				return (zfs_standard_error(hdl, errno,
				    dgettext(TEXT_DOMAIN, "failed to read "
				    "pool configuration")));
			}
		} else {
			hdl->libzfs_ns_gen = zc.zc_cookie;
			break;
		}
	}

	if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
		zcmd_free_nvlists(&zc);
		return (-1);
	}

	zcmd_free_nvlists(&zc);

	/*
	 * Clear out any existing configuration information.
	 */
	cookie = NULL;
	while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
		nvlist_free(cn->cn_config);
		free(cn->cn_name);
		free(cn);
	}

	elem = NULL;
	while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
		nvlist_t *child;
		uu_avl_index_t where;

		if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
			nvlist_free(config);
			return (-1);
		}

		if ((cn->cn_name = zfs_strdup(hdl,
		    nvpair_name(elem))) == NULL) {
			free(cn);
			nvlist_free(config);
			return (-1);
		}

		verify(nvpair_value_nvlist(elem, &child) == 0);
		if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
			free(cn->cn_name);
			free(cn);
			nvlist_free(config);
			return (no_memory(hdl));
		}
		verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
		    == NULL);

		uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
	}

	nvlist_free(config);
	return (0);
}
Пример #9
0
int
zfs_key_load(zfs_handle_t *zhp, boolean_t mount, boolean_t share,
    boolean_t recursive)
{
	zfs_handle_t *pzhp = NULL;
	zprop_source_t propsrctype;
	char source[ZFS_MAXNAMELEN];
	char keysource[MAXNAMELEN];
	uint64_t ret, crypt, keystatus;
	zfs_cmd_t zc = { {0 }};
	char errbuf[1024];

    fprintf(stderr, "zfs_key_load\r\n");


	(void) strlcpy(zc.zc_name, zfs_get_name(zhp), sizeof (zc.zc_name));
	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
	    "cannot load key for '%s'"), zc.zc_name);

	zfs_refresh_properties(zhp);

	crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);
	if (crypt == ZIO_CRYPT_OFF) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "encryption not enabled on dataset %s."), zc.zc_name);
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);

	if (keystatus == ZFS_CRYPT_KEY_AVAILABLE && !recursive) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "already loaded."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (zfs_prop_get(zhp, ZFS_PROP_KEYSOURCE, keysource, ZFS_MAXNAMELEN,
	    &propsrctype, source, sizeof (source), FALSE) != 0) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "no keysource property available."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (propsrctype == ZPROP_SRC_INHERITED) {
#if 0 // FIXME
		if (strcmp(source, ZONE_INVISIBLE_SOURCE) == 0) {
			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
			    "key must be loaded from global zone."));
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
#endif
		pzhp = make_dataset_handle(zhp->zfs_hdl, source);
		if (pzhp == NULL) {
			errno = EINVAL;
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
		keystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS);
		zfs_close(pzhp);
	}

	if (propsrctype == ZPROP_SRC_DEFAULT) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "invalid keysource property."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (!zfs_can_prompt_if_needed(keysource)) {
		errno = ENOTTY;
		return (-1);
	}
	/*
	 * NONE we are the top ds asking for crypto so we
	 * need to get and load the key.
	 *
	 * UNAVAILABLE we need to load the key of a higher level
	 * dataset.
	 *
	 * AVAILABLE we are done other than filling in who we
	 * are inheriting the wrapping key from.
	 */
	if (propsrctype == ZPROP_SRC_INHERITED &&
	    keystatus == ZFS_CRYPT_KEY_AVAILABLE) {
		(void) strlcpy(zc.zc_crypto.zic_inherit_dsname, source,
		    sizeof (zc.zc_crypto.zic_inherit_dsname));
		ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_INHERIT, &zc);
		goto out;
	}

	zc.zc_crypto.zic_crypt = crypt;

	ret = key_hdl_to_zc(zhp->zfs_hdl, zhp, keysource, crypt, &zc,
	    ZFS_CRYPTO_KEY_LOAD);
	if (ret != 0) {
		if (errno == ENOTTY)
			ret = 0;
		goto out;
	}

	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_LOAD, &zc);
out:
	if (ret != 0) {
		if (errno == EACCES) {
			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
			    "incorrect key."));
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		} else if (!recursive) {
			if (errno == EEXIST) {
				zfs_error_aux(zhp->zfs_hdl,
				    dgettext(TEXT_DOMAIN, "already loaded."));
			} else if (zhp->zfs_hdl->libzfs_desc_active == 0) {
				zfs_error_aux(zhp->zfs_hdl, strerror(errno));
			}
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
	}

	zfs_refresh_properties(zhp);
	if (mount) {
		if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
			if (recursive) {
				ret = zfs_mountall(zhp, 0);
			} else {
				ret = zfs_mount(zhp, NULL, 0);
			}
			if (ret == 0 && share) {
				ret = zfs_share(zhp);
			}
		}
	}

	return (ret);
}
Пример #10
0
int
zfs_key_change(zfs_handle_t *zhp, boolean_t recursing, nvlist_t *props)
{
	char errbuf[1024];
	int ret;
	zfs_cmd_t zc = { { 0 } };
	char keysource[ZFS_MAXNAMELEN];
	uint64_t crypt;
	zprop_source_t propsrctype = ZPROP_SRC_NONE;
	char propsrc[ZFS_MAXNAMELEN] = { 0 };

	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
	    "cannot change wrapping key for '%s'"), zfs_get_name(zhp));
	crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);
	if (crypt == ZIO_CRYPT_OFF) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "cannot change key when encryption=off"));
		goto error;
	}

	switch (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS)) {
	case ZFS_CRYPT_KEY_NONE:
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "inconsistent state encryption enabled but "
		    "key not defined."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	case ZFS_CRYPT_KEY_UNAVAILABLE:
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "load existing key first: 'zfs key -l <dataset>'."));
		goto error;
	}

	(void) zfs_prop_get(zhp, ZFS_PROP_KEYSOURCE, keysource,
	    ZFS_MAXNAMELEN, &propsrctype, propsrc, ZFS_MAXNAMELEN, B_TRUE);
	if (!(propsrctype & ZPROP_SRC_LOCAL ||
	    propsrctype & ZPROP_SRC_RECEIVED)) {
		if (recursing)
			return (0);
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "keysource property not local, change key on '%s'."),
		    propsrc);
		goto error;
	}

	zhp->zfs_hdl->libzfs_crypt.zc_is_key_change = B_TRUE;

	/*
	 * The only thing we currently expect in props is a keysource
	 * if we have props without keysource then that isn't valid.
	 */
	if (props != NULL) {
		char *nkeysource;
		ret = nvlist_lookup_string(props,
		    zfs_prop_to_name(ZFS_PROP_KEYSOURCE), (char **)&nkeysource);
		if (ret != 0) {
			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
			    "invalid props for key change; expected "
			    "%s property missing."),
			    zfs_prop_to_name(ZFS_PROP_KEYSOURCE));
			goto error;
		}
		(void) strlcpy(keysource, nkeysource, sizeof (keysource));
	}

	(void) strlcpy(zc.zc_name, zfs_get_name(zhp), sizeof (zc.zc_name));
	zc.zc_crypto.zic_crypt = crypt;

	if (!zfs_can_prompt_if_needed(keysource)) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "unable to prompt for new wrapping key."));
		errno = ENOTTY;
		goto error;
	}

	ret = key_hdl_to_zc(zhp->zfs_hdl, zhp, keysource, crypt, &zc,
	    ZFS_CRYPTO_KEY_CHANGE);
	if (props != NULL) {
		if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, props) != 0)
			goto error;
	}
	if (ret == 0) {
		/* Send change to kernel */
		ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_CHANGE, &zc);
		zcmd_free_nvlists(&zc);
		if (ret != 0) {
			return (zfs_standard_error(zhp->zfs_hdl,
			    errno, errbuf));
		}
		zfs_refresh_properties(zhp);
		return (ret);
	}
error:
	zcmd_free_nvlists(&zc);
	return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
}
Пример #11
0
libzfs_handle_t *
libzfs_init(void)
{
    libzfs_handle_t *hdl;
#ifdef __APPLE__
    struct vfsconf vfc;
    struct stat sb;
    int loaded;

    /* Attempt to load zfs kext if its not already loaded. */
    if (getvfsbyname("zfs", &vfc) != 0) {
        int pick = 0;
        int i;

        /* Find all possible zfs kext versions. */
        getkextvers(kextpaths[0], &kextvers[0]);
        getkextvers(kextpaths[1], &kextvers[1]);

        /* Pick the newest one. */
        for (i = 0; i < 2; ++i) {
            if (kextvers[i] > kextvers[pick])
                pick = i;
        }

        loaded = load_zfs_kext(kextpaths[pick]);
        ASSERT(loaded == 0);
    }
    /* Attempt to create "/etc/zfs" its not already there. */
    if (getuid() == 0 && stat("/etc/zfs", &sb)!= 0 &&  errno == ENOENT)
    {
        (void) mkdir("/etc/zfs", 0755);
    }
#endif

    if ((hdl = calloc(sizeof (libzfs_handle_t), 1)) == NULL) {
        return (NULL);
    }

    if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
        free(hdl);
        return (NULL);
    } else {
        /* Perform special version ceck ioctl() to unlock user-kernel
         * interface.  This serves as protection against using userland
         * tools of one implementation against kernel land of another
         * implementation.
         */
        zfs_cmd_t vers_zc = {0};
        strncpy(vers_zc.zc_name, __STRING(MACZFS_ID), sizeof(vers_zc.zc_name)-1);
        vers_zc.zc_value[0] = ZFS_IOC_NUM(ZFS_IOC__LAST_USED);
        vers_zc.zc_value[1] = MACZFS_VERS_MAJOR;
        vers_zc.zc_value[2] = MACZFS_VERS_MINOR;
        vers_zc.zc_value[3] = MACZFS_VERS_PATCH;
        hdl->libzfs_log_str = NULL;
        if (zfs_ioctl(hdl, ZFS_IOC__VERSION_CHECK, &vers_zc) != 0) {
            /* kernel - user version mismatch or kernel side not ready. */
            free(hdl);
            return (NULL);
        }
    }

#ifndef __APPLE__
    if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
        (void) close(hdl->libzfs_fd);
        free(hdl);
        return (NULL);
    }
#endif /*!__APPLE__*/

    hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "r");

    zfs_prop_init();

    return (hdl);
}