mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	 9530eb64e0
			
		
	
	
		9530eb64e0
		
	
	
	
	
		
			
			Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris <robn@despairlabs.com> Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
		
			
				
	
	
		
			350 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: CDDL-1.0
 | |
| /*
 | |
|  * This file and its contents are supplied under the terms of the
 | |
|  * Common Development and Distribution License ("CDDL"), version 1.0.
 | |
|  * You may only use this file in accordance with the terms of version
 | |
|  * 1.0 of the CDDL.
 | |
|  *
 | |
|  * A full copy of the text of the CDDL should have accompanied this
 | |
|  * source.  A copy of the CDDL is also available via the Internet at
 | |
|  * http://www.illumos.org/license/CDDL.
 | |
|  */
 | |
| /*
 | |
|  * Copyright 2020 Toomas Soome <tsoome@me.com>
 | |
|  */
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <string.h>
 | |
| #include <libzfs.h>
 | |
| #include <libzfsbootenv.h>
 | |
| #include <sys/zfs_bootenv.h>
 | |
| #include <sys/vdev_impl.h>
 | |
| 
 | |
| /*
 | |
|  * Get or create nvlist. If key is not NULL, get nvlist from bootenv,
 | |
|  * otherwise return bootenv.
 | |
|  */
 | |
| int
 | |
| lzbe_nvlist_get(const char *pool, const char *key, void **ptr)
 | |
| {
 | |
| 	libzfs_handle_t *hdl;
 | |
| 	zpool_handle_t *zphdl;
 | |
| 	nvlist_t *nv;
 | |
| 	int rv = -1;
 | |
| 
 | |
| 	if (pool == NULL || *pool == '\0')
 | |
| 		return (rv);
 | |
| 
 | |
| 	if ((hdl = libzfs_init()) == NULL) {
 | |
| 		return (rv);
 | |
| 	}
 | |
| 
 | |
| 	zphdl = zpool_open(hdl, pool);
 | |
| 	if (zphdl == NULL) {
 | |
| 		libzfs_fini(hdl);
 | |
| 		return (rv);
 | |
| 	}
 | |
| 
 | |
| 	rv = zpool_get_bootenv(zphdl, &nv);
 | |
| 	if (rv == 0) {
 | |
| 		nvlist_t *nvl, *dup;
 | |
| 
 | |
| 		if (key != NULL) {
 | |
| 			rv = nvlist_lookup_nvlist(nv, key, &nvl);
 | |
| 			if (rv == 0) {
 | |
| 				rv = nvlist_dup(nvl, &dup, 0);
 | |
| 				nvlist_free(nv);
 | |
| 				if (rv == 0)
 | |
| 					nv = dup;
 | |
| 				else
 | |
| 					nv = NULL;
 | |
| 			} else {
 | |
| 				nvlist_free(nv);
 | |
| 				rv = nvlist_alloc(&nv, NV_UNIQUE_NAME, 0);
 | |
| 			}
 | |
| 		}
 | |
| 		*ptr = nv;
 | |
| 	}
 | |
| 
 | |
| 	zpool_close(zphdl);
 | |
| 	libzfs_fini(hdl);
 | |
| 	return (rv);
 | |
| }
 | |
| 
 | |
| int
 | |
| lzbe_nvlist_set(const char *pool, const char *key, void *ptr)
 | |
| {
 | |
| 	libzfs_handle_t *hdl;
 | |
| 	zpool_handle_t *zphdl;
 | |
| 	nvlist_t *nv;
 | |
| 	uint64_t version;
 | |
| 	int rv = -1;
 | |
| 
 | |
| 	if (pool == NULL || *pool == '\0')
 | |
| 		return (rv);
 | |
| 
 | |
| 	if ((hdl = libzfs_init()) == NULL) {
 | |
| 		return (rv);
 | |
| 	}
 | |
| 
 | |
| 	zphdl = zpool_open(hdl, pool);
 | |
| 	if (zphdl == NULL) {
 | |
| 		libzfs_fini(hdl);
 | |
| 		return (rv);
 | |
| 	}
 | |
| 
 | |
| 	if (key != NULL) {
 | |
| 		rv = zpool_get_bootenv(zphdl, &nv);
 | |
| 		if (rv == 0) {
 | |
| 			/*
 | |
| 			 * We got the nvlist, check for version.
 | |
| 			 * if version is missing or is not VB_NVLIST,
 | |
| 			 * create new list.
 | |
| 			 */
 | |
| 			rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION,
 | |
| 			    &version);
 | |
| 			if (rv != 0 || version != VB_NVLIST) {
 | |
| 				/* Drop this nvlist */
 | |
| 				fnvlist_free(nv);
 | |
| 				/* Create and prepare new nvlist */
 | |
| 				nv = fnvlist_alloc();
 | |
| 				fnvlist_add_uint64(nv, BOOTENV_VERSION,
 | |
| 				    VB_NVLIST);
 | |
| 			}
 | |
| 			rv = nvlist_add_nvlist(nv, key, ptr);
 | |
| 			if (rv == 0)
 | |
| 				rv = zpool_set_bootenv(zphdl, nv);
 | |
| 			nvlist_free(nv);
 | |
| 		}
 | |
| 	} else {
 | |
| 		rv = zpool_set_bootenv(zphdl, ptr);
 | |
| 	}
 | |
| 
 | |
| 	zpool_close(zphdl);
 | |
| 	libzfs_fini(hdl);
 | |
| 	return (rv);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * free nvlist we got via lzbe_nvlist_get()
 | |
|  */
 | |
| void
 | |
| lzbe_nvlist_free(void *ptr)
 | |
| {
 | |
| 	nvlist_free(ptr);
 | |
| }
 | |
| 
 | |
| static const char *typenames[] = {
 | |
| 	"DATA_TYPE_UNKNOWN",
 | |
| 	"DATA_TYPE_BOOLEAN",
 | |
| 	"DATA_TYPE_BYTE",
 | |
| 	"DATA_TYPE_INT16",
 | |
| 	"DATA_TYPE_UINT16",
 | |
| 	"DATA_TYPE_INT32",
 | |
| 	"DATA_TYPE_UINT32",
 | |
| 	"DATA_TYPE_INT64",
 | |
| 	"DATA_TYPE_UINT64",
 | |
| 	"DATA_TYPE_STRING",
 | |
| 	"DATA_TYPE_BYTE_ARRAY",
 | |
| 	"DATA_TYPE_INT16_ARRAY",
 | |
| 	"DATA_TYPE_UINT16_ARRAY",
 | |
| 	"DATA_TYPE_INT32_ARRAY",
 | |
| 	"DATA_TYPE_UINT32_ARRAY",
 | |
| 	"DATA_TYPE_INT64_ARRAY",
 | |
| 	"DATA_TYPE_UINT64_ARRAY",
 | |
| 	"DATA_TYPE_STRING_ARRAY",
 | |
| 	"DATA_TYPE_HRTIME",
 | |
| 	"DATA_TYPE_NVLIST",
 | |
| 	"DATA_TYPE_NVLIST_ARRAY",
 | |
| 	"DATA_TYPE_BOOLEAN_VALUE",
 | |
| 	"DATA_TYPE_INT8",
 | |
| 	"DATA_TYPE_UINT8",
 | |
| 	"DATA_TYPE_BOOLEAN_ARRAY",
 | |
| 	"DATA_TYPE_INT8_ARRAY",
 | |
| 	"DATA_TYPE_UINT8_ARRAY"
 | |
| };
 | |
| 
 | |
| static int
 | |
| nvpair_type_from_name(const char *name)
 | |
| {
 | |
| 	unsigned i;
 | |
| 
 | |
| 	for (i = 0; i < ARRAY_SIZE(typenames); i++) {
 | |
| 		if (strcmp(name, typenames[i]) == 0)
 | |
| 			return (i);
 | |
| 	}
 | |
| 	return (0);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Add pair defined by key, type and value into nvlist.
 | |
|  */
 | |
| int
 | |
| lzbe_add_pair(void *ptr, const char *key, const char *type, void *value,
 | |
|     size_t size)
 | |
| {
 | |
| 	nvlist_t *nv = ptr;
 | |
| 	data_type_t dt;
 | |
| 	int rv = 0;
 | |
| 
 | |
| 	if (ptr == NULL || key == NULL || value == NULL)
 | |
| 		return (rv);
 | |
| 
 | |
| 	if (type == NULL)
 | |
| 		type = "DATA_TYPE_STRING";
 | |
| 	dt = nvpair_type_from_name(type);
 | |
| 	if (dt == DATA_TYPE_UNKNOWN)
 | |
| 		return (EINVAL);
 | |
| 
 | |
| 	switch (dt) {
 | |
| 	case DATA_TYPE_BYTE:
 | |
| 		if (size != sizeof (uint8_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_byte(nv, key, *(uint8_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT16:
 | |
| 		if (size != sizeof (int16_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_int16(nv, key, *(int16_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT16:
 | |
| 		if (size != sizeof (uint16_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_uint16(nv, key, *(uint16_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT32:
 | |
| 		if (size != sizeof (int32_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_int32(nv, key, *(int32_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT32:
 | |
| 		if (size != sizeof (uint32_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_uint32(nv, key, *(uint32_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT64:
 | |
| 		if (size != sizeof (int64_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_int64(nv, key, *(int64_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT64:
 | |
| 		if (size != sizeof (uint64_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_uint64(nv, key, *(uint64_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_STRING:
 | |
| 		rv = nvlist_add_string(nv, key, value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_BYTE_ARRAY:
 | |
| 		rv = nvlist_add_byte_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT16_ARRAY:
 | |
| 		rv = nvlist_add_int16_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT16_ARRAY:
 | |
| 		rv = nvlist_add_uint16_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT32_ARRAY:
 | |
| 		rv = nvlist_add_int32_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT32_ARRAY:
 | |
| 		rv = nvlist_add_uint32_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT64_ARRAY:
 | |
| 		rv = nvlist_add_int64_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT64_ARRAY:
 | |
| 		rv = nvlist_add_uint64_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_STRING_ARRAY:
 | |
| 		rv = nvlist_add_string_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_NVLIST:
 | |
| 		rv = nvlist_add_nvlist(nv, key, (nvlist_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_NVLIST_ARRAY:
 | |
| 		rv = nvlist_add_nvlist_array(nv, key, (const nvlist_t **)value,
 | |
| 		    size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_BOOLEAN_VALUE:
 | |
| 		if (size != sizeof (boolean_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_boolean_value(nv, key, *(boolean_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT8:
 | |
| 		if (size != sizeof (int8_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_int8(nv, key, *(int8_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT8:
 | |
| 		if (size != sizeof (uint8_t)) {
 | |
| 			rv = EINVAL;
 | |
| 			break;
 | |
| 		}
 | |
| 		rv = nvlist_add_uint8(nv, key, *(uint8_t *)value);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_BOOLEAN_ARRAY:
 | |
| 		rv = nvlist_add_boolean_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_INT8_ARRAY:
 | |
| 		rv = nvlist_add_int8_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	case DATA_TYPE_UINT8_ARRAY:
 | |
| 		rv = nvlist_add_uint8_array(nv, key, value, size);
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		return (ENOTSUP);
 | |
| 	}
 | |
| 
 | |
| 	return (rv);
 | |
| }
 | |
| 
 | |
| int
 | |
| lzbe_remove_pair(void *ptr, const char *key)
 | |
| {
 | |
| 
 | |
| 	return (nvlist_remove_all(ptr, key));
 | |
| }
 |