1b179da01SKyle Evans /*- 2b179da01SKyle Evans * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 328f16a0fSKyle Evans * 428f16a0fSKyle Evans * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in> 5b179da01SKyle Evans * Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 628f16a0fSKyle Evans * All rights reserved. 728f16a0fSKyle Evans * 828f16a0fSKyle Evans * Redistribution and use in source and binary forms, with or without 928f16a0fSKyle Evans * modification, are permitted provided that the following conditions 1028f16a0fSKyle Evans * are met: 1128f16a0fSKyle Evans * 1. Redistributions of source code must retain the above copyright 1228f16a0fSKyle Evans * notice, this list of conditions and the following disclaimer. 1328f16a0fSKyle Evans * 2. Redistributions in binary form must reproduce the above copyright 1428f16a0fSKyle Evans * notice, this list of conditions and the following disclaimer in the 1528f16a0fSKyle Evans * documentation and/or other materials provided with the distribution. 1628f16a0fSKyle Evans * 1728f16a0fSKyle Evans * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1828f16a0fSKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1928f16a0fSKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2028f16a0fSKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2128f16a0fSKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2228f16a0fSKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2328f16a0fSKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2428f16a0fSKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2528f16a0fSKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2628f16a0fSKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2728f16a0fSKyle Evans * SUCH DAMAGE. 2828f16a0fSKyle Evans */ 2928f16a0fSKyle Evans 30*b6e7c421SKyle Evans #include <sys/cdefs.h> 31*b6e7c421SKyle Evans __FBSDID("$FreeBSD$"); 32*b6e7c421SKyle Evans 3328f16a0fSKyle Evans #include "be.h" 3428f16a0fSKyle Evans #include "be_impl.h" 3528f16a0fSKyle Evans 365468566eSKyle Evans static int snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data); 3796c5db58SKyle Evans 3828f16a0fSKyle Evans /* 3928f16a0fSKyle Evans * Returns the name of the active boot environment 4028f16a0fSKyle Evans */ 4128f16a0fSKyle Evans const char * 4228f16a0fSKyle Evans be_active_name(libbe_handle_t *lbh) 4328f16a0fSKyle Evans { 44bfe0869cSKyle Evans 45c3a34c08SKyle Evans return (strrchr(lbh->rootfs, '/') + sizeof(char)); 4628f16a0fSKyle Evans } 4728f16a0fSKyle Evans 4828f16a0fSKyle Evans 4928f16a0fSKyle Evans /* 5028f16a0fSKyle Evans * Returns full path of the active boot environment 5128f16a0fSKyle Evans */ 5228f16a0fSKyle Evans const char * 5328f16a0fSKyle Evans be_active_path(libbe_handle_t *lbh) 5428f16a0fSKyle Evans { 55bfe0869cSKyle Evans 56c3a34c08SKyle Evans return (lbh->rootfs); 5728f16a0fSKyle Evans } 5828f16a0fSKyle Evans 59ff8676ccSKyle Evans /* 60ff8676ccSKyle Evans * Returns the name of the next active boot environment 61ff8676ccSKyle Evans */ 62ff8676ccSKyle Evans const char * 63ff8676ccSKyle Evans be_nextboot_name(libbe_handle_t *lbh) 64ff8676ccSKyle Evans { 65ff8676ccSKyle Evans 66ff8676ccSKyle Evans return (strrchr(lbh->bootfs, '/') + sizeof(char)); 67ff8676ccSKyle Evans } 68ff8676ccSKyle Evans 69ff8676ccSKyle Evans 70ff8676ccSKyle Evans /* 71ff8676ccSKyle Evans * Returns full path of the active boot environment 72ff8676ccSKyle Evans */ 73ff8676ccSKyle Evans const char * 74ff8676ccSKyle Evans be_nextboot_path(libbe_handle_t *lbh) 75ff8676ccSKyle Evans { 76ff8676ccSKyle Evans 77ff8676ccSKyle Evans return (lbh->bootfs); 78ff8676ccSKyle Evans } 79ff8676ccSKyle Evans 8028f16a0fSKyle Evans 8128f16a0fSKyle Evans /* 8228f16a0fSKyle Evans * Returns the path of the boot environment root dataset 8328f16a0fSKyle Evans */ 8428f16a0fSKyle Evans const char * 8528f16a0fSKyle Evans be_root_path(libbe_handle_t *lbh) 8628f16a0fSKyle Evans { 87bfe0869cSKyle Evans 8828f16a0fSKyle Evans return (lbh->root); 8928f16a0fSKyle Evans } 9028f16a0fSKyle Evans 9128f16a0fSKyle Evans 9228f16a0fSKyle Evans /* 933682d5e9SKyle Evans * Populates dsnvl with one nvlist per bootenv dataset describing the properties 943682d5e9SKyle Evans * of that dataset that we've declared ourselves to care about. 9528f16a0fSKyle Evans */ 963682d5e9SKyle Evans int 973682d5e9SKyle Evans be_get_bootenv_props(libbe_handle_t *lbh, nvlist_t *dsnvl) 9828f16a0fSKyle Evans { 9928f16a0fSKyle Evans prop_data_t data; 10028f16a0fSKyle Evans 10128f16a0fSKyle Evans data.lbh = lbh; 1023682d5e9SKyle Evans data.list = dsnvl; 1034146029bSKyle Evans data.single_object = false; 1045468566eSKyle Evans return (be_proplist_update(&data)); 10528f16a0fSKyle Evans } 10628f16a0fSKyle Evans 1074146029bSKyle Evans int 1089b1662e6SKyle Evans be_get_dataset_props(libbe_handle_t *lbh, const char *name, nvlist_t *props) 1094146029bSKyle Evans { 1104146029bSKyle Evans zfs_handle_t *snap_hdl; 1114146029bSKyle Evans prop_data_t data; 1124146029bSKyle Evans int ret; 1134146029bSKyle Evans 1144146029bSKyle Evans data.lbh = lbh; 1154146029bSKyle Evans data.list = props; 1164146029bSKyle Evans data.single_object = true; 1174146029bSKyle Evans if ((snap_hdl = zfs_open(lbh->lzh, name, 1189b1662e6SKyle Evans ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL) 1194146029bSKyle Evans return (BE_ERR_ZFSOPEN); 1204146029bSKyle Evans 1214146029bSKyle Evans ret = prop_list_builder_cb(snap_hdl, &data); 1224146029bSKyle Evans zfs_close(snap_hdl); 1234146029bSKyle Evans return (ret); 1244146029bSKyle Evans } 12528f16a0fSKyle Evans 12696c5db58SKyle Evans int 12796c5db58SKyle Evans be_get_dataset_snapshots(libbe_handle_t *lbh, const char *name, nvlist_t *props) 12896c5db58SKyle Evans { 12996c5db58SKyle Evans zfs_handle_t *ds_hdl; 13096c5db58SKyle Evans prop_data_t data; 13196c5db58SKyle Evans int ret; 13296c5db58SKyle Evans 13396c5db58SKyle Evans data.lbh = lbh; 13496c5db58SKyle Evans data.list = props; 13596c5db58SKyle Evans data.single_object = false; 13696c5db58SKyle Evans if ((ds_hdl = zfs_open(lbh->lzh, name, 13796c5db58SKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL) 13896c5db58SKyle Evans return (BE_ERR_ZFSOPEN); 13996c5db58SKyle Evans 1405468566eSKyle Evans ret = snapshot_proplist_update(ds_hdl, &data); 14196c5db58SKyle Evans zfs_close(ds_hdl); 14296c5db58SKyle Evans return (ret); 14396c5db58SKyle Evans } 14496c5db58SKyle Evans 14528f16a0fSKyle Evans /* 14628f16a0fSKyle Evans * Internal callback function used by zfs_iter_filesystems. For each dataset in 14728f16a0fSKyle Evans * the bootenv root, populate an nvlist_t of its relevant properties. 14828f16a0fSKyle Evans */ 149843e39ceSKyle Evans int 15028f16a0fSKyle Evans prop_list_builder_cb(zfs_handle_t *zfs_hdl, void *data_p) 15128f16a0fSKyle Evans { 1524831c931SKyle Evans char buf[512], *mountpoint; 153bfe0869cSKyle Evans prop_data_t *data; 154bfe0869cSKyle Evans libbe_handle_t *lbh; 155bfe0869cSKyle Evans nvlist_t *props; 156bfe0869cSKyle Evans const char *dataset, *name; 157b29bf2f8SKyle Evans boolean_t mounted; 158bfe0869cSKyle Evans 15928f16a0fSKyle Evans /* 160bfe0869cSKyle Evans * XXX TODO: 16128f16a0fSKyle Evans * some system for defining constants for the nvlist keys 16228f16a0fSKyle Evans * error checking 16328f16a0fSKyle Evans */ 16428f16a0fSKyle Evans data = (prop_data_t *)data_p; 165bfe0869cSKyle Evans lbh = data->lbh; 16628f16a0fSKyle Evans 1674146029bSKyle Evans if (data->single_object) 1684146029bSKyle Evans props = data->list; 1694146029bSKyle Evans else 17028f16a0fSKyle Evans nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); 17128f16a0fSKyle Evans 172bfe0869cSKyle Evans dataset = zfs_get_name(zfs_hdl); 17328f16a0fSKyle Evans nvlist_add_string(props, "dataset", dataset); 17428f16a0fSKyle Evans 175bfe0869cSKyle Evans name = strrchr(dataset, '/') + 1; 17628f16a0fSKyle Evans nvlist_add_string(props, "name", name); 17728f16a0fSKyle Evans 1784831c931SKyle Evans mounted = zfs_is_mounted(zfs_hdl, &mountpoint); 17928f16a0fSKyle Evans 1804831c931SKyle Evans if (mounted) 181709b553cSKyle Evans nvlist_add_string(props, "mounted", mountpoint); 182709b553cSKyle Evans 183709b553cSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, 512, 184709b553cSKyle Evans NULL, NULL, 0, 1) == 0) 185709b553cSKyle Evans nvlist_add_string(props, "mountpoint", buf); 18628f16a0fSKyle Evans 18728f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_ORIGIN, buf, 512, 188513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 18928f16a0fSKyle Evans nvlist_add_string(props, "origin", buf); 19028f16a0fSKyle Evans 19128f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_CREATION, buf, 512, 192513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 19328f16a0fSKyle Evans nvlist_add_string(props, "creation", buf); 19428f16a0fSKyle Evans 19528f16a0fSKyle Evans nvlist_add_boolean_value(props, "active", 19628f16a0fSKyle Evans (strcmp(be_active_path(lbh), dataset) == 0)); 19728f16a0fSKyle Evans 19828f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512, 199513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20028f16a0fSKyle Evans nvlist_add_string(props, "used", buf); 20128f16a0fSKyle Evans 20228f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDDS, buf, 512, 203513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20428f16a0fSKyle Evans nvlist_add_string(props, "usedds", buf); 20528f16a0fSKyle Evans 20628f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDSNAP, buf, 512, 207513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20828f16a0fSKyle Evans nvlist_add_string(props, "usedsnap", buf); 20928f16a0fSKyle Evans 21028f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDREFRESERV, buf, 512, 211513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 21228f16a0fSKyle Evans nvlist_add_string(props, "usedrefreserv", buf); 21328f16a0fSKyle Evans 21428f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_REFERENCED, buf, 512, 215513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 21628f16a0fSKyle Evans nvlist_add_string(props, "referenced", buf); 21728f16a0fSKyle Evans 218ff8676ccSKyle Evans nvlist_add_boolean_value(props, "nextboot", 219ff8676ccSKyle Evans (strcmp(be_nextboot_path(lbh), dataset) == 0)); 22028f16a0fSKyle Evans 2214146029bSKyle Evans if (!data->single_object) 22228f16a0fSKyle Evans nvlist_add_nvlist(data->list, name, props); 22328f16a0fSKyle Evans 22428f16a0fSKyle Evans return (0); 22528f16a0fSKyle Evans } 22628f16a0fSKyle Evans 22728f16a0fSKyle Evans 22828f16a0fSKyle Evans /* 22928f16a0fSKyle Evans * Updates the properties of each bootenv in the libbe handle 230bfe0869cSKyle Evans * XXX TODO: ensure that this is always consistent (run after adds, deletes, 23128f16a0fSKyle Evans * renames,etc 23228f16a0fSKyle Evans */ 233843e39ceSKyle Evans int 2345468566eSKyle Evans be_proplist_update(prop_data_t *data) 23528f16a0fSKyle Evans { 23628f16a0fSKyle Evans zfs_handle_t *root_hdl; 23728f16a0fSKyle Evans 238bfe0869cSKyle Evans if ((root_hdl = zfs_open(data->lbh->lzh, data->lbh->root, 239bfe0869cSKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL) 24028f16a0fSKyle Evans return (BE_ERR_ZFSOPEN); 24128f16a0fSKyle Evans 242bfe0869cSKyle Evans /* XXX TODO: some error checking here */ 24328f16a0fSKyle Evans zfs_iter_filesystems(root_hdl, prop_list_builder_cb, data); 24428f16a0fSKyle Evans 24528f16a0fSKyle Evans zfs_close(root_hdl); 24628f16a0fSKyle Evans 24728f16a0fSKyle Evans return (0); 24828f16a0fSKyle Evans } 24928f16a0fSKyle Evans 25096c5db58SKyle Evans static int 2515468566eSKyle Evans snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data) 25296c5db58SKyle Evans { 25396c5db58SKyle Evans 25496c5db58SKyle Evans return (zfs_iter_snapshots_sorted(hdl, prop_list_builder_cb, data)); 25596c5db58SKyle Evans } 25696c5db58SKyle Evans 25728f16a0fSKyle Evans 258734e362fSKyle Evans int 259734e362fSKyle Evans be_prop_list_alloc(nvlist_t **be_list) 260734e362fSKyle Evans { 261734e362fSKyle Evans 262734e362fSKyle Evans return (nvlist_alloc(be_list, NV_UNIQUE_NAME, KM_SLEEP)); 263734e362fSKyle Evans } 264734e362fSKyle Evans 26528f16a0fSKyle Evans /* 26628f16a0fSKyle Evans * frees property list and its children 26728f16a0fSKyle Evans */ 26828f16a0fSKyle Evans void 26928f16a0fSKyle Evans be_prop_list_free(nvlist_t *be_list) 27028f16a0fSKyle Evans { 27128f16a0fSKyle Evans nvlist_t *prop_list; 272bfe0869cSKyle Evans nvpair_t *be_pair; 27328f16a0fSKyle Evans 274bfe0869cSKyle Evans be_pair = nvlist_next_nvpair(be_list, NULL); 275bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0) 27628f16a0fSKyle Evans nvlist_free(prop_list); 27728f16a0fSKyle Evans 27828f16a0fSKyle Evans while ((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) { 279bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0) 28028f16a0fSKyle Evans nvlist_free(prop_list); 28128f16a0fSKyle Evans } 28228f16a0fSKyle Evans } 28328f16a0fSKyle Evans 28428f16a0fSKyle Evans 28528f16a0fSKyle Evans /* 28628f16a0fSKyle Evans * Usage 28728f16a0fSKyle Evans */ 28828f16a0fSKyle Evans bool 28928f16a0fSKyle Evans be_exists(libbe_handle_t *lbh, char *be) 29028f16a0fSKyle Evans { 29128f16a0fSKyle Evans char buf[BE_MAXPATHLEN]; 292709b553cSKyle Evans nvlist_t *dsprops; 293709b553cSKyle Evans char *mntpoint; 294709b553cSKyle Evans bool valid; 29528f16a0fSKyle Evans 29628f16a0fSKyle Evans be_root_concat(lbh, be, buf); 29728f16a0fSKyle Evans 298709b553cSKyle Evans if (!zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_DATASET)) 299709b553cSKyle Evans return (false); 300709b553cSKyle Evans 301709b553cSKyle Evans /* Also check if it's mounted at / */ 302709b553cSKyle Evans if (be_prop_list_alloc(&dsprops) != 0) { 303709b553cSKyle Evans set_error(lbh, BE_ERR_UNKNOWN); 304709b553cSKyle Evans return (false); 305709b553cSKyle Evans } 306709b553cSKyle Evans 307709b553cSKyle Evans if (be_get_dataset_props(lbh, buf, dsprops) != 0) { 308709b553cSKyle Evans nvlist_free(dsprops); 309709b553cSKyle Evans return (false); 310709b553cSKyle Evans } 311709b553cSKyle Evans 312709b553cSKyle Evans if (nvlist_lookup_string(dsprops, "mountpoint", &mntpoint) == 0) { 313709b553cSKyle Evans valid = (strcmp(mntpoint, "/") == 0); 314709b553cSKyle Evans nvlist_free(dsprops); 315709b553cSKyle Evans return (valid); 316709b553cSKyle Evans } 317709b553cSKyle Evans 318709b553cSKyle Evans nvlist_free(dsprops); 319709b553cSKyle Evans return (false); 32028f16a0fSKyle Evans } 321