Changeset View
Changeset View
Standalone View
Standalone View
sys/contrib/openzfs/lib/libzfsbootenv/lzbe_device.c
- This file was added.
/* | |||||
* This file and its contents are supplied under the terms of the | |||||
* Common Development and Distribution License ("CDDL"), version 1.0. | |||||
* You may only use this file in accordance with the terms of version | |||||
* 1.0 of the CDDL. | |||||
* | |||||
* A full copy of the text of the CDDL should have accompanied this | |||||
* source. A copy of the CDDL is also available via the Internet at | |||||
* http://www.illumos.org/license/CDDL. | |||||
*/ | |||||
/* | |||||
* Copyright 2020 Toomas Soome <tsoome@me.com> | |||||
*/ | |||||
#include <sys/types.h> | |||||
#include <string.h> | |||||
#include <libzfs.h> | |||||
#include <libzfsbootenv.h> | |||||
#include <sys/zfs_bootenv.h> | |||||
#include <sys/vdev_impl.h> | |||||
/* | |||||
* Store device name to zpool label bootenv area. | |||||
* This call will set bootenv version to VB_NVLIST, if bootenv currently | |||||
* does contain other version, then old data will be replaced. | |||||
*/ | |||||
int | |||||
lzbe_set_boot_device(const char *pool, lzbe_flags_t flag, const char *device) | |||||
{ | |||||
libzfs_handle_t *hdl; | |||||
zpool_handle_t *zphdl; | |||||
nvlist_t *nv; | |||||
char *descriptor; | |||||
uint64_t version; | |||||
int rv = -1; | |||||
if (pool == NULL || *pool == '\0') | |||||
return (rv); | |||||
if ((hdl = libzfs_init()) == NULL) | |||||
return (rv); | |||||
zphdl = zpool_open(hdl, pool); | |||||
if (zphdl == NULL) { | |||||
libzfs_fini(hdl); | |||||
return (rv); | |||||
} | |||||
switch (flag) { | |||||
case lzbe_add: | |||||
rv = zpool_get_bootenv(zphdl, &nv); | |||||
if (rv == 0) { | |||||
/* | |||||
* We got the nvlist, check for version. | |||||
* if version is missing or is not VB_NVLIST, | |||||
* create new list. | |||||
*/ | |||||
rv = nvlist_lookup_uint64(nv, BOOTENV_VERSION, | |||||
&version); | |||||
if (rv == 0 && version == VB_NVLIST) | |||||
break; | |||||
/* Drop this nvlist */ | |||||
fnvlist_free(nv); | |||||
} | |||||
/* FALLTHROUGH */ | |||||
case lzbe_replace: | |||||
nv = fnvlist_alloc(); | |||||
break; | |||||
default: | |||||
return (rv); | |||||
} | |||||
/* version is mandatory */ | |||||
fnvlist_add_uint64(nv, BOOTENV_VERSION, VB_NVLIST); | |||||
/* | |||||
* If device name is empty, remove boot device configuration. | |||||
*/ | |||||
if ((device == NULL || *device == '\0')) { | |||||
if (nvlist_exists(nv, OS_BOOTONCE)) | |||||
fnvlist_remove(nv, OS_BOOTONCE); | |||||
} else { | |||||
/* | |||||
* Use device name directly if it does start with | |||||
* prefix "zfs:". Otherwise, add prefix and sufix. | |||||
*/ | |||||
if (strncmp(device, "zfs:", 4) == 0) { | |||||
fnvlist_add_string(nv, OS_BOOTONCE, device); | |||||
} else { | |||||
descriptor = NULL; | |||||
if (asprintf(&descriptor, "zfs:%s:", device) > 0) | |||||
fnvlist_add_string(nv, OS_BOOTONCE, descriptor); | |||||
else | |||||
rv = ENOMEM; | |||||
free(descriptor); | |||||
} | |||||
} | |||||
rv = zpool_set_bootenv(zphdl, nv); | |||||
if (rv != 0) | |||||
fprintf(stderr, "%s\n", libzfs_error_description(hdl)); | |||||
fnvlist_free(nv); | |||||
zpool_close(zphdl); | |||||
libzfs_fini(hdl); | |||||
return (rv); | |||||
} | |||||
/* | |||||
* Return boot device name from bootenv, if set. | |||||
*/ | |||||
int | |||||
lzbe_get_boot_device(const char *pool, char **device) | |||||
{ | |||||
libzfs_handle_t *hdl; | |||||
zpool_handle_t *zphdl; | |||||
nvlist_t *nv; | |||||
char *val; | |||||
int rv = -1; | |||||
if (pool == NULL || *pool == '\0' || device == NULL) | |||||
return (rv); | |||||
if ((hdl = libzfs_init()) == NULL) | |||||
return (rv); | |||||
zphdl = zpool_open(hdl, pool); | |||||
if (zphdl == NULL) { | |||||
libzfs_fini(hdl); | |||||
return (rv); | |||||
} | |||||
rv = zpool_get_bootenv(zphdl, &nv); | |||||
if (rv == 0) { | |||||
rv = nvlist_lookup_string(nv, OS_BOOTONCE, &val); | |||||
if (rv == 0) { | |||||
/* | |||||
* zfs device descriptor is in form of "zfs:dataset:", | |||||
* we only do need dataset name. | |||||
*/ | |||||
if (strncmp(val, "zfs:", 4) == 0) { | |||||
val += 4; | |||||
val = strdup(val); | |||||
if (val != NULL) { | |||||
size_t len = strlen(val); | |||||
if (val[len - 1] == ':') | |||||
val[len - 1] = '\0'; | |||||
*device = val; | |||||
} else { | |||||
rv = ENOMEM; | |||||
} | |||||
} else { | |||||
rv = EINVAL; | |||||
} | |||||
} | |||||
nvlist_free(nv); | |||||
} | |||||
zpool_close(zphdl); | |||||
libzfs_fini(hdl); | |||||
return (rv); | |||||
} |