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
42void
43libzfs_set_pipe_max(int infd)
44{
45	/* FreeBSD automatically resizes */
46}
47
48static int
49execvPe(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
110retry:		(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;
163done:
164	return (-1);
165}
166
167int
168execvpe(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#define	ERRBUFLEN 256
180
181static __thread char errbuf[ERRBUFLEN];
182
183const char *
184libzfs_error_init(int error)
185{
186	char *msg = errbuf;
187	size_t len, msglen = ERRBUFLEN;
188
189	if (modfind("zfs") < 0) {
190		len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN,
191		    "Failed to load %s module: "), ZFS_KMOD);
192		msg += len;
193		msglen -= len;
194	}
195
196	(void) snprintf(msg, msglen, "%s", strerror(error));
197
198	return (errbuf);
199}
200
201int
202zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
203{
204	return (zfs_ioctl_fd(hdl->libzfs_fd, request, zc));
205}
206
207/*
208 * Verify the required ZFS_DEV device is available and optionally attempt
209 * to load the ZFS modules.  Under normal circumstances the modules
210 * should already have been loaded by some external mechanism.
211 */
212int
213libzfs_load_module(void)
214{
215	/*
216	 * XXX: kldfind(ZFS_KMOD) would be nice here, but we retain
217	 * modfind("zfs") so out-of-base openzfs userland works with the
218	 * in-base module.
219	 */
220	if (modfind("zfs") < 0) {
221		/* Not present in kernel, try loading it. */
222		if (kldload(ZFS_KMOD) < 0 && errno != EEXIST) {
223			return (errno);
224		}
225	}
226	return (0);
227}
228
229int
230zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg)
231{
232	return (0);
233}
234
235int
236zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
237{
238	return (0);
239}
240
241int
242find_shares_object(differ_info_t *di)
243{
244	return (0);
245}
246
247/*
248 * Attach/detach the given filesystem to/from the given jail.
249 */
250int
251zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
252{
253	libzfs_handle_t *hdl = zhp->zfs_hdl;
254	zfs_cmd_t zc = {"\0"};
255	char errbuf[1024];
256	unsigned long cmd;
257	int ret;
258
259	if (attach) {
260		(void) snprintf(errbuf, sizeof (errbuf),
261		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
262	} else {
263		(void) snprintf(errbuf, sizeof (errbuf),
264		    dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name);
265	}
266
267	switch (zhp->zfs_type) {
268	case ZFS_TYPE_VOLUME:
269		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
270		    "volumes can not be jailed"));
271		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
272	case ZFS_TYPE_SNAPSHOT:
273		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
274		    "snapshots can not be jailed"));
275		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
276	case ZFS_TYPE_BOOKMARK:
277		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
278		    "bookmarks can not be jailed"));
279		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
280	case ZFS_TYPE_POOL:
281	case ZFS_TYPE_FILESYSTEM:
282		/* OK */
283		;
284	}
285	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
286
287	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
288	zc.zc_objset_type = DMU_OST_ZFS;
289	zc.zc_zoneid = jailid;
290
291	cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL;
292	if ((ret = zfs_ioctl(hdl, cmd, &zc)) != 0)
293		zfs_standard_error(hdl, errno, errbuf);
294
295	return (ret);
296}
297
298/*
299 * Set loader options for next boot.
300 */
301int
302zpool_nextboot(libzfs_handle_t *hdl, uint64_t pool_guid, uint64_t dev_guid,
303    const char *command)
304{
305	zfs_cmd_t zc = {"\0"};
306	nvlist_t *args;
307	int error;
308
309	args = fnvlist_alloc();
310	fnvlist_add_uint64(args, ZPOOL_CONFIG_POOL_GUID, pool_guid);
311	fnvlist_add_uint64(args, ZPOOL_CONFIG_GUID, dev_guid);
312	fnvlist_add_string(args, "command", command);
313	error = zcmd_write_src_nvlist(hdl, &zc, args);
314	if (error == 0)
315		error = zfs_ioctl(hdl, ZFS_IOC_NEXTBOOT, &zc);
316	zcmd_free_nvlists(&zc);
317	nvlist_free(args);
318	return (error);
319}
320
321/*
322 * Fill given version buffer with zfs kernel version.
323 * Returns 0 on success, and -1 on error (with errno set)
324 */
325int
326zfs_version_kernel(char *version, int len)
327{
328	size_t l = len;
329
330	return (sysctlbyname("vfs.zfs.version.module",
331	    version, &l, NULL, 0));
332}
333