]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libbe/be_access.c
MFC r342362-r342363: config(8) duplicate option handling
[FreeBSD/FreeBSD.git] / lib / libbe / be_access.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 struct be_mountcheck_info {
37         const char *path;
38         char *name;
39 };
40
41 static int
42 be_mountcheck_cb(zfs_handle_t *zfs_hdl, void *data)
43 {
44         struct be_mountcheck_info *info;
45         char *mountpoint;
46
47         if (data == NULL)
48                 return (1);
49         info = (struct be_mountcheck_info *)data;
50         if (!zfs_is_mounted(zfs_hdl, &mountpoint))
51                 return (0);
52         if (strcmp(mountpoint, info->path) == 0) {
53                 info->name = strdup(zfs_get_name(zfs_hdl));
54                 free(mountpoint);
55                 return (1);
56         }
57         free(mountpoint);
58         return (0);
59 }
60
61 /*
62  * usage
63  */
64 int
65 be_mounted_at(libbe_handle_t *lbh, const char *path, nvlist_t *details)
66 {
67         char be[BE_MAXPATHLEN];
68         zfs_handle_t *root_hdl;
69         struct be_mountcheck_info info;
70         prop_data_t propinfo;
71
72         bzero(&be, BE_MAXPATHLEN);
73         if ((root_hdl = zfs_open(lbh->lzh, lbh->root,
74             ZFS_TYPE_FILESYSTEM)) == NULL)
75                 return (BE_ERR_ZFSOPEN);
76
77         info.path = path;
78         info.name = NULL;
79         zfs_iter_filesystems(root_hdl, be_mountcheck_cb, &info);
80         zfs_close(root_hdl);
81
82         if (info.name != NULL) {
83                 if (details != NULL) {
84                         if ((root_hdl = zfs_open(lbh->lzh, lbh->root,
85                             ZFS_TYPE_FILESYSTEM)) == NULL) {
86                                 free(info.name);
87                                 return (BE_ERR_ZFSOPEN);
88                         }
89
90                         propinfo.lbh = lbh;
91                         propinfo.list = details;
92                         propinfo.single_object = false;
93                         prop_list_builder_cb(root_hdl, &propinfo);
94                         zfs_close(root_hdl);
95                 }
96                 free(info.name);
97                 return (0);
98         }
99         return (1);
100 }
101
102 /*
103  * usage
104  */
105 int
106 be_mount(libbe_handle_t *lbh, char *bootenv, char *mountpoint, int flags,
107     char *result_loc)
108 {
109         char be[BE_MAXPATHLEN];
110         char mnt_temp[BE_MAXPATHLEN];
111         int mntflags;
112         int err;
113
114         if ((err = be_root_concat(lbh, bootenv, be)) != 0)
115                 return (set_error(lbh, err));
116
117         if ((err = be_exists(lbh, bootenv)) != 0)
118                 return (set_error(lbh, err));
119
120         if (is_mounted(lbh->lzh, be, NULL))
121                 return (set_error(lbh, BE_ERR_MOUNTED));
122
123         mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0;
124
125         /* Create mountpoint if it is not specified */
126         if (mountpoint == NULL) {
127                 strlcpy(mnt_temp, "/tmp/be_mount.XXXX", sizeof(mnt_temp));
128                 if (mkdtemp(mnt_temp) == NULL)
129                         return (set_error(lbh, BE_ERR_IO));
130         }
131
132         char opt = '\0';
133         if ((err = zmount(be, (mountpoint == NULL) ? mnt_temp : mountpoint,
134             mntflags, __DECONST(char *, MNTTYPE_ZFS), NULL, 0, &opt, 1)) != 0) {
135                 switch (errno) {
136                 case ENAMETOOLONG:
137                         return (set_error(lbh, BE_ERR_PATHLEN));
138                 case ELOOP:
139                 case ENOENT:
140                 case ENOTDIR:
141                         return (set_error(lbh, BE_ERR_BADPATH));
142                 case EPERM:
143                         return (set_error(lbh, BE_ERR_PERMS));
144                 case EBUSY:
145                         return (set_error(lbh, BE_ERR_PATHBUSY));
146                 default:
147                         return (set_error(lbh, BE_ERR_UNKNOWN));
148                 }
149         }
150
151         if (result_loc != NULL)
152                 strlcpy(result_loc, mountpoint == NULL ? mnt_temp : mountpoint,
153                     BE_MAXPATHLEN);
154
155         return (BE_ERR_SUCCESS);
156 }
157
158
159 /*
160  * usage
161  */
162 int
163 be_unmount(libbe_handle_t *lbh, char *bootenv, int flags)
164 {
165         int err, mntflags;
166         char be[BE_MAXPATHLEN];
167         struct statfs *mntbuf;
168         int mntsize;
169         char *mntpath;
170
171         if ((err = be_root_concat(lbh, bootenv, be)) != 0)
172                 return (set_error(lbh, err));
173
174         if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
175                 if (errno == EIO)
176                         return (set_error(lbh, BE_ERR_IO));
177                 return (set_error(lbh, BE_ERR_NOMOUNT));
178         }
179
180         mntpath = NULL;
181         for (int i = 0; i < mntsize; ++i) {
182                 /* 0x000000de is the type number of zfs */
183                 if (mntbuf[i].f_type != 0x000000de)
184                         continue;
185
186                 if (strcmp(mntbuf[i].f_mntfromname, be) == 0) {
187                         mntpath = mntbuf[i].f_mntonname;
188                         break;
189                 }
190         }
191
192         if (mntpath == NULL)
193                 return (set_error(lbh, BE_ERR_NOMOUNT));
194
195         mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0;
196
197         if ((err = unmount(mntpath, mntflags)) != 0) {
198                 switch (errno) {
199                 case ENAMETOOLONG:
200                         return (set_error(lbh, BE_ERR_PATHLEN));
201                 case ELOOP:
202                 case ENOENT:
203                 case ENOTDIR:
204                         return (set_error(lbh, BE_ERR_BADPATH));
205                 case EPERM:
206                         return (set_error(lbh, BE_ERR_PERMS));
207                 case EBUSY:
208                         return (set_error(lbh, BE_ERR_PATHBUSY));
209                 default:
210                         return (set_error(lbh, BE_ERR_UNKNOWN));
211                 }
212         }
213
214         return (set_error(lbh, BE_ERR_SUCCESS));
215 }