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