]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libzfs/os/freebsd/libzfs_compat.c
Update OpenZFS to 2.0.0-rc3-gbd565f
[FreeBSD/FreeBSD.git] / lib / libzfs / os / freebsd / libzfs_compat.c
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 #define ERRBUFLEN 256
180
181 __thread static char errbuf[ERRBUFLEN];
182
183 const char *
184 libzfs_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
201 int
202 zfs_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  */
212 int
213 libzfs_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
229 int
230 zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg)
231 {
232         return (0);
233 }
234
235 int
236 zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
237 {
238         return (0);
239 }
240
241 int
242 find_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  */
250 int
251 zfs_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  */
301 int
302 zpool_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  */
325 int
326 zfs_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 }