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 https://opensource.org/licenses/CDDL-1.0.
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) 2021 Klara, Inc.
24 */
25
26#include <alloca.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <libintl.h>
30#include <math.h>
31#include <poll.h>
32#include <stdarg.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <strings.h>
36#include <sys/inotify.h>
37#include <sys/mntent.h>
38#include <sys/mnttab.h>
39#include <sys/stat.h>
40#include <sys/timerfd.h>
41#include <sys/types.h>
42#include <sys/wait.h>
43#include <unistd.h>
44
45#include <libzfs.h>
46#include <libzfs_core.h>
47
48#include "../../libzfs_impl.h"
49#include "zfs_prop.h"
50#include <libzutil.h>
51#include <sys/zfs_sysfs.h>
52
53#define	ZDIFF_SHARESDIR		"/.zfs/shares/"
54
55int
56zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
57{
58	return (ioctl(hdl->libzfs_fd, request, zc));
59}
60
61const char *
62libzfs_error_init(int error)
63{
64	switch (error) {
65	case ENXIO:
66		return (dgettext(TEXT_DOMAIN, "The ZFS modules are not "
67		    "loaded.\nTry running 'modprobe zfs' as root "
68		    "to load them."));
69	case ENOENT:
70		return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts "
71		    "are required.\nTry running 'udevadm trigger' and 'mount "
72		    "-t proc proc /proc' as root."));
73	case ENOEXEC:
74		return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be "
75		    "auto-loaded.\nTry running 'modprobe zfs' as "
76		    "root to manually load them."));
77	case EACCES:
78		return (dgettext(TEXT_DOMAIN, "Permission denied the "
79		    "ZFS utilities must be run as root."));
80	default:
81		return (dgettext(TEXT_DOMAIN, "Failed to initialize the "
82		    "libzfs library."));
83	}
84}
85
86/*
87 * zfs(4) is loaded by udev if there's a fstype=zfs device present,
88 * but if there isn't, load them automatically;
89 * always wait for ZFS_DEV to appear via udev.
90 *
91 * Environment variables:
92 * - ZFS_MODULE_TIMEOUT="<seconds>" - Seconds to wait for ZFS_DEV,
93 *                                    defaults to 10, max. 10 min.
94 */
95int
96libzfs_load_module(void)
97{
98	if (access(ZFS_DEV, F_OK) == 0)
99		return (0);
100
101	if (access(ZFS_SYSFS_DIR, F_OK) != 0) {
102		char *argv[] = {(char *)"modprobe", (char *)"zfs", NULL};
103		if (libzfs_run_process("modprobe", argv, 0))
104			return (ENOEXEC);
105
106		if (access(ZFS_SYSFS_DIR, F_OK) != 0)
107			return (ENXIO);
108	}
109
110	const char *timeout_str = getenv("ZFS_MODULE_TIMEOUT");
111	int seconds = 10;
112	if (timeout_str)
113		seconds = MIN(strtol(timeout_str, NULL, 0), 600);
114	struct itimerspec timeout = {.it_value.tv_sec = MAX(seconds, 0)};
115
116	int ino = inotify_init1(IN_CLOEXEC);
117	if (ino == -1)
118		return (ENOENT);
119	inotify_add_watch(ino, ZFS_DEVDIR, IN_CREATE);
120
121	if (access(ZFS_DEV, F_OK) == 0) {
122		close(ino);
123		return (0);
124	} else if (seconds == 0) {
125		close(ino);
126		return (ENOENT);
127	}
128
129	size_t evsz = sizeof (struct inotify_event) + NAME_MAX + 1;
130	struct inotify_event *ev = alloca(evsz);
131
132	int tout = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
133	if (tout == -1) {
134		close(ino);
135		return (ENOENT);
136	}
137	timerfd_settime(tout, 0, &timeout, NULL);
138
139	int ret = ENOENT;
140	struct pollfd pfds[] = {
141		{.fd = ino, .events = POLLIN},
142		{.fd = tout, .events = POLLIN},
143	};
144	while (poll(pfds, ARRAY_SIZE(pfds), -1) != -1) {
145		if (pfds[0].revents & POLLIN) {
146			verify(read(ino, ev, evsz) >
147			    sizeof (struct inotify_event));
148			if (strncmp(ev->name, &ZFS_DEV[sizeof (ZFS_DEVDIR)],
149			    ev->len) == 0) {
150				ret = 0;
151				break;
152			}
153		}
154		if (pfds[1].revents & POLLIN)
155			break;
156	}
157	close(tout);
158	close(ino);
159	return (ret);
160}
161
162int
163find_shares_object(differ_info_t *di)
164{
165	char fullpath[MAXPATHLEN];
166	struct stat64 sb = { 0 };
167
168	(void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
169	(void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
170
171	if (stat64(fullpath, &sb) != 0) {
172		(void) snprintf(di->errbuf, sizeof (di->errbuf),
173		    dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
174		return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
175	}
176
177	di->shares = (uint64_t)sb.st_ino;
178	return (0);
179}
180
181int
182zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
183{
184	(void) hdl, (void) snaps;
185	return (0);
186}
187
188/*
189 * Return allocated loaded module version, or NULL on error (with errno set)
190 */
191char *
192zfs_version_kernel(void)
193{
194	FILE *f = fopen(ZFS_SYSFS_DIR "/version", "re");
195	if (f == NULL)
196		return (NULL);
197
198	char *ret = NULL;
199	size_t l;
200	ssize_t read;
201	if ((read = getline(&ret, &l, f)) == -1) {
202		int err = errno;
203		fclose(f);
204		errno = err;
205		return (NULL);
206	}
207
208	fclose(f);
209	if (ret[read - 1] == '\n')
210		ret[read - 1] = '\0';
211	return (ret);
212}
213
214/*
215 * Add or delete the given filesystem to/from the given user namespace.
216 */
217int
218zfs_userns(zfs_handle_t *zhp, const char *nspath, int attach)
219{
220	libzfs_handle_t *hdl = zhp->zfs_hdl;
221	zfs_cmd_t zc = {"\0"};
222	char errbuf[1024];
223	unsigned long cmd;
224	int ret;
225
226	if (attach) {
227		(void) snprintf(errbuf, sizeof (errbuf),
228		    dgettext(TEXT_DOMAIN, "cannot add '%s' to namespace"),
229		    zhp->zfs_name);
230	} else {
231		(void) snprintf(errbuf, sizeof (errbuf),
232		    dgettext(TEXT_DOMAIN, "cannot remove '%s' from namespace"),
233		    zhp->zfs_name);
234	}
235
236	switch (zhp->zfs_type) {
237	case ZFS_TYPE_VOLUME:
238		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
239		    "volumes can not be namespaced"));
240		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
241	case ZFS_TYPE_SNAPSHOT:
242		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
243		    "snapshots can not be namespaced"));
244		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
245	case ZFS_TYPE_BOOKMARK:
246		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
247		    "bookmarks can not be namespaced"));
248		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
249	case ZFS_TYPE_VDEV:
250		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
251		    "vdevs can not be namespaced"));
252		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
253	case ZFS_TYPE_INVALID:
254		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
255		    "invalid zfs_type_t: ZFS_TYPE_INVALID"));
256		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
257	case ZFS_TYPE_POOL:
258		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
259		    "pools can not be namespaced"));
260		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
261	case ZFS_TYPE_FILESYSTEM:
262		break;
263	}
264	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
265
266	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
267	zc.zc_objset_type = DMU_OST_ZFS;
268	zc.zc_cleanup_fd = open(nspath, O_RDONLY);
269	if (zc.zc_cleanup_fd < 0) {
270		return (zfs_error(hdl, EZFS_NOT_USER_NAMESPACE, errbuf));
271	}
272
273	cmd = attach ? ZFS_IOC_USERNS_ATTACH : ZFS_IOC_USERNS_DETACH;
274	if ((ret = zfs_ioctl(hdl, cmd, &zc)) != 0)
275		zfs_standard_error(hdl, errno, errbuf);
276
277	(void) close(zc.zc_cleanup_fd);
278
279	return (ret);
280}
281