1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
22fa9e4066Sahrens /*
233f9d6ad7SLin Ling  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24c4ecba8aSPaul Dagnelie  * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
25c1d5c2a4SKody Kantor  * Copyright 2019 Joyent, Inc.
266401734dSWill Andrews  * Copyright 2016 Nexenta Systems, Inc.
2788f61deeSIgor Kozhukhov  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
281702cce7SAlek Pinchuk  * Copyright (c) 2017 Datto Inc.
29663207adSDon Brady  * Copyright (c) 2017, Intel Corporation.
30fa9e4066Sahrens  */
32fa9e4066Sahrens #include <ctype.h>
33fa9e4066Sahrens #include <errno.h>
34fa9e4066Sahrens #include <devid.h>
35fa9e4066Sahrens #include <fcntl.h>
36fa9e4066Sahrens #include <libintl.h>
37fa9e4066Sahrens #include <stdio.h>
38fa9e4066Sahrens #include <stdlib.h>
39f3861e1aSahl #include <strings.h>
40fa9e4066Sahrens #include <unistd.h>
414445fffbSMatthew Ahrens #include <libgen.h>
428488aeb5Staylor #include <sys/efi_partition.h>
438488aeb5Staylor #include <sys/vtoc.h>
44fa9e4066Sahrens #include <sys/zfs_ioctl.h>
45573ca77eSGeorge Wilson #include <dlfcn.h>
46d8ab6e12SDon Brady #include <libzutil.h>
48fa9e4066Sahrens #include "zfs_namecheck.h"
49b1b8ab34Slling #include "zfs_prop.h"
50fa9e4066Sahrens #include "libzfs_impl.h"
51468c413aSTim Haley #include "zfs_comutil.h"
52ad135b5dSChristopher Siden #include "zfeature_common.h"
547855d95bSToomas Soome static int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *);
552ba5f978SAlan Somers static boolean_t zpool_vdev_is_interior(const char *name);
57573ca77eSGeorge Wilson #define	BACKUP_SLICE	"s2"
58573ca77eSGeorge Wilson 
59f9af39baSGeorge Wilson typedef struct prop_flags {
60f9af39baSGeorge Wilson 	int create:1;	/* Validate property on creation */
61f9af39baSGeorge Wilson 	int import:1;	/* Validate property on import */
62f9af39baSGeorge Wilson } prop_flags_t;
63f9af39baSGeorge Wilson 
64990b4856Slling /*
65990b4856Slling  * ====================================================================
66990b4856Slling  *   zpool property functions
67990b4856Slling  * ====================================================================
68990b4856Slling  */
70990b4856Slling static int
zpool_get_all_props(zpool_handle_t * zhp)71990b4856Slling zpool_get_all_props(zpool_handle_t *zhp)
72990b4856Slling {
73990b4856Slling 	zfs_cmd_t zc = { 0 };
74990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
76990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
78990b4856Slling 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
79990b4856Slling 		return (-1);
81990b4856Slling 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
82990b4856Slling 		if (errno == ENOMEM) {
83990b4856Slling 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
84990b4856Slling 				zcmd_free_nvlists(&zc);
85990b4856Slling 				return (-1);
86990b4856Slling 			}
87990b4856Slling 		} else {
88990b4856Slling 			zcmd_free_nvlists(&zc);
89990b4856Slling 			return (-1);
90990b4856Slling 		}
91990b4856Slling 	}
93990b4856Slling 	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
94990b4856Slling 		zcmd_free_nvlists(&zc);
95990b4856Slling 		return (-1);
96990b4856Slling 	}
98990b4856Slling 	zcmd_free_nvlists(&zc);
100990b4856Slling 	return (0);
101990b4856Slling }
103990b4856Slling static int
zpool_props_refresh(zpool_handle_t * zhp)104990b4856Slling zpool_props_refresh(zpool_handle_t *zhp)
105990b4856Slling {
106990b4856Slling 	nvlist_t *old_props;
108990b4856Slling 	old_props = zhp->zpool_props;
110990b4856Slling 	if (zpool_get_all_props(zhp) != 0)
111990b4856Slling 		return (-1);
113990b4856Slling 	nvlist_free(old_props);
114990b4856Slling 	return (0);
115990b4856Slling }
117990b4856Slling static char *
zpool_get_prop_string(zpool_handle_t * zhp,zpool_prop_t prop,zprop_source_t * src)118990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
119990b4856Slling     zprop_source_t *src)
120990b4856Slling {
121990b4856Slling 	nvlist_t *nv, *nvl;
122990b4856Slling 	uint64_t ival;
123990b4856Slling 	char *value;
124990b4856Slling 	zprop_source_t source;
126990b4856Slling 	nvl = zhp->zpool_props;
127990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
128990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
129990b4856Slling 		source = ival;
130990b4856Slling 		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
131990b4856Slling 	} else {
132990b4856Slling 		source = ZPROP_SRC_DEFAULT;
133990b4856Slling 		if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
134990b4856Slling 			value = "-";
135990b4856Slling 	}
137990b4856Slling 	if (src)
138990b4856Slling 		*src = source;
140990b4856Slling 	return (value);
141990b4856Slling }
143990b4856Slling uint64_t
zpool_get_prop_int(zpool_handle_t * zhp,zpool_prop_t prop,zprop_source_t * src)144990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
145990b4856Slling {
146990b4856Slling 	nvlist_t *nv, *nvl;
147990b4856Slling 	uint64_t value;
148990b4856Slling 	zprop_source_t source;
150b87f3af3Sperrin 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
151b87f3af3Sperrin 		/*
152b87f3af3Sperrin 		 * zpool_get_all_props() has most likely failed because
153b87f3af3Sperrin 		 * the pool is faulted, but if all we need is the top level
154b87f3af3Sperrin 		 * vdev's guid then get it from the zhp config nvlist.
155b87f3af3Sperrin 		 */
156b87f3af3Sperrin 		if ((prop == ZPOOL_PROP_GUID) &&
157b87f3af3Sperrin 		    (nvlist_lookup_nvlist(zhp->zpool_config,
158b87f3af3Sperrin 		    ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
159b87f3af3Sperrin 		    (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
160b87f3af3Sperrin 		    == 0)) {
161b87f3af3Sperrin 			return (value);
162b87f3af3Sperrin 		}
163990b4856Slling 		return (zpool_prop_default_numeric(prop));
164b87f3af3Sperrin 	}
166990b4856Slling 	nvl = zhp->zpool_props;
167990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
168990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
169990b4856Slling 		source = value;
170990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
171990b4856Slling 	} else {
172990b4856Slling 		source = ZPROP_SRC_DEFAULT;
173990b4856Slling 		value = zpool_prop_default_numeric(prop);
174990b4856Slling 	}
176990b4856Slling 	if (src)
177990b4856Slling 		*src = source;
179990b4856Slling 	return (value);
180990b4856Slling }
182990b4856Slling /*
183990b4856Slling  * Map VDEV STATE to printed strings.
184990b4856Slling  */
1856401734dSWill Andrews const char *
zpool_state_to_name(vdev_state_t state,vdev_aux_t aux)186990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
187990b4856Slling {
188990b4856Slling 	switch (state) {
189990b4856Slling 	case VDEV_STATE_CLOSED:
190990b4856Slling 	case VDEV_STATE_OFFLINE:
191990b4856Slling 		return (gettext("OFFLINE"));
192990b4856Slling 	case VDEV_STATE_REMOVED:
193990b4856Slling 		return (gettext("REMOVED"));
194990b4856Slling 	case VDEV_STATE_CANT_OPEN:
195b87f3af3Sperrin 		if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
196990b4856Slling 			return (gettext("FAULTED"));
1971195e687SMark J Musante 		else if (aux == VDEV_AUX_SPLIT_POOL)
1981195e687SMark J Musante 			return (gettext("SPLIT"));
199990b4856Slling 		else
200990b4856Slling 			return (gettext("UNAVAIL"));
201990b4856Slling 	case VDEV_STATE_FAULTED:
202990b4856Slling 		return (gettext("FAULTED"));
203990b4856Slling 	case VDEV_STATE_DEGRADED:
204990b4856Slling 		return (gettext("DEGRADED"));
205990b4856Slling 	case VDEV_STATE_HEALTHY:
206990b4856Slling 		return (gettext("ONLINE"));
20788f61deeSIgor Kozhukhov 
20888f61deeSIgor Kozhukhov 	default:
20988f61deeSIgor Kozhukhov 		break;
210990b4856Slling 	}
212990b4856Slling 	return (gettext("UNKNOWN"));
213990b4856Slling }
2156401734dSWill Andrews /*
2166401734dSWill Andrews  * Map POOL STATE to printed strings.
2176401734dSWill Andrews  */
2186401734dSWill Andrews const char *
zpool_pool_state_to_name(pool_state_t state)2196401734dSWill Andrews zpool_pool_state_to_name(pool_state_t state)
2206401734dSWill Andrews {
2216401734dSWill Andrews 	switch (state) {
2226401734dSWill Andrews 	case POOL_STATE_ACTIVE:
2236401734dSWill Andrews 		return (gettext("ACTIVE"));
2246401734dSWill Andrews 	case POOL_STATE_EXPORTED:
2256401734dSWill Andrews 		return (gettext("EXPORTED"));
2266401734dSWill Andrews 	case POOL_STATE_DESTROYED:
2276401734dSWill Andrews 		return (gettext("DESTROYED"));
2286401734dSWill Andrews 	case POOL_STATE_SPARE:
2296401734dSWill Andrews 		return (gettext("SPARE"));
2306401734dSWill Andrews 	case POOL_STATE_L2CACHE:
2316401734dSWill Andrews 		return (gettext("L2CACHE"));
2326401734dSWill Andrews 	case POOL_STATE_UNINITIALIZED:
2336401734dSWill Andrews 		return (gettext("UNINITIALIZED"));
2346401734dSWill Andrews 	case POOL_STATE_UNAVAIL:
2356401734dSWill Andrews 		return (gettext("UNAVAIL"));
2366401734dSWill Andrews 	case POOL_STATE_POTENTIALLY_ACTIVE:
2376401734dSWill Andrews 		return (gettext("POTENTIALLY_ACTIVE"));
2386401734dSWill Andrews 	}
2396401734dSWill Andrews 
2406401734dSWill Andrews 	return (gettext("UNKNOWN"));
2416401734dSWill Andrews }
2426401734dSWill Andrews 
243990b4856Slling /*
244990b4856Slling  * Get a zpool property value for 'prop' and return the value in
245990b4856Slling  * a pre-allocated buffer.
246990b4856Slling  */
247990b4856Slling int
zpool_get_prop(zpool_handle_t * zhp,zpool_prop_t prop,char * buf,size_t len,zprop_source_t * srctype,boolean_t literal)248990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
249c58b3526SAdam Stevko     zprop_source_t *srctype, boolean_t literal)
250990b4856Slling {
251990b4856Slling 	uint64_t intval;
252990b4856Slling 	const char *strval;
253990b4856Slling 	zprop_source_t src = ZPROP_SRC_NONE;
254990b4856Slling 	nvlist_t *nvroot;
255990b4856Slling 	vdev_stat_t *vs;
256990b4856Slling 	uint_t vsc;
258990b4856Slling 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
259379c004dSEric Schrock 		switch (prop) {
260379c004dSEric Schrock 		case ZPOOL_PROP_NAME:
261990b4856Slling 			(void) strlcpy(buf, zpool_get_name(zhp), len);
262379c004dSEric Schrock 			break;
263379c004dSEric Schrock 
264379c004dSEric Schrock 		case ZPOOL_PROP_HEALTH:
265990b4856Slling 			(void) strlcpy(buf, "FAULTED", len);
266379c004dSEric Schrock 			break;
267379c004dSEric Schrock 
268379c004dSEric Schrock 		case ZPOOL_PROP_GUID:
269379c004dSEric Schrock 			intval = zpool_get_prop_int(zhp, prop, &src);
270379c004dSEric Schrock 			(void) snprintf(buf, len, "%llu", intval);
271379c004dSEric Schrock 			break;
272379c004dSEric Schrock 
273379c004dSEric Schrock 		case ZPOOL_PROP_ALTROOT:
274379c004dSEric Schrock 		case ZPOOL_PROP_CACHEFILE:
2758704186eSDan McDonald 		case ZPOOL_PROP_COMMENT:
276379c004dSEric Schrock 			if (zhp->zpool_props != NULL ||
277379c004dSEric Schrock 			    zpool_get_all_props(zhp) == 0) {
278379c004dSEric Schrock 				(void) strlcpy(buf,
279379c004dSEric Schrock 				    zpool_get_prop_string(zhp, prop, &src),
280379c004dSEric Schrock 				    len);
281c58b3526SAdam Stevko 				break;
282379c004dSEric Schrock 			}
283379c004dSEric Schrock 			/* FALLTHROUGH */
284379c004dSEric Schrock 		default:
285990b4856Slling 			(void) strlcpy(buf, "-", len);
286379c004dSEric Schrock 			break;
287379c004dSEric Schrock 		}
288379c004dSEric Schrock 
289379c004dSEric Schrock 		if (srctype != NULL)
290379c004dSEric Schrock 			*srctype = src;
291990b4856Slling 		return (0);
292990b4856Slling 	}
294990b4856Slling 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
295990b4856Slling 	    prop != ZPOOL_PROP_NAME)
296990b4856Slling 		return (-1);
298990b4856Slling 	switch (zpool_prop_get_type(prop)) {
299990b4856Slling 	case PROP_TYPE_STRING:
300990b4856Slling 		(void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
301990b4856Slling 		    len);
302990b4856Slling 		break;
304990b4856Slling 	case PROP_TYPE_NUMBER:
305990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
307990b4856Slling 		switch (prop) {
308990b4856Slling 		case ZPOOL_PROP_SIZE:
309485bbbf5SGeorge Wilson 		case ZPOOL_PROP_ALLOCATED:
310485bbbf5SGeorge Wilson 		case ZPOOL_PROP_FREE:
311ad135b5dSChristopher Siden 		case ZPOOL_PROP_FREEING:
3127fd05ac4SMatthew Ahrens 		case ZPOOL_PROP_LEAKED:
3135711d393Sloli 		case ZPOOL_PROP_ASHIFT:
314c58b3526SAdam Stevko 			if (literal) {
315c58b3526SAdam Stevko 				(void) snprintf(buf, len, "%llu",
316c58b3526SAdam Stevko 				    (u_longlong_t)intval);
317c58b3526SAdam Stevko 			} else {
318c58b3526SAdam Stevko 				(void) zfs_nicenum(intval, buf, len);
319c58b3526SAdam Stevko 			}
320990b4856Slling 			break;
3217855d95bSToomas Soome 		case ZPOOL_PROP_BOOTSIZE:
3227a09f97bSGeorge Wilson 		case ZPOOL_PROP_EXPANDSZ:
32386714001SSerapheim Dimitropoulos 		case ZPOOL_PROP_CHECKPOINT:
3247a09f97bSGeorge Wilson 			if (intval == 0) {
3257a09f97bSGeorge Wilson 				(void) strlcpy(buf, "-", len);
3267a09f97bSGeorge Wilson 			} else if (literal) {
3277a09f97bSGeorge Wilson 				(void) snprintf(buf, len, "%llu",
3287a09f97bSGeorge Wilson 				    (u_longlong_t)intval);
3297a09f97bSGeorge Wilson 			} else {
3307a09f97bSGeorge Wilson 				(void) zfs_nicenum(intval, buf, len);
3317a09f97bSGeorge Wilson 			}
3327a09f97bSGeorge Wilson 			break;
333990b4856Slling 		case ZPOOL_PROP_CAPACITY:
334c58b3526SAdam Stevko 			if (literal) {
335c58b3526SAdam Stevko 				(void) snprintf(buf, len, "%llu",
336c58b3526SAdam Stevko 				    (u_longlong_t)intval);
337c58b3526SAdam Stevko 			} else {
338c58b3526SAdam Stevko 				(void) snprintf(buf, len, "%llu%%",
339c58b3526SAdam Stevko 				    (u_longlong_t)intval);
340c58b3526SAdam Stevko 			}
341990b4856Slling 			break;
3422e4c9986SGeorge Wilson 		case ZPOOL_PROP_FRAGMENTATION:
3432e4c9986SGeorge Wilson 			if (intval == UINT64_MAX) {
3442e4c9986SGeorge Wilson 				(void) strlcpy(buf, "-", len);
3453dfe8017SChrister Ekholm 			} else if (literal) {
3463dfe8017SChrister Ekholm 				(void) snprintf(buf, len, "%llu",
3473dfe8017SChrister Ekholm 				    (u_longlong_t)intval);
3482e4c9986SGeorge Wilson 			} else {
3492e4c9986SGeorge Wilson 				(void) snprintf(buf, len, "%llu%%",
3502e4c9986SGeorge Wilson 				    (u_longlong_t)intval);
3512e4c9986SGeorge Wilson 			}
3522e4c9986SGeorge Wilson 			break;
353b24ab676SJeff Bonwick 		case ZPOOL_PROP_DEDUPRATIO:
3543dfe8017SChrister Ekholm 			if (literal)
3553dfe8017SChrister Ekholm 				(void) snprintf(buf, len, "%llu.%02llu",
3563dfe8017SChrister Ekholm 				    (u_longlong_t)(intval / 100),
3573dfe8017SChrister Ekholm 				    (u_longlong_t)(intval % 100));
3583dfe8017SChrister Ekholm 			else
3593dfe8017SChrister Ekholm 				(void) snprintf(buf, len, "%llu.%02llux",
3603dfe8017SChrister Ekholm 				    (u_longlong_t)(intval / 100),
3613dfe8017SChrister Ekholm 				    (u_longlong_t)(intval % 100));
362b24ab676SJeff Bonwick 			break;
363990b4856Slling 		case ZPOOL_PROP_HEALTH:
364990b4856Slling 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
365990b4856Slling 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
366990b4856Slling 			verify(nvlist_lookup_uint64_array(nvroot,
3673f9d6ad7SLin Ling 			    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
3683f9d6ad7SLin Ling 			    == 0);
370990b4856Slling 			(void) strlcpy(buf, zpool_state_to_name(intval,
371990b4856Slling 			    vs->vs_aux), len);
372990b4856Slling 			break;
373ad135b5dSChristopher Siden 		case ZPOOL_PROP_VERSION:
374ad135b5dSChristopher Siden 			if (intval >= SPA_VERSION_FEATURES) {
375ad135b5dSChristopher Siden 				(void) snprintf(buf, len, "-");
376ad135b5dSChristopher Siden 				break;
377ad135b5dSChristopher Siden 			}
378ad135b5dSChristopher Siden 			/* FALLTHROUGH */
379990b4856Slling 		default:
380990b4856Slling 			(void) snprintf(buf, len, "%llu", intval);
381990b4856Slling 		}
382990b4856Slling 		break;
384990b4856Slling 	case PROP_TYPE_INDEX:
385990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
386990b4856Slling 		if (zpool_prop_index_to_string(prop, intval, &strval)
387990b4856Slling 		    != 0)
388990b4856Slling 			return (-1);
389990b4856Slling 		(void) strlcpy(buf, strval, len);
390990b4856Slling 		break;
392990b4856Slling 	default:
393990b4856Slling 		abort();
394990b4856Slling 	}
396990b4856Slling 	if (srctype)
397990b4856Slling 		*srctype = src;
399990b4856Slling 	return (0);
400990b4856Slling }
402990b4856Slling /*
403990b4856Slling  * Check if the bootfs name has the same pool name as it is set to.
404990b4856Slling  * Assuming bootfs is a valid dataset name.
405990b4856Slling  */
406990b4856Slling static boolean_t
bootfs_name_valid(const char * pool,const char * bootfs)407c4ecba8aSPaul Dagnelie bootfs_name_valid(const char *pool, const char *bootfs)
408990b4856Slling {
409990b4856Slling 	int len = strlen(pool);
410015f38bbSPaul Dagnelie 	if (bootfs[0] == '\0')
411015f38bbSPaul Dagnelie 		return (B_TRUE);
413fe3e2633SEric Taylor 	if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
414990b4856Slling 		return (B_FALSE);
416990b4856Slling 	if (strncmp(pool, bootfs, len) == 0 &&
417990b4856Slling 	    (bootfs[len] == '/' || bootfs[len] == '\0'))
418990b4856Slling 		return (B_TRUE);
420990b4856Slling 	return (B_FALSE);
421990b4856Slling }
4234263d13fSGeorge Wilson boolean_t
zpool_is_bootable(zpool_handle_t * zhp)4244263d13fSGeorge Wilson zpool_is_bootable(zpool_handle_t *zhp)
425b5b76fecSGeorge Wilson {
4269adfa60dSMatthew Ahrens 	char bootfs[ZFS_MAX_DATASET_NAME_LEN];
427b5b76fecSGeorge Wilson 
428b5b76fecSGeorge Wilson 	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
429c58b3526SAdam Stevko 	    sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
430b5b76fecSGeorge Wilson 	    sizeof (bootfs)) != 0);
431b5b76fecSGeorge Wilson }
432b5b76fecSGeorge Wilson 
433b5b76fecSGeorge Wilson 
434990b4856Slling /*
435990b4856Slling  * Given an nvlist of zpool properties to be set, validate that they are
436990b4856Slling  * correct, and parse any numeric properties (index, boolean, etc) if they are
437990b4856Slling  * specified as strings.
438990b4856Slling  */
439990b4856Slling static nvlist_t *
zpool_valid_proplist(libzfs_handle_t * hdl,const char * poolname,nvlist_t * props,uint64_t version,prop_flags_t flags,char * errbuf)4400a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
441f9af39baSGeorge Wilson     nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
442990b4856Slling {
443990b4856Slling 	nvpair_t *elem;
444990b4856Slling 	nvlist_t *retprops;
445990b4856Slling 	zpool_prop_t prop;
446990b4856Slling 	char *strval;
447990b4856Slling 	uint64_t intval;
4488704186eSDan McDonald 	char *slash, *check;
4492f8aaab3Seschrock 	struct stat64 statbuf;
45015e6edf1Sgw 	zpool_handle_t *zhp;
452990b4856Slling 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
453990b4856Slling 		(void) no_memory(hdl);
454990b4856Slling 		return (NULL);
455990b4856Slling 	}
457990b4856Slling 	elem = NULL;
458990b4856Slling 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
459990b4856Slling 		const char *propname = nvpair_name(elem);
461ad135b5dSChristopher Siden 		prop = zpool_name_to_prop(propname);
4624ae5f5f0SAlan Somers 		if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
463ad135b5dSChristopher Siden 			int err;
464ad135b5dSChristopher Siden 			char *fname = strchr(propname, '@') + 1;
465ad135b5dSChristopher Siden 
4662acef22dSMatthew Ahrens 			err = zfeature_lookup_name(fname, NULL);
467ad135b5dSChristopher Siden 			if (err != 0) {
468ad135b5dSChristopher Siden 				ASSERT3U(err, ==, ENOENT);
469ad135b5dSChristopher Siden 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4705711d393Sloli 				    "invalid feature '%s', '%s'"), fname,
4715711d393Sloli 				    propname);
472ad135b5dSChristopher Siden 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
473ad135b5dSChristopher Siden 				goto error;
474ad135b5dSChristopher Siden 			}
475ad135b5dSChristopher Siden 
476ad135b5dSChristopher Siden 			if (nvpair_type(elem) != DATA_TYPE_STRING) {
477ad135b5dSChristopher Siden 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
478ad135b5dSChristopher Siden 				    "'%s' must be a string"), propname);
479ad135b5dSChristopher Siden 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
480ad135b5dSChristopher Siden 				goto error;
481ad135b5dSChristopher Siden 			}
482ad135b5dSChristopher Siden 
483ad135b5dSChristopher Siden 			(void) nvpair_value_string(elem, &strval);
484f3434519SLOLi 			if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0 &&
485f3434519SLOLi 			    strcmp(strval, ZFS_FEATURE_DISABLED) != 0) {
486ad135b5dSChristopher Siden 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
487ad135b5dSChristopher Siden 				    "property '%s' can only be set to "
488f3434519SLOLi 				    "'enabled' or 'disabled'"), propname);
489ad135b5dSChristopher Siden 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
490ad135b5dSChristopher Siden 				goto error;
491ad135b5dSChristopher Siden 			}
492ad135b5dSChristopher Siden 
493ad135b5dSChristopher Siden 			if (nvlist_add_uint64(retprops, propname, 0) != 0) {
494ad135b5dSChristopher Siden 				(void) no_memory(hdl);
495ad135b5dSChristopher Siden 				goto error;
496ad135b5dSChristopher Siden 			}
497ad135b5dSChristopher Siden 			continue;
498ad135b5dSChristopher Siden 		}
499ad135b5dSChristopher Siden 
500990b4856Slling 		/*
501990b4856Slling 		 * Make sure this property is valid and applies to this type.
502990b4856Slling 		 */
5034ae5f5f0SAlan Somers 		if (prop == ZPOOL_PROP_INVAL) {
504990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
505990b4856Slling 			    "invalid property '%s'"), propname);
506990b4856Slling 			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
507990b4856Slling 			goto error;
508990b4856Slling 		}
510990b4856Slling 		if (zpool_prop_readonly(prop)) {
511990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
512990b4856Slling 			    "is readonly"), propname);
513990b4856Slling 			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
514990b4856Slling 			goto error;
515990b4856Slling 		}
517990b4856Slling 		if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
518990b4856Slling 		    &strval, &intval, errbuf) != 0)
519990b4856Slling 			goto error;
521990b4856Slling 		/*
522990b4856Slling 		 * Perform additional checking for specific properties.
523990b4856Slling 		 */
524990b4856Slling 		switch (prop) {
525990b4856Slling 		case ZPOOL_PROP_VERSION:
526ad135b5dSChristopher Siden 			if (intval < version ||
527ad135b5dSChristopher Siden 			    !SPA_VERSION_IS_SUPPORTED(intval)) {
528990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
529990b4856Slling 				    "property '%s' number %d is invalid."),
530990b4856Slling 				    propname, intval);
531990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
532990b4856Slling 				goto error;
533990b4856Slling 			}
534990b4856Slling 			break;
5367855d95bSToomas Soome 		case ZPOOL_PROP_BOOTSIZE:
5377855d95bSToomas Soome 			if (!flags.create) {
5387855d95bSToomas Soome 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5397855d95bSToomas Soome 				    "property '%s' can only be set during pool "
5407855d95bSToomas Soome 				    "creation"), propname);
5417855d95bSToomas Soome 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
5427855d95bSToomas Soome 				goto error;
5437855d95bSToomas Soome 			}
5447855d95bSToomas Soome 			break;
5457855d95bSToomas Soome 
5465711d393Sloli 		case ZPOOL_PROP_ASHIFT:
5475711d393Sloli 			if (intval != 0 &&
5485711d393Sloli 			    (intval < ASHIFT_MIN || intval > ASHIFT_MAX)) {
5495711d393Sloli 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5505711d393Sloli 				    "invalid '%s=%d' property: only values "
5515711d393Sloli 				    "between %" PRId32 " and %" PRId32 " "
5525711d393Sloli 				    "are allowed.\n"),
5535711d393Sloli 				    propname, intval, ASHIFT_MIN, ASHIFT_MAX);
5545711d393Sloli 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
5555711d393Sloli 				goto error;
5565711d393Sloli 			}
5575711d393Sloli 			break;
559990b4856Slling 		case ZPOOL_PROP_BOOTFS:
560f9af39baSGeorge Wilson 			if (flags.create || flags.import) {
561990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
562990b4856Slling 				    "property '%s' cannot be set at creation "
563990b4856Slling 				    "or import time"), propname);
564990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
565990b4856Slling 				goto error;
566990b4856Slling 			}
568990b4856Slling 			if (version < SPA_VERSION_BOOTFS) {
569990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
570990b4856Slling 				    "pool must be upgraded to support "
571990b4856Slling 				    "'%s' property"), propname);
572990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
573990b4856Slling 				goto error;
574990b4856Slling 			}
576990b4856Slling 			/*
577990b4856Slling 			 * bootfs property value has to be a dataset name and
578990b4856Slling 			 * the dataset has to be in the same pool as it sets to.
579990b4856Slling 			 */
580015f38bbSPaul Dagnelie 			if (!bootfs_name_valid(poolname, strval)) {
581990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
582990b4856Slling 				    "is an invalid name"), strval);
583990b4856Slling 				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
584990b4856Slling 				goto error;
585990b4856Slling 			}
58715e6edf1Sgw 			if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
58815e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
58915e6edf1Sgw 				    "could not open pool '%s'"), poolname);
59015e6edf1Sgw 				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
59115e6edf1Sgw 				goto error;
59215e6edf1Sgw 			}
59315e6edf1Sgw 			zpool_close(zhp);
594990b4856Slling 			break;
5962f8aaab3Seschrock 		case ZPOOL_PROP_ALTROOT:
597f9af39baSGeorge Wilson 			if (!flags.create && !flags.import) {
598990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
599990b4856Slling 				    "property '%s' can only be set during pool "
600990b4856Slling 				    "creation or import"), propname);
601990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
602990b4856Slling 				goto error;
603990b4856Slling 			}
6052f8aaab3Seschrock 			if (strval[0] != '/') {
606990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6072f8aaab3Seschrock 				    "bad alternate root '%s'"), strval);
6082f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
609990b4856Slling 				goto error;
610990b4856Slling 			}
6112f8aaab3Seschrock 			break;
6132f8aaab3Seschrock 		case ZPOOL_PROP_CACHEFILE:
6142f8aaab3Seschrock 			if (strval[0] == '\0')
6152f8aaab3Seschrock 				break;
6172f8aaab3Seschrock 			if (strcmp(strval, "none") == 0)
6182f8aaab3Seschrock 				break;
620990b4856Slling 			if (strval[0] != '/') {
621990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6222f8aaab3Seschrock 				    "property '%s' must be empty, an "
6232f8aaab3Seschrock 				    "absolute path, or 'none'"), propname);
624990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
625990b4856Slling 				goto error;
626990b4856Slling 			}
6282f8aaab3Seschrock 			slash = strrchr(strval, '/');
6302f8aaab3Seschrock 			if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
6312f8aaab3Seschrock 			    strcmp(slash, "/..") == 0) {
6322f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6332f8aaab3Seschrock 				    "'%s' is not a valid file"), strval);
6342f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
6352f8aaab3Seschrock 				goto error;
6362f8aaab3Seschrock 			}
6382f8aaab3Seschrock 			*slash = '\0';
6402c32020fSeschrock 			if (