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 #include <errno.h>
24 #include <fcntl.h>
25 #include <libintl.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <math.h>
32 #include <sys/stat.h>
33 #include <sys/mnttab.h>
34 #include <sys/mntent.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 
38 #include <libzfs.h>
39 #include <libzfs_core.h>
40 
41 #include "../../libzfs_impl.h"
42 #include "zfs_prop.h"
43 #include <libzutil.h>
44 #include <sys/zfs_sysfs.h>
45 
46 #define	ZDIFF_SHARESDIR		"/.zfs/shares/"
47 
48 int
49 zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
50 {
51 	return (ioctl(hdl->libzfs_fd, request, zc));
52 }
53 
54 const char *
55 libzfs_error_init(int error)
56 {
57 	switch (error) {
58 	case ENXIO:
59 		return (dgettext(TEXT_DOMAIN, "The ZFS modules are not "
60 		    "loaded.\nTry running '/sbin/modprobe zfs' as root "
61 		    "to load them."));
62 	case ENOENT:
63 		return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts "
64 		    "are required.\nTry running 'udevadm trigger' and 'mount "
65 		    "-t proc proc /proc' as root."));
66 	case ENOEXEC:
67 		return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be "
68 		    "auto-loaded.\nTry running '/sbin/modprobe zfs' as "
69 		    "root to manually load them."));
70 	case EACCES:
71 		return (dgettext(TEXT_DOMAIN, "Permission denied the "
72 		    "ZFS utilities must be run as root."));
73 	default:
74 		return (dgettext(TEXT_DOMAIN, "Failed to initialize the "
75 		    "libzfs library."));
76 	}
77 }
78 
79 static int
80 libzfs_module_loaded(const char *module)
81 {
82 	const char path_prefix[] = "/sys/module/";
83 	char path[256];
84 
85 	memcpy(path, path_prefix, sizeof (path_prefix) - 1);
86 	strcpy(path + sizeof (path_prefix) - 1, module);
87 
88 	return (access(path, F_OK) == 0);
89 }
90 
91 /*
92  * Verify the required ZFS_DEV device is available and optionally attempt
93  * to load the ZFS modules.  Under normal circumstances the modules
94  * should already have been loaded by some external mechanism.
95  *
96  * Environment variables:
97  * - ZFS_MODULE_LOADING="YES|yes|ON|on" - Attempt to load modules.
98  * - ZFS_MODULE_TIMEOUT="<seconds>"     - Seconds to wait for ZFS_DEV
99  */
100 static int
101 libzfs_load_module_impl(const char *module)
102 {
103 	char *argv[4] = {"/sbin/modprobe", "-q", (char *)module, (char *)0};
104 	char *load_str, *timeout_str;
105 	long timeout = 10; /* seconds */
106 	long busy_timeout = 10; /* milliseconds */
107 	int load = 0, fd;
108 	hrtime_t start;
109 
110 	/* Optionally request module loading */
111 	if (!libzfs_module_loaded(module)) {
112 		load_str = getenv("ZFS_MODULE_LOADING");
113 		if (load_str) {
114 			if (!strncasecmp(load_str, "YES", strlen("YES")) ||
115 			    !strncasecmp(load_str, "ON", strlen("ON")))
116 				load = 1;
117 			else
118 				load = 0;
119 		}
120 
121 		if (load) {
122 			if (libzfs_run_process("/sbin/modprobe", argv, 0))
123 				return (ENOEXEC);
124 		}
125 
126 		if (!libzfs_module_loaded(module))
127 			return (ENXIO);
128 	}
129 
130 	/*
131 	 * Device creation by udev is asynchronous and waiting may be
132 	 * required.  Busy wait for 10ms and then fall back to polling every
133 	 * 10ms for the allowed timeout (default 10s, max 10m).  This is
134 	 * done to optimize for the common case where the device is
135 	 * immediately available and to avoid penalizing the possible
136 	 * case where udev is slow or unable to create the device.
137 	 */
138 	timeout_str = getenv("ZFS_MODULE_TIMEOUT");
139 	if (timeout_str) {
140 		timeout = strtol(timeout_str, NULL, 0);
141 		timeout = MAX(MIN(timeout, (10 * 60)), 0); /* 0 <= N <= 600 */
142 	}
143 
144 	start = gethrtime();
145 	do {
146 		fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC);
147 		if (fd >= 0) {
148 			(void) close(fd);
149 			return (0);
150 		} else if (errno != ENOENT) {
151 			return (errno);
152 		} else if (NSEC2MSEC(gethrtime() - start) < busy_timeout) {
153 			sched_yield();
154 		} else {
155 			usleep(10 * MILLISEC);
156 		}
157 	} while (NSEC2MSEC(gethrtime() - start) < (timeout * MILLISEC));
158 
159 	return (ENOENT);
160 }
161 
162 int
163 libzfs_load_module(void)
164 {
165 	return (libzfs_load_module_impl(ZFS_DRIVER));
166 }
167 
168 int
169 find_shares_object(differ_info_t *di)
170 {
171 	char fullpath[MAXPATHLEN];
172 	struct stat64 sb = { 0 };
173 
174 	(void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
175 	(void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
176 
177 	if (stat64(fullpath, &sb) != 0) {
178 		(void) snprintf(di->errbuf, sizeof (di->errbuf),
179 		    dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
180 		return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
181 	}
182 
183 	di->shares = (uint64_t)sb.st_ino;
184 	return (0);
185 }
186 
187 int
188 zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
189 {
190 	(void) hdl, (void) snaps;
191 	return (0);
192 }
193 
194 /*
195  * Fill given version buffer with zfs kernel version read from ZFS_SYSFS_DIR
196  * Returns 0 on success, and -1 on error (with errno set)
197  */
198 int
199 zfs_version_kernel(char *version, int len)
200 {
201 	int _errno;
202 	int fd;
203 	int rlen;
204 
205 	if ((fd = open(ZFS_SYSFS_DIR "/version", O_RDONLY | O_CLOEXEC)) == -1)
206 		return (-1);
207 
208 	if ((rlen = read(fd, version, len)) == -1) {
209 		version[0] = '\0';
210 		_errno = errno;
211 		(void) close(fd);
212 		errno = _errno;
213 		return (-1);
214 	}
215 
216 	version[rlen-1] = '\0';  /* discard '\n' */
217 
218 	if (close(fd) == -1)
219 		return (-1);
220 
221 	return (0);
222 }
223