1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * CDDL HEADER START
3eda14cbcSMatt Macy  *
4eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy  *
8eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11eda14cbcSMatt Macy  * and limitations under the License.
12eda14cbcSMatt Macy  *
13eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy  *
19eda14cbcSMatt Macy  * CDDL HEADER END
20eda14cbcSMatt Macy  */
21eda14cbcSMatt Macy 
221f1e2261SMartin Matuska /*
231f1e2261SMartin Matuska  * Copyright (c) 2021 Klara, Inc.
241f1e2261SMartin Matuska  */
25eda14cbcSMatt Macy 
26e3aa18adSMartin Matuska #include <alloca.h>
27eda14cbcSMatt Macy #include <errno.h>
28eda14cbcSMatt Macy #include <fcntl.h>
29eda14cbcSMatt Macy #include <libintl.h>
30e3aa18adSMartin Matuska #include <math.h>
31e3aa18adSMartin Matuska #include <poll.h>
32eda14cbcSMatt Macy #include <stdarg.h>
33eda14cbcSMatt Macy #include <stdio.h>
34eda14cbcSMatt Macy #include <stdlib.h>
35eda14cbcSMatt Macy #include <strings.h>
36e3aa18adSMartin Matuska #include <sys/inotify.h>
37eda14cbcSMatt Macy #include <sys/mntent.h>
38e3aa18adSMartin Matuska #include <sys/mnttab.h>
39e3aa18adSMartin Matuska #include <sys/stat.h>
40e3aa18adSMartin Matuska #include <sys/timerfd.h>
41eda14cbcSMatt Macy #include <sys/types.h>
42eda14cbcSMatt Macy #include <sys/wait.h>
43e3aa18adSMartin Matuska #include <unistd.h>
44eda14cbcSMatt Macy 
45eda14cbcSMatt Macy #include <libzfs.h>
46eda14cbcSMatt Macy #include <libzfs_core.h>
47eda14cbcSMatt Macy 
4816038816SMartin Matuska #include "../../libzfs_impl.h"
49eda14cbcSMatt Macy #include "zfs_prop.h"
50eda14cbcSMatt Macy #include <libzutil.h>
51eda14cbcSMatt Macy #include <sys/zfs_sysfs.h>
52eda14cbcSMatt Macy 
53eda14cbcSMatt Macy #define	ZDIFF_SHARESDIR		"/.zfs/shares/"
54eda14cbcSMatt Macy 
55eda14cbcSMatt Macy int
zfs_ioctl(libzfs_handle_t * hdl,int request,zfs_cmd_t * zc)56eda14cbcSMatt Macy zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
57eda14cbcSMatt Macy {
58eda14cbcSMatt Macy 	return (ioctl(hdl->libzfs_fd, request, zc));
59eda14cbcSMatt Macy }
60eda14cbcSMatt Macy 
61eda14cbcSMatt Macy const char *
libzfs_error_init(int error)62eda14cbcSMatt Macy libzfs_error_init(int error)
63eda14cbcSMatt Macy {
64eda14cbcSMatt Macy 	switch (error) {
65eda14cbcSMatt Macy 	case ENXIO:
66eda14cbcSMatt Macy 		return (dgettext(TEXT_DOMAIN, "The ZFS modules are not "
67e3aa18adSMartin Matuska 		    "loaded.\nTry running 'modprobe zfs' as root "
68eda14cbcSMatt Macy 		    "to load them."));
69eda14cbcSMatt Macy 	case ENOENT:
70eda14cbcSMatt Macy 		return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts "
71eda14cbcSMatt Macy 		    "are required.\nTry running 'udevadm trigger' and 'mount "
72eda14cbcSMatt Macy 		    "-t proc proc /proc' as root."));
73eda14cbcSMatt Macy 	case ENOEXEC:
74eda14cbcSMatt Macy 		return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be "
75e3aa18adSMartin Matuska 		    "auto-loaded.\nTry running 'modprobe zfs' as "
76eda14cbcSMatt Macy 		    "root to manually load them."));
77eda14cbcSMatt Macy 	case EACCES:
78eda14cbcSMatt Macy 		return (dgettext(TEXT_DOMAIN, "Permission denied the "
79eda14cbcSMatt Macy 		    "ZFS utilities must be run as root."));
80eda14cbcSMatt Macy 	default:
81eda14cbcSMatt Macy 		return (dgettext(TEXT_DOMAIN, "Failed to initialize the "
82eda14cbcSMatt Macy 		    "libzfs library."));
83eda14cbcSMatt Macy 	}
84eda14cbcSMatt Macy }
85eda14cbcSMatt Macy 
86eda14cbcSMatt Macy /*
87e3aa18adSMartin Matuska  * zfs(4) is loaded by udev if there's a fstype=zfs device present,
88e3aa18adSMartin Matuska  * but if there isn't, load them automatically;
89e3aa18adSMartin Matuska  * always wait for ZFS_DEV to appear via udev.
90eda14cbcSMatt Macy  *
91eda14cbcSMatt Macy  * Environment variables:
92e3aa18adSMartin Matuska  * - ZFS_MODULE_TIMEOUT="<seconds>" - Seconds to wait for ZFS_DEV,
93e3aa18adSMartin Matuska  *                                    defaults to 10, max. 10 min.
94eda14cbcSMatt Macy  */
95eda14cbcSMatt Macy int
libzfs_load_module(void)96eda14cbcSMatt Macy libzfs_load_module(void)
97eda14cbcSMatt Macy {
98e3aa18adSMartin Matuska 	if (access(ZFS_DEV, F_OK) == 0)
99e3aa18adSMartin Matuska 		return (0);
100e3aa18adSMartin Matuska 
101e3aa18adSMartin Matuska 	if (access(ZFS_SYSFS_DIR, F_OK) != 0) {
102a0b956f5SMartin Matuska 		char *argv[] = {(char *)"modprobe", (char *)"zfs", NULL};
103e3aa18adSMartin Matuska 		if (libzfs_run_process("modprobe", argv, 0))
104e3aa18adSMartin Matuska 			return (ENOEXEC);
105e3aa18adSMartin Matuska 
106e3aa18adSMartin Matuska 		if (access(ZFS_SYSFS_DIR, F_OK) != 0)
107e3aa18adSMartin Matuska 			return (ENXIO);
108e3aa18adSMartin Matuska 	}
109e3aa18adSMartin Matuska 
110e3aa18adSMartin Matuska 	const char *timeout_str = getenv("ZFS_MODULE_TIMEOUT");
111e3aa18adSMartin Matuska 	int seconds = 10;
112e3aa18adSMartin Matuska 	if (timeout_str)
113e3aa18adSMartin Matuska 		seconds = MIN(strtol(timeout_str, NULL, 0), 600);
114e3aa18adSMartin Matuska 	struct itimerspec timeout = {.it_value.tv_sec = MAX(seconds, 0)};
115e3aa18adSMartin Matuska 
116e3aa18adSMartin Matuska 	int ino = inotify_init1(IN_CLOEXEC);
117e3aa18adSMartin Matuska 	if (ino == -1)
118e3aa18adSMartin Matuska 		return (ENOENT);
119e3aa18adSMartin Matuska 	inotify_add_watch(ino, ZFS_DEVDIR, IN_CREATE);
120e3aa18adSMartin Matuska 
121e3aa18adSMartin Matuska 	if (access(ZFS_DEV, F_OK) == 0) {
122e3aa18adSMartin Matuska 		close(ino);
123e3aa18adSMartin Matuska 		return (0);
124e3aa18adSMartin Matuska 	} else if (seconds == 0) {
125e3aa18adSMartin Matuska 		close(ino);
126e3aa18adSMartin Matuska 		return (ENOENT);
127e3aa18adSMartin Matuska 	}
128e3aa18adSMartin Matuska 
129e3aa18adSMartin Matuska 	size_t evsz = sizeof (struct inotify_event) + NAME_MAX + 1;
130e3aa18adSMartin Matuska 	struct inotify_event *ev = alloca(evsz);
131e3aa18adSMartin Matuska 
132e3aa18adSMartin Matuska 	int tout = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
133e3aa18adSMartin Matuska 	if (tout == -1) {
134e3aa18adSMartin Matuska 		close(ino);
135e3aa18adSMartin Matuska 		return (ENOENT);
136e3aa18adSMartin Matuska 	}
137e3aa18adSMartin Matuska 	timerfd_settime(tout, 0, &timeout, NULL);
138e3aa18adSMartin Matuska 
139e3aa18adSMartin Matuska 	int ret = ENOENT;
140e3aa18adSMartin Matuska 	struct pollfd pfds[] = {
141e3aa18adSMartin Matuska 		{.fd = ino, .events = POLLIN},
142e3aa18adSMartin Matuska 		{.fd = tout, .events = POLLIN},
143e3aa18adSMartin Matuska 	};
144e3aa18adSMartin Matuska 	while (poll(pfds, ARRAY_SIZE(pfds), -1) != -1) {
145e3aa18adSMartin Matuska 		if (pfds[0].revents & POLLIN) {
146e3aa18adSMartin Matuska 			verify(read(ino, ev, evsz) >
147e3aa18adSMartin Matuska 			    sizeof (struct inotify_event));
148*be181ee2SMartin Matuska 			if (strncmp(ev->name, &ZFS_DEV[sizeof (ZFS_DEVDIR)],
149*be181ee2SMartin Matuska 			    ev->len) == 0) {
150e3aa18adSMartin Matuska 				ret = 0;
151e3aa18adSMartin Matuska 				break;
152e3aa18adSMartin Matuska 			}
153e3aa18adSMartin Matuska 		}
154e3aa18adSMartin Matuska 		if (pfds[1].revents & POLLIN)
155e3aa18adSMartin Matuska 			break;
156e3aa18adSMartin Matuska 	}
157e3aa18adSMartin Matuska 	close(tout);
158e3aa18adSMartin Matuska 	close(ino);
159e3aa18adSMartin Matuska 	return (ret);
160eda14cbcSMatt Macy }
161eda14cbcSMatt Macy 
162eda14cbcSMatt Macy int
find_shares_object(differ_info_t * di)163eda14cbcSMatt Macy find_shares_object(differ_info_t *di)
164eda14cbcSMatt Macy {
165eda14cbcSMatt Macy 	char fullpath[MAXPATHLEN];
166eda14cbcSMatt Macy 	struct stat64 sb = { 0 };
167eda14cbcSMatt Macy 
168eda14cbcSMatt Macy 	(void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
169eda14cbcSMatt Macy 	(void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
170eda14cbcSMatt Macy 
171eda14cbcSMatt Macy 	if (stat64(fullpath, &sb) != 0) {
172eda14cbcSMatt Macy 		(void) snprintf(di->errbuf, sizeof (di->errbuf),
173eda14cbcSMatt Macy 		    dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
174eda14cbcSMatt Macy 		return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
175eda14cbcSMatt Macy 	}
176eda14cbcSMatt Macy 
177eda14cbcSMatt Macy 	di->shares = (uint64_t)sb.st_ino;
178eda14cbcSMatt Macy 	return (0);
179eda14cbcSMatt Macy }
180eda14cbcSMatt Macy 
1816ba2210eSMartin Matuska int
zfs_destroy_snaps_nvl_os(libzfs_handle_t * hdl,nvlist_t * snaps)1826ba2210eSMartin Matuska zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
1836ba2210eSMartin Matuska {
184e92ffd9bSMartin Matuska 	(void) hdl, (void) snaps;
1856ba2210eSMartin Matuska 	return (0);
1866ba2210eSMartin Matuska }
1876ba2210eSMartin Matuska 
188eda14cbcSMatt Macy /*
189e3aa18adSMartin Matuska  * Return allocated loaded module version, or NULL on error (with errno set)
190eda14cbcSMatt Macy  */
191e3aa18adSMartin Matuska char *
zfs_version_kernel(void)192e3aa18adSMartin Matuska zfs_version_kernel(void)
193eda14cbcSMatt Macy {
194e3aa18adSMartin Matuska 	FILE *f = fopen(ZFS_SYSFS_DIR "/version", "re");
195e3aa18adSMartin Matuska 	if (f == NULL)
196e3aa18adSMartin Matuska 		return (NULL);
197eda14cbcSMatt Macy 
198e3aa18adSMartin Matuska 	char *ret = NULL;
199e3aa18adSMartin Matuska 	size_t l;
200e3aa18adSMartin Matuska 	ssize_t read;
201e3aa18adSMartin Matuska 	if ((read = getline(&ret, &l, f)) == -1) {
202e3aa18adSMartin Matuska 		int err = errno;
203e3aa18adSMartin Matuska 		fclose(f);
204e3aa18adSMartin Matuska 		errno = err;
205e3aa18adSMartin Matuska 		return (NULL);
206eda14cbcSMatt Macy 	}
207eda14cbcSMatt Macy 
208e3aa18adSMartin Matuska 	fclose(f);
209e3aa18adSMartin Matuska 	if (ret[read - 1] == '\n')
210e3aa18adSMartin Matuska 		ret[read - 1] = '\0';
211e3aa18adSMartin Matuska 	return (ret);
212eda14cbcSMatt Macy }
2131f1e2261SMartin Matuska 
2141f1e2261SMartin Matuska /*
2151f1e2261SMartin Matuska  * Add or delete the given filesystem to/from the given user namespace.
2161f1e2261SMartin Matuska  */
2171f1e2261SMartin Matuska int
zfs_userns(zfs_handle_t * zhp,const char * nspath,int attach)2181f1e2261SMartin Matuska zfs_userns(zfs_handle_t *zhp, const char *nspath, int attach)
2191f1e2261SMartin Matuska {
2201f1e2261SMartin Matuska 	libzfs_handle_t *hdl = zhp->zfs_hdl;
2211f1e2261SMartin Matuska 	zfs_cmd_t zc = {"\0"};
2221f1e2261SMartin Matuska 	char errbuf[1024];
2231f1e2261SMartin Matuska 	unsigned long cmd;
2241f1e2261SMartin Matuska 	int ret;
2251f1e2261SMartin Matuska 
2261f1e2261SMartin Matuska 	if (attach) {
2271f1e2261SMartin Matuska 		(void) snprintf(errbuf, sizeof (errbuf),
2281f1e2261SMartin Matuska 		    dgettext(TEXT_DOMAIN, "cannot add '%s' to namespace"),
2291f1e2261SMartin Matuska 		    zhp->zfs_name);
2301f1e2261SMartin Matuska 	} else {
2311f1e2261SMartin Matuska 		(void) snprintf(errbuf, sizeof (errbuf),
2321f1e2261SMartin Matuska 		    dgettext(TEXT_DOMAIN, "cannot remove '%s' from namespace"),
2331f1e2261SMartin Matuska 		    zhp->zfs_name);
2341f1e2261SMartin Matuska 	}
2351f1e2261SMartin Matuska 
2361f1e2261SMartin Matuska 	switch (zhp->zfs_type) {
2371f1e2261SMartin Matuska 	case ZFS_TYPE_VOLUME:
2381f1e2261SMartin Matuska 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2391f1e2261SMartin Matuska 		    "volumes can not be namespaced"));
2401f1e2261SMartin Matuska 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2411f1e2261SMartin Matuska 	case ZFS_TYPE_SNAPSHOT:
2421f1e2261SMartin Matuska 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2431f1e2261SMartin Matuska 		    "snapshots can not be namespaced"));
2441f1e2261SMartin Matuska 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2451f1e2261SMartin Matuska 	case ZFS_TYPE_BOOKMARK:
2461f1e2261SMartin Matuska 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2471f1e2261SMartin Matuska 		    "bookmarks can not be namespaced"));
2481f1e2261SMartin Matuska 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2491f1e2261SMartin Matuska 	case ZFS_TYPE_VDEV:
2501f1e2261SMartin Matuska 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2511f1e2261SMartin Matuska 		    "vdevs can not be namespaced"));
2521f1e2261SMartin Matuska 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2531f1e2261SMartin Matuska 	case ZFS_TYPE_INVALID:
2541f1e2261SMartin Matuska 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2551f1e2261SMartin Matuska 		    "invalid zfs_type_t: ZFS_TYPE_INVALID"));
2561f1e2261SMartin Matuska 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2571f1e2261SMartin Matuska 	case ZFS_TYPE_POOL:
2581f1e2261SMartin Matuska 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2591f1e2261SMartin Matuska 		    "pools can not be namespaced"));
2601f1e2261SMartin Matuska 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2611f1e2261SMartin Matuska 	case ZFS_TYPE_FILESYSTEM:
262a0b956f5SMartin Matuska 		break;
2631f1e2261SMartin Matuska 	}
2641f1e2261SMartin Matuska 	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
2651f1e2261SMartin Matuska 
2661f1e2261SMartin Matuska 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2671f1e2261SMartin Matuska 	zc.zc_objset_type = DMU_OST_ZFS;
2681f1e2261SMartin Matuska 	zc.zc_cleanup_fd = open(nspath, O_RDONLY);
2691f1e2261SMartin Matuska 	if (zc.zc_cleanup_fd < 0) {
2701f1e2261SMartin Matuska 		return (zfs_error(hdl, EZFS_NOT_USER_NAMESPACE, errbuf));
2711f1e2261SMartin Matuska 	}
2721f1e2261SMartin Matuska 
2731f1e2261SMartin Matuska 	cmd = attach ? ZFS_IOC_USERNS_ATTACH : ZFS_IOC_USERNS_DETACH;
2741f1e2261SMartin Matuska 	if ((ret = zfs_ioctl(hdl, cmd, &zc)) != 0)
2751f1e2261SMartin Matuska 		zfs_standard_error(hdl, errno, errbuf);
2761f1e2261SMartin Matuska 
2771f1e2261SMartin Matuska 	(void) close(zc.zc_cleanup_fd);
2781f1e2261SMartin Matuska 
2791f1e2261SMartin Matuska 	return (ret);
2801f1e2261SMartin Matuska }
281