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