xref: /freebsd-src/sys/contrib/openzfs/lib/libzfsbootenv/lzbe_pair.c (revision 681ce946f33e75c590e97c53076e86dff1fe8f4a)
12c48331dSMatt Macy /*
22c48331dSMatt Macy  * This file and its contents are supplied under the terms of the
32c48331dSMatt Macy  * Common Development and Distribution License ("CDDL"), version 1.0.
42c48331dSMatt Macy  * You may only use this file in accordance with the terms of version
52c48331dSMatt Macy  * 1.0 of the CDDL.
62c48331dSMatt Macy  *
72c48331dSMatt Macy  * A full copy of the text of the CDDL should have accompanied this
82c48331dSMatt Macy  * source.  A copy of the CDDL is also available via the Internet at
92c48331dSMatt Macy  * http://www.illumos.org/license/CDDL.
102c48331dSMatt Macy  */
112c48331dSMatt Macy /*
122c48331dSMatt Macy  * Copyright 2020 Toomas Soome <tsoome@me.com>
132c48331dSMatt Macy  */
142c48331dSMatt Macy 
152c48331dSMatt Macy #include <sys/types.h>
162c48331dSMatt Macy #include <string.h>
172c48331dSMatt Macy #include <libzfs.h>
182c48331dSMatt Macy #include <libzfsbootenv.h>
192c48331dSMatt Macy #include <sys/zfs_bootenv.h>
202c48331dSMatt Macy #include <sys/vdev_impl.h>
212c48331dSMatt Macy 
222c48331dSMatt Macy /*
232c48331dSMatt Macy  * Get or create nvlist. If key is not NULL, get nvlist from bootenv,
242c48331dSMatt Macy  * otherwise return bootenv.
252c48331dSMatt Macy  */
262c48331dSMatt Macy int
lzbe_nvlist_get(const char * pool,const char * key,void ** ptr)272c48331dSMatt Macy lzbe_nvlist_get(const char *pool, const char *key, void **ptr)
282c48331dSMatt Macy {
292c48331dSMatt Macy 	libzfs_handle_t *hdl;
302c48331dSMatt Macy 	zpool_handle_t *zphdl;
312c48331dSMatt Macy 	nvlist_t *nv;
322c48331dSMatt Macy 	int rv = -1;
332c48331dSMatt Macy 
342c48331dSMatt Macy 	if (pool == NULL || *pool == '\0')
352c48331dSMatt Macy 		return (rv);
362c48331dSMatt Macy 
372c48331dSMatt Macy 	if ((hdl = libzfs_init()) == NULL) {
382c48331dSMatt Macy 		return (rv);
392c48331dSMatt Macy 	}
402c48331dSMatt Macy 
412c48331dSMatt Macy 	zphdl = zpool_open(hdl, pool);
422c48331dSMatt Macy 	if (zphdl == NULL) {
432c48331dSMatt Macy 		libzfs_fini(hdl);
442c48331dSMatt Macy 		return (rv);
452c48331dSMatt Macy 	}
462c48331dSMatt Macy 
472c48331dSMatt Macy 	rv = zpool_get_bootenv(zphdl, &nv);
482c48331dSMatt Macy 	if (rv == 0) {
492c48331dSMatt Macy 		nvlist_t *nvl, *dup;
502c48331dSMatt Macy 
512c48331dSMatt Macy 		if (key != NULL) {
522c48331dSMatt Macy 			rv = nvlist_lookup_nvlist(nv, key, &nvl);
532c48331dSMatt Macy 			if (rv == 0) {
542c48331dSMatt Macy 				rv = nvlist_dup(nvl, &dup, 0);
552c48331dSMatt Macy 				nvlist_free(nv);
562c48331dSMatt Macy 				if (rv == 0)
572c48331dSMatt Macy 					nv = dup;
582c48331dSMatt Macy 				else
592c48331dSMatt Macy 					nv = NULL;
602c48331dSMatt Macy 			} else {
612c48331dSMatt Macy 				nvlist_free(nv);
622c48331dSMatt Macy 				rv = nvlist_alloc(&nv, NV_UNIQUE_NAME, 0);
632c48331dSMatt Macy 			}
642c48331dSMatt Macy 		}
652c48331dSMatt Macy 		*ptr = nv;
662c48331dSMatt Macy 	}
672c48331dSMatt Macy 
682c48331dSMatt Macy 	zpool_close(zphdl);
692c48331dSMatt Macy 	libzfs_fini(hdl);
702c48331dSMatt Macy 	return (rv);
712c48331dSMatt Macy }
722c48331dSMatt Macy 
732c48331dSMatt Macy int
lzbe_nvlist_set(const char * pool,const char * key,void * ptr)742c48331dSMatt Macy lzbe_nvlist_set(const char *pool, const char *key, void *ptr)
752c48331dSMatt Macy {
762c48331dSMatt Macy 	libzfs_handle_t *hdl;
772c48331dSMatt Macy 	zpool_handle_t *zphdl;
782c48331dSMatt Macy 	nvlist_t *nv;
792c48331dSMatt Macy 	uint64_t version;
802c48331dSMatt Macy 	int rv = -1;
812c48331dSMatt Macy 
822c48331dSMatt Macy 	if (pool == NULL || *pool == '\0')
832c48331dSMatt Macy 		return (rv);
842c48331dSMatt Macy 
852c48331dSMatt Macy 	if ((hdl = libzfs_init()) == NULL) {
862c48331dSMatt Macy 		return (rv);
872c48331dSMatt Macy 	}
882c48331dSMatt Macy 
892c48331dSMatt Macy 	zphdl = zpool_open(hdl, pool);
902c48331dSMatt Macy 	if (zphdl == NULL) {
912c48331dSMatt Macy 		libzfs_fini(hdl);
922c48331dSMatt Macy 		return (rv);
932c48331dSMatt Macy 	}
942c48331dSMatt Macy 
952c48331dSMatt Macy 	if (key != NULL) {
962c48331dSMatt Macy 		rv = zpool_get_bootenv(zphdl, &nv);
972c48331dSMatt Macy 		if (rv == 0) {
982c48331dSMatt Macy 			/*
992c48331dSMatt Macy 			 * We got the nvlist, check for version.
1002c48331dSMatt Macy 			 * if version is missing or is not VB_NVLIST,
1012c48331dSMatt Macy 			 * create new list.
1022c48331dSMatt Macy 			 */
1032c48331dSMatt Macy 			rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION,
1042c48331dSMatt Macy 			    &version);
1052c48331dSMatt Macy 			if (rv != 0 || version != VB_NVLIST) {
1062c48331dSMatt Macy 				/* Drop this nvlist */
1072c48331dSMatt Macy 				fnvlist_free(nv);
1082c48331dSMatt Macy 				/* Create and prepare new nvlist */
1092c48331dSMatt Macy 				nv = fnvlist_alloc();
1102c48331dSMatt Macy 				fnvlist_add_uint64(nv, BOOTENV_VERSION,
1112c48331dSMatt Macy 				    VB_NVLIST);
1122c48331dSMatt Macy 			}
1132c48331dSMatt Macy 			rv = nvlist_add_nvlist(nv, key, ptr);
1142c48331dSMatt Macy 			if (rv == 0)
1152c48331dSMatt Macy 				rv = zpool_set_bootenv(zphdl, nv);
1162c48331dSMatt Macy 			nvlist_free(nv);
1172c48331dSMatt Macy 		}
1182c48331dSMatt Macy 	} else {
1192c48331dSMatt Macy 		rv = zpool_set_bootenv(zphdl, ptr);
1202c48331dSMatt Macy 	}
1212c48331dSMatt Macy 
1222c48331dSMatt Macy 	zpool_close(zphdl);
1232c48331dSMatt Macy 	libzfs_fini(hdl);
1242c48331dSMatt Macy 	return (rv);
1252c48331dSMatt Macy }
1262c48331dSMatt Macy 
1272c48331dSMatt Macy /*
1282c48331dSMatt Macy  * free nvlist we got via lzbe_nvlist_get()
1292c48331dSMatt Macy  */
1302c48331dSMatt Macy void
lzbe_nvlist_free(void * ptr)1312c48331dSMatt Macy lzbe_nvlist_free(void *ptr)
1322c48331dSMatt Macy {
1332c48331dSMatt Macy 	nvlist_free(ptr);
1342c48331dSMatt Macy }
1352c48331dSMatt Macy 
1362c48331dSMatt Macy static const char *typenames[] = {
1372c48331dSMatt Macy 	"DATA_TYPE_UNKNOWN",
1382c48331dSMatt Macy 	"DATA_TYPE_BOOLEAN",
1392c48331dSMatt Macy 	"DATA_TYPE_BYTE",
1402c48331dSMatt Macy 	"DATA_TYPE_INT16",
1412c48331dSMatt Macy 	"DATA_TYPE_UINT16",
1422c48331dSMatt Macy 	"DATA_TYPE_INT32",
1432c48331dSMatt Macy 	"DATA_TYPE_UINT32",
1442c48331dSMatt Macy 	"DATA_TYPE_INT64",
1452c48331dSMatt Macy 	"DATA_TYPE_UINT64",
1462c48331dSMatt Macy 	"DATA_TYPE_STRING",
1472c48331dSMatt Macy 	"DATA_TYPE_BYTE_ARRAY",
1482c48331dSMatt Macy 	"DATA_TYPE_INT16_ARRAY",
1492c48331dSMatt Macy 	"DATA_TYPE_UINT16_ARRAY",
1502c48331dSMatt Macy 	"DATA_TYPE_INT32_ARRAY",
1512c48331dSMatt Macy 	"DATA_TYPE_UINT32_ARRAY",
1522c48331dSMatt Macy 	"DATA_TYPE_INT64_ARRAY",
1532c48331dSMatt Macy 	"DATA_TYPE_UINT64_ARRAY",
1542c48331dSMatt Macy 	"DATA_TYPE_STRING_ARRAY",
1552c48331dSMatt Macy 	"DATA_TYPE_HRTIME",
1562c48331dSMatt Macy 	"DATA_TYPE_NVLIST",
1572c48331dSMatt Macy 	"DATA_TYPE_NVLIST_ARRAY",
1582c48331dSMatt Macy 	"DATA_TYPE_BOOLEAN_VALUE",
1592c48331dSMatt Macy 	"DATA_TYPE_INT8",
1602c48331dSMatt Macy 	"DATA_TYPE_UINT8",
1612c48331dSMatt Macy 	"DATA_TYPE_BOOLEAN_ARRAY",
1622c48331dSMatt Macy 	"DATA_TYPE_INT8_ARRAY",
1632c48331dSMatt Macy 	"DATA_TYPE_UINT8_ARRAY"
1642c48331dSMatt Macy };
1652c48331dSMatt Macy 
1662c48331dSMatt Macy static int
nvpair_type_from_name(const char * name)1672c48331dSMatt Macy nvpair_type_from_name(const char *name)
1682c48331dSMatt Macy {
1692c48331dSMatt Macy 	unsigned i;
1702c48331dSMatt Macy 
1712c48331dSMatt Macy 	for (i = 0; i < ARRAY_SIZE(typenames); i++) {
1722c48331dSMatt Macy 		if (strcmp(name, typenames[i]) == 0)
1732c48331dSMatt Macy 			return (i);
1742c48331dSMatt Macy 	}
1752c48331dSMatt Macy 	return (0);
1762c48331dSMatt Macy }
1772c48331dSMatt Macy 
1782c48331dSMatt Macy /*
1792c48331dSMatt Macy  * Add pair defined by key, type and value into nvlist.
1802c48331dSMatt Macy  */
1812c48331dSMatt Macy int
lzbe_add_pair(void * ptr,const char * key,const char * type,void * value,size_t size)1822c48331dSMatt Macy lzbe_add_pair(void *ptr, const char *key, const char *type, void *value,
1832c48331dSMatt Macy     size_t size)
1842c48331dSMatt Macy {
1852c48331dSMatt Macy 	nvlist_t *nv = ptr;
1862c48331dSMatt Macy 	data_type_t dt;
1872c48331dSMatt Macy 	int rv = 0;
1882c48331dSMatt Macy 
1892c48331dSMatt Macy 	if (ptr == NULL || key == NULL || value == NULL)
1902c48331dSMatt Macy 		return (rv);
1912c48331dSMatt Macy 
1922c48331dSMatt Macy 	if (type == NULL)
1932c48331dSMatt Macy 		type = "DATA_TYPE_STRING";
1942c48331dSMatt Macy 	dt = nvpair_type_from_name(type);
1952c48331dSMatt Macy 	if (dt == DATA_TYPE_UNKNOWN)
1962c48331dSMatt Macy 		return (EINVAL);
1972c48331dSMatt Macy 
1982c48331dSMatt Macy 	switch (dt) {
1992c48331dSMatt Macy 	case DATA_TYPE_BYTE:
2002c48331dSMatt Macy 		if (size != sizeof (uint8_t)) {
2012c48331dSMatt Macy 			rv = EINVAL;
2022c48331dSMatt Macy 			break;
2032c48331dSMatt Macy 		}
2042c48331dSMatt Macy 		rv = nvlist_add_byte(nv, key, *(uint8_t *)value);
2052c48331dSMatt Macy 		break;
2062c48331dSMatt Macy 
2072c48331dSMatt Macy 	case DATA_TYPE_INT16:
2082c48331dSMatt Macy 		if (size != sizeof (int16_t)) {
2092c48331dSMatt Macy 			rv = EINVAL;
2102c48331dSMatt Macy 			break;
2112c48331dSMatt Macy 		}
2122c48331dSMatt Macy 		rv = nvlist_add_int16(nv, key, *(int16_t *)value);
2132c48331dSMatt Macy 		break;
2142c48331dSMatt Macy 
2152c48331dSMatt Macy 	case DATA_TYPE_UINT16:
2162c48331dSMatt Macy 		if (size != sizeof (uint16_t)) {
2172c48331dSMatt Macy 			rv = EINVAL;
2182c48331dSMatt Macy 			break;
2192c48331dSMatt Macy 		}
2202c48331dSMatt Macy 		rv = nvlist_add_uint16(nv, key, *(uint16_t *)value);
2212c48331dSMatt Macy 		break;
2222c48331dSMatt Macy 
2232c48331dSMatt Macy 	case DATA_TYPE_INT32:
2242c48331dSMatt Macy 		if (size != sizeof (int32_t)) {
2252c48331dSMatt Macy 			rv = EINVAL;
2262c48331dSMatt Macy 			break;
2272c48331dSMatt Macy 		}
2282c48331dSMatt Macy 		rv = nvlist_add_int32(nv, key, *(int32_t *)value);
2292c48331dSMatt Macy 		break;
2302c48331dSMatt Macy 
2312c48331dSMatt Macy 	case DATA_TYPE_UINT32:
2322c48331dSMatt Macy 		if (size != sizeof (uint32_t)) {
2332c48331dSMatt Macy 			rv = EINVAL;
2342c48331dSMatt Macy 			break;
2352c48331dSMatt Macy 		}
2362c48331dSMatt Macy 		rv = nvlist_add_uint32(nv, key, *(uint32_t *)value);
2372c48331dSMatt Macy 		break;
2382c48331dSMatt Macy 
2392c48331dSMatt Macy 	case DATA_TYPE_INT64:
2402c48331dSMatt Macy 		if (size != sizeof (int64_t)) {
2412c48331dSMatt Macy 			rv = EINVAL;
2422c48331dSMatt Macy 			break;
2432c48331dSMatt Macy 		}
2442c48331dSMatt Macy 		rv = nvlist_add_int64(nv, key, *(int64_t *)value);
2452c48331dSMatt Macy 		break;
2462c48331dSMatt Macy 
2472c48331dSMatt Macy 	case DATA_TYPE_UINT64:
2482c48331dSMatt Macy 		if (size != sizeof (uint64_t)) {
2492c48331dSMatt Macy 			rv = EINVAL;
2502c48331dSMatt Macy 			break;
2512c48331dSMatt Macy 		}
2522c48331dSMatt Macy 		rv = nvlist_add_uint64(nv, key, *(uint64_t *)value);
2532c48331dSMatt Macy 		break;
2542c48331dSMatt Macy 
2552c48331dSMatt Macy 	case DATA_TYPE_STRING:
2562c48331dSMatt Macy 		rv = nvlist_add_string(nv, key, value);
2572c48331dSMatt Macy 		break;
2582c48331dSMatt Macy 
2592c48331dSMatt Macy 	case DATA_TYPE_BYTE_ARRAY:
2602c48331dSMatt Macy 		rv = nvlist_add_byte_array(nv, key, value, size);
2612c48331dSMatt Macy 		break;
2622c48331dSMatt Macy 
2632c48331dSMatt Macy 	case DATA_TYPE_INT16_ARRAY:
2642c48331dSMatt Macy 		rv = nvlist_add_int16_array(nv, key, value, size);
2652c48331dSMatt Macy 		break;
2662c48331dSMatt Macy 
2672c48331dSMatt Macy 	case DATA_TYPE_UINT16_ARRAY:
2682c48331dSMatt Macy 		rv = nvlist_add_uint16_array(nv, key, value, size);
2692c48331dSMatt Macy 		break;
2702c48331dSMatt Macy 
2712c48331dSMatt Macy 	case DATA_TYPE_INT32_ARRAY:
2722c48331dSMatt Macy 		rv = nvlist_add_int32_array(nv, key, value, size);
2732c48331dSMatt Macy 		break;
2742c48331dSMatt Macy 
2752c48331dSMatt Macy 	case DATA_TYPE_UINT32_ARRAY:
2762c48331dSMatt Macy 		rv = nvlist_add_uint32_array(nv, key, value, size);
2772c48331dSMatt Macy 		break;
2782c48331dSMatt Macy 
2792c48331dSMatt Macy 	case DATA_TYPE_INT64_ARRAY:
2802c48331dSMatt Macy 		rv = nvlist_add_int64_array(nv, key, value, size);
2812c48331dSMatt Macy 		break;
2822c48331dSMatt Macy 
2832c48331dSMatt Macy 	case DATA_TYPE_UINT64_ARRAY:
2842c48331dSMatt Macy 		rv = nvlist_add_uint64_array(nv, key, value, size);
2852c48331dSMatt Macy 		break;
2862c48331dSMatt Macy 
2872c48331dSMatt Macy 	case DATA_TYPE_STRING_ARRAY:
2882c48331dSMatt Macy 		rv = nvlist_add_string_array(nv, key, value, size);
2892c48331dSMatt Macy 		break;
2902c48331dSMatt Macy 
2912c48331dSMatt Macy 	case DATA_TYPE_NVLIST:
2922c48331dSMatt Macy 		rv = nvlist_add_nvlist(nv, key, (nvlist_t *)value);
2932c48331dSMatt Macy 		break;
2942c48331dSMatt Macy 
2952c48331dSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY:
296*681ce946SMartin Matuska 		rv = nvlist_add_nvlist_array(nv, key, (const nvlist_t **)value,
297*681ce946SMartin Matuska 		    size);
2982c48331dSMatt Macy 		break;
2992c48331dSMatt Macy 
3002c48331dSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
3012c48331dSMatt Macy 		if (size != sizeof (boolean_t)) {
3022c48331dSMatt Macy 			rv = EINVAL;
3032c48331dSMatt Macy 			break;
3042c48331dSMatt Macy 		}
3052c48331dSMatt Macy 		rv = nvlist_add_boolean_value(nv, key, *(boolean_t *)value);
3062c48331dSMatt Macy 		break;
3072c48331dSMatt Macy 
3082c48331dSMatt Macy 	case DATA_TYPE_INT8:
3092c48331dSMatt Macy 		if (size != sizeof (int8_t)) {
3102c48331dSMatt Macy 			rv = EINVAL;
3112c48331dSMatt Macy 			break;
3122c48331dSMatt Macy 		}
3132c48331dSMatt Macy 		rv = nvlist_add_int8(nv, key, *(int8_t *)value);
3142c48331dSMatt Macy 		break;
3152c48331dSMatt Macy 
3162c48331dSMatt Macy 	case DATA_TYPE_UINT8:
3172c48331dSMatt Macy 		if (size != sizeof (uint8_t)) {
3182c48331dSMatt Macy 			rv = EINVAL;
3192c48331dSMatt Macy 			break;
3202c48331dSMatt Macy 		}
3212c48331dSMatt Macy 		rv = nvlist_add_uint8(nv, key, *(uint8_t *)value);
3222c48331dSMatt Macy 		break;
3232c48331dSMatt Macy 
3242c48331dSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY:
3252c48331dSMatt Macy 		rv = nvlist_add_boolean_array(nv, key, value, size);
3262c48331dSMatt Macy 		break;
3272c48331dSMatt Macy 
3282c48331dSMatt Macy 	case DATA_TYPE_INT8_ARRAY:
3292c48331dSMatt Macy 		rv = nvlist_add_int8_array(nv, key, value, size);
3302c48331dSMatt Macy 		break;
3312c48331dSMatt Macy 
3322c48331dSMatt Macy 	case DATA_TYPE_UINT8_ARRAY:
3332c48331dSMatt Macy 		rv = nvlist_add_uint8_array(nv, key, value, size);
3342c48331dSMatt Macy 		break;
3352c48331dSMatt Macy 
3362c48331dSMatt Macy 	default:
3372c48331dSMatt Macy 		return (ENOTSUP);
3382c48331dSMatt Macy 	}
3392c48331dSMatt Macy 
3402c48331dSMatt Macy 	return (rv);
3412c48331dSMatt Macy }
3422c48331dSMatt Macy 
3432c48331dSMatt Macy int
lzbe_remove_pair(void * ptr,const char * key)3442c48331dSMatt Macy lzbe_remove_pair(void *ptr, const char *key)
3452c48331dSMatt Macy {
3462c48331dSMatt Macy 
3472c48331dSMatt Macy 	return (nvlist_remove_all(ptr, key));
3482c48331dSMatt Macy }
349