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