xref: /freebsd/sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_compat.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
25  */
26 #include "../../libzfs_impl.h"
27 #include <libzfs.h>
28 #include <libzutil.h>
29 #include <sys/sysctl.h>
30 #include <libintl.h>
31 #include <sys/linker.h>
32 #include <sys/module.h>
33 #include <sys/stat.h>
34 #include <sys/param.h>
35 
36 #ifdef IN_BASE
37 #define	ZFS_KMOD	"zfs"
38 #else
39 #define	ZFS_KMOD	"openzfs"
40 #endif
41 
42 #ifndef HAVE_EXECVPE
43 /* FreeBSD prior to 15 lacks execvpe */
44 static int
execvPe(const char * name,const char * path,char * const * argv,char * const * envp)45 execvPe(const char *name, const char *path, char * const *argv,
46     char * const *envp)
47 {
48 	const char **memp;
49 	size_t cnt, lp, ln;
50 	int eacces, save_errno;
51 	char buf[MAXPATHLEN];
52 	const char *bp, *np, *op, *p;
53 	struct stat sb;
54 
55 	eacces = 0;
56 
57 	/* If it's an absolute or relative path name, it's easy. */
58 	if (strchr(name, '/')) {
59 		bp = name;
60 		op = NULL;
61 		goto retry;
62 	}
63 	bp = buf;
64 
65 	/* If it's an empty path name, fail in the usual POSIX way. */
66 	if (*name == '\0') {
67 		errno = ENOENT;
68 		return (-1);
69 	}
70 
71 	op = path;
72 	ln = strlen(name);
73 	while (op != NULL) {
74 		np = strchrnul(op, ':');
75 
76 		/*
77 		 * It's a SHELL path -- double, leading and trailing colons
78 		 * mean the current directory.
79 		 */
80 		if (np == op) {
81 			/* Empty component. */
82 			p = ".";
83 			lp = 1;
84 		} else {
85 			/* Non-empty component. */
86 			p = op;
87 			lp = np - op;
88 		}
89 
90 		/* Advance to the next component or terminate after this. */
91 		if (*np == '\0')
92 			op = NULL;
93 		else
94 			op = np + 1;
95 
96 		/*
97 		 * If the path is too long complain.  This is a possible
98 		 * security issue; given a way to make the path too long
99 		 * the user may execute the wrong program.
100 		 */
101 		if (lp + ln + 2 > sizeof (buf)) {
102 			(void) write(STDERR_FILENO, "execvP: ", 8);
103 			(void) write(STDERR_FILENO, p, lp);
104 			(void) write(STDERR_FILENO, ": path too long\n",
105 			    16);
106 			continue;
107 		}
108 		memcpy(buf, p, lp);
109 		buf[lp] = '/';
110 		memcpy(buf + lp + 1, name, ln);
111 		buf[lp + ln + 1] = '\0';
112 
113 retry:		(void) execve(bp, argv, envp);
114 		switch (errno) {
115 		case E2BIG:
116 			goto done;
117 		case ELOOP:
118 		case ENAMETOOLONG:
119 		case ENOENT:
120 			break;
121 		case ENOEXEC:
122 			for (cnt = 0; argv[cnt]; ++cnt)
123 				;
124 
125 			/*
126 			 * cnt may be 0 above; always allocate at least
127 			 * 3 entries so that we can at least fit "sh", bp, and
128 			 * the NULL terminator.  We can rely on cnt to take into
129 			 * account the NULL terminator in all other scenarios,
130 			 * as we drop argv[0].
131 			 */
132 			memp = alloca(MAX(3, cnt + 2) * sizeof (char *));
133 			if (memp == NULL) {
134 				/* errno = ENOMEM; XXX override ENOEXEC? */
135 				goto done;
136 			}
137 			if (cnt > 0) {
138 				memp[0] = argv[0];
139 				memp[1] = bp;
140 				memcpy(memp + 2, argv + 1,
141 				    cnt * sizeof (char *));
142 			} else {
143 				memp[0] = "sh";
144 				memp[1] = bp;
145 				memp[2] = NULL;
146 			}
147 			(void) execve(_PATH_BSHELL,
148 			    __DECONST(char **, memp), envp);
149 			goto done;
150 		case ENOMEM:
151 			goto done;
152 		case ENOTDIR:
153 			break;
154 		case ETXTBSY:
155 			/*
156 			 * We used to retry here, but sh(1) doesn't.
157 			 */
158 			goto done;
159 		default:
160 			/*
161 			 * EACCES may be for an inaccessible directory or
162 			 * a non-executable file.  Call stat() to decide
163 			 * which.  This also handles ambiguities for EFAULT
164 			 * and EIO, and undocumented errors like ESTALE.
165 			 * We hope that the race for a stat() is unimportant.
166 			 */
167 			save_errno = errno;
168 			if (stat(bp, &sb) != 0)
169 				break;
170 			if (save_errno == EACCES) {
171 				eacces = 1;
172 				continue;
173 			}
174 			errno = save_errno;
175 			goto done;
176 		}
177 	}
178 	if (eacces)
179 		errno = EACCES;
180 	else
181 		errno = ENOENT;
182 done:
183 	return (-1);
184 }
185 
186 int
execvpe(const char * name,char * const argv[],char * const envp[])187 execvpe(const char *name, char * const argv[], char * const envp[])
188 {
189 	const char *path;
190 
191 	/* Get the path we're searching. */
192 	if ((path = getenv("PATH")) == NULL)
193 		path = _PATH_DEFPATH;
194 
195 	return (execvPe(name, path, argv, envp));
196 }
197 #endif /* !HAVE_EXECVPE */
198 
199 static __thread char errbuf[ERRBUFLEN];
200 
201 const char *
libzfs_error_init(int error)202 libzfs_error_init(int error)
203 {
204 	char *msg = errbuf;
205 	size_t msglen = sizeof (errbuf);
206 
207 	if (modfind("zfs") < 0) {
208 		size_t len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN,
209 		    "Failed to load %s module: "), ZFS_KMOD);
210 		if (len >= msglen)
211 			len = msglen - 1;
212 		msg += len;
213 		msglen -= len;
214 	}
215 
216 	(void) snprintf(msg, msglen, "%s", zfs_strerror(error));
217 
218 	return (errbuf);
219 }
220 
221 int
zfs_ioctl(libzfs_handle_t * hdl,int request,zfs_cmd_t * zc)222 zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
223 {
224 	return (lzc_ioctl_fd(hdl->libzfs_fd, request, zc));
225 }
226 
227 /*
228  * Verify the required ZFS_DEV device is available and optionally attempt
229  * to load the ZFS modules.  Under normal circumstances the modules
230  * should already have been loaded by some external mechanism.
231  */
232 int
libzfs_load_module(void)233 libzfs_load_module(void)
234 {
235 	/*
236 	 * XXX: kldfind(ZFS_KMOD) would be nice here, but we retain
237 	 * modfind("zfs") so out-of-base openzfs userland works with the
238 	 * in-base module.
239 	 */
240 	if (modfind("zfs") < 0) {
241 		/* Not present in kernel, try loading it. */
242 		if (kldload(ZFS_KMOD) < 0 && errno != EEXIST) {
243 			return (errno);
244 		}
245 	}
246 	return (0);
247 }
248 
249 int
zpool_relabel_disk(libzfs_handle_t * hdl,const char * path,const char * msg)250 zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg)
251 {
252 	(void) hdl, (void) path, (void) msg;
253 	return (0);
254 }
255 
256 int
zpool_label_disk(libzfs_handle_t * hdl,zpool_handle_t * zhp,const char * name)257 zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
258 {
259 	(void) hdl, (void) zhp, (void) name;
260 	return (0);
261 }
262 
263 int
find_shares_object(differ_info_t * di)264 find_shares_object(differ_info_t *di)
265 {
266 	(void) di;
267 	return (0);
268 }
269 
270 int
zfs_destroy_snaps_nvl_os(libzfs_handle_t * hdl,nvlist_t * snaps)271 zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
272 {
273 	(void) hdl, (void) snaps;
274 	return (0);
275 }
276 
277 /*
278  * Attach/detach the given filesystem to/from the given jail.
279  */
280 int
zfs_jail(zfs_handle_t * zhp,int jailid,int attach)281 zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
282 {
283 	libzfs_handle_t *hdl = zhp->zfs_hdl;
284 	zfs_cmd_t zc = {"\0"};
285 	unsigned long cmd;
286 	int ret;
287 
288 	if (attach) {
289 		(void) snprintf(errbuf, sizeof (errbuf),
290 		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
291 	} else {
292 		(void) snprintf(errbuf, sizeof (errbuf),
293 		    dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name);
294 	}
295 
296 	switch (zhp->zfs_type) {
297 	case ZFS_TYPE_VOLUME:
298 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
299 		    "volumes can not be jailed"));
300 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
301 	case ZFS_TYPE_SNAPSHOT:
302 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
303 		    "snapshots can not be jailed"));
304 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
305 	case ZFS_TYPE_BOOKMARK:
306 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
307 		    "bookmarks can not be jailed"));
308 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
309 	case ZFS_TYPE_VDEV:
310 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
311 		    "vdevs can not be jailed"));
312 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
313 	case ZFS_TYPE_INVALID:
314 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
315 		    "invalid zfs_type_t: ZFS_TYPE_INVALID"));
316 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
317 	case ZFS_TYPE_POOL:
318 	case ZFS_TYPE_FILESYSTEM:
319 		/* OK */
320 		;
321 	}
322 	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
323 
324 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
325 	zc.zc_objset_type = DMU_OST_ZFS;
326 	zc.zc_zoneid = jailid;
327 
328 	cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL;
329 	if ((ret = zfs_ioctl(hdl, cmd, &zc)) != 0)
330 		zfs_standard_error(hdl, errno, errbuf);
331 
332 	return (ret);
333 }
334 
335 /*
336  * Set loader options for next boot.
337  */
338 int
zpool_nextboot(libzfs_handle_t * hdl,uint64_t pool_guid,uint64_t dev_guid,const char * command)339 zpool_nextboot(libzfs_handle_t *hdl, uint64_t pool_guid, uint64_t dev_guid,
340     const char *command)
341 {
342 	zfs_cmd_t zc = {"\0"};
343 	nvlist_t *args;
344 
345 	args = fnvlist_alloc();
346 	fnvlist_add_uint64(args, ZPOOL_CONFIG_POOL_GUID, pool_guid);
347 	fnvlist_add_uint64(args, ZPOOL_CONFIG_GUID, dev_guid);
348 	fnvlist_add_string(args, "command", command);
349 	zcmd_write_src_nvlist(hdl, &zc, args);
350 	int error = zfs_ioctl(hdl, ZFS_IOC_NEXTBOOT, &zc);
351 	zcmd_free_nvlists(&zc);
352 	nvlist_free(args);
353 	return (error);
354 }
355 
356 /*
357  * Return allocated loaded module version, or NULL on error (with errno set)
358  */
359 char *
zfs_version_kernel(void)360 zfs_version_kernel(void)
361 {
362 	size_t l;
363 	if (sysctlbyname("vfs.zfs.version.module",
364 	    NULL, &l, NULL, 0) == -1)
365 		return (NULL);
366 	char *version = malloc(l);
367 	if (version == NULL)
368 		return (NULL);
369 	if (sysctlbyname("vfs.zfs.version.module",
370 	    version, &l, NULL, 0) == -1) {
371 		free(version);
372 		return (NULL);
373 	}
374 	return (version);
375 }
376