12c48331dSMatt Macy /* 22c48331dSMatt Macy * This file and its contents are supplied under the terms of the 32c48331dSMatt Macy * Common Development and Distribution License ("CDDL"), version 1.0. 42c48331dSMatt Macy * You may only use this file in accordance with the terms of version 52c48331dSMatt Macy * 1.0 of the CDDL. 62c48331dSMatt Macy * 72c48331dSMatt Macy * A full copy of the text of the CDDL should have accompanied this 82c48331dSMatt Macy * source. A copy of the CDDL is also available via the Internet at 92c48331dSMatt Macy * http://www.illumos.org/license/CDDL. 102c48331dSMatt Macy */ 112c48331dSMatt Macy /* 122c48331dSMatt Macy * Copyright 2020 Toomas Soome <tsoome@me.com> 132c48331dSMatt Macy */ 142c48331dSMatt Macy 152c48331dSMatt Macy #include <sys/types.h> 162c48331dSMatt Macy #include <string.h> 172c48331dSMatt Macy #include <libzfs.h> 182c48331dSMatt Macy #include <libzfsbootenv.h> 192c48331dSMatt Macy #include <sys/zfs_bootenv.h> 202c48331dSMatt Macy #include <sys/vdev_impl.h> 212c48331dSMatt Macy 222c48331dSMatt Macy /* 232c48331dSMatt Macy * Store device name to zpool label bootenv area. 242c48331dSMatt Macy * This call will set bootenv version to VB_NVLIST, if bootenv currently 252c48331dSMatt Macy * does contain other version, then old data will be replaced. 262c48331dSMatt Macy */ 272c48331dSMatt Macy int 282c48331dSMatt Macy lzbe_set_boot_device(const char *pool, lzbe_flags_t flag, const char *device) 292c48331dSMatt Macy { 302c48331dSMatt Macy libzfs_handle_t *hdl; 312c48331dSMatt Macy zpool_handle_t *zphdl; 322c48331dSMatt Macy nvlist_t *nv; 332c48331dSMatt Macy char *descriptor; 342c48331dSMatt Macy uint64_t version; 352c48331dSMatt Macy int rv = -1; 362c48331dSMatt Macy 372c48331dSMatt Macy if (pool == NULL || *pool == '\0') 382c48331dSMatt Macy return (rv); 392c48331dSMatt Macy 402c48331dSMatt Macy if ((hdl = libzfs_init()) == NULL) 412c48331dSMatt Macy return (rv); 422c48331dSMatt Macy 432c48331dSMatt Macy zphdl = zpool_open(hdl, pool); 442c48331dSMatt Macy if (zphdl == NULL) { 452c48331dSMatt Macy libzfs_fini(hdl); 462c48331dSMatt Macy return (rv); 472c48331dSMatt Macy } 482c48331dSMatt Macy 492c48331dSMatt Macy switch (flag) { 502c48331dSMatt Macy case lzbe_add: 512c48331dSMatt Macy rv = zpool_get_bootenv(zphdl, &nv); 522c48331dSMatt Macy if (rv == 0) { 532c48331dSMatt Macy /* 542c48331dSMatt Macy * We got the nvlist, check for version. 552c48331dSMatt Macy * if version is missing or is not VB_NVLIST, 562c48331dSMatt Macy * create new list. 572c48331dSMatt Macy */ 582c48331dSMatt Macy rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION, 592c48331dSMatt Macy &version); 602c48331dSMatt Macy if (rv == 0 && version == VB_NVLIST) 612c48331dSMatt Macy break; 622c48331dSMatt Macy 632c48331dSMatt Macy /* Drop this nvlist */ 642c48331dSMatt Macy fnvlist_free(nv); 652c48331dSMatt Macy } 662c48331dSMatt Macy /* FALLTHROUGH */ 672c48331dSMatt Macy case lzbe_replace: 682c48331dSMatt Macy nv = fnvlist_alloc(); 692c48331dSMatt Macy break; 702c48331dSMatt Macy default: 712c48331dSMatt Macy return (rv); 722c48331dSMatt Macy } 732c48331dSMatt Macy 742c48331dSMatt Macy /* version is mandatory */ 752c48331dSMatt Macy fnvlist_add_uint64(nv, BOOTENV_VERSION, VB_NVLIST); 762c48331dSMatt Macy 772c48331dSMatt Macy /* 782c48331dSMatt Macy * If device name is empty, remove boot device configuration. 792c48331dSMatt Macy */ 802c48331dSMatt Macy if ((device == NULL || *device == '\0')) { 812c48331dSMatt Macy if (nvlist_exists(nv, OS_BOOTONCE)) 822c48331dSMatt Macy fnvlist_remove(nv, OS_BOOTONCE); 832c48331dSMatt Macy } else { 842c48331dSMatt Macy /* 852c48331dSMatt Macy * Use device name directly if it does start with 86*16038816SMartin Matuska * prefix "zfs:". Otherwise, add prefix and suffix. 872c48331dSMatt Macy */ 882c48331dSMatt Macy if (strncmp(device, "zfs:", 4) == 0) { 892c48331dSMatt Macy fnvlist_add_string(nv, OS_BOOTONCE, device); 902c48331dSMatt Macy } else { 91*16038816SMartin Matuska if (asprintf(&descriptor, "zfs:%s:", device) > 0) { 922c48331dSMatt Macy fnvlist_add_string(nv, OS_BOOTONCE, descriptor); 932c48331dSMatt Macy free(descriptor); 94*16038816SMartin Matuska } else 95*16038816SMartin Matuska rv = ENOMEM; 962c48331dSMatt Macy } 972c48331dSMatt Macy } 982c48331dSMatt Macy 992c48331dSMatt Macy rv = zpool_set_bootenv(zphdl, nv); 1002c48331dSMatt Macy if (rv != 0) 1012c48331dSMatt Macy fprintf(stderr, "%s\n", libzfs_error_description(hdl)); 1022c48331dSMatt Macy 1032c48331dSMatt Macy fnvlist_free(nv); 1042c48331dSMatt Macy zpool_close(zphdl); 1052c48331dSMatt Macy libzfs_fini(hdl); 1062c48331dSMatt Macy return (rv); 1072c48331dSMatt Macy } 1082c48331dSMatt Macy 1092c48331dSMatt Macy /* 1102c48331dSMatt Macy * Return boot device name from bootenv, if set. 1112c48331dSMatt Macy */ 1122c48331dSMatt Macy int 1132c48331dSMatt Macy lzbe_get_boot_device(const char *pool, char **device) 1142c48331dSMatt Macy { 1152c48331dSMatt Macy libzfs_handle_t *hdl; 1162c48331dSMatt Macy zpool_handle_t *zphdl; 1172c48331dSMatt Macy nvlist_t *nv; 1182c48331dSMatt Macy char *val; 1192c48331dSMatt Macy int rv = -1; 1202c48331dSMatt Macy 1212c48331dSMatt Macy if (pool == NULL || *pool == '\0' || device == NULL) 1222c48331dSMatt Macy return (rv); 1232c48331dSMatt Macy 1242c48331dSMatt Macy if ((hdl = libzfs_init()) == NULL) 1252c48331dSMatt Macy return (rv); 1262c48331dSMatt Macy 1272c48331dSMatt Macy zphdl = zpool_open(hdl, pool); 1282c48331dSMatt Macy if (zphdl == NULL) { 1292c48331dSMatt Macy libzfs_fini(hdl); 1302c48331dSMatt Macy return (rv); 1312c48331dSMatt Macy } 1322c48331dSMatt Macy 1332c48331dSMatt Macy rv = zpool_get_bootenv(zphdl, &nv); 1342c48331dSMatt Macy if (rv == 0) { 1352c48331dSMatt Macy rv = nvlist_lookup_string(nv, OS_BOOTONCE, &val); 1362c48331dSMatt Macy if (rv == 0) { 1372c48331dSMatt Macy /* 1382c48331dSMatt Macy * zfs device descriptor is in form of "zfs:dataset:", 1392c48331dSMatt Macy * we only do need dataset name. 1402c48331dSMatt Macy */ 1412c48331dSMatt Macy if (strncmp(val, "zfs:", 4) == 0) { 1422c48331dSMatt Macy val += 4; 1432c48331dSMatt Macy val = strdup(val); 1442c48331dSMatt Macy if (val != NULL) { 1452c48331dSMatt Macy size_t len = strlen(val); 1462c48331dSMatt Macy 1472c48331dSMatt Macy if (val[len - 1] == ':') 1482c48331dSMatt Macy val[len - 1] = '\0'; 1492c48331dSMatt Macy *device = val; 1502c48331dSMatt Macy } else { 1512c48331dSMatt Macy rv = ENOMEM; 1522c48331dSMatt Macy } 1532c48331dSMatt Macy } else { 1542c48331dSMatt Macy rv = EINVAL; 1552c48331dSMatt Macy } 1562c48331dSMatt Macy } 1572c48331dSMatt Macy nvlist_free(nv); 1582c48331dSMatt Macy } 1592c48331dSMatt Macy 1602c48331dSMatt Macy zpool_close(zphdl); 1612c48331dSMatt Macy libzfs_fini(hdl); 1622c48331dSMatt Macy return (rv); 1632c48331dSMatt Macy } 164