xref: /freebsd/lib/libbe/be_info.c (revision b179da0111bf5734c60d07c110e8abae9cea300f)
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