xref: /freebsd-src/sys/contrib/openzfs/lib/libzfsbootenv/lzbe_pair.c (revision 2c48331d28f16c0efce5a72a81e7d71668c4a158)
1*2c48331dSMatt Macy /*
2*2c48331dSMatt Macy  * This file and its contents are supplied under the terms of the
3*2c48331dSMatt Macy  * Common Development and Distribution License ("CDDL"), version 1.0.
4*2c48331dSMatt Macy  * You may only use this file in accordance with the terms of version
5*2c48331dSMatt Macy  * 1.0 of the CDDL.
6*2c48331dSMatt Macy  *
7*2c48331dSMatt Macy  * A full copy of the text of the CDDL should have accompanied this
8*2c48331dSMatt Macy  * source.  A copy of the CDDL is also available via the Internet at
9*2c48331dSMatt Macy  * http://www.illumos.org/license/CDDL.
10*2c48331dSMatt Macy  */
11*2c48331dSMatt Macy /*
12*2c48331dSMatt Macy  * Copyright 2020 Toomas Soome <tsoome@me.com>
13*2c48331dSMatt Macy  */
14*2c48331dSMatt Macy 
15*2c48331dSMatt Macy #include <sys/types.h>
16*2c48331dSMatt Macy #include <string.h>
17*2c48331dSMatt Macy #include <libzfs.h>
18*2c48331dSMatt Macy #include <libzfsbootenv.h>
19*2c48331dSMatt Macy #include <sys/zfs_bootenv.h>
20*2c48331dSMatt Macy #include <sys/vdev_impl.h>
21*2c48331dSMatt Macy 
22*2c48331dSMatt Macy /*
23*2c48331dSMatt Macy  * Get or create nvlist. If key is not NULL, get nvlist from bootenv,
24*2c48331dSMatt Macy  * otherwise return bootenv.
25*2c48331dSMatt Macy  */
26*2c48331dSMatt Macy int
27*2c48331dSMatt Macy lzbe_nvlist_get(const char *pool, const char *key, void **ptr)
28*2c48331dSMatt Macy {
29*2c48331dSMatt Macy 	libzfs_handle_t *hdl;
30*2c48331dSMatt Macy 	zpool_handle_t *zphdl;
31*2c48331dSMatt Macy 	nvlist_t *nv;
32*2c48331dSMatt Macy 	int rv = -1;
33*2c48331dSMatt Macy 
34*2c48331dSMatt Macy 	if (pool == NULL || *pool == '\0')
35*2c48331dSMatt Macy 		return (rv);
36*2c48331dSMatt Macy 
37*2c48331dSMatt Macy 	if ((hdl = libzfs_init()) == NULL) {
38*2c48331dSMatt Macy 		return (rv);
39*2c48331dSMatt Macy 	}
40*2c48331dSMatt Macy 
41*2c48331dSMatt Macy 	zphdl = zpool_open(hdl, pool);
42*2c48331dSMatt Macy 	if (zphdl == NULL) {
43*2c48331dSMatt Macy 		libzfs_fini(hdl);
44*2c48331dSMatt Macy 		return (rv);
45*2c48331dSMatt Macy 	}
46*2c48331dSMatt Macy 
47*2c48331dSMatt Macy 	rv = zpool_get_bootenv(zphdl, &nv);
48*2c48331dSMatt Macy 	if (rv == 0) {
49*2c48331dSMatt Macy 		nvlist_t *nvl, *dup;
50*2c48331dSMatt Macy 
51*2c48331dSMatt Macy 		if (key != NULL) {
52*2c48331dSMatt Macy 			rv = nvlist_lookup_nvlist(nv, key, &nvl);
53*2c48331dSMatt Macy 			if (rv == 0) {
54*2c48331dSMatt Macy 				rv = nvlist_dup(nvl, &dup, 0);
55*2c48331dSMatt Macy 				nvlist_free(nv);
56*2c48331dSMatt Macy 				if (rv == 0)
57*2c48331dSMatt Macy 					nv = dup;
58*2c48331dSMatt Macy 				else
59*2c48331dSMatt Macy 					nv = NULL;
60*2c48331dSMatt Macy 			} else {
61*2c48331dSMatt Macy 				nvlist_free(nv);
62*2c48331dSMatt Macy 				rv = nvlist_alloc(&nv, NV_UNIQUE_NAME, 0);
63*2c48331dSMatt Macy 			}
64*2c48331dSMatt Macy 		}
65*2c48331dSMatt Macy 		*ptr = nv;
66*2c48331dSMatt Macy 	}
67*2c48331dSMatt Macy 
68*2c48331dSMatt Macy 	zpool_close(zphdl);
69*2c48331dSMatt Macy 	libzfs_fini(hdl);
70*2c48331dSMatt Macy 	return (rv);
71*2c48331dSMatt Macy }
72*2c48331dSMatt Macy 
73*2c48331dSMatt Macy int
74*2c48331dSMatt Macy lzbe_nvlist_set(const char *pool, const char *key, void *ptr)
75*2c48331dSMatt Macy {
76*2c48331dSMatt Macy 	libzfs_handle_t *hdl;
77*2c48331dSMatt Macy 	zpool_handle_t *zphdl;
78*2c48331dSMatt Macy 	nvlist_t *nv;
79*2c48331dSMatt Macy 	uint64_t version;
80*2c48331dSMatt Macy 	int rv = -1;
81*2c48331dSMatt Macy 
82*2c48331dSMatt Macy 	if (pool == NULL || *pool == '\0')
83*2c48331dSMatt Macy 		return (rv);
84*2c48331dSMatt Macy 
85*2c48331dSMatt Macy 	if ((hdl = libzfs_init()) == NULL) {
86*2c48331dSMatt Macy 		return (rv);
87*2c48331dSMatt Macy 	}
88*2c48331dSMatt Macy 
89*2c48331dSMatt Macy 	zphdl = zpool_open(hdl, pool);
90*2c48331dSMatt Macy 	if (zphdl == NULL) {
91*2c48331dSMatt Macy 		libzfs_fini(hdl);
92*2c48331dSMatt Macy 		return (rv);
93*2c48331dSMatt Macy 	}
94*2c48331dSMatt Macy 
95*2c48331dSMatt Macy 	if (key != NULL) {
96*2c48331dSMatt Macy 		rv = zpool_get_bootenv(zphdl, &nv);
97*2c48331dSMatt Macy 		if (rv == 0) {
98*2c48331dSMatt Macy 			/*
99*2c48331dSMatt Macy 			 * We got the nvlist, check for version.
100*2c48331dSMatt Macy 			 * if version is missing or is not VB_NVLIST,
101*2c48331dSMatt Macy 			 * create new list.
102*2c48331dSMatt Macy 			 */
103*2c48331dSMatt Macy 			rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION,
104*2c48331dSMatt Macy 			    &version);
105*2c48331dSMatt Macy 			if (rv != 0 || version != VB_NVLIST) {
106*2c48331dSMatt Macy 				/* Drop this nvlist */
107*2c48331dSMatt Macy 				fnvlist_free(nv);
108*2c48331dSMatt Macy 				/* Create and prepare new nvlist */
109*2c48331dSMatt Macy 				nv = fnvlist_alloc();
110*2c48331dSMatt Macy 				fnvlist_add_uint64(nv, BOOTENV_VERSION,
111*2c48331dSMatt Macy 				    VB_NVLIST);
112*2c48331dSMatt Macy 			}
113*2c48331dSMatt Macy 			rv = nvlist_add_nvlist(nv, key, ptr);
114*2c48331dSMatt Macy 			if (rv == 0)
115*2c48331dSMatt Macy 				rv = zpool_set_bootenv(zphdl, nv);
116*2c48331dSMatt Macy 			nvlist_free(nv);
117*2c48331dSMatt Macy 		}
118*2c48331dSMatt Macy 	} else {
119*2c48331dSMatt Macy 		rv = zpool_set_bootenv(zphdl, ptr);
120*2c48331dSMatt Macy 	}
121*2c48331dSMatt Macy 
122*2c48331dSMatt Macy 	zpool_close(zphdl);
123*2c48331dSMatt Macy 	libzfs_fini(hdl);
124*2c48331dSMatt Macy 	return (rv);
125*2c48331dSMatt Macy }
126*2c48331dSMatt Macy 
127*2c48331dSMatt Macy /*
128*2c48331dSMatt Macy  * free nvlist we got via lzbe_nvlist_get()
129*2c48331dSMatt Macy  */
130*2c48331dSMatt Macy void
131*2c48331dSMatt Macy lzbe_nvlist_free(void *ptr)
132*2c48331dSMatt Macy {
133*2c48331dSMatt Macy 	nvlist_free(ptr);
134*2c48331dSMatt Macy }
135*2c48331dSMatt Macy 
136*2c48331dSMatt Macy static const char *typenames[] = {
137*2c48331dSMatt Macy 	"DATA_TYPE_UNKNOWN",
138*2c48331dSMatt Macy 	"DATA_TYPE_BOOLEAN",
139*2c48331dSMatt Macy 	"DATA_TYPE_BYTE",
140*2c48331dSMatt Macy 	"DATA_TYPE_INT16",
141*2c48331dSMatt Macy 	"DATA_TYPE_UINT16",
142*2c48331dSMatt Macy 	"DATA_TYPE_INT32",
143*2c48331dSMatt Macy 	"DATA_TYPE_UINT32",
144*2c48331dSMatt Macy 	"DATA_TYPE_INT64",
145*2c48331dSMatt Macy 	"DATA_TYPE_UINT64",
146*2c48331dSMatt Macy 	"DATA_TYPE_STRING",
147*2c48331dSMatt Macy 	"DATA_TYPE_BYTE_ARRAY",
148*2c48331dSMatt Macy 	"DATA_TYPE_INT16_ARRAY",
149*2c48331dSMatt Macy 	"DATA_TYPE_UINT16_ARRAY",
150*2c48331dSMatt Macy 	"DATA_TYPE_INT32_ARRAY",
151*2c48331dSMatt Macy 	"DATA_TYPE_UINT32_ARRAY",
152*2c48331dSMatt Macy 	"DATA_TYPE_INT64_ARRAY",
153*2c48331dSMatt Macy 	"DATA_TYPE_UINT64_ARRAY",
154*2c48331dSMatt Macy 	"DATA_TYPE_STRING_ARRAY",
155*2c48331dSMatt Macy 	"DATA_TYPE_HRTIME",
156*2c48331dSMatt Macy 	"DATA_TYPE_NVLIST",
157*2c48331dSMatt Macy 	"DATA_TYPE_NVLIST_ARRAY",
158*2c48331dSMatt Macy 	"DATA_TYPE_BOOLEAN_VALUE",
159*2c48331dSMatt Macy 	"DATA_TYPE_INT8",
160*2c48331dSMatt Macy 	"DATA_TYPE_UINT8",
161*2c48331dSMatt Macy 	"DATA_TYPE_BOOLEAN_ARRAY",
162*2c48331dSMatt Macy 	"DATA_TYPE_INT8_ARRAY",
163*2c48331dSMatt Macy 	"DATA_TYPE_UINT8_ARRAY"
164*2c48331dSMatt Macy };
165*2c48331dSMatt Macy 
166*2c48331dSMatt Macy static int
167*2c48331dSMatt Macy nvpair_type_from_name(const char *name)
168*2c48331dSMatt Macy {
169*2c48331dSMatt Macy 	unsigned i;
170*2c48331dSMatt Macy 
171*2c48331dSMatt Macy 	for (i = 0; i < ARRAY_SIZE(typenames); i++) {
172*2c48331dSMatt Macy 		if (strcmp(name, typenames[i]) == 0)
173*2c48331dSMatt Macy 			return (i);
174*2c48331dSMatt Macy 	}
175*2c48331dSMatt Macy 	return (0);
176*2c48331dSMatt Macy }
177*2c48331dSMatt Macy 
178*2c48331dSMatt Macy /*
179*2c48331dSMatt Macy  * Add pair defined by key, type and value into nvlist.
180*2c48331dSMatt Macy  */
181*2c48331dSMatt Macy int
182*2c48331dSMatt Macy lzbe_add_pair(void *ptr, const char *key, const char *type, void *value,
183*2c48331dSMatt Macy     size_t size)
184*2c48331dSMatt Macy {
185*2c48331dSMatt Macy 	nvlist_t *nv = ptr;
186*2c48331dSMatt Macy 	data_type_t dt;
187*2c48331dSMatt Macy 	int rv = 0;
188*2c48331dSMatt Macy 
189*2c48331dSMatt Macy 	if (ptr == NULL || key == NULL || value == NULL)
190*2c48331dSMatt Macy 		return (rv);
191*2c48331dSMatt Macy 
192*2c48331dSMatt Macy 	if (type == NULL)
193*2c48331dSMatt Macy 		type = "DATA_TYPE_STRING";
194*2c48331dSMatt Macy 	dt = nvpair_type_from_name(type);
195*2c48331dSMatt Macy 	if (dt == DATA_TYPE_UNKNOWN)
196*2c48331dSMatt Macy 		return (EINVAL);
197*2c48331dSMatt Macy 
198*2c48331dSMatt Macy 	switch (dt) {
199*2c48331dSMatt Macy 	case DATA_TYPE_BYTE:
200*2c48331dSMatt Macy 		if (size != sizeof (uint8_t)) {
201*2c48331dSMatt Macy 			rv = EINVAL;
202*2c48331dSMatt Macy 			break;
203*2c48331dSMatt Macy 		}
204*2c48331dSMatt Macy 		rv = nvlist_add_byte(nv, key, *(uint8_t *)value);
205*2c48331dSMatt Macy 		break;
206*2c48331dSMatt Macy 
207*2c48331dSMatt Macy 	case DATA_TYPE_INT16:
208*2c48331dSMatt Macy 		if (size != sizeof (int16_t)) {
209*2c48331dSMatt Macy 			rv = EINVAL;
210*2c48331dSMatt Macy 			break;
211*2c48331dSMatt Macy 		}
212*2c48331dSMatt Macy 		rv = nvlist_add_int16(nv, key, *(int16_t *)value);
213*2c48331dSMatt Macy 		break;
214*2c48331dSMatt Macy 
215*2c48331dSMatt Macy 	case DATA_TYPE_UINT16:
216*2c48331dSMatt Macy 		if (size != sizeof (uint16_t)) {
217*2c48331dSMatt Macy 			rv = EINVAL;
218*2c48331dSMatt Macy 			break;
219*2c48331dSMatt Macy 		}
220*2c48331dSMatt Macy 		rv = nvlist_add_uint16(nv, key, *(uint16_t *)value);
221*2c48331dSMatt Macy 		break;
222*2c48331dSMatt Macy 
223*2c48331dSMatt Macy 	case DATA_TYPE_INT32:
224*2c48331dSMatt Macy 		if (size != sizeof (int32_t)) {
225*2c48331dSMatt Macy 			rv = EINVAL;
226*2c48331dSMatt Macy 			break;
227*2c48331dSMatt Macy 		}
228*2c48331dSMatt Macy 		rv = nvlist_add_int32(nv, key, *(int32_t *)value);
229*2c48331dSMatt Macy 		break;
230*2c48331dSMatt Macy 
231*2c48331dSMatt Macy 	case DATA_TYPE_UINT32:
232*2c48331dSMatt Macy 		if (size != sizeof (uint32_t)) {
233*2c48331dSMatt Macy 			rv = EINVAL;
234*2c48331dSMatt Macy 			break;
235*2c48331dSMatt Macy 		}
236*2c48331dSMatt Macy 		rv = nvlist_add_uint32(nv, key, *(uint32_t *)value);
237*2c48331dSMatt Macy 		break;
238*2c48331dSMatt Macy 
239*2c48331dSMatt Macy 	case DATA_TYPE_INT64:
240*2c48331dSMatt Macy 		if (size != sizeof (int64_t)) {
241*2c48331dSMatt Macy 			rv = EINVAL;
242*2c48331dSMatt Macy 			break;
243*2c48331dSMatt Macy 		}
244*2c48331dSMatt Macy 		rv = nvlist_add_int64(nv, key, *(int64_t *)value);
245*2c48331dSMatt Macy 		break;
246*2c48331dSMatt Macy 
247*2c48331dSMatt Macy 	case DATA_TYPE_UINT64:
248*2c48331dSMatt Macy 		if (size != sizeof (uint64_t)) {
249*2c48331dSMatt Macy 			rv = EINVAL;
250*2c48331dSMatt Macy 			break;
251*2c48331dSMatt Macy 		}
252*2c48331dSMatt Macy 		rv = nvlist_add_uint64(nv, key, *(uint64_t *)value);
253*2c48331dSMatt Macy 		break;
254*2c48331dSMatt Macy 
255*2c48331dSMatt Macy 	case DATA_TYPE_STRING:
256*2c48331dSMatt Macy 		rv = nvlist_add_string(nv, key, value);
257*2c48331dSMatt Macy 		break;
258*2c48331dSMatt Macy 
259*2c48331dSMatt Macy 	case DATA_TYPE_BYTE_ARRAY:
260*2c48331dSMatt Macy 		rv = nvlist_add_byte_array(nv, key, value, size);
261*2c48331dSMatt Macy 		break;
262*2c48331dSMatt Macy 
263*2c48331dSMatt Macy 	case DATA_TYPE_INT16_ARRAY:
264*2c48331dSMatt Macy 		rv = nvlist_add_int16_array(nv, key, value, size);
265*2c48331dSMatt Macy 		break;
266*2c48331dSMatt Macy 
267*2c48331dSMatt Macy 	case DATA_TYPE_UINT16_ARRAY:
268*2c48331dSMatt Macy 		rv = nvlist_add_uint16_array(nv, key, value, size);
269*2c48331dSMatt Macy 		break;
270*2c48331dSMatt Macy 
271*2c48331dSMatt Macy 	case DATA_TYPE_INT32_ARRAY:
272*2c48331dSMatt Macy 		rv = nvlist_add_int32_array(nv, key, value, size);
273*2c48331dSMatt Macy 		break;
274*2c48331dSMatt Macy 
275*2c48331dSMatt Macy 	case DATA_TYPE_UINT32_ARRAY:
276*2c48331dSMatt Macy 		rv = nvlist_add_uint32_array(nv, key, value, size);
277*2c48331dSMatt Macy 		break;
278*2c48331dSMatt Macy 
279*2c48331dSMatt Macy 	case DATA_TYPE_INT64_ARRAY:
280*2c48331dSMatt Macy 		rv = nvlist_add_int64_array(nv, key, value, size);
281*2c48331dSMatt Macy 		break;
282*2c48331dSMatt Macy 
283*2c48331dSMatt Macy 	case DATA_TYPE_UINT64_ARRAY:
284*2c48331dSMatt Macy 		rv = nvlist_add_uint64_array(nv, key, value, size);
285*2c48331dSMatt Macy 		break;
286*2c48331dSMatt Macy 
287*2c48331dSMatt Macy 	case DATA_TYPE_STRING_ARRAY:
288*2c48331dSMatt Macy 		rv = nvlist_add_string_array(nv, key, value, size);
289*2c48331dSMatt Macy 		break;
290*2c48331dSMatt Macy 
291*2c48331dSMatt Macy 	case DATA_TYPE_NVLIST:
292*2c48331dSMatt Macy 		rv = nvlist_add_nvlist(nv, key, (nvlist_t *)value);
293*2c48331dSMatt Macy 		break;
294*2c48331dSMatt Macy 
295*2c48331dSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY:
296*2c48331dSMatt Macy 		rv = nvlist_add_nvlist_array(nv, key, value, size);
297*2c48331dSMatt Macy 		break;
298*2c48331dSMatt Macy 
299*2c48331dSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
300*2c48331dSMatt Macy 		if (size != sizeof (boolean_t)) {
301*2c48331dSMatt Macy 			rv = EINVAL;
302*2c48331dSMatt Macy 			break;
303*2c48331dSMatt Macy 		}
304*2c48331dSMatt Macy 		rv = nvlist_add_boolean_value(nv, key, *(boolean_t *)value);
305*2c48331dSMatt Macy 		break;
306*2c48331dSMatt Macy 
307*2c48331dSMatt Macy 	case DATA_TYPE_INT8:
308*2c48331dSMatt Macy 		if (size != sizeof (int8_t)) {
309*2c48331dSMatt Macy 			rv = EINVAL;
310*2c48331dSMatt Macy 			break;
311*2c48331dSMatt Macy 		}
312*2c48331dSMatt Macy 		rv = nvlist_add_int8(nv, key, *(int8_t *)value);
313*2c48331dSMatt Macy 		break;
314*2c48331dSMatt Macy 
315*2c48331dSMatt Macy 	case DATA_TYPE_UINT8:
316*2c48331dSMatt Macy 		if (size != sizeof (uint8_t)) {
317*2c48331dSMatt Macy 			rv = EINVAL;
318*2c48331dSMatt Macy 			break;
319*2c48331dSMatt Macy 		}
320*2c48331dSMatt Macy 		rv = nvlist_add_uint8(nv, key, *(uint8_t *)value);
321*2c48331dSMatt Macy 		break;
322*2c48331dSMatt Macy 
323*2c48331dSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY:
324*2c48331dSMatt Macy 		rv = nvlist_add_boolean_array(nv, key, value, size);
325*2c48331dSMatt Macy 		break;
326*2c48331dSMatt Macy 
327*2c48331dSMatt Macy 	case DATA_TYPE_INT8_ARRAY:
328*2c48331dSMatt Macy 		rv = nvlist_add_int8_array(nv, key, value, size);
329*2c48331dSMatt Macy 		break;
330*2c48331dSMatt Macy 
331*2c48331dSMatt Macy 	case DATA_TYPE_UINT8_ARRAY:
332*2c48331dSMatt Macy 		rv = nvlist_add_uint8_array(nv, key, value, size);
333*2c48331dSMatt Macy 		break;
334*2c48331dSMatt Macy 
335*2c48331dSMatt Macy 	default:
336*2c48331dSMatt Macy 		return (ENOTSUP);
337*2c48331dSMatt Macy 	}
338*2c48331dSMatt Macy 
339*2c48331dSMatt Macy 	return (rv);
340*2c48331dSMatt Macy }
341*2c48331dSMatt Macy 
342*2c48331dSMatt Macy int
343*2c48331dSMatt Macy lzbe_remove_pair(void *ptr, const char *key)
344*2c48331dSMatt Macy {
345*2c48331dSMatt Macy 
346*2c48331dSMatt Macy 	return (nvlist_remove_all(ptr, key));
347*2c48331dSMatt Macy }
348