1fa9e406ahrens/*
2fa9e406ahrens * CDDL HEADER START
3fa9e406ahrens *
4fa9e406ahrens * The contents of this file are subject to the terms of the
5441d80alling * Common Development and Distribution License (the "License").
6441d80alling * You may not use this file except in compliance with the License.
7fa9e406ahrens *
8fa9e406ahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e406ahrens * or http://www.opensolaris.org/os/licensing.
10fa9e406ahrens * See the License for the specific language governing permissions
11fa9e406ahrens * and limitations under the License.
12fa9e406ahrens *
13fa9e406ahrens * When distributing Covered Code, include this CDDL HEADER in each
14fa9e406ahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e406ahrens * If applicable, add the following below this CDDL HEADER, with the
16fa9e406ahrens * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e406ahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e406ahrens *
19fa9e406ahrens * CDDL HEADER END
20fa9e406ahrens */
2199653d4eschrock
22fa9e406ahrens/*
233f9d6adLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
245cabbc6Prashanth Sreenivasa * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
25c1d5c2aKody Kantor * Copyright 2019 Joyent, Inc.
266401734Will Andrews * Copyright 2016 Nexenta Systems, Inc.
2788f61deIgor Kozhukhov * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
281702cceAlek Pinchuk * Copyright (c) 2017 Datto Inc.
29663207aDon Brady * Copyright (c) 2017, Intel Corporation.
30fa9e406ahrens */
31fa9e406ahrens
32fa9e406ahrens#include <ctype.h>
33fa9e406ahrens#include <errno.h>
34fa9e406ahrens#include <devid.h>
35fa9e406ahrens#include <fcntl.h>
36fa9e406ahrens#include <libintl.h>
37fa9e406ahrens#include <stdio.h>
38fa9e406ahrens#include <stdlib.h>
39f3861e1ahl#include <strings.h>
40fa9e406ahrens#include <unistd.h>
414445fffMatthew Ahrens#include <libgen.h>
428488aebtaylor#include <sys/efi_partition.h>
438488aebtaylor#include <sys/vtoc.h>
44fa9e406ahrens#include <sys/zfs_ioctl.h>
45573ca77George Wilson#include <dlfcn.h>
46d8ab6e1Don Brady#include <libzutil.h>
47fa9e406ahrens
48fa9e406ahrens#include "zfs_namecheck.h"
49b1b8ab3lling#include "zfs_prop.h"
50fa9e406ahrens#include "libzfs_impl.h"
51468c413Tim Haley#include "zfs_comutil.h"
52ad135b5Christopher Siden#include "zfeature_common.h"
53fa9e406ahrens
547855d95Toomas Soomestatic int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *);
552ba5f97Alan Somersstatic boolean_t zpool_vdev_is_interior(const char *name);
56990b485lling
57573ca77George Wilson#define	BACKUP_SLICE	"s2"
58573ca77George Wilson
59f9af39bGeorge Wilsontypedef struct prop_flags {
60f9af39bGeorge Wilson	int create:1;	/* Validate property on creation */
61f9af39bGeorge Wilson	int import:1;	/* Validate property on import */
62f9af39bGeorge Wilson} prop_flags_t;
63f9af39bGeorge Wilson
64990b485lling/*
65990b485lling * ====================================================================
66990b485lling *   zpool property functions
67990b485lling * ====================================================================
68990b485lling */
69990b485lling
70990b485llingstatic int
71990b485llingzpool_get_all_props(zpool_handle_t *zhp)
72990b485lling{
73990b485lling	zfs_cmd_t zc = { 0 };
74990b485lling	libzfs_handle_t *hdl = zhp->zpool_hdl;
75990b485lling
76990b485lling	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
77990b485lling
78990b485lling	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
79990b485lling		return (-1);
80990b485lling
81990b485lling	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
82990b485lling		if (errno == ENOMEM) {
83990b485lling			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
84990b485lling				zcmd_free_nvlists(&zc);
85990b485lling				return (-1);
86990b485lling			}
87990b485lling		} else {
88990b485lling			zcmd_free_nvlists(&zc);
89990b485lling			return (-1);
90990b485lling		}
91990b485lling	}
92990b485lling
93990b485lling	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
94990b485lling		zcmd_free_nvlists(&zc);
95990b485lling		return (-1);
96990b485lling	}
97990b485lling
98990b485lling	zcmd_free_nvlists(&zc);
99990b485lling
100990b485lling	return (0);
101990b485lling}
102990b485lling
103990b485llingstatic int
104990b485llingzpool_props_refresh(zpool_handle_t *zhp)
105990b485lling{
106990b485lling	nvlist_t *old_props;
107990b485lling
108990b485lling	old_props = zhp->zpool_props;
109990b485lling
110990b485lling	if (zpool_get_all_props(zhp) != 0)
111990b485lling		return (-1);
112990b485lling
113990b485lling	nvlist_free(old_props);
114990b485lling	return (0);
115990b485lling}
116990b485lling
117990b485llingstatic char *
118990b485llingzpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
119990b485lling    zprop_source_t *src)
120990b485lling{
121990b485lling	nvlist_t *nv, *nvl;
122990b485lling	uint64_t ival;
123990b485lling	char *value;
124990b485lling	zprop_source_t source;
125990b485lling
126990b485lling	nvl = zhp->zpool_props;
127990b485lling	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
128990b485lling		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
129990b485lling		source = ival;
130990b485lling		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
131990b485lling	} else {
132990b485lling		source = ZPROP_SRC_DEFAULT;
133990b485lling		if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
134990b485lling			value = "-";
135990b485lling	}
136990b485lling
137990b485lling	if (src)
138990b485lling		*src = source;
139990b485lling
140990b485lling	return (value);
141990b485lling}
142990b485lling
143990b485llinguint64_t
144990b485llingzpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
145990b485lling{
146990b485lling	nvlist_t *nv, *nvl;
147990b485lling	uint64_t value;
148990b485lling	zprop_source_t source;
149990b485lling
150b87f3afperrin	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
151b87f3afperrin		/*
152b87f3afperrin		 * zpool_get_all_props() has most likely failed because
153b87f3afperrin		 * the pool is faulted, but if all we need is the top level
154b87f3afperrin		 * vdev's guid then get it from the zhp config nvlist.
155b87f3afperrin		 */
156b87f3afperrin		if ((prop == ZPOOL_PROP_GUID) &&
157b87f3afperrin		    (nvlist_lookup_nvlist(zhp->zpool_config,
158b87f3afperrin		    ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
159b87f3afperrin		    (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
160b87f3afperrin		    == 0)) {
161b87f3afperrin			return (value);
162b87f3afperrin		}
163990b485lling		return (zpool_prop_default_numeric(prop));
164b87f3afperrin	}
165990b485lling
166990b485lling	nvl = zhp->zpool_props;
167990b485lling	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
168990b485lling		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
169990b485lling		source = value;
170990b485lling		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
171990b485lling	} else {
172990b485lling		source = ZPROP_SRC_DEFAULT;
173990b485lling		value = zpool_prop_default_numeric(prop);
174990b485lling	}
175990b485lling
176990b485lling	if (src)
177990b485lling		*src = source;
178990b485lling
179990b485lling	return (value);
180990b485lling}
181990b485lling
182990b485lling/*
183990b485lling * Map VDEV STATE to printed strings.
184990b485lling */
1856401734Will Andrewsconst char *
186990b485llingzpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
187990b485lling{
188990b485lling	switch (state) {
189990b485lling	case VDEV_STATE_CLOSED:
190990b485lling	case VDEV_STATE_OFFLINE:
191990b485lling		return (gettext("OFFLINE"));
192990b485lling	case VDEV_STATE_REMOVED:
193990b485lling		return (gettext("REMOVED"));
194990b485lling	case VDEV_STATE_CANT_OPEN:
195b87f3afperrin		if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
196990b485lling			return (gettext("FAULTED"));
1971195e68Mark J Musante		else if (aux == VDEV_AUX_SPLIT_POOL)
1981195e68Mark J Musante			return (gettext("SPLIT"));
199990b485lling		else
200990b485lling			return (gettext("UNAVAIL"));
201990b485lling	case VDEV_STATE_FAULTED:
202990b485lling		return (gettext("FAULTED"));
203990b485lling	case VDEV_STATE_DEGRADED:
204990b485lling		return (gettext("DEGRADED"));
205990b485lling	case VDEV_STATE_HEALTHY:
206990b485lling		return (gettext("ONLINE"));
20788f61deIgor Kozhukhov
20888f61deIgor Kozhukhov	default:
20988f61deIgor Kozhukhov		break;
210990b485lling	}
211990b485lling
212990b485lling	return (gettext("UNKNOWN"));
213990b485lling}
214990b485lling
215990b485lling/*
2166401734Will Andrews * Map POOL STATE to printed strings.
2176401734Will Andrews */
2186401734Will Andrewsconst char *
2196401734Will Andrewszpool_pool_state_to_name(pool_state_t state)
2206401734Will Andrews{
2216401734Will Andrews	switch (state) {
2226401734Will Andrews	case POOL_STATE_ACTIVE:
2236401734Will Andrews		return (gettext("ACTIVE"));
2246401734Will Andrews	case POOL_STATE_EXPORTED:
2256401734Will Andrews		return (gettext("EXPORTED"));
2266401734Will Andrews	case POOL_STATE_DESTROYED:
2276401734Will Andrews		return (gettext("DESTROYED"));
2286401734Will Andrews	case POOL_STATE_SPARE:
2296401734Will Andrews		return (gettext("SPARE"));
2306401734Will Andrews	case POOL_STATE_L2CACHE:
2316401734Will Andrews		return (gettext("L2CACHE"));
2326401734Will Andrews	case POOL_STATE_UNINITIALIZED:
2336401734Will Andrews		return (gettext("UNINITIALIZED"));
2346401734Will Andrews	case POOL_STATE_UNAVAIL:
2356401734Will Andrews		return (gettext("UNAVAIL"));
2366401734Will Andrews	case POOL_STATE_POTENTIALLY_ACTIVE:
2376401734Will Andrews		return (gettext("POTENTIALLY_ACTIVE"));
2386401734Will Andrews	}
2396401734Will Andrews
2406401734Will Andrews	return (gettext("UNKNOWN"));
2416401734Will Andrews}
2426401734Will Andrews
2436401734Will Andrews/*
244990b485lling * Get a zpool property value for 'prop' and return the value in
245990b485lling * a pre-allocated buffer.
246990b485lling */
247990b485llingint
248990b485llingzpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
249c58b352Adam Stevko    zprop_source_t *srctype, boolean_t literal)
250990b485lling{
251990b485lling	uint64_t intval;
252990b485lling	const char *strval;
253990b485lling	zprop_source_t src = ZPROP_SRC_NONE;
254990b485lling	nvlist_t *nvroot;
255990b485lling	vdev_stat_t *vs;
256990b485lling	uint_t vsc;
257990b485lling
258990b485lling	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
259379c004Eric Schrock		switch (prop) {
260379c004Eric Schrock		case ZPOOL_PROP_NAME:
261990b485lling			(void) strlcpy(buf, zpool_get_name(zhp), len);
262379c004Eric Schrock			break;
263379c004Eric Schrock
264379c004Eric Schrock		case ZPOOL_PROP_HEALTH:
265990b485lling			(void) strlcpy(buf, "FAULTED", len);
266379c004Eric Schrock			break;
267379c004Eric Schrock
268379c004Eric Schrock		case ZPOOL_PROP_GUID:
269379c004Eric Schrock			intval = zpool_get_prop_int(zhp, prop, &src);
270379c004Eric Schrock			(void) snprintf(buf, len, "%llu", intval);
271379c004Eric Schrock			break;
272379c004Eric Schrock
273379c004Eric Schrock		case ZPOOL_PROP_ALTROOT:
274379c004Eric Schrock		case ZPOOL_PROP_CACHEFILE:
2758704186Dan McDonald		case ZPOOL_PROP_COMMENT:
276379c004Eric Schrock			if (zhp->zpool_props != NULL ||
277379c004Eric Schrock			    zpool_get_all_props(zhp) == 0) {
278379c004Eric Schrock				(void) strlcpy(buf,
279379c004Eric Schrock				    zpool_get_prop_string(zhp, prop, &src),
280379c004Eric Schrock				    len);
281c58b352Adam Stevko				break;
282379c004Eric Schrock			}
283379c004Eric Schrock			/* FALLTHROUGH */
284379c004Eric Schrock		default:
285990b485lling			(void) strlcpy(buf, "-", len);
286379c004Eric Schrock			break;
287379c004Eric Schrock		}
288379c004Eric Schrock
289379c004Eric Schrock		if (srctype != NULL)
290379c004Eric Schrock			*srctype = src;
291990b485lling		return (0);
292990b485lling	}
293990b485lling
294990b485lling	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
295990b485lling	    prop != ZPOOL_PROP_NAME)
296990b485lling		return (-1);
297990b485lling
298990b485lling	switch (zpool_prop_get_type(prop)) {
299990b485lling	case PROP_TYPE_STRING:
300990b485lling		(void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
301990b485lling		    len);
302990b485lling		break;
303990b485lling
304990b485lling	case PROP_TYPE_NUMBER:
305990b485lling		intval = zpool_get_prop_int(zhp, prop, &src);
306990b485lling
307990b485lling		switch (prop) {
308990b485lling		case ZPOOL_PROP_SIZE:
309485bbbfGeorge Wilson		case ZPOOL_PROP_ALLOCATED:
310485bbbfGeorge Wilson		case ZPOOL_PROP_FREE:
311ad135b5Christopher Siden		case ZPOOL_PROP_FREEING:
3127fd05acMatthew Ahrens		case ZPOOL_PROP_LEAKED:
3135711d39loli		case ZPOOL_PROP_ASHIFT:
314c58b352Adam Stevko			if (literal) {
315c58b352Adam Stevko				(void) snprintf(buf, len, "%llu",
316c58b352Adam Stevko				    (u_longlong_t)intval);
317c58b352Adam Stevko			} else {
318c58b352Adam Stevko				(void) zfs_nicenum(intval, buf, len);
319c58b352Adam Stevko			}
320990b485lling			break;
3217855d95Toomas Soome		case ZPOOL_PROP_BOOTSIZE:
3227a09f97George Wilson		case ZPOOL_PROP_EXPANDSZ:
3238671400Serapheim Dimitropoulos		case ZPOOL_PROP_CHECKPOINT:
3247a09f97George Wilson			if (intval == 0) {
3257a09f97George Wilson				(void) strlcpy(buf, "-", len);
3267a09f97George Wilson			} else if (literal) {
3277a09f97George Wilson				(void) snprintf(buf, len, "%llu",
3287a09f97George Wilson				    (u_longlong_t)intval);
3297a09f97George Wilson			} else {
3307a09f97George Wilson				(void) zfs_nicenum(intval, buf, len);
3317a09f97George Wilson			}
3327a09f97George Wilson			break;
333990b485lling		case ZPOOL_PROP_CAPACITY:
334c58b352Adam Stevko			if (literal) {
335c58b352Adam Stevko				(void) snprintf(buf, len, "%llu",
336c58b352Adam Stevko				    (u_longlong_t)intval);
337c58b352Adam Stevko			} else {
338c58b352Adam Stevko				(void) snprintf(buf, len, "%llu%%",
339c58b352Adam Stevko				    (u_longlong_t)intval);
340c58b352Adam Stevko			}
341990b485lling			break;
3422e4c998George Wilson		case ZPOOL_PROP_FRAGMENTATION:
3432e4c998George Wilson			if (intval == UINT64_MAX) {
3442e4c998George Wilson				(void) strlcpy(buf, "-", len);
3452e4c998George Wilson			} else {
3462e4c998George Wilson				(void) snprintf(buf, len, "%llu%%",
3472e4c998George Wilson				    (u_longlong_t)intval);
3482e4c998George Wilson			}
3492e4c998George Wilson			break;
350b24ab67Jeff Bonwick		case ZPOOL_PROP_DEDUPRATIO:
351b24ab67Jeff Bonwick			(void) snprintf(buf, len, "%llu.%02llux",
352b24ab67Jeff Bonwick			    (u_longlong_t)(intval / 100),
353b24ab67Jeff Bonwick			    (u_longlong_t)(intval % 100));
354b24ab67Jeff Bonwick			break;
355990b485lling		case ZPOOL_PROP_HEALTH:
356990b485lling			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
357990b485lling			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
358990b485lling			verify(nvlist_lookup_uint64_array(nvroot,
3593f9d6adLin Ling			    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
3603f9d6adLin Ling			    == 0);
361990b485lling
362990b485lling			(void) strlcpy(buf, zpool_state_to_name(intval,
363990b485lling			    vs->vs_aux), len);
364990b485lling			break;
365ad135b5Christopher Siden		case ZPOOL_PROP_VERSION:
366ad135b5Christopher Siden			if (intval >= SPA_VERSION_FEATURES) {
367ad135b5Christopher Siden				(void) snprintf(buf, len, "-");
368ad135b5Christopher Siden				break;
369ad135b5Christopher Siden			}
370ad135b5Christopher Siden			/* FALLTHROUGH */
371990b485lling		default:
372990b485lling			(void) snprintf(buf, len, "%llu", intval);
373990b485lling		}
374990b485lling		break;
375990b485lling
376990b485lling	case PROP_TYPE_INDEX:
377990b485lling		intval = zpool_get_prop_int(zhp, prop, &src);
378990b485lling		if (zpool_prop_index_to_string(prop, intval, &strval)
379990b485lling		    != 0)
380990b485lling			return (-1);
381990b485lling		(void) strlcpy(buf, strval, len);
382990b485lling		break;
383990b485lling
384990b485lling	default:
385990b485lling		abort();
386990b485lling	}
387990b485lling
388990b485lling	if (srctype)
389990b485lling		*srctype = src;
390990b485lling
391990b485lling	return (0);
392990b485lling}
393990b485lling
394990b485lling/*
395990b485lling * Check if the bootfs name has the same pool name as it is set to.
396990b485lling * Assuming bootfs is a valid dataset name.
397990b485lling */
398990b485llingstatic boolean_t
399990b485llingbootfs_name_valid(const char *pool, char *bootfs)
400990b485lling{
401990b485lling	int len = strlen(pool);
402015f38bPaul Dagnelie	if (bootfs[0] == '\0')
403015f38bPaul Dagnelie		return (B_TRUE);
404990b485lling
405fe3e263Eric Taylor	if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
406990b485lling		return (B_FALSE);
407990b485lling
408990b485lling	if (strncmp(pool, bootfs, len) == 0 &&
409990b485lling	    (bootfs[len] == '/' || bootfs[len] == '\0'))
410990b485lling		return (B_TRUE);
411990b485lling
412990b485lling	return (B_FALSE);
413990b485lling}
414990b485lling
4154263d13George Wilsonboolean_t
4164263d13George Wilsonzpool_is_bootable(zpool_handle_t *zhp)
417b5b76feGeorge Wilson{
4189adfa60Matthew Ahrens	char bootfs[ZFS_MAX_DATASET_NAME_LEN];
419b5b76feGeorge Wilson
420b5b76feGeorge Wilson	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
421c58b352Adam Stevko	    sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
422b5b76feGeorge Wilson	    sizeof (bootfs)) != 0);
423b5b76feGeorge Wilson}
424b5b76feGeorge Wilson
425b5b76feGeorge Wilson
42615e6edfgw/*
427990b485lling * Given an nvlist of zpool properties to be set, validate that they are
428990b485lling * correct, and parse any numeric properties (index, boolean, etc) if they are
429990b485lling * specified as strings.
430990b485lling */
431990b485llingstatic nvlist_t *
4320a48a24timhzpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
433f9af39bGeorge Wilson    nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
434990b485lling{
435990b485lling	nvpair_t *elem;
436990b485lling	nvlist_t *retprops;
437990b485lling	zpool_prop_t prop;
438990b485lling	char *strval;
439990b485lling	uint64_t intval;
4408704186Dan McDonald	char *slash, *check;
4412f8aaabeschrock	struct stat64 statbuf;
44215e6edfgw	zpool_handle_t *zhp;
443990b485lling
444990b485lling	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
445990b485lling		(void) no_memory(hdl);
446990b485lling		return (NULL);
447990b485lling	}
448990b485lling
449990b485lling	elem = NULL;
450990b485lling	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
451990b485lling		const char *propname = nvpair_name(elem);
452990b485lling
453ad135b5Christopher Siden		prop = zpool_name_to_prop(propname);
4544ae5f5fAlan Somers		if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
455ad135b5Christopher Siden			int err;
456ad135b5Christopher Siden			char *fname = strchr(propname, '@') + 1;
457ad135b5Christopher Siden
4582acef22Matthew Ahrens			err = zfeature_lookup_name(fname, NULL);
459ad135b5Christopher Siden			if (err != 0) {
460ad135b5Christopher Siden				ASSERT3U(err, ==, ENOENT);
461ad135b5Christopher Siden				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4625711d39loli				    "invalid feature '%s', '%s'"), fname,
4635711d39loli				    propname);
464ad135b5Christopher Siden				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
465ad135b5Christopher Siden				goto error;
466ad135b5Christopher Siden			}
467ad135b5Christopher Siden
468ad135b5Christopher Siden			if (nvpair_type(elem) != DATA_TYPE_STRING) {
469ad135b5Christopher Siden				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
470ad135b5Christopher Siden				    "'%s' must be a string"), propname);
471ad135b5Christopher Siden				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
472ad135b5Christopher Siden				goto error;
473ad135b5Christopher Siden			}
474ad135b5Christopher Siden
475ad135b5Christopher Siden			(void) nvpair_value_string(elem, &strval);
476f343451LOLi			if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0 &&
477f343451LOLi			    strcmp(strval, ZFS_FEATURE_DISABLED) != 0) {
478ad135b5Christopher Siden				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
479ad135b5Christopher Siden				    "property '%s' can only be set to "
480f343451LOLi				    "'enabled' or 'disabled'"), propname);
481ad135b5Christopher Siden				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
482ad135b5Christopher Siden				goto error;
483ad135b5Christopher Siden			}
484ad135b5Christopher Siden
485ad135b5Christopher Siden			if (nvlist_add_uint64(retprops, propname, 0) != 0) {
486ad135b5Christopher Siden				(void) no_memory(hdl);
487ad135b5Christopher Siden				goto error;
488ad135b5Christopher Siden			}
489ad135b5Christopher Siden			continue;
490ad135b5Christopher Siden		}
491ad135b5Christopher Siden
492990b485lling		/*
493990b485lling		 * Make sure this property is valid and applies to this type.
494990b485lling		 */
4954ae5f5fAlan Somers		if (prop == ZPOOL_PROP_INVAL) {
496990b485lling			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
497990b485lling			    "invalid property '%s'"), propname);
498990b485lling			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
499990b485lling			goto error;
500990b485lling		}
501990b485lling
502990b485lling		if (zpool_prop_readonly(prop)) {
503990b485lling			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
504990b485lling			    "is readonly"), propname);
505990b485lling			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
506990b485lling			goto error;
507990b485lling		}
508990b485lling
509990b485lling		if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
510990b485lling		    &strval, &intval, errbuf) != 0)
511990b485lling			goto error;
512990b485lling
513990b485lling		/*
514990b485lling		 * Perform additional checking for specific properties.
515990b485lling		 */
516990b485lling		switch (prop) {
517990b485lling		case ZPOOL_PROP_VERSION:
518ad135b5Christopher Siden			if (intval < version ||
519ad135b5Christopher Siden			    !SPA_VERSION_IS_SUPPORTED(intval)) {
520990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
521990b485lling				    "property '%s' number %d is invalid."),
522990b485lling				    propname, intval);
523990b485lling				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
524990b485lling				goto error;
525990b485lling			}
526990b485lling			break;
527990b485lling
5287855d95Toomas Soome		case ZPOOL_PROP_BOOTSIZE:
5297855d95Toomas Soome			if (!flags.create) {
5307855d95Toomas Soome				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5317855d95Toomas Soome				    "property '%s' can only be set during pool "
5327855d95Toomas Soome				    "creation"), propname);
5337855d95Toomas Soome				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
5347855d95Toomas Soome				goto error;
5357855d95Toomas Soome			}
5367855d95Toomas Soome			break;
5377855d95Toomas Soome
5385711d39loli		case ZPOOL_PROP_ASHIFT:
5395711d39loli			if (intval != 0 &&
5405711d39loli			    (intval < ASHIFT_MIN || intval > ASHIFT_MAX)) {
5415711d39loli				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5425711d39loli				    "invalid '%s=%d' property: only values "
5435711d39loli				    "between %" PRId32 " and %" PRId32 " "
5445711d39loli				    "are allowed.\n"),
5455711d39loli				    propname, intval, ASHIFT_MIN, ASHIFT_MAX);
5465711d39loli				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
5475711d39loli				goto error;
5485711d39loli			}
5495711d39loli			break;
5505711d39loli
551990b485lling		case ZPOOL_PROP_BOOTFS:
552f9af39bGeorge Wilson			if (flags.create || flags.import) {
553990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
554990b485lling				    "property '%s' cannot be set at creation "
555990b485lling				    "or import time"), propname);
556990b485lling				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
557990b485lling				goto error;
558990b485lling			}
559990b485lling
560990b485lling			if (version < SPA_VERSION_BOOTFS) {
561990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
562990b485lling				    "pool must be upgraded to support "
563990b485lling				    "'%s' property"), propname);
564990b485lling				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
565990b485lling				goto error;
566990b485lling			}
567990b485lling
568990b485lling			/*
569990b485lling			 * bootfs property value has to be a dataset name and
570990b485lling			 * the dataset has to be in the same pool as it sets to.
571990b485lling			 */
572015f38bPaul Dagnelie			if (!bootfs_name_valid(poolname, strval)) {
573990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
574990b485lling				    "is an invalid name"), strval);
575990b485lling				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
576990b485lling				goto error;
577990b485lling			}
57815e6edfgw
57915e6edfgw			if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
58015e6edfgw				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
58115e6edfgw				    "could not open pool '%s'"), poolname);
58215e6edfgw				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
58315e6edfgw				goto error;
58415e6edfgw			}
58515e6edfgw			zpool_close(zhp);
586990b485lling			break;
587990b485lling
5882f8aaabeschrock		case ZPOOL_PROP_ALTROOT:
589f9af39bGeorge Wilson			if (!flags.create && !flags.import) {
590990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
591990b485lling				    "property '%s' can only be set during pool "
592990b485lling				    "creation or import"), propname);
593990b485lling				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
594990b485lling				goto error;
595990b485lling			}
596990b485lling
5972f8aaabeschrock			if (strval[0] != '/') {
598990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5992f8aaabeschrock				    "bad alternate root '%s'"), strval);
6002f8aaabeschrock				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
601990b485lling				goto error;
602990b485lling			}
6032f8aaabeschrock			break;
6042f8aaabeschrock
6052f8aaabeschrock		case ZPOOL_PROP_CACHEFILE:
6062f8aaabeschrock			if (strval[0] == '\0')
6072f8aaabeschrock				break;
6082f8aaabeschrock
6092f8aaabeschrock			if (strcmp(strval, "none") == 0)
6102f8aaabeschrock				break;
611990b485lling
612990b485lling			if (strval[0] != '/') {
613990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6142f8aaabeschrock				    "property '%s' must be empty, an "
6152f8aaabeschrock				    "absolute path, or 'none'"), propname);
616990b485lling				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
617990b485lling				goto error;
618990b485lling			}
619990b485lling
6202f8aaabeschrock			slash = strrchr(strval, '/');
621990b485lling
6222f8aaabeschrock			if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
6232f8aaabeschrock			    strcmp(slash, "/..") == 0) {
6242f8aaabeschrock				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6252f8aaabeschrock				    "'%s' is not a valid file"), strval);
6262f8aaabeschrock				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
6272f8aaabeschrock				goto error;
6282f8aaabeschrock			}
629990b485lling
6302f8aaabeschrock			*slash = '\0';
6312f8aaabeschrock
6322c32020eschrock			if (strval[0] != '\0' &&
6332c32020eschrock			    (stat64(strval, &statbuf) != 0 ||
6342c32020eschrock			    !S_ISDIR(statbuf.st_mode))) {
6352f8aaabeschrock				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6362f8aaabeschrock				    "'%s' is not a valid directory"),
6372f8aaabeschrock				    strval);
6382f8aaabeschrock				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
6392f8aaabeschrock				goto error;
6402f8aaabeschrock			}
6412f8aaabeschrock
6422f8aaabeschrock			*slash = '/';
6432f8aaabeschrock			break;
644f9af39bGeorge Wilson
6458704186Dan McDonald		case ZPOOL_PROP_COMMENT:
6468704186Dan McDonald			for (check = strval; *check != '\0'; check++) {
6478704186Dan McDonald				if (!isprint(*check)) {
6488704186Dan McDonald					zfs_error_aux(hdl,
6498704186Dan McDonald					    dgettext(TEXT_DOMAIN,
6508704186Dan McDonald					    "comment may only have printable "
6518704186Dan McDonald					    "characters"));
6528704186Dan McDonald					(void) zfs_error(hdl, EZFS_BADPROP,
6538704186Dan McDonald					    errbuf);
6548704186Dan McDonald					goto error;
6558704186Dan McDonald				}
6568704186Dan McDonald			}
6578704186Dan McDonald			if (strlen(strval) > ZPROP_MAX_COMMENT) {
6588704186Dan McDonald				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6598704186Dan McDonald				    "comment must not exceed %d characters"),
6608704186Dan McDonald				    ZPROP_MAX_COMMENT);
6618704186Dan McDonald				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
6628704186Dan McDonald				goto error;
6638704186Dan McDonald			}
6648704186Dan McDonald			break;
66504e5635Andriy Gapon
666f9af39bGeorge Wilson		case ZPOOL_PROP_READONLY:
667f9af39bGeorge Wilson			if (!flags.import) {
668f9af39bGeorge Wilson				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
669f9af39bGeorge Wilson				    "property '%s' can only be set at "
670f9af39bGeorge Wilson				    "import time"), propname);
671f9af39bGeorge Wilson				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
672f9af39bGeorge Wilson				goto error;
673f9af39bGeorge Wilson			}
674f9af39bGeorge Wilson			break;
67588f61deIgor Kozhukhov
67604e5635Andriy Gapon		case ZPOOL_PROP_TNAME:
67704e5635Andriy Gapon			if (!flags.create) {
67804e5635Andriy Gapon				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
67904e5635Andriy Gapon				    "property '%s' can only be set at "
68004e5635Andriy Gapon				    "creation time"), propname);
68104e5635Andriy Gapon				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
68204e5635Andriy Gapon				goto error;
68304e5635Andriy Gapon			}
68404e5635Andriy Gapon			break;
68504e5635Andriy Gapon
686e0f1c0aOlaf Faaland		case ZPOOL_PROP_MULTIHOST:
687e0f1c0aOlaf Faaland			if (get_system_hostid() == 0) {
688e0f1c0aOlaf Faaland				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
689e0f1c0aOlaf Faaland				    "requires a non-zero system hostid"));
690e0f1c0aOlaf Faaland				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
691e0f1c0aOlaf Faaland				goto error;
692e0f1c0aOlaf Faaland			}
693e0f1c0aOlaf Faaland			break;
694e0f1c0aOlaf Faaland
69588f61deIgor Kozhukhov		default:
69688f61deIgor Kozhukhov			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
69788f61deIgor Kozhukhov			    "property '%s'(%d) not defined"), propname, prop);
69888f61deIgor Kozhukhov			break;
699990b485lling		}
700990b485lling	}
701990b485lling
702990b485lling	return (retprops);
703990b485llingerror:
704990b485lling	nvlist_free(retprops);
705990b485lling	return (NULL);
706990b485lling}
707990b485lling
708990b485lling/*
709990b485lling * Set zpool property : propname=propval.
710990b485lling */
711990b485llingint
712990b485llingzpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
713990b485lling{
714990b485lling	zfs_cmd_t zc = { 0 };
715990b485lling	int ret = -1;
716990b485lling	char errbuf[1024];
717990b485lling	nvlist_t *nvl = NULL;
718990b485lling	nvlist_t *realprops;
719990b485lling	uint64_t version;
720f9af39bGeorge Wilson	prop_flags_t flags = { 0 };
721990b485lling
722990b485lling	(void) snprintf(errbuf, sizeof (errbuf),
723990b485lling	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
724990b485lling	    zhp->zpool_name);
725990b485lling
726990b485lling	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
727990b485lling		return (no_memory(zhp->zpool_hdl));
728990b485lling
729990b485lling	if (nvlist_add_string(nvl, propname, propval) != 0) {
730990b485lling		nvlist_free(nvl);
731990b485lling		return (no_memory(zhp->zpool_hdl));
732990b485lling	}
733990b485lling
734990b485lling	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
7350a48a24timh	if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
736f9af39bGeorge Wilson	    zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) {
737990b485lling		nvlist_free(nvl);
738990b485lling		return (-1);
739990b485lling	}
740990b485lling
741990b485lling	nvlist_free(nvl);
742990b485lling	nvl = realprops;
743990b485lling
744990b485lling	/*
745990b485lling	 * Execute the corresponding ioctl() to set this property.
746990b485lling	 */
747990b485lling	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
748990b485lling
749990b485lling	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
750990b485lling		nvlist_free(nvl);
751990b485lling		return (-1);
752990b485lling	}
753990b485lling
754990b485lling	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
755990b485lling
756990b485lling	zcmd_free_nvlists(&zc);
757990b485lling	nvlist_free(nvl);
758990b485lling
759990b485lling	if (ret)
760990b485lling		(void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
761990b485lling	else
762990b485lling		(void) zpool_props_refresh(zhp);
763990b485lling
764990b485