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