]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libbe/be_info.c
Update our devicetree to 4.19 for arm and arm64
[FreeBSD/FreeBSD.git] / lib / libbe / be_info.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
5  * Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "be.h"
34 #include "be_impl.h"
35
36 static int snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data);
37
38 /*
39  * Returns the name of the active boot environment
40  */
41 const char *
42 be_active_name(libbe_handle_t *lbh)
43 {
44
45         return (strrchr(lbh->rootfs, '/') + sizeof(char));
46 }
47
48
49 /*
50  * Returns full path of the active boot environment
51  */
52 const char *
53 be_active_path(libbe_handle_t *lbh)
54 {
55
56         return (lbh->rootfs);
57 }
58
59 /*
60  * Returns the name of the next active boot environment
61  */
62 const char *
63 be_nextboot_name(libbe_handle_t *lbh)
64 {
65
66         return (strrchr(lbh->bootfs, '/') + sizeof(char));
67 }
68
69
70 /*
71  * Returns full path of the active boot environment
72  */
73 const char *
74 be_nextboot_path(libbe_handle_t *lbh)
75 {
76
77         return (lbh->bootfs);
78 }
79
80
81 /*
82  * Returns the path of the boot environment root dataset
83  */
84 const char *
85 be_root_path(libbe_handle_t *lbh)
86 {
87
88         return (lbh->root);
89 }
90
91
92 /*
93  * Populates dsnvl with one nvlist per bootenv dataset describing the properties
94  * of that dataset that we've declared ourselves to care about.
95  */
96 int
97 be_get_bootenv_props(libbe_handle_t *lbh, nvlist_t *dsnvl)
98 {
99         prop_data_t data;
100
101         data.lbh = lbh;
102         data.list = dsnvl;
103         data.single_object = false;
104         return (be_proplist_update(&data));
105 }
106
107 int
108 be_get_dataset_props(libbe_handle_t *lbh, const char *name, nvlist_t *props)
109 {
110         zfs_handle_t *snap_hdl;
111         prop_data_t data;
112         int ret;
113
114         data.lbh = lbh;
115         data.list = props;
116         data.single_object = true;
117         if ((snap_hdl = zfs_open(lbh->lzh, name,
118             ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL)
119                 return (BE_ERR_ZFSOPEN);
120
121         ret = prop_list_builder_cb(snap_hdl, &data);
122         zfs_close(snap_hdl);
123         return (ret);
124 }
125
126 int
127 be_get_dataset_snapshots(libbe_handle_t *lbh, const char *name, nvlist_t *props)
128 {
129         zfs_handle_t *ds_hdl;
130         prop_data_t data;
131         int ret;
132
133         data.lbh = lbh;
134         data.list = props;
135         data.single_object = false;
136         if ((ds_hdl = zfs_open(lbh->lzh, name,
137             ZFS_TYPE_FILESYSTEM)) == NULL)
138                 return (BE_ERR_ZFSOPEN);
139
140         ret = snapshot_proplist_update(ds_hdl, &data);
141         zfs_close(ds_hdl);
142         return (ret);
143 }
144
145 /*
146  * Internal callback function used by zfs_iter_filesystems. For each dataset in
147  * the bootenv root, populate an nvlist_t of its relevant properties.
148  */
149 int
150 prop_list_builder_cb(zfs_handle_t *zfs_hdl, void *data_p)
151 {
152         char buf[512], *mountpoint;
153         prop_data_t *data;
154         libbe_handle_t *lbh;
155         nvlist_t *props;
156         const char *dataset, *name;
157         boolean_t mounted;
158
159         /*
160          * XXX TODO:
161          *      some system for defining constants for the nvlist keys
162          *      error checking
163          */
164         data = (prop_data_t *)data_p;
165         lbh = data->lbh;
166
167         if (data->single_object)
168                 props = data->list;
169         else
170                 nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
171
172         dataset = zfs_get_name(zfs_hdl);
173         nvlist_add_string(props, "dataset", dataset);
174
175         name = strrchr(dataset, '/') + 1;
176         nvlist_add_string(props, "name", name);
177
178         mounted = zfs_is_mounted(zfs_hdl, &mountpoint);
179
180         if (mounted)
181                 nvlist_add_string(props, "mounted", mountpoint);
182
183         if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, 512,
184             NULL, NULL, 0, 1) == 0)
185                 nvlist_add_string(props, "mountpoint", buf);
186
187         if (zfs_prop_get(zfs_hdl, ZFS_PROP_ORIGIN, buf, 512,
188             NULL, NULL, 0, 1) == 0)
189                 nvlist_add_string(props, "origin", buf);
190
191         if (zfs_prop_get(zfs_hdl, ZFS_PROP_CREATION, buf, 512,
192             NULL, NULL, 0, 1) == 0)
193                 nvlist_add_string(props, "creation", buf);
194
195         nvlist_add_boolean_value(props, "active",
196             (strcmp(be_active_path(lbh), dataset) == 0));
197
198         if (zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512,
199             NULL, NULL, 0, 1) == 0)
200                 nvlist_add_string(props, "used", buf);
201
202         if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDDS, buf, 512,
203             NULL, NULL, 0, 1) == 0)
204                 nvlist_add_string(props, "usedds", buf);
205
206         if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDSNAP, buf, 512,
207             NULL, NULL, 0, 1) == 0)
208                 nvlist_add_string(props, "usedsnap", buf);
209
210         if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDREFRESERV, buf, 512,
211             NULL, NULL, 0, 1) == 0)
212                 nvlist_add_string(props, "usedrefreserv", buf);
213
214         if (zfs_prop_get(zfs_hdl, ZFS_PROP_REFERENCED, buf, 512,
215             NULL, NULL, 0, 1) == 0)
216                 nvlist_add_string(props, "referenced", buf);
217
218         nvlist_add_boolean_value(props, "nextboot",
219             (strcmp(be_nextboot_path(lbh), dataset) == 0));
220
221         if (!data->single_object)
222                 nvlist_add_nvlist(data->list, name, props);
223
224         return (0);
225 }
226
227
228 /*
229  * Updates the properties of each bootenv in the libbe handle
230  * XXX TODO: ensure that this is always consistent (run after adds, deletes,
231  *       renames,etc
232  */
233 int
234 be_proplist_update(prop_data_t *data)
235 {
236         zfs_handle_t *root_hdl;
237
238         if ((root_hdl = zfs_open(data->lbh->lzh, data->lbh->root,
239             ZFS_TYPE_FILESYSTEM)) == NULL)
240                 return (BE_ERR_ZFSOPEN);
241
242         /* XXX TODO: some error checking here */
243         zfs_iter_filesystems(root_hdl, prop_list_builder_cb, data);
244
245         zfs_close(root_hdl);
246
247         return (0);
248 }
249
250 static int
251 snapshot_proplist_update(zfs_handle_t *hdl, prop_data_t *data)
252 {
253
254         return (zfs_iter_snapshots_sorted(hdl, prop_list_builder_cb, data));
255 }
256
257
258 int
259 be_prop_list_alloc(nvlist_t **be_list)
260 {
261
262         return (nvlist_alloc(be_list, NV_UNIQUE_NAME, KM_SLEEP));
263 }
264
265 /*
266  * frees property list and its children
267  */
268 void
269 be_prop_list_free(nvlist_t *be_list)
270 {
271         nvlist_t *prop_list;
272         nvpair_t *be_pair;
273
274         be_pair = nvlist_next_nvpair(be_list, NULL);
275         if (nvpair_value_nvlist(be_pair, &prop_list) == 0)
276                 nvlist_free(prop_list);
277
278         while ((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) {
279                 if (nvpair_value_nvlist(be_pair, &prop_list) == 0)
280                         nvlist_free(prop_list);
281         }
282 }
283
284
285 /*
286  * Usage
287  */
288 int
289 be_exists(libbe_handle_t *lbh, char *be)
290 {
291         char buf[BE_MAXPATHLEN];
292         nvlist_t *dsprops;
293         char *mntpoint;
294         bool valid;
295
296         be_root_concat(lbh, be, buf);
297
298         if (!zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_DATASET))
299                 return (BE_ERR_NOENT);
300
301         /* Also check if it's mounted at / */
302         if (be_prop_list_alloc(&dsprops) != 0)
303                 return (BE_ERR_UNKNOWN);
304
305         if (be_get_dataset_props(lbh, buf, dsprops) != 0) {
306                 nvlist_free(dsprops);
307                 return (BE_ERR_UNKNOWN);
308         }
309
310         if (nvlist_lookup_string(dsprops, "mountpoint", &mntpoint) == 0) {
311                 valid = (strcmp(mntpoint, "/") == 0);
312                 nvlist_free(dsprops);
313                 return (valid ? BE_ERR_SUCCESS : BE_ERR_BADMOUNT);
314         }
315
316         nvlist_free(dsprops);
317         return (BE_ERR_BADMOUNT);
318 }