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 <sys/sysmacros.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 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 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 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 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 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, value, 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 344 lzbe_remove_pair(void *ptr, const char *key) 345 { 346 347 return (nvlist_remove_all(ptr, key)); 348 } 349