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