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