1*b179da01SKyle Evans /*- 2*b179da01SKyle Evans * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 328f16a0fSKyle Evans * 428f16a0fSKyle Evans * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in> 5*b179da01SKyle 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 3028f16a0fSKyle Evans #include "be.h" 3128f16a0fSKyle Evans #include "be_impl.h" 3228f16a0fSKyle Evans 335468566eSKyle Evans static int snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data); 3496c5db58SKyle Evans 3528f16a0fSKyle Evans /* 3628f16a0fSKyle Evans * Returns the name of the active boot environment 3728f16a0fSKyle Evans */ 3828f16a0fSKyle Evans const char * 3928f16a0fSKyle Evans be_active_name(libbe_handle_t *lbh) 4028f16a0fSKyle Evans { 41bfe0869cSKyle Evans 42c3a34c08SKyle Evans return (strrchr(lbh->rootfs, '/') + sizeof(char)); 4328f16a0fSKyle Evans } 4428f16a0fSKyle Evans 4528f16a0fSKyle Evans 4628f16a0fSKyle Evans /* 4728f16a0fSKyle Evans * Returns full path of the active boot environment 4828f16a0fSKyle Evans */ 4928f16a0fSKyle Evans const char * 5028f16a0fSKyle Evans be_active_path(libbe_handle_t *lbh) 5128f16a0fSKyle Evans { 52bfe0869cSKyle Evans 53c3a34c08SKyle Evans return (lbh->rootfs); 5428f16a0fSKyle Evans } 5528f16a0fSKyle Evans 56ff8676ccSKyle Evans /* 57ff8676ccSKyle Evans * Returns the name of the next active boot environment 58ff8676ccSKyle Evans */ 59ff8676ccSKyle Evans const char * 60ff8676ccSKyle Evans be_nextboot_name(libbe_handle_t *lbh) 61ff8676ccSKyle Evans { 62ff8676ccSKyle Evans 63ff8676ccSKyle Evans return (strrchr(lbh->bootfs, '/') + sizeof(char)); 64ff8676ccSKyle Evans } 65ff8676ccSKyle Evans 66ff8676ccSKyle Evans 67ff8676ccSKyle Evans /* 68ff8676ccSKyle Evans * Returns full path of the active boot environment 69ff8676ccSKyle Evans */ 70ff8676ccSKyle Evans const char * 71ff8676ccSKyle Evans be_nextboot_path(libbe_handle_t *lbh) 72ff8676ccSKyle Evans { 73ff8676ccSKyle Evans 74ff8676ccSKyle Evans return (lbh->bootfs); 75ff8676ccSKyle Evans } 76ff8676ccSKyle Evans 7728f16a0fSKyle Evans 7828f16a0fSKyle Evans /* 7928f16a0fSKyle Evans * Returns the path of the boot environment root dataset 8028f16a0fSKyle Evans */ 8128f16a0fSKyle Evans const char * 8228f16a0fSKyle Evans be_root_path(libbe_handle_t *lbh) 8328f16a0fSKyle Evans { 84bfe0869cSKyle Evans 8528f16a0fSKyle Evans return (lbh->root); 8628f16a0fSKyle Evans } 8728f16a0fSKyle Evans 8828f16a0fSKyle Evans 8928f16a0fSKyle Evans /* 903682d5e9SKyle Evans * Populates dsnvl with one nvlist per bootenv dataset describing the properties 913682d5e9SKyle Evans * of that dataset that we've declared ourselves to care about. 9228f16a0fSKyle Evans */ 933682d5e9SKyle Evans int 943682d5e9SKyle Evans be_get_bootenv_props(libbe_handle_t *lbh, nvlist_t *dsnvl) 9528f16a0fSKyle Evans { 9628f16a0fSKyle Evans prop_data_t data; 9728f16a0fSKyle Evans 9828f16a0fSKyle Evans data.lbh = lbh; 993682d5e9SKyle Evans data.list = dsnvl; 1004146029bSKyle Evans data.single_object = false; 1015468566eSKyle Evans return (be_proplist_update(&data)); 10228f16a0fSKyle Evans } 10328f16a0fSKyle Evans 1044146029bSKyle Evans int 1059b1662e6SKyle Evans be_get_dataset_props(libbe_handle_t *lbh, const char *name, nvlist_t *props) 1064146029bSKyle Evans { 1074146029bSKyle Evans zfs_handle_t *snap_hdl; 1084146029bSKyle Evans prop_data_t data; 1094146029bSKyle Evans int ret; 1104146029bSKyle Evans 1114146029bSKyle Evans data.lbh = lbh; 1124146029bSKyle Evans data.list = props; 1134146029bSKyle Evans data.single_object = true; 1144146029bSKyle Evans if ((snap_hdl = zfs_open(lbh->lzh, name, 1159b1662e6SKyle Evans ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL) 1164146029bSKyle Evans return (BE_ERR_ZFSOPEN); 1174146029bSKyle Evans 1184146029bSKyle Evans ret = prop_list_builder_cb(snap_hdl, &data); 1194146029bSKyle Evans zfs_close(snap_hdl); 1204146029bSKyle Evans return (ret); 1214146029bSKyle Evans } 12228f16a0fSKyle Evans 12396c5db58SKyle Evans int 12496c5db58SKyle Evans be_get_dataset_snapshots(libbe_handle_t *lbh, const char *name, nvlist_t *props) 12596c5db58SKyle Evans { 12696c5db58SKyle Evans zfs_handle_t *ds_hdl; 12796c5db58SKyle Evans prop_data_t data; 12896c5db58SKyle Evans int ret; 12996c5db58SKyle Evans 13096c5db58SKyle Evans data.lbh = lbh; 13196c5db58SKyle Evans data.list = props; 13296c5db58SKyle Evans data.single_object = false; 13396c5db58SKyle Evans if ((ds_hdl = zfs_open(lbh->lzh, name, 13496c5db58SKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL) 13596c5db58SKyle Evans return (BE_ERR_ZFSOPEN); 13696c5db58SKyle Evans 1375468566eSKyle Evans ret = snapshot_proplist_update(ds_hdl, &data); 13896c5db58SKyle Evans zfs_close(ds_hdl); 13996c5db58SKyle Evans return (ret); 14096c5db58SKyle Evans } 14196c5db58SKyle Evans 14228f16a0fSKyle Evans /* 14328f16a0fSKyle Evans * Internal callback function used by zfs_iter_filesystems. For each dataset in 14428f16a0fSKyle Evans * the bootenv root, populate an nvlist_t of its relevant properties. 14528f16a0fSKyle Evans */ 146843e39ceSKyle Evans int 14728f16a0fSKyle Evans prop_list_builder_cb(zfs_handle_t *zfs_hdl, void *data_p) 14828f16a0fSKyle Evans { 1494831c931SKyle Evans char buf[512], *mountpoint; 150bfe0869cSKyle Evans prop_data_t *data; 151bfe0869cSKyle Evans libbe_handle_t *lbh; 152bfe0869cSKyle Evans nvlist_t *props; 153bfe0869cSKyle Evans const char *dataset, *name; 154b29bf2f8SKyle Evans boolean_t mounted; 155bfe0869cSKyle Evans 15628f16a0fSKyle Evans /* 157bfe0869cSKyle Evans * XXX TODO: 15828f16a0fSKyle Evans * some system for defining constants for the nvlist keys 15928f16a0fSKyle Evans * error checking 16028f16a0fSKyle Evans */ 16128f16a0fSKyle Evans data = (prop_data_t *)data_p; 162bfe0869cSKyle Evans lbh = data->lbh; 16328f16a0fSKyle Evans 1644146029bSKyle Evans if (data->single_object) 1654146029bSKyle Evans props = data->list; 1664146029bSKyle Evans else 16728f16a0fSKyle Evans nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); 16828f16a0fSKyle Evans 169bfe0869cSKyle Evans dataset = zfs_get_name(zfs_hdl); 17028f16a0fSKyle Evans nvlist_add_string(props, "dataset", dataset); 17128f16a0fSKyle Evans 172bfe0869cSKyle Evans name = strrchr(dataset, '/') + 1; 17328f16a0fSKyle Evans nvlist_add_string(props, "name", name); 17428f16a0fSKyle Evans 1754831c931SKyle Evans mounted = zfs_is_mounted(zfs_hdl, &mountpoint); 17628f16a0fSKyle Evans 1774831c931SKyle Evans if (mounted) 178709b553cSKyle Evans nvlist_add_string(props, "mounted", mountpoint); 179709b553cSKyle Evans 180709b553cSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, 512, 181709b553cSKyle Evans NULL, NULL, 0, 1) == 0) 182709b553cSKyle Evans nvlist_add_string(props, "mountpoint", buf); 18328f16a0fSKyle Evans 18428f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_ORIGIN, buf, 512, 185513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 18628f16a0fSKyle Evans nvlist_add_string(props, "origin", buf); 18728f16a0fSKyle Evans 18828f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_CREATION, buf, 512, 189513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 19028f16a0fSKyle Evans nvlist_add_string(props, "creation", buf); 19128f16a0fSKyle Evans 19228f16a0fSKyle Evans nvlist_add_boolean_value(props, "active", 19328f16a0fSKyle Evans (strcmp(be_active_path(lbh), dataset) == 0)); 19428f16a0fSKyle Evans 19528f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512, 196513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 19728f16a0fSKyle Evans nvlist_add_string(props, "used", buf); 19828f16a0fSKyle Evans 19928f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDDS, buf, 512, 200513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20128f16a0fSKyle Evans nvlist_add_string(props, "usedds", buf); 20228f16a0fSKyle Evans 20328f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDSNAP, buf, 512, 204513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20528f16a0fSKyle Evans nvlist_add_string(props, "usedsnap", buf); 20628f16a0fSKyle Evans 20728f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDREFRESERV, buf, 512, 208513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20928f16a0fSKyle Evans nvlist_add_string(props, "usedrefreserv", buf); 21028f16a0fSKyle Evans 21128f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_REFERENCED, buf, 512, 212513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 21328f16a0fSKyle Evans nvlist_add_string(props, "referenced", buf); 21428f16a0fSKyle Evans 215ff8676ccSKyle Evans nvlist_add_boolean_value(props, "nextboot", 216ff8676ccSKyle Evans (strcmp(be_nextboot_path(lbh), dataset) == 0)); 21728f16a0fSKyle Evans 2184146029bSKyle Evans if (!data->single_object) 21928f16a0fSKyle Evans nvlist_add_nvlist(data->list, name, props); 22028f16a0fSKyle Evans 22128f16a0fSKyle Evans return (0); 22228f16a0fSKyle Evans } 22328f16a0fSKyle Evans 22428f16a0fSKyle Evans 22528f16a0fSKyle Evans /* 22628f16a0fSKyle Evans * Updates the properties of each bootenv in the libbe handle 227bfe0869cSKyle Evans * XXX TODO: ensure that this is always consistent (run after adds, deletes, 22828f16a0fSKyle Evans * renames,etc 22928f16a0fSKyle Evans */ 230843e39ceSKyle Evans int 2315468566eSKyle Evans be_proplist_update(prop_data_t *data) 23228f16a0fSKyle Evans { 23328f16a0fSKyle Evans zfs_handle_t *root_hdl; 23428f16a0fSKyle Evans 235bfe0869cSKyle Evans if ((root_hdl = zfs_open(data->lbh->lzh, data->lbh->root, 236bfe0869cSKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL) 23728f16a0fSKyle Evans return (BE_ERR_ZFSOPEN); 23828f16a0fSKyle Evans 239bfe0869cSKyle Evans /* XXX TODO: some error checking here */ 24028f16a0fSKyle Evans zfs_iter_filesystems(root_hdl, prop_list_builder_cb, data); 24128f16a0fSKyle Evans 24228f16a0fSKyle Evans zfs_close(root_hdl); 24328f16a0fSKyle Evans 24428f16a0fSKyle Evans return (0); 24528f16a0fSKyle Evans } 24628f16a0fSKyle Evans 24796c5db58SKyle Evans static int 2485468566eSKyle Evans snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data) 24996c5db58SKyle Evans { 25096c5db58SKyle Evans 25196c5db58SKyle Evans return (zfs_iter_snapshots_sorted(hdl, prop_list_builder_cb, data)); 25296c5db58SKyle Evans } 25396c5db58SKyle Evans 25428f16a0fSKyle Evans 255734e362fSKyle Evans int 256734e362fSKyle Evans be_prop_list_alloc(nvlist_t **be_list) 257734e362fSKyle Evans { 258734e362fSKyle Evans 259734e362fSKyle Evans return (nvlist_alloc(be_list, NV_UNIQUE_NAME, KM_SLEEP)); 260734e362fSKyle Evans } 261734e362fSKyle Evans 26228f16a0fSKyle Evans /* 26328f16a0fSKyle Evans * frees property list and its children 26428f16a0fSKyle Evans */ 26528f16a0fSKyle Evans void 26628f16a0fSKyle Evans be_prop_list_free(nvlist_t *be_list) 26728f16a0fSKyle Evans { 26828f16a0fSKyle Evans nvlist_t *prop_list; 269bfe0869cSKyle Evans nvpair_t *be_pair; 27028f16a0fSKyle Evans 271bfe0869cSKyle Evans be_pair = nvlist_next_nvpair(be_list, NULL); 272bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0) 27328f16a0fSKyle Evans nvlist_free(prop_list); 27428f16a0fSKyle Evans 27528f16a0fSKyle Evans while ((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) { 276bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0) 27728f16a0fSKyle Evans nvlist_free(prop_list); 27828f16a0fSKyle Evans } 27928f16a0fSKyle Evans } 28028f16a0fSKyle Evans 28128f16a0fSKyle Evans 28228f16a0fSKyle Evans /* 28328f16a0fSKyle Evans * Usage 28428f16a0fSKyle Evans */ 28528f16a0fSKyle Evans bool 28628f16a0fSKyle Evans be_exists(libbe_handle_t *lbh, char *be) 28728f16a0fSKyle Evans { 28828f16a0fSKyle Evans char buf[BE_MAXPATHLEN]; 289709b553cSKyle Evans nvlist_t *dsprops; 290709b553cSKyle Evans char *mntpoint; 291709b553cSKyle Evans bool valid; 29228f16a0fSKyle Evans 29328f16a0fSKyle Evans be_root_concat(lbh, be, buf); 29428f16a0fSKyle Evans 295709b553cSKyle Evans if (!zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_DATASET)) 296709b553cSKyle Evans return (false); 297709b553cSKyle Evans 298709b553cSKyle Evans /* Also check if it's mounted at / */ 299709b553cSKyle Evans if (be_prop_list_alloc(&dsprops) != 0) { 300709b553cSKyle Evans set_error(lbh, BE_ERR_UNKNOWN); 301709b553cSKyle Evans return (false); 302709b553cSKyle Evans } 303709b553cSKyle Evans 304709b553cSKyle Evans if (be_get_dataset_props(lbh, buf, dsprops) != 0) { 305709b553cSKyle Evans nvlist_free(dsprops); 306709b553cSKyle Evans return (false); 307709b553cSKyle Evans } 308709b553cSKyle Evans 309709b553cSKyle Evans if (nvlist_lookup_string(dsprops, "mountpoint", &mntpoint) == 0) { 310709b553cSKyle Evans valid = (strcmp(mntpoint, "/") == 0); 311709b553cSKyle Evans nvlist_free(dsprops); 312709b553cSKyle Evans return (valid); 313709b553cSKyle Evans } 314709b553cSKyle Evans 315709b553cSKyle Evans nvlist_free(dsprops); 316709b553cSKyle Evans return (false); 31728f16a0fSKyle Evans } 318