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