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 */
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 */
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>
47fa9e406ahrens#include "zfs_namecheck.h"
48b1b8ab3lling#include "zfs_prop.h"
49fa9e406ahrens#include "libzfs_impl.h"
50468c413Tim Haley#include "zfs_comutil.h"
51ad135b5Christopher Siden#include "zfeature_common.h"
537855d95Toomas Soomestatic int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *);
542ba5f97Alan Somersstatic boolean_t zpool_vdev_is_interior(const char *name);
56573ca77George Wilson#define	BACKUP_SLICE	"s2"
57573ca77George Wilson
58f9af39bGeorge Wilsontypedef struct prop_flags {
59f9af39bGeorge Wilson	int create:1;	/* Validate property on creation */
60f9af39bGeorge Wilson	int import:1;	/* Validate property on import */
61f9af39bGeorge Wilson} prop_flags_t;
62f9af39bGeorge Wilson
64990b485lling * ====================================================================
65990b485lling *   zpool property functions
66990b485lling * ====================================================================
67990b485lling */
69990b485llingstatic int
70990b485llingzpool_get_all_props(zpool_handle_t *zhp)
72990b485lling	zfs_cmd_t zc = { 0 };
73990b485lling	libzfs_handle_t *hdl = zhp->zpool_hdl;
75990b485lling	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
77990b485lling	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
78990b485lling		return (-1);
80990b485lling	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
81990b485lling		if (errno == ENOMEM) {
82990b485lling			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
83990b485lling				zcmd_free_nvlists(&zc);
84990b485lling				return (-1);
85990b485lling			}
86990b485lling		} else {
87990b485lling			zcmd_free_nvlists(&zc);
88990b485lling			return (-1);
89990b485lling		}
90990b485lling	}
92990b485lling	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
93990b485lling		zcmd_free_nvlists(&zc);
94990b485lling		return (-1);
95990b485lling	}
97990b485lling	zcmd_free_nvlists(&zc);
99990b485lling	return (0);
102990b485llingstatic int
103990b485llingzpool_props_refresh(zpool_handle_t *zhp)
105990b485lling	nvlist_t *old_props;
107990b485lling	old_props = zhp->zpool_props;
109990b485lling	if (zpool_get_all_props(zhp) != 0)
110990b485lling		return (-1);
112990b485lling	nvlist_free(old_props);
113990b485lling	return (0);
116990b485llingstatic char *
117990b485llingzpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
118990b485lling    zprop_source_t *src)
120990b485lling	nvlist_t *nv, *nvl;
121990b485lling	uint64_t ival;
122990b485lling	char *value;
123990b485lling	zprop_source_t source;
125990b485lling	nvl = zhp->zpool_props;
126990b485lling	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
127990b485lling		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
128990b485lling		source = ival;
129990b485lling		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
130990b485lling	} else {
131990b485lling		source = ZPROP_SRC_DEFAULT;
132990b485lling		if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
133990b485lling			value = "-";
134990b485lling	}
136990b485lling	if (src)
137990b485lling		*src = source;
139990b485lling	return (value);
143990b485llingzpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
145990b485lling	nvlist_t *nv, *nvl;
146990b485lling	uint64_t value;
147990b485lling	zprop_source_t source;
149b87f3afperrin	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
150b87f3afperrin		/*
151b87f3afperrin		 * zpool_get_all_props() has most likely failed because
152b87f3afperrin		 * the pool is faulted, but if all we need is the top level
153b87f3afperrin		 * vdev's guid then get it from the zhp config nvlist.
154b87f3afperrin		 */
155b87f3afperrin		if ((prop == ZPOOL_PROP_GUID) &&
156b87f3afperrin		    (nvlist_lookup_nvlist(zhp->zpool_config,
157b87f3afperrin		    ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
158b87f3afperrin		    (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
159b87f3afperrin		    == 0)) {
160b87f3afperrin			return (value);
161b87f3afperrin		}
162990b485lling		return (zpool_prop_default_numeric(prop));
163b87f3afperrin	}
165990b485lling	nvl = zhp->zpool_props;
166990b485lling	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
167990b485lling		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
168990b485lling		source = value;
169990b485lling		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
170990b485lling	} else {
171990b485lling		source = ZPROP_SRC_DEFAULT;
172990b485lling		value = zpool_prop_default_numeric(prop);
173990b485lling	}
175990b485lling	if (src)
176990b485lling		*src = source;
178990b485lling	return (value);
182990b485lling * Map VDEV STATE to printed strings.
183990b485lling */
1846401734Will Andrewsconst char *
185990b485llingzpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
187990b485lling	switch (state) {
188990b485lling	case VDEV_STATE_CLOSED:
189990b485lling	case VDEV_STATE_OFFLINE:
190990b485lling		return (gettext("OFFLINE"));
191990b485lling	case VDEV_STATE_REMOVED:
192990b485lling		return (gettext("REMOVED"));
193990b485lling	case VDEV_STATE_CANT_OPEN:
194b87f3afperrin		if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
195990b485lling			return (gettext("FAULTED"));
1961195e68Mark J Musante		else if (aux == VDEV_AUX_SPLIT_POOL)
1971195e68Mark J Musante			return (gettext("SPLIT"));
198990b485lling		else
199990b485lling			return (gettext("UNAVAIL"));
200990b485lling	case VDEV_STATE_FAULTED:
201990b485lling		return (gettext("FAULTED"));
202990b485lling	case VDEV_STATE_DEGRADED:
203990b485lling		return (gettext("DEGRADED"));
204990b485lling	case VDEV_STATE_HEALTHY:
205990b485lling		return (gettext("ONLINE"));
20688f61deIgor Kozhukhov
20788f61deIgor Kozhukhov	default:
20888f61deIgor Kozhukhov		break;
209990b485lling	}
211990b485lling	return (gettext("UNKNOWN"));
2156401734Will Andrews * Map POOL STATE to printed strings.
2166401734Will Andrews */
2176401734Will Andrewsconst char *
2186401734Will Andrewszpool_pool_state_to_name(pool_state_t state)
2196401734Will Andrews{
2206401734Will Andrews	switch (state) {
2216401734Will Andrews	case POOL_STATE_ACTIVE:
2226401734Will Andrews		return (gettext("ACTIVE"));
2236401734Will Andrews	case POOL_STATE_EXPORTED:
2246401734Will Andrews		return (gettext("EXPORTED"));
2256401734Will Andrews	case POOL_STATE_DESTROYED:
2266401734Will Andrews		return (gettext("DESTROYED"));
2276401734Will Andrews	case POOL_STATE_SPARE:
2286401734Will Andrews		return (gettext("SPARE"));
2296401734Will Andrews	case POOL_STATE_L2CACHE:
2306401734Will Andrews		return (gettext("L2CACHE"));
2316401734Will Andrews	case POOL_STATE_UNINITIALIZED:
2326401734Will Andrews		return (gettext("UNINITIALIZED"));
2336401734Will Andrews	case POOL_STATE_UNAVAIL:
2346401734Will Andrews		return (gettext("UNAVAIL"));
2356401734Will Andrews	case POOL_STATE_POTENTIALLY_ACTIVE:
2366401734Will Andrews		return (gettext("POTENTIALLY_ACTIVE"));
2376401734Will Andrews	}
2386401734Will Andrews
2396401734Will Andrews	return (gettext("UNKNOWN"));
2406401734Will Andrews}
2416401734Will Andrews
2426401734Will Andrews/*
243990b485lling * Get a zpool property value for 'prop' and return the value in
244990b485lling * a pre-allocated buffer.
245990b485lling */
247990b485llingzpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
248c58b352Adam Stevko    zprop_source_t *srctype, boolean_t literal)
250990b485lling	uint64_t intval;
251990b485lling	const char *strval;
252990b485lling	zprop_source_t src = ZPROP_SRC_NONE;
253990b485lling	nvlist_t *nvroot;
254990b485lling	vdev_stat_t *vs;
255990b485lling	uint_t vsc;
257990b485lling	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
258379c004Eric Schrock		switch (prop) {
259379c004Eric Schrock		case ZPOOL_PROP_NAME:
260990b485lling			(void) strlcpy(buf, zpool_get_name(zhp), len);
261379c004Eric Schrock			break;
262379c004Eric Schrock
263379c004Eric Schrock		case ZPOOL_PROP_HEALTH:
264990b485lling			(void) strlcpy(buf, "FAULTED", len);
265379c004Eric Schrock			break;
266379c004Eric Schrock
267379c004Eric Schrock		case ZPOOL_PROP_GUID:
268379c004Eric Schrock			intval = zpool_get_prop_int(zhp, prop, &src);
269379c004Eric Schrock			(void) snprintf(buf, len, "%llu", intval);
270379c004Eric Schrock			break;
271379c004Eric Schrock
272379c004Eric Schrock		case ZPOOL_PROP_ALTROOT:
273379c004Eric Schrock		case ZPOOL_PROP_CACHEFILE:
2748704186Dan McDonald		case ZPOOL_PROP_COMMENT:
275379c004Eric Schrock			if (zhp->zpool_props != NULL ||
276379c004Eric Schrock			    zpool_get_all_props(zhp) == 0) {
277379c004Eric Schrock				(void) strlcpy(buf,
278379c004Eric Schrock				    zpool_get_prop_string(zhp, prop, &src),
279379c004Eric Schrock				    len);
280c58b352Adam Stevko				break;
281379c004Eric Schrock			}
282379c004Eric Schrock			/* FALLTHROUGH */
283379c004Eric Schrock		default:
284990b485lling			(void) strlcpy(buf, "-", len);
285379c004Eric Schrock			break;
286379c004Eric Schrock		}
287379c004Eric Schrock
288379c004Eric Schrock		if (srctype != NULL)
289379c004Eric Schrock			*srctype = src;
290990b485lling		return (0);
291990b485lling	}
293990b485lling	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
294990b485lling	    prop != ZPOOL_PROP_NAME)
295990b485lling		return (-1);
297990b485lling	switch (zpool_prop_get_type(prop)) {
298990b485lling	case PROP_TYPE_STRING:
299990b485lling		(void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
300990b485lling		    len);
301990b485lling		break;
303990b485lling	case PROP_TYPE_NUMBER:
304990b485lling		intval = zpool_get_prop_int(zhp, prop, &src);
306990b485lling		switch (prop) {
307990b485lling		case ZPOOL_PROP_SIZE:
308485bbbfGeorge Wilson		case ZPOOL_PROP_ALLOCATED:
309485bbbfGeorge Wilson		case ZPOOL_PROP_FREE:
310ad135b5Christopher Siden		case ZPOOL_PROP_FREEING:
3117fd05acMatthew Ahrens		case ZPOOL_PROP_LEAKED:
3125711d39loli		case ZPOOL_PROP_ASHIFT:
313c58b352Adam Stevko			if (literal) {
314c58b352Adam Stevko				(void) snprintf(buf, len, "%llu",
315c58b352Adam Stevko				    (u_longlong_t)intval);
316c58b352Adam Stevko			} else {
317c58b352Adam Stevko				(void) zfs_nicenum(intval, buf, len);
318c58b352Adam Stevko			}
319990b485lling			break;
3207855d95Toomas Soome		case ZPOOL_PROP_BOOTSIZE:
3217a09f97George Wilson		case ZPOOL_PROP_EXPANDSZ:
3228671400Serapheim Dimitropoulos		case ZPOOL_PROP_CHECKPOINT:
3237a09f97George Wilson			if (intval == 0) {
3247a09f97George Wilson				(void) strlcpy(buf, "-", len);
3257a09f97George Wilson			} else if (literal) {
3267a09f97George Wilson				(void) snprintf(buf, len, "%llu",
3277a09f97George Wilson				    (u_longlong_t)intval);
3287a09f97George Wilson			} else {
3297a09f97George Wilson				(void) zfs_nicenum(intval, buf, len);
3307a09f97George Wilson			}
3317a09f97George Wilson			break;
332990b485lling		case ZPOOL_PROP_CAPACITY:
333c58b352Adam Stevko			if (literal) {
334c58b352Adam Stevko				(void) snprintf(buf, len, "%llu",
335c58b352Adam Stevko				    (u_longlong_t)intval);
336c58b352Adam Stevko			} else {
337c58b352Adam Stevko				(void) snprintf(buf, len, "%llu%%",
338c58b352Adam Stevko				    (u_longlong_t)intval);
339c58b352Adam Stevko			}
340990b485lling			break;
3412e4c998George Wilson		case ZPOOL_PROP_FRAGMENTATION:
3422e4c998George Wilson			if (intval == UINT64_MAX) {
3432e4c998George Wilson				(void) strlcpy(buf, "-", len);
3442e4c998George Wilson			} else {
3452e4c998George Wilson				(void) snprintf(buf, len, "%llu%%",
3462e4c998George Wilson				    (u_longlong_t)intval);
3472e4c998George Wilson			}
3482e4c998George Wilson			break;
349b24ab67Jeff Bonwick		case ZPOOL_PROP_DEDUPRATIO:
350b24ab67Jeff Bonwick			(void) snprintf(buf, len, "%llu.%02llux",
351b24ab67Jeff Bonwick			    (u_longlong_t)(intval / 100),
352b24ab67Jeff Bonwick			    (u_longlong_t)(intval % 100));
353b24ab67Jeff Bonwick			break;
354990b485lling		case ZPOOL_PROP_HEALTH:
355990b485lling			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
356990b485lling			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
357990b485lling			verify(nvlist_lookup_uint64_array(nvroot,
3583f9d6adLin Ling			    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
3593f9d6adLin Ling			    == 0);
361990b485lling			(void) strlcpy(buf, zpool_state_to_name(intval,
362990b485lling			    vs->vs_aux), len);
363990b485lling			break;
364ad135b5Christopher Siden		case ZPOOL_PROP_VERSION:
365ad135b5Christopher Siden			if (intval >= SPA_VERSION_FEATURES) {
366ad135b5Christopher Siden				(void) snprintf(buf, len, "-");
367ad135b5Christopher Siden				break;
368ad135b5Christopher Siden			}
369ad135b5Christopher Siden			/* FALLTHROUGH */
370990b485lling		default:
371990b485lling			(void) snprintf(buf, len, "%llu", intval);
372990b485lling		}
373990b485lling		break;
375990b485lling	case PROP_TYPE_INDEX:
376990b485lling		intval = zpool_get_prop_int(zhp, prop, &src);
377990b485lling		if (zpool_prop_index_to_string(prop, intval, &strval)
378990b485lling		    != 0)
379990b485lling			return (-1);
380990b485lling		(void) strlcpy(buf, strval, len);
381990b485lling		break;
383990b485lling	default:
384990b485lling		abort();
385990b485lling	}
387990b485lling	if (srctype)
388990b485lling		*srctype = src;
390990b485lling	return (0);
394990b485lling * Check if the bootfs name has the same pool name as it is set to.
395990b485lling * Assuming bootfs is a valid dataset name.
396990b485lling */
397990b485llingstatic boolean_t
398990b485llingbootfs_name_valid(const char *pool, char *bootfs)
400990b485lling	int len = strlen(pool);
401015f38bPaul Dagnelie	if (bootfs[0] == '\0')
402015f38bPaul Dagnelie		return (B_TRUE);
404fe3e263Eric Taylor	if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
405990b485lling		return (B_FALSE);
407990b485lling	if (strncmp(pool, bootfs, len) == 0 &&
408990b485lling	    (bootfs[len] == '/' || bootfs[len] == '\0'))
409990b485lling		return (B_TRUE);
411990b485lling	return (B_FALSE);
4144263d13George Wilsonboolean_t
4154263d13George Wilsonzpool_is_bootable(zpool_handle_t *zhp)
416b5b76feGeorge Wilson{
4179adfa60Matthew Ahrens	char bootfs[ZFS_MAX_DATASET_NAME_LEN];
418b5b76feGeorge Wilson
419b5b76feGeorge Wilson	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
420c58b352Adam Stevko	    sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
421b5b76feGeorge Wilson	    sizeof (bootfs)) != 0);
422b5b76feGeorge Wilson}
423b5b76feGeorge Wilson
424b5b76feGeorge Wilson
426990b485lling * Given an nvlist of zpool properties to be set, validate that they are
427990b485lling * correct, and parse any numeric properties (index, boolean, etc) if they are
428990b485lling * specified as strings.
429990b485lling */
430990b485llingstatic nvlist_t *
4310a48a24timhzpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
432f9af39bGeorge Wilson    nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
434990b485lling	nvpair_t *elem;
435990b485lling	nvlist_t *retprops;
436990b485lling	zpool_prop_t prop;
437990b485lling	char *strval;
438990b485lling	uint64_t intval;
4398704186Dan McDonald	char *slash, *check;
4402f8aaabeschrock	struct stat64 statbuf;
44115e6edfgw	zpool_handle_t *zhp;
443990b485lling	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
444990b485lling		(void) no_memory(hdl);
445990b485lling		return (NULL);
446990b485lling	}
448990b485lling	elem = NULL;
449990b485lling	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
450990b485lling		const char *propname = nvpair_name(elem);
452ad135b5Christopher Siden		prop = zpool_name_to_prop(propname);
4534ae5f5fAlan Somers		if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
454ad135b5Christopher Siden			int err;
455ad135b5Christopher Siden			char *fname = strchr(propname, '@') + 1;
456ad135b5Christopher Siden
4572acef22Matthew Ahrens			err = zfeature_lookup_name(fname, NULL);
458ad135b5Christopher Siden			if (err != 0) {
459ad135b5Christopher Siden				ASSERT3U(err, ==, ENOENT);
460ad135b5Christopher Siden				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4615711d39loli				    "invalid feature '%s', '%s'"), fname,
4625711d39loli				    propname);
463ad135b5Christopher Siden				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
464ad135b5Christopher Siden				goto error;
465ad135b5Christopher Siden			}
466ad135b5Christopher Siden
467ad135b5Christopher Siden			if (nvpair_type(elem) != DATA_TYPE_STRING) {
468ad135b5Christopher Siden				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
469ad135b5Christopher Siden				    "'%s' must be a string"), propname);
470ad135b5Christopher Siden				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
471ad135b5Christopher Siden				goto error;
472ad135b5Christopher Siden			}
473ad135b5Christopher Siden
474ad135b5Christopher Siden			(void) nvpair_value_string(elem, &strval);
475ad135b5Christopher Siden			if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) {
476ad135b5Christopher Siden				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
477ad135b5Christopher Siden				    "property '%s' can only be set to "
478ad135b5Christopher Siden				    "'enabled'"), propname);
479ad135b5Christopher Siden				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
480ad135b5Christopher Siden				goto error;
481ad135b5Christopher Siden			}
482ad135b5Christopher Siden
483ad135b5Christopher Siden			if (nvlist_add_uint64(retprops, propname, 0) != 0) {
484ad135b5Christopher Siden				(void) no_memory(hdl);
485ad135b5Christopher Siden				goto error;
486ad135b5Christopher Siden			}
487ad135b5Christopher Siden			continue;
488ad135b5Christopher Siden		}
489ad135b5Christopher Siden
490990b485lling		/*
491990b485lling		 * Make sure this property is valid and applies to this type.
492990b485lling		 */
4934ae5f5fAlan Somers		if (prop == ZPOOL_PROP_INVAL) {
494990b485lling			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
495990b485lling			    "invalid property '%s'"), propname);
496990b485lling			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
497990b485lling			goto error;
498990b485lling		}
500990b485lling		if (zpool_prop_readonly(prop)) {
501990b485lling			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
502990b485lling			    "is readonly"), propname);
503990b485lling			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
504990b485lling			goto error;
505990b485lling		}
507990b485lling		if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
508990b485lling		    &strval, &intval, errbuf) != 0)
509990b485lling			goto error;
511990b485lling		/*
512990b485lling		 * Perform additional checking for specific properties.
513990b485lling		 */
514990b485lling		switch (prop) {
515990b485lling		case ZPOOL_PROP_VERSION:
516ad135b5Christopher Siden			if (intval < version ||
517ad135b5Christopher Siden			    !SPA_VERSION_IS_SUPPORTED(intval)) {
518990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
519990b485lling				    "property '%s' number %d is invalid."),
520990b485lling				    propname, intval);
521990b485lling				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
522990b485lling				goto error;
523990b485lling			}
524990b485lling			break;
5267855d95Toomas Soome		case ZPOOL_PROP_BOOTSIZE:
5277855d95Toomas Soome			if (!flags.create) {
5287855d95Toomas Soome				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5297855d95Toomas Soome				    "property '%s' can only be set during pool "
5307855d95Toomas Soome				    "creation"), propname);
5317855d95Toomas Soome				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
5327855d95Toomas Soome				goto error;
5337855d95Toomas Soome			}
5347855d95Toomas Soome			break;
5357855d95Toomas Soome
5365711d39loli		case ZPOOL_PROP_ASHIFT:
5375711d39loli			if (intval != 0 &&
5385711d39loli			    (intval < ASHIFT_MIN || intval > ASHIFT_MAX)) {
5395711d39loli				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5405711d39loli				    "invalid '%s=%d' property: only values "
5415711d39loli				    "between %" PRId32 " and %" PRId32 " "
5425711d39loli				    "are allowed.\n"),
5435711d39loli				    propname, intval, ASHIFT_MIN, ASHIFT_MAX);
5445711d39loli				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
5455711d39loli				goto error;
5465711d39loli			}
5475711d39loli			break;
549990b485lling		case ZPOOL_PROP_BOOTFS:
550f9af39bGeorge Wilson			if (flags.create || flags.import) {
551990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
552990b485lling				    "property '%s' cannot be set at creation "
553990b485lling				    "or import time"), propname);
554990b485lling				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
555990b485lling				goto error;
556990b485lling			}
558990b485lling			if (version < SPA_VERSION_BOOTFS) {
559990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
560990b485lling				    "pool must be upgraded to support "
561990b485lling				    "'%s' property"), propname);
562990b485lling				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
563990b485lling				goto error;
564990b485lling			}
566990b485lling			/*
567990b485lling			 * bootfs property value has to be a dataset name and
568990b485lling			 * the dataset has to be in the same pool as it sets to.
569990b485lling			 */
570015f38bPaul Dagnelie			if (!bootfs_name_valid(poolname, strval)) {
571990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
572990b485lling				    "is an invalid name"), strval);
573990b485lling				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
574990b485lling				goto error;
575990b485lling			}
57715e6edfgw			if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
57815e6edfgw				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
57915e6edfgw				    "could not open pool '%s'"), poolname);
58015e6edfgw				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
58115e6edfgw				goto error;
58215e6edfgw			}
58315e6edfgw			zpool_close(zhp);
584990b485lling			break;
5862f8aaabeschrock		case ZPOOL_PROP_ALTROOT:
587f9af39bGeorge Wilson			if (!flags.create && !flags.import) {
588990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
589990b485lling				    "property '%s' can only be set during pool "
590990b485lling				    "creation or import"), propname);
591990b485lling				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
592990b485lling				goto error;
593990b485lling			}
5952f8aaabeschrock			if (strval[0] != '/') {
596990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5972f8aaabeschrock				    "bad alternate root '%s'"), strval);
5982f8aaabeschrock				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
599990b485lling				goto error;
600990b485lling			}
6012f8aaabeschrock			break;
6032f8aaabeschrock		case ZPOOL_PROP_CACHEFILE:
6042f8aaabeschrock			if (strval[0] == '\0')
6052f8aaabeschrock				break;
6072f8aaabeschrock			if (strcmp(strval, "none") == 0)
6082f8aaabeschrock				break;
610990b485lling			if (strval[0] != '/') {
611990b485lling				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6122f8aaabeschrock				    "property '%s' must be empty, an "
6132f8aaabeschrock				    "absolute path, or 'none'"), propname);
614990b485lling				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
615990b485lling				goto error;
616990b485lling			}
6182f8aaabeschrock			slash = strrchr(strval, '/');
6202f8aaabeschrock			if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
6212f8aaabeschrock			    strcmp(slash, "/..") == 0) {
6222f8aaabeschrock				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6232f8aaabeschrock				    "'%s' is not a valid file"), strval);
6242f8aaabeschrock				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
6252f8aaabeschrock				goto error;
6262f8aaabeschrock			}
6282f8aaabeschrock			*slash = '\0';
6302c32020eschrock			if (strval[0] != '\0' &&
6312c32020eschrock			    (stat64(strval, &statbuf) != 0 ||
6322c32020eschrock			    !S_ISDIR(statbuf.st_mode))) {
6332f8aaabeschrock				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6342f8aaabeschrock				    "'%s' is not a valid directory"),
6352f8aaabeschrock				    strval);
6362f8aaabeschrock				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
6372f8aaabeschrock				goto error;
6382f8aaabeschrock			}
6402f8aaabeschrock			*slash = '/';
6412f8aaabeschrock			break;
642f9af39bGeorge Wilson
6438704186Dan McDonald		case ZPOOL_PROP_COMMENT:
6448704186Dan McDonald			for (check = strval; *check != '\0'; check++) {
6458704186Dan McDonald				if (!isprint(*check)) {
6468704186Dan McDonald					zfs_error_aux(hdl,
6478704186Dan McDonald					    dgettext(TEXT_DOMAIN,
6488704186Dan McDonald					    "comment may only have printable "
6498704186Dan McDonald					    "characters"));
6508704186Dan McDonald					(void) zfs_error(hdl, EZFS_BADPROP,
6518704186Dan McDonald					    errbuf);
6528704186Dan McDonald					goto error;
6538704186Dan McDonald				}
6548704186Dan McDonald			}
6558704186Dan McDonald			if (strlen(strval) > ZPROP_MAX_COMMENT) {
6568704186Dan McDonald				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6578704186Dan McDonald				    "comment must not exceed %d characters"),
6588704186Dan McDonald				    ZPROP_MAX_COMMENT);
6598704186Dan McDonald				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
6608704186Dan McDonald				goto error;
6618704186Dan McDonald			}
6628704186Dan McDonald			break;
66304e5635Andriy Gapon
664f9af39bGeorge Wilson		case ZPOOL_PROP_READONLY:
665f9af39bGeorge Wilson			if (!flags.import) {
666f9af39bGeorge Wilson				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
667f9af39bGeorge Wilson				    "property '%s' can only be set at "
668f9af39bGeorge Wilson				    "import time"), propname);
669f9af39bGeorge Wilson				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
670f9af39bGeorge Wilson				goto error;
671f9af39bGeorge Wilson			}
672f9af39bGeorge Wilson			break;
67388f61deIgor Kozhukhov
67404e5635Andriy Gapon		case ZPOOL_PROP_TNAME:
67504e5635Andriy Gapon			if (!flags.create) {
67604e5635Andriy Gapon				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
67704e5635Andriy Gapon				    "property '%s' can only be set at "
67804e5635Andriy Gapon				    "creation time"), propname);
67904e5635Andriy Gapon				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
68004e5635Andriy Gapon				goto error;
68104e5635Andriy Gapon			}
68204e5635Andriy Gapon			break;
68304e5635Andriy Gapon
684e0f1c0aOlaf Faaland		case ZPOOL_PROP_MULTIHOST:
685e0f1c0aOlaf Faaland			if (get_system_hostid() == 0) {
686e0f1c0aOlaf Faaland				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
687e0f1c0aOlaf Faaland				    "requires a non-zero system hostid"));
688e0f1c0aOlaf Faaland				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
689e0f1c0aOlaf Faaland				goto error;
690e0f1c0aOlaf Faaland			}
691e0f1c0aOlaf Faaland			break;
692e0f1c0aOlaf Faaland
69388f61deIgor Kozhukhov		default:
69488f61deIgor Kozhukhov			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
69588f61deIgor Kozhukhov			    "property '%s'(%d) not defined"), propname, prop);
69688f61deIgor Kozhukhov			break;
697990b485lling		}
698990b485lling	}
700990b485lling	return (retprops);
702990b485lling	nvlist_free(retprops);
703990b485lling	return (NULL);
707990b485lling * Set zpool property : propname=propval.
708990b485lling */
710990b485llingzpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
712990b485lling	zfs_cmd_t zc = { 0 };
713990b485lling	int ret = -1;
714990b485lling	char errbuf[1024];
715990b485lling	nvlist_t *nvl = NULL;
716990b485lling	nvlist_t *realprops;
717990b485lling	uint64_t version;
718f9af39bGeorge Wilson	prop_flags_t flags = { 0 };
720990b485lling	(void) snprintf(errbuf, sizeof (errbuf),
721990b485lling	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
722990b485lling	    zhp->zpool_name);
724990b485lling	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
725990b485lling		return (no_memory(zhp->zpool_hdl));
727990b485lling	if (nvlist_add_string(nvl, propname, propval) != 0) {
728990b485lling		nvlist_free(nvl);
729990b485lling		return (no_memory(zhp->zpool_hdl));
730990b485lling	}
732990b485lling	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
7330a48a24timh	if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
734f9af39bGeorge Wilson	    zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) {
735990b485lling		nvlist_free(nvl);
736990b485lling		return (-1);
737990b485lling	}
739990b485lling	nvlist_free(nvl);
740990b485lling	nvl = realprops;
742990b485lling	/*
743990b485lling	 * Execute the corresponding ioctl() to set this property.
744990b485lling	 */
745990b485lling	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
747990b485lling	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
748990b485lling		nvlist_free(nvl);
749990b485lling		return (-1);
750990b485lling	}
752990b485lling	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
754990b485lling	zcmd_free_nvlists(&zc);
755990b485lling	nvlist_free(nvl);
757990b485lling	if (ret)
758990b485lling		(void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
759990b485lling	else
760990b485lling		(void) zpool_props_refresh(zhp);
762990b485lling	return (ret);