1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2021 Klara, Inc.
24 */
25
26 #include <alloca.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <libintl.h>
30 #include <math.h>
31 #include <poll.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <strings.h>
36 #include <sys/inotify.h>
37 #include <sys/mntent.h>
38 #include <sys/mnttab.h>
39 #include <sys/stat.h>
40 #include <sys/timerfd.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <unistd.h>
44
45 #include <libzfs.h>
46 #include <libzfs_core.h>
47
48 #include "../../libzfs_impl.h"
49 #include "zfs_prop.h"
50 #include <libzutil.h>
51 #include <sys/zfs_sysfs.h>
52
53 #define ZDIFF_SHARESDIR "/.zfs/shares/"
54
55 int
zfs_ioctl(libzfs_handle_t * hdl,int request,zfs_cmd_t * zc)56 zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
57 {
58 return (ioctl(hdl->libzfs_fd, request, zc));
59 }
60
61 const char *
libzfs_error_init(int error)62 libzfs_error_init(int error)
63 {
64 switch (error) {
65 case ENXIO:
66 return (dgettext(TEXT_DOMAIN, "The ZFS modules are not "
67 "loaded.\nTry running 'modprobe zfs' as root "
68 "to load them."));
69 case ENOENT:
70 return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts "
71 "are required.\nTry running 'udevadm trigger' and 'mount "
72 "-t proc proc /proc' as root."));
73 case ENOEXEC:
74 return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be "
75 "auto-loaded.\nTry running 'modprobe zfs' as "
76 "root to manually load them."));
77 case EACCES:
78 return (dgettext(TEXT_DOMAIN, "Permission denied the "
79 "ZFS utilities must be run as root."));
80 default:
81 return (dgettext(TEXT_DOMAIN, "Failed to initialize the "
82 "libzfs library."));
83 }
84 }
85
86 /*
87 * zfs(4) is loaded by udev if there's a fstype=zfs device present,
88 * but if there isn't, load them automatically;
89 * always wait for ZFS_DEV to appear via udev.
90 *
91 * Environment variables:
92 * - ZFS_MODULE_TIMEOUT="<seconds>" - Seconds to wait for ZFS_DEV,
93 * defaults to 10, max. 10 min.
94 */
95 int
libzfs_load_module(void)96 libzfs_load_module(void)
97 {
98 if (access(ZFS_DEV, F_OK) == 0)
99 return (0);
100
101 if (access(ZFS_SYSFS_DIR, F_OK) != 0) {
102 char *argv[] = {(char *)"modprobe", (char *)"zfs", NULL};
103 if (libzfs_run_process("modprobe", argv, 0))
104 return (ENOEXEC);
105
106 if (access(ZFS_SYSFS_DIR, F_OK) != 0)
107 return (ENXIO);
108 }
109
110 const char *timeout_str = getenv("ZFS_MODULE_TIMEOUT");
111 int seconds = 10;
112 if (timeout_str)
113 seconds = MIN(strtol(timeout_str, NULL, 0), 600);
114 struct itimerspec timeout = {.it_value.tv_sec = MAX(seconds, 0)};
115
116 int ino = inotify_init1(IN_CLOEXEC);
117 if (ino == -1)
118 return (ENOENT);
119 inotify_add_watch(ino, ZFS_DEVDIR, IN_CREATE);
120
121 if (access(ZFS_DEV, F_OK) == 0) {
122 close(ino);
123 return (0);
124 } else if (seconds == 0) {
125 close(ino);
126 return (ENOENT);
127 }
128
129 size_t evsz = sizeof (struct inotify_event) + NAME_MAX + 1;
130 struct inotify_event *ev = alloca(evsz);
131
132 int tout = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
133 if (tout == -1) {
134 close(ino);
135 return (ENOENT);
136 }
137 timerfd_settime(tout, 0, &timeout, NULL);
138
139 int ret = ENOENT;
140 struct pollfd pfds[] = {
141 {.fd = ino, .events = POLLIN},
142 {.fd = tout, .events = POLLIN},
143 };
144 while (poll(pfds, ARRAY_SIZE(pfds), -1) != -1) {
145 if (pfds[0].revents & POLLIN) {
146 verify(read(ino, ev, evsz) >
147 sizeof (struct inotify_event));
148 if (strncmp(ev->name, &ZFS_DEV[sizeof (ZFS_DEVDIR)],
149 ev->len) == 0) {
150 ret = 0;
151 break;
152 }
153 }
154 if (pfds[1].revents & POLLIN)
155 break;
156 }
157 close(tout);
158 close(ino);
159 return (ret);
160 }
161
162 int
find_shares_object(differ_info_t * di)163 find_shares_object(differ_info_t *di)
164 {
165 char fullpath[MAXPATHLEN];
166 struct stat64 sb = { 0 };
167
168 (void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
169 (void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
170
171 if (stat64(fullpath, &sb) != 0) {
172 (void) snprintf(di->errbuf, sizeof (di->errbuf),
173 dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
174 return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
175 }
176
177 di->shares = (uint64_t)sb.st_ino;
178 return (0);
179 }
180
181 int
zfs_destroy_snaps_nvl_os(libzfs_handle_t * hdl,nvlist_t * snaps)182 zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
183 {
184 (void) hdl, (void) snaps;
185 return (0);
186 }
187
188 /*
189 * Return allocated loaded module version, or NULL on error (with errno set)
190 */
191 char *
zfs_version_kernel(void)192 zfs_version_kernel(void)
193 {
194 FILE *f = fopen(ZFS_SYSFS_DIR "/version", "re");
195 if (f == NULL)
196 return (NULL);
197
198 char *ret = NULL;
199 size_t l;
200 ssize_t read;
201 if ((read = getline(&ret, &l, f)) == -1) {
202 int err = errno;
203 fclose(f);
204 errno = err;
205 return (NULL);
206 }
207
208 fclose(f);
209 if (ret[read - 1] == '\n')
210 ret[read - 1] = '\0';
211 return (ret);
212 }
213
214 /*
215 * Add or delete the given filesystem to/from the given user namespace.
216 */
217 int
zfs_userns(zfs_handle_t * zhp,const char * nspath,int attach)218 zfs_userns(zfs_handle_t *zhp, const char *nspath, int attach)
219 {
220 libzfs_handle_t *hdl = zhp->zfs_hdl;
221 zfs_cmd_t zc = {"\0"};
222 char errbuf[1024];
223 unsigned long cmd;
224 int ret;
225
226 if (attach) {
227 (void) snprintf(errbuf, sizeof (errbuf),
228 dgettext(TEXT_DOMAIN, "cannot add '%s' to namespace"),
229 zhp->zfs_name);
230 } else {
231 (void) snprintf(errbuf, sizeof (errbuf),
232 dgettext(TEXT_DOMAIN, "cannot remove '%s' from namespace"),
233 zhp->zfs_name);
234 }
235
236 switch (zhp->zfs_type) {
237 case ZFS_TYPE_VOLUME:
238 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
239 "volumes can not be namespaced"));
240 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
241 case ZFS_TYPE_SNAPSHOT:
242 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
243 "snapshots can not be namespaced"));
244 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
245 case ZFS_TYPE_BOOKMARK:
246 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
247 "bookmarks can not be namespaced"));
248 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
249 case ZFS_TYPE_VDEV:
250 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
251 "vdevs can not be namespaced"));
252 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
253 case ZFS_TYPE_INVALID:
254 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
255 "invalid zfs_type_t: ZFS_TYPE_INVALID"));
256 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
257 case ZFS_TYPE_POOL:
258 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
259 "pools can not be namespaced"));
260 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
261 case ZFS_TYPE_FILESYSTEM:
262 break;
263 }
264 assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
265
266 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
267 zc.zc_objset_type = DMU_OST_ZFS;
268 zc.zc_cleanup_fd = open(nspath, O_RDONLY);
269 if (zc.zc_cleanup_fd < 0) {
270 return (zfs_error(hdl, EZFS_NOT_USER_NAMESPACE, errbuf));
271 }
272
273 cmd = attach ? ZFS_IOC_USERNS_ATTACH : ZFS_IOC_USERNS_DETACH;
274 if ((ret = zfs_ioctl(hdl, cmd, &zc)) != 0)
275 zfs_standard_error(hdl, errno, errbuf);
276
277 (void) close(zc.zc_cleanup_fd);
278
279 return (ret);
280 }
281