Path: blob/main/sys/contrib/openzfs/lib/libzfsbootenv/lzbe_device.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* This file and its contents are supplied under the terms of the3* Common Development and Distribution License ("CDDL"), version 1.0.4* You may only use this file in accordance with the terms of version5* 1.0 of the CDDL.6*7* A full copy of the text of the CDDL should have accompanied this8* source. A copy of the CDDL is also available via the Internet at9* http://www.illumos.org/license/CDDL.10*/11/*12* Copyright 2020 Toomas Soome <[email protected]>13*/1415#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>2122/*23* Store device name to zpool label bootenv area.24* This call will set bootenv version to VB_NVLIST, if bootenv currently25* does contain other version, then old data will be replaced.26*/27int28lzbe_set_boot_device(const char *pool, lzbe_flags_t flag, const char *device)29{30libzfs_handle_t *hdl;31zpool_handle_t *zphdl;32nvlist_t *nv;33char *descriptor;34uint64_t version;35int rv = -1;3637if (pool == NULL || *pool == '\0')38return (rv);3940if ((hdl = libzfs_init()) == NULL)41return (rv);4243zphdl = zpool_open(hdl, pool);44if (zphdl == NULL) {45libzfs_fini(hdl);46return (rv);47}4849switch (flag) {50case lzbe_add:51rv = zpool_get_bootenv(zphdl, &nv);52if (rv == 0) {53/*54* We got the nvlist, check for version.55* if version is missing or is not VB_NVLIST,56* create new list.57*/58rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION,59&version);60if (rv == 0 && version == VB_NVLIST)61break;6263/* Drop this nvlist */64fnvlist_free(nv);65}66zfs_fallthrough;67case lzbe_replace:68nv = fnvlist_alloc();69break;70default:71return (rv);72}7374/* version is mandatory */75fnvlist_add_uint64(nv, BOOTENV_VERSION, VB_NVLIST);7677rv = 0;78/*79* If device name is empty, remove boot device configuration.80*/81if ((device == NULL || *device == '\0')) {82if (nvlist_exists(nv, OS_BOOTONCE))83fnvlist_remove(nv, OS_BOOTONCE);84} else {85/*86* Use device name directly if it does start with87* prefix "zfs:". Otherwise, add prefix and suffix.88*/89if (strncmp(device, "zfs:", 4) == 0) {90fnvlist_add_string(nv, OS_BOOTONCE, device);91} else {92if (asprintf(&descriptor, "zfs:%s:", device) > 0) {93fnvlist_add_string(nv, OS_BOOTONCE, descriptor);94free(descriptor);95} else96rv = ENOMEM;97}98}99if (rv == 0)100rv = zpool_set_bootenv(zphdl, nv);101if (rv != 0)102fprintf(stderr, "%s\n", libzfs_error_description(hdl));103104fnvlist_free(nv);105zpool_close(zphdl);106libzfs_fini(hdl);107return (rv);108}109110/*111* Return boot device name from bootenv, if set.112*/113int114lzbe_get_boot_device(const char *pool, char **device)115{116libzfs_handle_t *hdl;117zpool_handle_t *zphdl;118nvlist_t *nv;119const char *val;120int rv = -1;121122if (pool == NULL || *pool == '\0' || device == NULL)123return (rv);124125if ((hdl = libzfs_init()) == NULL)126return (rv);127128zphdl = zpool_open(hdl, pool);129if (zphdl == NULL) {130libzfs_fini(hdl);131return (rv);132}133134rv = zpool_get_bootenv(zphdl, &nv);135if (rv == 0) {136rv = nvlist_lookup_string(nv, OS_BOOTONCE, &val);137if (rv == 0) {138/*139* zfs device descriptor is in form of "zfs:dataset:",140* we only do need dataset name.141*/142if (strncmp(val, "zfs:", 4) == 0) {143char *tmp = strdup(val + 4);144if (tmp != NULL) {145size_t len = strlen(tmp);146147if (tmp[len - 1] == ':')148tmp[len - 1] = '\0';149*device = tmp;150} else {151rv = ENOMEM;152}153} else {154rv = EINVAL;155}156}157nvlist_free(nv);158}159160zpool_close(zphdl);161libzfs_fini(hdl);162return (rv);163}164165166