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 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 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 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 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 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, value, size); 297 break; 298 299 case DATA_TYPE_BOOLEAN_VALUE: 300 if (size != sizeof (boolean_t)) { 301 rv = EINVAL; 302 break; 303 } 304 rv = nvlist_add_boolean_value(nv, key, *(boolean_t *)value); 305 break; 306 307 case DATA_TYPE_INT8: 308 if (size != sizeof (int8_t)) { 309 rv = EINVAL; 310 break; 311 } 312 rv = nvlist_add_int8(nv, key, *(int8_t *)value); 313 break; 314 315 case DATA_TYPE_UINT8: 316 if (size != sizeof (uint8_t)) { 317 rv = EINVAL; 318 break; 319 } 320 rv = nvlist_add_uint8(nv, key, *(uint8_t *)value); 321 break; 322 323 case DATA_TYPE_BOOLEAN_ARRAY: 324 rv = nvlist_add_boolean_array(nv, key, value, size); 325 break; 326 327 case DATA_TYPE_INT8_ARRAY: 328 rv = nvlist_add_int8_array(nv, key, value, size); 329 break; 330 331 case DATA_TYPE_UINT8_ARRAY: 332 rv = nvlist_add_uint8_array(nv, key, value, size); 333 break; 334 335 default: 336 return (ENOTSUP); 337 } 338 339 return (rv); 340 } 341 342 int 343 lzbe_remove_pair(void *ptr, const char *key) 344 { 345 346 return (nvlist_remove_all(ptr, key)); 347 } 348