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 * 728f16a0fSKyle Evans * Redistribution and use in source and binary forms, with or without 828f16a0fSKyle Evans * modification, are permitted provided that the following conditions 928f16a0fSKyle Evans * are met: 1028f16a0fSKyle Evans * 1. Redistributions of source code must retain the above copyright 1128f16a0fSKyle Evans * notice, this list of conditions and the following disclaimer. 1228f16a0fSKyle Evans * 2. Redistributions in binary form must reproduce the above copyright 1328f16a0fSKyle Evans * notice, this list of conditions and the following disclaimer in the 1428f16a0fSKyle Evans * documentation and/or other materials provided with the distribution. 1528f16a0fSKyle Evans * 1628f16a0fSKyle Evans * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1728f16a0fSKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1828f16a0fSKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1928f16a0fSKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2028f16a0fSKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2128f16a0fSKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2228f16a0fSKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2328f16a0fSKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2428f16a0fSKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2528f16a0fSKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2628f16a0fSKyle Evans * SUCH DAMAGE. 2728f16a0fSKyle Evans */ 2828f16a0fSKyle Evans 29b6e7c421SKyle Evans #include <sys/cdefs.h> 30b6e7c421SKyle Evans __FBSDID("$FreeBSD$"); 31b6e7c421SKyle Evans 32485172f5SKyle Evans #include <sys/zfs_context.h> 33e307eb94SToomas Soome #include <libzfsbootenv.h> 34485172f5SKyle Evans 3528f16a0fSKyle Evans #include "be.h" 3628f16a0fSKyle Evans #include "be_impl.h" 3728f16a0fSKyle Evans 385468566eSKyle Evans static int snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data); 3996c5db58SKyle Evans 4028f16a0fSKyle Evans /* 4128f16a0fSKyle Evans * Returns the name of the active boot environment 4228f16a0fSKyle Evans */ 4328f16a0fSKyle Evans const char * 4428f16a0fSKyle Evans be_active_name(libbe_handle_t *lbh) 4528f16a0fSKyle Evans { 46bfe0869cSKyle Evans 47cc624025SKyle Evans if (*lbh->rootfs != '\0') 48c3a34c08SKyle Evans return (strrchr(lbh->rootfs, '/') + sizeof(char)); 49cc624025SKyle Evans else 50cc624025SKyle Evans return (lbh->rootfs); 5128f16a0fSKyle Evans } 5228f16a0fSKyle Evans 5328f16a0fSKyle Evans 5428f16a0fSKyle Evans /* 5528f16a0fSKyle Evans * Returns full path of the active boot environment 5628f16a0fSKyle Evans */ 5728f16a0fSKyle Evans const char * 5828f16a0fSKyle Evans be_active_path(libbe_handle_t *lbh) 5928f16a0fSKyle Evans { 60bfe0869cSKyle Evans 61c3a34c08SKyle Evans return (lbh->rootfs); 6228f16a0fSKyle Evans } 6328f16a0fSKyle Evans 64ff8676ccSKyle Evans /* 65ff8676ccSKyle Evans * Returns the name of the next active boot environment 66ff8676ccSKyle Evans */ 67ff8676ccSKyle Evans const char * 68ff8676ccSKyle Evans be_nextboot_name(libbe_handle_t *lbh) 69ff8676ccSKyle Evans { 70ff8676ccSKyle Evans 71cc624025SKyle Evans if (*lbh->bootfs != '\0') 72ff8676ccSKyle Evans return (strrchr(lbh->bootfs, '/') + sizeof(char)); 73cc624025SKyle Evans else 74cc624025SKyle Evans return (lbh->bootfs); 75ff8676ccSKyle Evans } 76ff8676ccSKyle Evans 77ff8676ccSKyle Evans 78ff8676ccSKyle Evans /* 79ff8676ccSKyle Evans * Returns full path of the active boot environment 80ff8676ccSKyle Evans */ 81ff8676ccSKyle Evans const char * 82ff8676ccSKyle Evans be_nextboot_path(libbe_handle_t *lbh) 83ff8676ccSKyle Evans { 84ff8676ccSKyle Evans 85ff8676ccSKyle Evans return (lbh->bootfs); 86ff8676ccSKyle Evans } 87ff8676ccSKyle Evans 8828f16a0fSKyle Evans 8928f16a0fSKyle Evans /* 9028f16a0fSKyle Evans * Returns the path of the boot environment root dataset 9128f16a0fSKyle Evans */ 9228f16a0fSKyle Evans const char * 9328f16a0fSKyle Evans be_root_path(libbe_handle_t *lbh) 9428f16a0fSKyle Evans { 95bfe0869cSKyle Evans 9628f16a0fSKyle Evans return (lbh->root); 9728f16a0fSKyle Evans } 9828f16a0fSKyle Evans 9928f16a0fSKyle Evans 10028f16a0fSKyle Evans /* 1013682d5e9SKyle Evans * Populates dsnvl with one nvlist per bootenv dataset describing the properties 1023682d5e9SKyle Evans * of that dataset that we've declared ourselves to care about. 10328f16a0fSKyle Evans */ 1043682d5e9SKyle Evans int 1053682d5e9SKyle Evans be_get_bootenv_props(libbe_handle_t *lbh, nvlist_t *dsnvl) 10628f16a0fSKyle Evans { 10728f16a0fSKyle Evans prop_data_t data; 10828f16a0fSKyle Evans 10928f16a0fSKyle Evans data.lbh = lbh; 1103682d5e9SKyle Evans data.list = dsnvl; 1114146029bSKyle Evans data.single_object = false; 112e307eb94SToomas Soome data.bootonce = NULL; 1135468566eSKyle Evans return (be_proplist_update(&data)); 11428f16a0fSKyle Evans } 11528f16a0fSKyle Evans 1164146029bSKyle Evans int 1179b1662e6SKyle Evans be_get_dataset_props(libbe_handle_t *lbh, const char *name, nvlist_t *props) 1184146029bSKyle Evans { 1194146029bSKyle Evans zfs_handle_t *snap_hdl; 1204146029bSKyle Evans prop_data_t data; 1214146029bSKyle Evans int ret; 1224146029bSKyle Evans 1234146029bSKyle Evans data.lbh = lbh; 1244146029bSKyle Evans data.list = props; 1254146029bSKyle Evans data.single_object = true; 126e307eb94SToomas Soome data.bootonce = NULL; 1274146029bSKyle Evans if ((snap_hdl = zfs_open(lbh->lzh, name, 1289b1662e6SKyle Evans ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL) 1294146029bSKyle Evans return (BE_ERR_ZFSOPEN); 1304146029bSKyle Evans 1314146029bSKyle Evans ret = prop_list_builder_cb(snap_hdl, &data); 1324146029bSKyle Evans zfs_close(snap_hdl); 1334146029bSKyle Evans return (ret); 1344146029bSKyle Evans } 13528f16a0fSKyle Evans 13696c5db58SKyle Evans int 13796c5db58SKyle Evans be_get_dataset_snapshots(libbe_handle_t *lbh, const char *name, nvlist_t *props) 13896c5db58SKyle Evans { 13996c5db58SKyle Evans zfs_handle_t *ds_hdl; 14096c5db58SKyle Evans prop_data_t data; 14196c5db58SKyle Evans int ret; 14296c5db58SKyle Evans 14396c5db58SKyle Evans data.lbh = lbh; 14496c5db58SKyle Evans data.list = props; 14596c5db58SKyle Evans data.single_object = false; 146e307eb94SToomas Soome data.bootonce = NULL; 14796c5db58SKyle Evans if ((ds_hdl = zfs_open(lbh->lzh, name, 14896c5db58SKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL) 14996c5db58SKyle Evans return (BE_ERR_ZFSOPEN); 15096c5db58SKyle Evans 1515468566eSKyle Evans ret = snapshot_proplist_update(ds_hdl, &data); 15296c5db58SKyle Evans zfs_close(ds_hdl); 15396c5db58SKyle Evans return (ret); 15496c5db58SKyle Evans } 15596c5db58SKyle Evans 15628f16a0fSKyle Evans /* 15728f16a0fSKyle Evans * Internal callback function used by zfs_iter_filesystems. For each dataset in 15828f16a0fSKyle Evans * the bootenv root, populate an nvlist_t of its relevant properties. 15928f16a0fSKyle Evans */ 160843e39ceSKyle Evans int 16128f16a0fSKyle Evans prop_list_builder_cb(zfs_handle_t *zfs_hdl, void *data_p) 16228f16a0fSKyle Evans { 1634831c931SKyle Evans char buf[512], *mountpoint; 164bfe0869cSKyle Evans prop_data_t *data; 165bfe0869cSKyle Evans libbe_handle_t *lbh; 166bfe0869cSKyle Evans nvlist_t *props; 167bfe0869cSKyle Evans const char *dataset, *name; 168b29bf2f8SKyle Evans boolean_t mounted; 169bfe0869cSKyle Evans 17028f16a0fSKyle Evans /* 171bfe0869cSKyle Evans * XXX TODO: 17228f16a0fSKyle Evans * some system for defining constants for the nvlist keys 17328f16a0fSKyle Evans * error checking 17428f16a0fSKyle Evans */ 17528f16a0fSKyle Evans data = (prop_data_t *)data_p; 176bfe0869cSKyle Evans lbh = data->lbh; 17728f16a0fSKyle Evans 1784146029bSKyle Evans if (data->single_object) 1794146029bSKyle Evans props = data->list; 1804146029bSKyle Evans else 18128f16a0fSKyle Evans nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); 18228f16a0fSKyle Evans 183bfe0869cSKyle Evans dataset = zfs_get_name(zfs_hdl); 18428f16a0fSKyle Evans nvlist_add_string(props, "dataset", dataset); 18528f16a0fSKyle Evans 186e307eb94SToomas Soome if (data->bootonce != NULL && 187e307eb94SToomas Soome strcmp(dataset, data->bootonce) == 0) 188e307eb94SToomas Soome nvlist_add_boolean_value(props, "bootonce", true); 189e307eb94SToomas Soome 190bfe0869cSKyle Evans name = strrchr(dataset, '/') + 1; 19128f16a0fSKyle Evans nvlist_add_string(props, "name", name); 19228f16a0fSKyle Evans 1934831c931SKyle Evans mounted = zfs_is_mounted(zfs_hdl, &mountpoint); 19428f16a0fSKyle Evans 1954831c931SKyle Evans if (mounted) 196709b553cSKyle Evans nvlist_add_string(props, "mounted", mountpoint); 197709b553cSKyle Evans 198709b553cSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, 512, 199709b553cSKyle Evans NULL, NULL, 0, 1) == 0) 200709b553cSKyle Evans nvlist_add_string(props, "mountpoint", buf); 20128f16a0fSKyle Evans 20228f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_ORIGIN, buf, 512, 203513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20428f16a0fSKyle Evans nvlist_add_string(props, "origin", buf); 20528f16a0fSKyle Evans 20628f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_CREATION, buf, 512, 207513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 20828f16a0fSKyle Evans nvlist_add_string(props, "creation", buf); 20928f16a0fSKyle Evans 21028f16a0fSKyle Evans nvlist_add_boolean_value(props, "active", 21128f16a0fSKyle Evans (strcmp(be_active_path(lbh), dataset) == 0)); 21228f16a0fSKyle Evans 21328f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512, 214513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 21528f16a0fSKyle Evans nvlist_add_string(props, "used", buf); 21628f16a0fSKyle Evans 21728f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDDS, buf, 512, 218513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 21928f16a0fSKyle Evans nvlist_add_string(props, "usedds", buf); 22028f16a0fSKyle Evans 22128f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDSNAP, buf, 512, 222513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 22328f16a0fSKyle Evans nvlist_add_string(props, "usedsnap", buf); 22428f16a0fSKyle Evans 22528f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDREFRESERV, buf, 512, 226513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 22728f16a0fSKyle Evans nvlist_add_string(props, "usedrefreserv", buf); 22828f16a0fSKyle Evans 22928f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_REFERENCED, buf, 512, 230513044c1SKyle Evans NULL, NULL, 0, 1) == 0) 23128f16a0fSKyle Evans nvlist_add_string(props, "referenced", buf); 23228f16a0fSKyle Evans 233ff8676ccSKyle Evans nvlist_add_boolean_value(props, "nextboot", 234ff8676ccSKyle Evans (strcmp(be_nextboot_path(lbh), dataset) == 0)); 23528f16a0fSKyle Evans 2364146029bSKyle Evans if (!data->single_object) 23728f16a0fSKyle Evans nvlist_add_nvlist(data->list, name, props); 23828f16a0fSKyle Evans 23928f16a0fSKyle Evans return (0); 24028f16a0fSKyle Evans } 24128f16a0fSKyle Evans 24228f16a0fSKyle Evans 24328f16a0fSKyle Evans /* 24428f16a0fSKyle Evans * Updates the properties of each bootenv in the libbe handle 245bfe0869cSKyle Evans * XXX TODO: ensure that this is always consistent (run after adds, deletes, 24628f16a0fSKyle Evans * renames,etc 24728f16a0fSKyle Evans */ 248843e39ceSKyle Evans int 2495468566eSKyle Evans be_proplist_update(prop_data_t *data) 25028f16a0fSKyle Evans { 25128f16a0fSKyle Evans zfs_handle_t *root_hdl; 25228f16a0fSKyle Evans 253bfe0869cSKyle Evans if ((root_hdl = zfs_open(data->lbh->lzh, data->lbh->root, 254bfe0869cSKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL) 25528f16a0fSKyle Evans return (BE_ERR_ZFSOPEN); 25628f16a0fSKyle Evans 257e307eb94SToomas Soome (void) lzbe_get_boot_device(zpool_get_name(data->lbh->active_phandle), 258e307eb94SToomas Soome &data->bootonce); 259e307eb94SToomas Soome 260bfe0869cSKyle Evans /* XXX TODO: some error checking here */ 261*d411c1d6SMartin Matuska zfs_iter_filesystems(root_hdl, prop_list_builder_cb, data); 26228f16a0fSKyle Evans 26328f16a0fSKyle Evans zfs_close(root_hdl); 26428f16a0fSKyle Evans 26528f16a0fSKyle Evans return (0); 26628f16a0fSKyle Evans } 26728f16a0fSKyle Evans 26896c5db58SKyle Evans static int 2695468566eSKyle Evans snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data) 27096c5db58SKyle Evans { 27196c5db58SKyle Evans 272*d411c1d6SMartin Matuska return (zfs_iter_snapshots_sorted(hdl, prop_list_builder_cb, data, 273cefbdf3eSAlan Somers 0, 0)); 27496c5db58SKyle Evans } 27596c5db58SKyle Evans 27628f16a0fSKyle Evans 277734e362fSKyle Evans int 278734e362fSKyle Evans be_prop_list_alloc(nvlist_t **be_list) 279734e362fSKyle Evans { 280734e362fSKyle Evans 281734e362fSKyle Evans return (nvlist_alloc(be_list, NV_UNIQUE_NAME, KM_SLEEP)); 282734e362fSKyle Evans } 283734e362fSKyle Evans 28428f16a0fSKyle Evans /* 28528f16a0fSKyle Evans * frees property list and its children 28628f16a0fSKyle Evans */ 28728f16a0fSKyle Evans void 28828f16a0fSKyle Evans be_prop_list_free(nvlist_t *be_list) 28928f16a0fSKyle Evans { 29028f16a0fSKyle Evans nvlist_t *prop_list; 291bfe0869cSKyle Evans nvpair_t *be_pair; 29228f16a0fSKyle Evans 293bfe0869cSKyle Evans be_pair = nvlist_next_nvpair(be_list, NULL); 294bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0) 29528f16a0fSKyle Evans nvlist_free(prop_list); 29628f16a0fSKyle Evans 29728f16a0fSKyle Evans while ((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) { 298bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0) 29928f16a0fSKyle Evans nvlist_free(prop_list); 30028f16a0fSKyle Evans } 30128f16a0fSKyle Evans } 30228f16a0fSKyle Evans 30328f16a0fSKyle Evans 30428f16a0fSKyle Evans /* 30528f16a0fSKyle Evans * Usage 30628f16a0fSKyle Evans */ 307162ec569SKyle Evans int 3085773e924SKyle Evans be_exists(libbe_handle_t *lbh, const char *be) 30928f16a0fSKyle Evans { 31028f16a0fSKyle Evans char buf[BE_MAXPATHLEN]; 31128f16a0fSKyle Evans 31228f16a0fSKyle Evans be_root_concat(lbh, be, buf); 31328f16a0fSKyle Evans 314709b553cSKyle Evans if (!zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_DATASET)) 315162ec569SKyle Evans return (BE_ERR_NOENT); 316709b553cSKyle Evans 31751aecc89SKyle Evans return (BE_ERR_SUCCESS); 31828f16a0fSKyle Evans } 319