libzfs_import.c revision fa9e4066f08beec538e775443c5be79dd423fcab
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * Pool import support functions.
31 *
32 * To import a pool, we rely on reading the configuration information from the
33 * ZFS label of each device.  If we successfully read the label, then we
34 * organize the configuration information in the following hierarchy:
35 *
36 * 	pool guid -> toplevel vdev guid -> label txg
37 *
38 * Duplicate entries matching this same tuple will be discarded.  Once we have
39 * examined every device, we pick the best label txg config for each toplevel
40 * vdev.  We then arrange these toplevel vdevs into a complete pool config, and
41 * update any paths that have changed.  Finally, we attempt to import the pool
42 * using our derived config, and record the results.
43 */
44
45#include <devid.h>
46#include <dirent.h>
47#include <errno.h>
48#include <libintl.h>
49#include <stdlib.h>
50#include <string.h>
51#include <sys/stat.h>
52#include <unistd.h>
53#include <fcntl.h>
54
55#include <sys/vdev_impl.h>
56
57#include "libzfs.h"
58#include "libzfs_impl.h"
59
60/*
61 * Intermediate structures used to gather configuration information.
62 */
63typedef struct config_entry {
64	uint64_t		ce_txg;
65	nvlist_t		*ce_config;
66	struct config_entry	*ce_next;
67} config_entry_t;
68
69typedef struct vdev_entry {
70	uint64_t		ve_guid;
71	config_entry_t		*ve_configs;
72	struct vdev_entry	*ve_next;
73} vdev_entry_t;
74
75typedef struct pool_entry {
76	uint64_t		pe_guid;
77	vdev_entry_t		*pe_vdevs;
78	struct pool_entry	*pe_next;
79} pool_entry_t;
80
81typedef struct name_entry {
82	const char		*ne_name;
83	uint64_t		ne_guid;
84	struct name_entry	*ne_next;
85} name_entry_t;
86
87typedef struct pool_list {
88	pool_entry_t		*pools;
89	name_entry_t		*names;
90} pool_list_t;
91
92static char *
93get_devid(const char *path)
94{
95	int fd;
96	ddi_devid_t devid;
97	char *minor, *ret;
98
99	if ((fd = open(path, O_RDONLY)) < 0)
100		return (NULL);
101
102	minor = NULL;
103	ret = NULL;
104	if (devid_get(fd, &devid) == 0) {
105		if (devid_get_minor_name(fd, &minor) == 0)
106			ret = devid_str_encode(devid, minor);
107		if (minor != NULL)
108			devid_str_free(minor);
109		devid_free(devid);
110	}
111
112	return (ret);
113}
114
115
116/*
117 * Go through and fix up any path and/or devid information for the given vdev
118 * configuration.
119 */
120static void
121fix_paths(nvlist_t *nv, name_entry_t *names)
122{
123	nvlist_t **child;
124	uint_t c, children;
125	uint64_t guid;
126	name_entry_t *ne;
127	char *devid;
128
129	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
130	    &child, &children) == 0) {
131		for (c = 0; c < children; c++)
132			fix_paths(child[c], names);
133		return;
134	}
135
136	/*
137	 * This is a leaf (file or disk) vdev.  In either case, go through
138	 * the name list and see if we find a matching guid.  If so, replace
139	 * the path and see if we can calculate a new devid.
140	 */
141	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0);
142
143	for (ne = names; ne != NULL; ne = ne->ne_next)
144		if (ne->ne_guid == guid)
145			break;
146
147	if (ne == NULL)
148		return;
149
150	verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, ne->ne_name) == 0);
151
152	if ((devid = get_devid(ne->ne_name)) == NULL) {
153		(void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
154	} else {
155		verify(nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) == 0);
156		devid_str_free(devid);
157	}
158}
159
160/*
161 * Add the given configuration to the list of known devices.
162 */
163static void
164add_config(pool_list_t *pl, const char *path, nvlist_t *config)
165{
166	uint64_t pool_guid, vdev_guid, top_guid, txg;
167	pool_entry_t *pe;
168	vdev_entry_t *ve;
169	config_entry_t *ce;
170	name_entry_t *ne;
171
172	/*
173	 * If we have a valid config but cannot read any of these fields, then
174	 * it means we have a half-initialized label.  In vdev_label_init()
175	 * we write a label with txg == 0 so that we can identify the device
176	 * in case the user refers to the same disk later on.  If we fail to
177	 * create the pool, we'll be left with a label in this state
178	 * which should not be considered part of a valid pool.
179	 */
180	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
181	    &pool_guid) != 0 ||
182	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
183	    &vdev_guid) != 0 ||
184	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_TOP_GUID,
185	    &top_guid) != 0 ||
186	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
187	    &txg) != 0 || txg == 0) {
188		nvlist_free(config);
189		return;
190	}
191
192	/*
193	 * First, see if we know about this pool.  If not, then add it to the
194	 * list of known pools.
195	 */
196	for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
197		if (pe->pe_guid == pool_guid)
198			break;
199	}
200
201	if (pe == NULL) {
202		pe = zfs_malloc(sizeof (pool_entry_t));
203		pe->pe_guid = pool_guid;
204		pe->pe_next = pl->pools;
205		pl->pools = pe;
206	}
207
208	/*
209	 * Second, see if we know about this toplevel vdev.  Add it if its
210	 * missing.
211	 */
212	for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
213		if (ve->ve_guid == top_guid)
214			break;
215	}
216
217	if (ve == NULL) {
218		ve = zfs_malloc(sizeof (vdev_entry_t));
219		ve->ve_guid = top_guid;
220		ve->ve_next = pe->pe_vdevs;
221		pe->pe_vdevs = ve;
222	}
223
224	/*
225	 * Third, see if we have a config with a matching transaction group.  If
226	 * so, then we do nothing.  Otherwise, add it to the list of known
227	 * configs.
228	 */
229	for (ce = ve->ve_configs; ce != NULL; ce = ce->ce_next) {
230		if (ce->ce_txg == txg)
231			break;
232	}
233
234	if (ce == NULL) {
235		ce = zfs_malloc(sizeof (config_entry_t));
236		ce->ce_txg = txg;
237		ce->ce_config = config;
238		ce->ce_next = ve->ve_configs;
239		ve->ve_configs = ce;
240	} else {
241		nvlist_free(config);
242	}
243
244	/*
245	 * At this point we've successfully added our config to the list of
246	 * known configs.  The last thing to do is add the vdev guid -> path
247	 * mappings so that we can fix up the configuration as necessary before
248	 * doing the import.
249	 */
250	ne = zfs_malloc(sizeof (name_entry_t));
251
252	ne->ne_name = zfs_strdup(path);
253	ne->ne_guid = vdev_guid;
254	ne->ne_next = pl->names;
255	pl->names = ne;
256}
257
258/*
259 * Convert our list of pools into the definitive set of configurations.  We
260 * start by picking the best config for each toplevel vdev.  Once that's done,
261 * we assemble the toplevel vdevs into a full config for the pool.  We make a
262 * pass to fix up any incorrect paths, and then add it to the main list to
263 * return to the user.
264 */
265static nvlist_t *
266get_configs(pool_list_t *pl)
267{
268	pool_entry_t *pe, *penext;
269	vdev_entry_t *ve, *venext;
270	config_entry_t *ce, *cenext;
271	nvlist_t *ret, *config, *tmp, *nvtop, *nvroot;
272	int config_seen;
273	uint64_t best_txg;
274	char *name;
275	zfs_cmd_t zc = { 0 };
276	uint64_t guid;
277	char *packed;
278	size_t len;
279	int err;
280
281	verify(nvlist_alloc(&ret, 0, 0) == 0);
282
283	for (pe = pl->pools; pe != NULL; pe = penext) {
284		uint_t c;
285		uint_t children = 0;
286		uint64_t id;
287		nvlist_t **child = NULL;
288
289		penext = pe->pe_next;
290
291		verify(nvlist_alloc(&config, NV_UNIQUE_NAME, 0) == 0);
292		config_seen = FALSE;
293
294		/*
295		 * Iterate over all toplevel vdevs.  Grab the pool configuration
296		 * from the first one we find, and then go through the rest and
297		 * add them as necessary to the 'vdevs' member of the config.
298		 */
299		for (ve = pe->pe_vdevs; ve != NULL; ve = venext) {
300			venext = ve->ve_next;
301
302			/*
303			 * Determine the best configuration for this vdev by
304			 * selecting the config with the latest transaction
305			 * group.
306			 */
307			best_txg = 0;
308			for (ce = ve->ve_configs; ce != NULL;
309			    ce = ce->ce_next) {
310
311				if (ce->ce_txg > best_txg)
312					tmp = ce->ce_config;
313			}
314
315			if (!config_seen) {
316				/*
317				 * Copy the relevant pieces of data to the pool
318				 * configuration:
319				 *
320				 * 	pool guid
321				 * 	name
322				 * 	pool state
323				 */
324				uint64_t state;
325
326				verify(nvlist_lookup_uint64(tmp,
327				    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
328				verify(nvlist_add_uint64(config,
329				    ZPOOL_CONFIG_POOL_GUID, guid) == 0);
330				verify(nvlist_lookup_string(tmp,
331				    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
332				verify(nvlist_add_string(config,
333				    ZPOOL_CONFIG_POOL_NAME, name) == 0);
334				verify(nvlist_lookup_uint64(tmp,
335				    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
336				verify(nvlist_add_uint64(config,
337				    ZPOOL_CONFIG_POOL_STATE, state) == 0);
338
339				config_seen = TRUE;
340			}
341
342			/*
343			 * Add this top-level vdev to the child array.
344			 */
345			verify(nvlist_lookup_nvlist(tmp,
346			    ZPOOL_CONFIG_VDEV_TREE, &nvtop) == 0);
347			verify(nvlist_lookup_uint64(nvtop, ZPOOL_CONFIG_ID,
348			    &id) == 0);
349			if (id >= children) {
350				nvlist_t **newchild;
351
352				newchild = zfs_malloc((id + 1) *
353				    sizeof (nvlist_t *));
354
355				for (c = 0; c < children; c++)
356					newchild[c] = child[c];
357
358				free(child);
359				child = newchild;
360				children = id + 1;
361			}
362			verify(nvlist_dup(nvtop, &child[id], 0) == 0);
363
364			/*
365			 * Go through and free all config information.
366			 */
367			for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
368				cenext = ce->ce_next;
369
370				nvlist_free(ce->ce_config);
371				free(ce);
372			}
373
374			/*
375			 * Free this vdev entry, since it has now been merged
376			 * into the main config.
377			 */
378			free(ve);
379		}
380
381		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
382		    &guid) == 0);
383
384		/*
385		 * Look for any missing top-level vdevs.  If this is the case,
386		 * create a faked up 'missing' vdev as a placeholder.  We cannot
387		 * simply compress the child array, because the kernel performs
388		 * certain checks to make sure the vdev IDs match their location
389		 * in the configuration.
390		 */
391		for (c = 0; c < children; c++)
392			if (child[c] == NULL) {
393				nvlist_t *missing;
394				verify(nvlist_alloc(&missing, NV_UNIQUE_NAME,
395				    0) == 0);
396				verify(nvlist_add_string(missing,
397				    ZPOOL_CONFIG_TYPE, VDEV_TYPE_MISSING) == 0);
398				verify(nvlist_add_uint64(missing,
399				    ZPOOL_CONFIG_ID, c) == 0);
400				verify(nvlist_add_uint64(missing,
401				    ZPOOL_CONFIG_GUID, 0ULL) == 0);
402				child[c] = missing;
403			}
404
405		/*
406		 * Put all of this pool's top-level vdevs into a root vdev.
407		 */
408		verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
409		verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
410		    VDEV_TYPE_ROOT) == 0);
411		verify(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) == 0);
412		verify(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, guid) == 0);
413		verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
414		    child, children) == 0);
415
416		for (c = 0; c < children; c++)
417			nvlist_free(child[c]);
418		free(child);
419
420		/*
421		 * Go through and fix up any paths and/or devids based on our
422		 * known list of vdev GUID -> path mappings.
423		 */
424		fix_paths(nvroot, pl->names);
425
426		/*
427		 * Add the root vdev to this pool's configuration.
428		 */
429		verify(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
430		    nvroot) == 0);
431		nvlist_free(nvroot);
432
433		/*
434		 * Free this pool entry.
435		 */
436		free(pe);
437
438		/*
439		 * Determine if this pool is currently active, in which case we
440		 * can't actually import it.
441		 */
442		verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
443		    &name) == 0);
444		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
445		    &guid) == 0);
446
447		(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
448		if (ioctl(zfs_fd, ZFS_IOC_POOL_GUID, &zc) == 0 &&
449		    guid == zc.zc_pool_guid) {
450			nvlist_free(config);
451			continue;
452		}
453
454		/*
455		 * Try to do the import in order to get vdev state.
456		 */
457		if ((err = nvlist_size(config, &len, NV_ENCODE_NATIVE)) != 0)
458			zfs_baderror(err);
459
460		packed = zfs_malloc(len);
461
462		if ((err = nvlist_pack(config, &packed, &len,
463		    NV_ENCODE_NATIVE, 0)) != 0)
464			zfs_baderror(err);
465
466		nvlist_free(config);
467		config = NULL;
468
469		zc.zc_config_src_size = len;
470		zc.zc_config_src = (uint64_t)(uintptr_t)packed;
471
472		zc.zc_config_dst_size = 2 * len;
473		zc.zc_config_dst = (uint64_t)(uintptr_t)
474		    zfs_malloc(zc.zc_config_dst_size);
475
476		while ((err = ioctl(zfs_fd, ZFS_IOC_POOL_TRYIMPORT,
477		    &zc)) != 0 && errno == ENOMEM) {
478			free((void *)(uintptr_t)zc.zc_config_dst);
479			zc.zc_config_dst = (uint64_t)(uintptr_t)
480			    zfs_malloc(zc.zc_config_dst_size);
481		}
482
483		free(packed);
484
485		if (err)
486			zfs_baderror(errno);
487
488		verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
489		    zc.zc_config_dst_size, &config, 0) == 0);
490
491		set_pool_health(config);
492
493		/*
494		 * Add this pool to the list of configs.
495		 */
496		verify(nvlist_add_nvlist(ret, name, config) == 0);
497
498		nvlist_free(config);
499
500		free((void *)(uintptr_t)zc.zc_config_dst);
501	}
502
503	return (ret);
504}
505
506/*
507 * Return the offset of the given label.
508 */
509static uint64_t
510label_offset(size_t size, int l)
511{
512	return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ?
513	    0 : size - VDEV_LABELS * sizeof (vdev_label_t)));
514}
515
516/*
517 * Given a file descriptor, read the label information and return an nvlist
518 * describing the configuration, if there is one.
519 */
520nvlist_t *
521zpool_read_label(int fd)
522{
523	struct stat64 statbuf;
524	int l;
525	vdev_label_t *label;
526	nvlist_t *config;
527	uint64_t version, state, txg;
528
529	if (fstat64(fd, &statbuf) == -1)
530		return (NULL);
531
532	label = zfs_malloc(sizeof (vdev_label_t));
533
534	for (l = 0; l < VDEV_LABELS; l++) {
535		if (pread(fd, label, sizeof (vdev_label_t),
536		    label_offset(statbuf.st_size, l)) != sizeof (vdev_label_t))
537			continue;
538
539		if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist,
540		    sizeof (label->vl_vdev_phys.vp_nvlist), &config, 0) != 0)
541			continue;
542
543		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
544		    &version) != 0 || version != UBERBLOCK_VERSION) {
545			nvlist_free(config);
546			continue;
547		}
548
549		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
550		    &state) != 0 || state > POOL_STATE_EXPORTED) {
551			nvlist_free(config);
552			continue;
553		}
554
555		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
556		    &txg) != 0 || txg == 0) {
557			nvlist_free(config);
558			continue;
559		}
560
561		free(label);
562		return (config);
563	}
564
565	free(label);
566	return (NULL);
567}
568
569/*
570 * Given a list of directories to search, find all pools stored on disk.  This
571 * includes partial pools which are not available to import.  If no args are
572 * given (argc is 0), then the default directory (/dev/dsk) is searched.
573 */
574nvlist_t *
575zpool_find_import(int argc, char **argv)
576{
577	int i;
578	DIR *dirp;
579	struct dirent64 *dp;
580	char path[MAXPATHLEN];
581	struct stat64 statbuf;
582	nvlist_t *ret, *config;
583	static char *default_dir = "/dev/dsk";
584	int fd;
585	pool_list_t pools = { 0 };
586
587	if (argc == 0) {
588		argc = 1;
589		argv = &default_dir;
590	}
591
592	/*
593	 * Go through and read the label configuration information from every
594	 * possible device, organizing the information according to pool GUID
595	 * and toplevel GUID.
596	 */
597	for (i = 0; i < argc; i++) {
598		if (argv[i][0] != '/') {
599			zfs_error(dgettext(TEXT_DOMAIN,
600			    "cannot open '%s': must be an absolute path"),
601			    argv[i]);
602			return (NULL);
603		}
604
605		if ((dirp = opendir(argv[i])) == NULL) {
606			zfs_error(dgettext(TEXT_DOMAIN,
607			    "cannot open '%s': %s"), argv[i],
608			    strerror(errno));
609			return (NULL);
610		}
611
612		/*
613		 * This is not MT-safe, but we have no MT consumers of libzfs
614		 */
615		while ((dp = readdir64(dirp)) != NULL) {
616
617			(void) snprintf(path, sizeof (path), "%s/%s",
618			    argv[i], dp->d_name);
619
620			if (stat64(path, &statbuf) != 0)
621				continue;
622
623			/*
624			 * Ignore directories (which includes "." and "..").
625			 */
626			if (S_ISDIR(statbuf.st_mode))
627				continue;
628
629			if ((fd = open64(path, O_RDONLY)) < 0)
630				continue;
631
632			config = zpool_read_label(fd);
633
634			(void) close(fd);
635
636			if (config != NULL)
637				add_config(&pools, path, config);
638		}
639	}
640
641	ret = get_configs(&pools);
642
643	return (ret);
644}
645
646int
647find_guid(nvlist_t *nv, uint64_t guid)
648{
649	uint64_t tmp;
650	nvlist_t **child;
651	uint_t c, children;
652
653	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &tmp) == 0);
654	if (tmp == guid)
655		return (TRUE);
656
657	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
658	    &child, &children) == 0) {
659		for (c = 0; c < children; c++)
660			if (find_guid(child[c], guid))
661				return (TRUE);
662	}
663
664	return (FALSE);
665}
666
667/*
668 * Determines if the pool is in use.  If so, it returns TRUE and the state of
669 * the pool as well as the name of the pool.  Both strings are allocated and
670 * must be freed by the caller.
671 */
672int
673zpool_in_use(int fd, char **statestr, char **namestr)
674{
675	nvlist_t *config;
676	uint64_t state;
677	char *name;
678	int ret;
679	zfs_cmd_t zc = { 0 };
680	uint64_t guid, vdev_guid;
681	zpool_handle_t *zhp;
682	nvlist_t *pool_config;
683
684	if ((config = zpool_read_label(fd)) == NULL)
685		return (FALSE);
686
687	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
688	    &name) == 0);
689	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
690	    &state) == 0);
691	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
692	    &guid) == 0);
693	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
694	    &vdev_guid) == 0);
695
696	switch (state) {
697	case POOL_STATE_EXPORTED:
698		*statestr = zfs_strdup(dgettext(TEXT_DOMAIN, "exported"));
699		*namestr = zfs_strdup(name);
700		ret = TRUE;
701		break;
702
703	case POOL_STATE_ACTIVE:
704		/*
705		 * For an active pool, we have to determine if it's really part
706		 * of an active pool (in which case the pool will exist and the
707		 * guid will be the same), or whether it's part of an active
708		 * pool that was disconnected without being explicitly exported.
709		 *
710		 * We use the direct ioctl() first to avoid triggering an error
711		 * message if the pool cannot be opened.
712		 */
713		(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
714		if (ioctl(zfs_fd, ZFS_IOC_POOL_GUID, &zc) == 0 &&
715		    guid == zc.zc_pool_guid) {
716			/*
717			 * Because the device may have been removed while
718			 * offlined, we only report it as active if the vdev is
719			 * still present in the config.  Otherwise, pretend like
720			 * it's not in use.
721			 */
722			if ((zhp = zpool_open_canfail(name)) != NULL &&
723			    (pool_config = zpool_get_config(zhp)) != NULL) {
724				nvlist_t *nvroot;
725
726				verify(nvlist_lookup_nvlist(pool_config,
727				    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
728				if (find_guid(nvroot, vdev_guid)) {
729					*statestr = zfs_strdup(
730					    dgettext(TEXT_DOMAIN, "active"));
731					*namestr = zfs_strdup(name);
732					ret = TRUE;
733				} else {
734					ret = FALSE;
735				}
736			} else {
737				ret = FALSE;
738			}
739		} else {
740			*statestr = zfs_strdup(dgettext(TEXT_DOMAIN,
741			    "potentially active"));
742			*namestr = zfs_strdup(name);
743			ret = TRUE;
744		}
745		break;
746
747	default:
748		ret = FALSE;
749	}
750
751	nvlist_free(config);
752	return (ret);
753}
754