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