1b179da01SKyle Evans /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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>
30485172f5SKyle Evans #include <sys/zfs_context.h>
31e307eb94SToomas Soome #include <libzfsbootenv.h>
32485172f5SKyle 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 *
be_active_name(libbe_handle_t * lbh)4228f16a0fSKyle Evans be_active_name(libbe_handle_t *lbh)
4328f16a0fSKyle Evans {
44bfe0869cSKyle Evans
45cc624025SKyle Evans if (*lbh->rootfs != '\0')
46c3a34c08SKyle Evans return (strrchr(lbh->rootfs, '/') + sizeof(char));
47cc624025SKyle Evans else
48cc624025SKyle Evans return (lbh->rootfs);
4928f16a0fSKyle Evans }
5028f16a0fSKyle Evans
5128f16a0fSKyle Evans
5228f16a0fSKyle Evans /*
5328f16a0fSKyle Evans * Returns full path of the active boot environment
5428f16a0fSKyle Evans */
5528f16a0fSKyle Evans const char *
be_active_path(libbe_handle_t * lbh)5628f16a0fSKyle Evans be_active_path(libbe_handle_t *lbh)
5728f16a0fSKyle Evans {
58bfe0869cSKyle Evans
59c3a34c08SKyle Evans return (lbh->rootfs);
6028f16a0fSKyle Evans }
6128f16a0fSKyle Evans
62ff8676ccSKyle Evans /*
63ff8676ccSKyle Evans * Returns the name of the next active boot environment
64ff8676ccSKyle Evans */
65ff8676ccSKyle Evans const char *
be_nextboot_name(libbe_handle_t * lbh)66ff8676ccSKyle Evans be_nextboot_name(libbe_handle_t *lbh)
67ff8676ccSKyle Evans {
68ff8676ccSKyle Evans
69cc624025SKyle Evans if (*lbh->bootfs != '\0')
70ff8676ccSKyle Evans return (strrchr(lbh->bootfs, '/') + sizeof(char));
71cc624025SKyle Evans else
72cc624025SKyle Evans return (lbh->bootfs);
73ff8676ccSKyle Evans }
74ff8676ccSKyle Evans
75ff8676ccSKyle Evans
76ff8676ccSKyle Evans /*
77ff8676ccSKyle Evans * Returns full path of the active boot environment
78ff8676ccSKyle Evans */
79ff8676ccSKyle Evans const char *
be_nextboot_path(libbe_handle_t * lbh)80ff8676ccSKyle Evans be_nextboot_path(libbe_handle_t *lbh)
81ff8676ccSKyle Evans {
82ff8676ccSKyle Evans
83ff8676ccSKyle Evans return (lbh->bootfs);
84ff8676ccSKyle Evans }
85ff8676ccSKyle Evans
8628f16a0fSKyle Evans
8728f16a0fSKyle Evans /*
8828f16a0fSKyle Evans * Returns the path of the boot environment root dataset
8928f16a0fSKyle Evans */
9028f16a0fSKyle Evans const char *
be_root_path(libbe_handle_t * lbh)9128f16a0fSKyle Evans be_root_path(libbe_handle_t *lbh)
9228f16a0fSKyle Evans {
93bfe0869cSKyle Evans
9428f16a0fSKyle Evans return (lbh->root);
9528f16a0fSKyle Evans }
9628f16a0fSKyle Evans
9728f16a0fSKyle Evans
9828f16a0fSKyle Evans /*
993682d5e9SKyle Evans * Populates dsnvl with one nvlist per bootenv dataset describing the properties
1003682d5e9SKyle Evans * of that dataset that we've declared ourselves to care about.
10128f16a0fSKyle Evans */
1023682d5e9SKyle Evans int
be_get_bootenv_props(libbe_handle_t * lbh,nvlist_t * dsnvl)1033682d5e9SKyle Evans be_get_bootenv_props(libbe_handle_t *lbh, nvlist_t *dsnvl)
10428f16a0fSKyle Evans {
10528f16a0fSKyle Evans prop_data_t data;
10628f16a0fSKyle Evans
10728f16a0fSKyle Evans data.lbh = lbh;
1083682d5e9SKyle Evans data.list = dsnvl;
1094146029bSKyle Evans data.single_object = false;
110e307eb94SToomas Soome data.bootonce = NULL;
1115468566eSKyle Evans return (be_proplist_update(&data));
11228f16a0fSKyle Evans }
11328f16a0fSKyle Evans
1144146029bSKyle Evans int
be_get_dataset_props(libbe_handle_t * lbh,const char * name,nvlist_t * props)1159b1662e6SKyle Evans be_get_dataset_props(libbe_handle_t *lbh, const char *name, nvlist_t *props)
1164146029bSKyle Evans {
1174146029bSKyle Evans zfs_handle_t *snap_hdl;
1184146029bSKyle Evans prop_data_t data;
1194146029bSKyle Evans int ret;
1204146029bSKyle Evans
1214146029bSKyle Evans data.lbh = lbh;
1224146029bSKyle Evans data.list = props;
1234146029bSKyle Evans data.single_object = true;
124e307eb94SToomas Soome data.bootonce = NULL;
1254146029bSKyle Evans if ((snap_hdl = zfs_open(lbh->lzh, name,
1269b1662e6SKyle Evans ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL)
1274146029bSKyle Evans return (BE_ERR_ZFSOPEN);
1284146029bSKyle Evans
1294146029bSKyle Evans ret = prop_list_builder_cb(snap_hdl, &data);
1304146029bSKyle Evans zfs_close(snap_hdl);
1314146029bSKyle Evans return (ret);
1324146029bSKyle Evans }
13328f16a0fSKyle Evans
13496c5db58SKyle Evans int
be_get_dataset_snapshots(libbe_handle_t * lbh,const char * name,nvlist_t * props)13596c5db58SKyle Evans be_get_dataset_snapshots(libbe_handle_t *lbh, const char *name, nvlist_t *props)
13696c5db58SKyle Evans {
13796c5db58SKyle Evans zfs_handle_t *ds_hdl;
13896c5db58SKyle Evans prop_data_t data;
13996c5db58SKyle Evans int ret;
14096c5db58SKyle Evans
14196c5db58SKyle Evans data.lbh = lbh;
14296c5db58SKyle Evans data.list = props;
14396c5db58SKyle Evans data.single_object = false;
144e307eb94SToomas Soome data.bootonce = NULL;
14596c5db58SKyle Evans if ((ds_hdl = zfs_open(lbh->lzh, name,
14696c5db58SKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL)
14796c5db58SKyle Evans return (BE_ERR_ZFSOPEN);
14896c5db58SKyle Evans
1495468566eSKyle Evans ret = snapshot_proplist_update(ds_hdl, &data);
15096c5db58SKyle Evans zfs_close(ds_hdl);
15196c5db58SKyle Evans return (ret);
15296c5db58SKyle Evans }
15396c5db58SKyle Evans
15428f16a0fSKyle Evans /*
15528f16a0fSKyle Evans * Internal callback function used by zfs_iter_filesystems. For each dataset in
15628f16a0fSKyle Evans * the bootenv root, populate an nvlist_t of its relevant properties.
15728f16a0fSKyle Evans */
158843e39ceSKyle Evans int
prop_list_builder_cb(zfs_handle_t * zfs_hdl,void * data_p)15928f16a0fSKyle Evans prop_list_builder_cb(zfs_handle_t *zfs_hdl, void *data_p)
16028f16a0fSKyle Evans {
1614831c931SKyle Evans char buf[512], *mountpoint;
162bfe0869cSKyle Evans prop_data_t *data;
163bfe0869cSKyle Evans libbe_handle_t *lbh;
164bfe0869cSKyle Evans nvlist_t *props;
165bfe0869cSKyle Evans const char *dataset, *name;
166b29bf2f8SKyle Evans boolean_t mounted;
167bfe0869cSKyle Evans
16828f16a0fSKyle Evans /*
169bfe0869cSKyle Evans * XXX TODO:
17028f16a0fSKyle Evans * some system for defining constants for the nvlist keys
17128f16a0fSKyle Evans * error checking
17228f16a0fSKyle Evans */
17328f16a0fSKyle Evans data = (prop_data_t *)data_p;
174bfe0869cSKyle Evans lbh = data->lbh;
17528f16a0fSKyle Evans
1764146029bSKyle Evans if (data->single_object)
1774146029bSKyle Evans props = data->list;
1784146029bSKyle Evans else
17928f16a0fSKyle Evans nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
18028f16a0fSKyle Evans
181bfe0869cSKyle Evans dataset = zfs_get_name(zfs_hdl);
18228f16a0fSKyle Evans nvlist_add_string(props, "dataset", dataset);
18328f16a0fSKyle Evans
184*5086b6ecSR. Christian McDonald if (data->lbh->bootonce != NULL &&
185*5086b6ecSR. Christian McDonald strcmp(dataset, data->lbh->bootonce) == 0)
186e307eb94SToomas Soome nvlist_add_boolean_value(props, "bootonce", true);
187e307eb94SToomas Soome
188bfe0869cSKyle Evans name = strrchr(dataset, '/') + 1;
18928f16a0fSKyle Evans nvlist_add_string(props, "name", name);
19028f16a0fSKyle Evans
1914831c931SKyle Evans mounted = zfs_is_mounted(zfs_hdl, &mountpoint);
19228f16a0fSKyle Evans
1934831c931SKyle Evans if (mounted)
194709b553cSKyle Evans nvlist_add_string(props, "mounted", mountpoint);
195709b553cSKyle Evans
196709b553cSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, 512,
197709b553cSKyle Evans NULL, NULL, 0, 1) == 0)
198709b553cSKyle Evans nvlist_add_string(props, "mountpoint", buf);
19928f16a0fSKyle Evans
20028f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_ORIGIN, buf, 512,
201513044c1SKyle Evans NULL, NULL, 0, 1) == 0)
20228f16a0fSKyle Evans nvlist_add_string(props, "origin", buf);
20328f16a0fSKyle Evans
20428f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_CREATION, buf, 512,
205513044c1SKyle Evans NULL, NULL, 0, 1) == 0)
20628f16a0fSKyle Evans nvlist_add_string(props, "creation", buf);
20728f16a0fSKyle Evans
20828f16a0fSKyle Evans nvlist_add_boolean_value(props, "active",
20928f16a0fSKyle Evans (strcmp(be_active_path(lbh), dataset) == 0));
21028f16a0fSKyle Evans
21128f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512,
212513044c1SKyle Evans NULL, NULL, 0, 1) == 0)
21328f16a0fSKyle Evans nvlist_add_string(props, "used", buf);
21428f16a0fSKyle Evans
21528f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDDS, buf, 512,
216513044c1SKyle Evans NULL, NULL, 0, 1) == 0)
21728f16a0fSKyle Evans nvlist_add_string(props, "usedds", buf);
21828f16a0fSKyle Evans
21928f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDSNAP, buf, 512,
220513044c1SKyle Evans NULL, NULL, 0, 1) == 0)
22128f16a0fSKyle Evans nvlist_add_string(props, "usedsnap", buf);
22228f16a0fSKyle Evans
22328f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDREFRESERV, buf, 512,
224513044c1SKyle Evans NULL, NULL, 0, 1) == 0)
22528f16a0fSKyle Evans nvlist_add_string(props, "usedrefreserv", buf);
22628f16a0fSKyle Evans
22728f16a0fSKyle Evans if (zfs_prop_get(zfs_hdl, ZFS_PROP_REFERENCED, buf, 512,
228513044c1SKyle Evans NULL, NULL, 0, 1) == 0)
22928f16a0fSKyle Evans nvlist_add_string(props, "referenced", buf);
23028f16a0fSKyle Evans
231ff8676ccSKyle Evans nvlist_add_boolean_value(props, "nextboot",
232ff8676ccSKyle Evans (strcmp(be_nextboot_path(lbh), dataset) == 0));
23328f16a0fSKyle Evans
2344146029bSKyle Evans if (!data->single_object)
23528f16a0fSKyle Evans nvlist_add_nvlist(data->list, name, props);
23628f16a0fSKyle Evans
23728f16a0fSKyle Evans return (0);
23828f16a0fSKyle Evans }
23928f16a0fSKyle Evans
24028f16a0fSKyle Evans
24128f16a0fSKyle Evans /*
24228f16a0fSKyle Evans * Updates the properties of each bootenv in the libbe handle
243bfe0869cSKyle Evans * XXX TODO: ensure that this is always consistent (run after adds, deletes,
24428f16a0fSKyle Evans * renames,etc
24528f16a0fSKyle Evans */
246843e39ceSKyle Evans int
be_proplist_update(prop_data_t * data)2475468566eSKyle Evans be_proplist_update(prop_data_t *data)
24828f16a0fSKyle Evans {
24928f16a0fSKyle Evans zfs_handle_t *root_hdl;
25028f16a0fSKyle Evans
251bfe0869cSKyle Evans if ((root_hdl = zfs_open(data->lbh->lzh, data->lbh->root,
252bfe0869cSKyle Evans ZFS_TYPE_FILESYSTEM)) == NULL)
25328f16a0fSKyle Evans return (BE_ERR_ZFSOPEN);
25428f16a0fSKyle Evans
255bfe0869cSKyle Evans /* XXX TODO: some error checking here */
256d411c1d6SMartin Matuska zfs_iter_filesystems(root_hdl, prop_list_builder_cb, data);
25728f16a0fSKyle Evans
25828f16a0fSKyle Evans zfs_close(root_hdl);
25928f16a0fSKyle Evans
26028f16a0fSKyle Evans return (0);
26128f16a0fSKyle Evans }
26228f16a0fSKyle Evans
26396c5db58SKyle Evans static int
snapshot_proplist_update(zfs_handle_t * hdl,prop_data_t * data)2645468566eSKyle Evans snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data)
26596c5db58SKyle Evans {
26696c5db58SKyle Evans
267d411c1d6SMartin Matuska return (zfs_iter_snapshots_sorted(hdl, prop_list_builder_cb, data,
268cefbdf3eSAlan Somers 0, 0));
26996c5db58SKyle Evans }
27096c5db58SKyle Evans
27128f16a0fSKyle Evans
272734e362fSKyle Evans int
be_prop_list_alloc(nvlist_t ** be_list)273734e362fSKyle Evans be_prop_list_alloc(nvlist_t **be_list)
274734e362fSKyle Evans {
275734e362fSKyle Evans
276734e362fSKyle Evans return (nvlist_alloc(be_list, NV_UNIQUE_NAME, KM_SLEEP));
277734e362fSKyle Evans }
278734e362fSKyle Evans
27928f16a0fSKyle Evans /*
28028f16a0fSKyle Evans * frees property list and its children
28128f16a0fSKyle Evans */
28228f16a0fSKyle Evans void
be_prop_list_free(nvlist_t * be_list)28328f16a0fSKyle Evans be_prop_list_free(nvlist_t *be_list)
28428f16a0fSKyle Evans {
28528f16a0fSKyle Evans nvlist_t *prop_list;
286bfe0869cSKyle Evans nvpair_t *be_pair;
28728f16a0fSKyle Evans
288bfe0869cSKyle Evans be_pair = nvlist_next_nvpair(be_list, NULL);
289bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0)
29028f16a0fSKyle Evans nvlist_free(prop_list);
29128f16a0fSKyle Evans
29228f16a0fSKyle Evans while ((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) {
293bfe0869cSKyle Evans if (nvpair_value_nvlist(be_pair, &prop_list) == 0)
29428f16a0fSKyle Evans nvlist_free(prop_list);
29528f16a0fSKyle Evans }
29628f16a0fSKyle Evans }
29728f16a0fSKyle Evans
29828f16a0fSKyle Evans
29928f16a0fSKyle Evans /*
30028f16a0fSKyle Evans * Usage
30128f16a0fSKyle Evans */
302162ec569SKyle Evans int
be_exists(libbe_handle_t * lbh,const char * be)3035773e924SKyle Evans be_exists(libbe_handle_t *lbh, const char *be)
30428f16a0fSKyle Evans {
30528f16a0fSKyle Evans char buf[BE_MAXPATHLEN];
30628f16a0fSKyle Evans
30728f16a0fSKyle Evans be_root_concat(lbh, be, buf);
30828f16a0fSKyle Evans
309709b553cSKyle Evans if (!zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_DATASET))
310162ec569SKyle Evans return (BE_ERR_NOENT);
311709b553cSKyle Evans
31251aecc89SKyle Evans return (BE_ERR_SUCCESS);
31328f16a0fSKyle Evans }
314