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