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 * Store device name to zpool label bootenv area. 24*2c48331dSMatt Macy * This call will set bootenv version to VB_NVLIST, if bootenv currently 25*2c48331dSMatt Macy * does contain other version, then old data will be replaced. 26*2c48331dSMatt Macy */ 27*2c48331dSMatt Macy int 28*2c48331dSMatt Macy lzbe_set_boot_device(const char *pool, lzbe_flags_t flag, const char *device) 29*2c48331dSMatt Macy { 30*2c48331dSMatt Macy libzfs_handle_t *hdl; 31*2c48331dSMatt Macy zpool_handle_t *zphdl; 32*2c48331dSMatt Macy nvlist_t *nv; 33*2c48331dSMatt Macy char *descriptor; 34*2c48331dSMatt Macy uint64_t version; 35*2c48331dSMatt Macy int rv = -1; 36*2c48331dSMatt Macy 37*2c48331dSMatt Macy if (pool == NULL || *pool == '\0') 38*2c48331dSMatt Macy return (rv); 39*2c48331dSMatt Macy 40*2c48331dSMatt Macy if ((hdl = libzfs_init()) == NULL) 41*2c48331dSMatt Macy return (rv); 42*2c48331dSMatt Macy 43*2c48331dSMatt Macy zphdl = zpool_open(hdl, pool); 44*2c48331dSMatt Macy if (zphdl == NULL) { 45*2c48331dSMatt Macy libzfs_fini(hdl); 46*2c48331dSMatt Macy return (rv); 47*2c48331dSMatt Macy } 48*2c48331dSMatt Macy 49*2c48331dSMatt Macy switch (flag) { 50*2c48331dSMatt Macy case lzbe_add: 51*2c48331dSMatt Macy rv = zpool_get_bootenv(zphdl, &nv); 52*2c48331dSMatt Macy if (rv == 0) { 53*2c48331dSMatt Macy /* 54*2c48331dSMatt Macy * We got the nvlist, check for version. 55*2c48331dSMatt Macy * if version is missing or is not VB_NVLIST, 56*2c48331dSMatt Macy * create new list. 57*2c48331dSMatt Macy */ 58*2c48331dSMatt Macy rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION, 59*2c48331dSMatt Macy &version); 60*2c48331dSMatt Macy if (rv == 0 && version == VB_NVLIST) 61*2c48331dSMatt Macy break; 62*2c48331dSMatt Macy 63*2c48331dSMatt Macy /* Drop this nvlist */ 64*2c48331dSMatt Macy fnvlist_free(nv); 65*2c48331dSMatt Macy } 66*2c48331dSMatt Macy /* FALLTHROUGH */ 67*2c48331dSMatt Macy case lzbe_replace: 68*2c48331dSMatt Macy nv = fnvlist_alloc(); 69*2c48331dSMatt Macy break; 70*2c48331dSMatt Macy default: 71*2c48331dSMatt Macy return (rv); 72*2c48331dSMatt Macy } 73*2c48331dSMatt Macy 74*2c48331dSMatt Macy /* version is mandatory */ 75*2c48331dSMatt Macy fnvlist_add_uint64(nv, BOOTENV_VERSION, VB_NVLIST); 76*2c48331dSMatt Macy 77*2c48331dSMatt Macy /* 78*2c48331dSMatt Macy * If device name is empty, remove boot device configuration. 79*2c48331dSMatt Macy */ 80*2c48331dSMatt Macy if ((device == NULL || *device == '\0')) { 81*2c48331dSMatt Macy if (nvlist_exists(nv, OS_BOOTONCE)) 82*2c48331dSMatt Macy fnvlist_remove(nv, OS_BOOTONCE); 83*2c48331dSMatt Macy } else { 84*2c48331dSMatt Macy /* 85*2c48331dSMatt Macy * Use device name directly if it does start with 86*2c48331dSMatt Macy * prefix "zfs:". Otherwise, add prefix and sufix. 87*2c48331dSMatt Macy */ 88*2c48331dSMatt Macy if (strncmp(device, "zfs:", 4) == 0) { 89*2c48331dSMatt Macy fnvlist_add_string(nv, OS_BOOTONCE, device); 90*2c48331dSMatt Macy } else { 91*2c48331dSMatt Macy descriptor = NULL; 92*2c48331dSMatt Macy if (asprintf(&descriptor, "zfs:%s:", device) > 0) 93*2c48331dSMatt Macy fnvlist_add_string(nv, OS_BOOTONCE, descriptor); 94*2c48331dSMatt Macy else 95*2c48331dSMatt Macy rv = ENOMEM; 96*2c48331dSMatt Macy free(descriptor); 97*2c48331dSMatt Macy } 98*2c48331dSMatt Macy } 99*2c48331dSMatt Macy 100*2c48331dSMatt Macy rv = zpool_set_bootenv(zphdl, nv); 101*2c48331dSMatt Macy if (rv != 0) 102*2c48331dSMatt Macy fprintf(stderr, "%s\n", libzfs_error_description(hdl)); 103*2c48331dSMatt Macy 104*2c48331dSMatt Macy fnvlist_free(nv); 105*2c48331dSMatt Macy zpool_close(zphdl); 106*2c48331dSMatt Macy libzfs_fini(hdl); 107*2c48331dSMatt Macy return (rv); 108*2c48331dSMatt Macy } 109*2c48331dSMatt Macy 110*2c48331dSMatt Macy /* 111*2c48331dSMatt Macy * Return boot device name from bootenv, if set. 112*2c48331dSMatt Macy */ 113*2c48331dSMatt Macy int 114*2c48331dSMatt Macy lzbe_get_boot_device(const char *pool, char **device) 115*2c48331dSMatt Macy { 116*2c48331dSMatt Macy libzfs_handle_t *hdl; 117*2c48331dSMatt Macy zpool_handle_t *zphdl; 118*2c48331dSMatt Macy nvlist_t *nv; 119*2c48331dSMatt Macy char *val; 120*2c48331dSMatt Macy int rv = -1; 121*2c48331dSMatt Macy 122*2c48331dSMatt Macy if (pool == NULL || *pool == '\0' || device == NULL) 123*2c48331dSMatt Macy return (rv); 124*2c48331dSMatt Macy 125*2c48331dSMatt Macy if ((hdl = libzfs_init()) == NULL) 126*2c48331dSMatt Macy return (rv); 127*2c48331dSMatt Macy 128*2c48331dSMatt Macy zphdl = zpool_open(hdl, pool); 129*2c48331dSMatt Macy if (zphdl == NULL) { 130*2c48331dSMatt Macy libzfs_fini(hdl); 131*2c48331dSMatt Macy return (rv); 132*2c48331dSMatt Macy } 133*2c48331dSMatt Macy 134*2c48331dSMatt Macy rv = zpool_get_bootenv(zphdl, &nv); 135*2c48331dSMatt Macy if (rv == 0) { 136*2c48331dSMatt Macy rv = nvlist_lookup_string(nv, OS_BOOTONCE, &val); 137*2c48331dSMatt Macy if (rv == 0) { 138*2c48331dSMatt Macy /* 139*2c48331dSMatt Macy * zfs device descriptor is in form of "zfs:dataset:", 140*2c48331dSMatt Macy * we only do need dataset name. 141*2c48331dSMatt Macy */ 142*2c48331dSMatt Macy if (strncmp(val, "zfs:", 4) == 0) { 143*2c48331dSMatt Macy val += 4; 144*2c48331dSMatt Macy val = strdup(val); 145*2c48331dSMatt Macy if (val != NULL) { 146*2c48331dSMatt Macy size_t len = strlen(val); 147*2c48331dSMatt Macy 148*2c48331dSMatt Macy if (val[len - 1] == ':') 149*2c48331dSMatt Macy val[len - 1] = '\0'; 150*2c48331dSMatt Macy *device = val; 151*2c48331dSMatt Macy } else { 152*2c48331dSMatt Macy rv = ENOMEM; 153*2c48331dSMatt Macy } 154*2c48331dSMatt Macy } else { 155*2c48331dSMatt Macy rv = EINVAL; 156*2c48331dSMatt Macy } 157*2c48331dSMatt Macy } 158*2c48331dSMatt Macy nvlist_free(nv); 159*2c48331dSMatt Macy } 160*2c48331dSMatt Macy 161*2c48331dSMatt Macy zpool_close(zphdl); 162*2c48331dSMatt Macy libzfs_fini(hdl); 163*2c48331dSMatt Macy return (rv); 164*2c48331dSMatt Macy } 165