]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/openzfs/lib/libzfs/os/freebsd/libzfs_compat.c
zfs: merge openzfs/zfs@deb121309
[FreeBSD/FreeBSD.git] / sys / contrib / openzfs / 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 "../../libzfs_impl.h"
26 #include <libzfs.h>
27 #include <libzutil.h>
28 #include <sys/sysctl.h>
29 #include <libintl.h>
30 #include <sys/linker.h>
31 #include <sys/module.h>
32 #include <sys/stat.h>
33 #include <sys/param.h>
34
35 #ifdef IN_BASE
36 #define ZFS_KMOD        "zfs"
37 #else
38 #define ZFS_KMOD        "openzfs"
39 #endif
40
41
42 static int
43 execvPe(const char *name, const char *path, char * const *argv,
44     char * const *envp)
45 {
46         const char **memp;
47         size_t cnt, lp, ln;
48         int eacces, save_errno;
49         char buf[MAXPATHLEN];
50         const char *bp, *np, *op, *p;
51         struct stat sb;
52
53         eacces = 0;
54
55         /* If it's an absolute or relative path name, it's easy. */
56         if (strchr(name, '/')) {
57                 bp = name;
58                 op = NULL;
59                 goto retry;
60         }
61         bp = buf;
62
63         /* If it's an empty path name, fail in the usual POSIX way. */
64         if (*name == '\0') {
65                 errno = ENOENT;
66                 return (-1);
67         }
68
69         op = path;
70         ln = strlen(name);
71         while (op != NULL) {
72                 np = strchrnul(op, ':');
73
74                 /*
75                  * It's a SHELL path -- double, leading and trailing colons
76                  * mean the current directory.
77                  */
78                 if (np == op) {
79                         /* Empty component. */
80                         p = ".";
81                         lp = 1;
82                 } else {
83                         /* Non-empty component. */
84                         p = op;
85                         lp = np - op;
86                 }
87
88                 /* Advance to the next component or terminate after this. */
89                 if (*np == '\0')
90                         op = NULL;
91                 else
92                         op = np + 1;
93
94                 /*
95                  * If the path is too long complain.  This is a possible
96                  * security issue; given a way to make the path too long
97                  * the user may execute the wrong program.
98                  */
99                 if (lp + ln + 2 > sizeof (buf)) {
100                         (void) write(STDERR_FILENO, "execvP: ", 8);
101                         (void) write(STDERR_FILENO, p, lp);
102                         (void) write(STDERR_FILENO, ": path too long\n",
103                             16);
104                         continue;
105                 }
106                 memcpy(buf, p, lp);
107                 buf[lp] = '/';
108                 memcpy(buf + lp + 1, name, ln);
109                 buf[lp + ln + 1] = '\0';
110
111 retry:          (void) execve(bp, argv, envp);
112                 switch (errno) {
113                 case E2BIG:
114                         goto done;
115                 case ELOOP:
116                 case ENAMETOOLONG:
117                 case ENOENT:
118                         break;
119                 case ENOEXEC:
120                         for (cnt = 0; argv[cnt]; ++cnt)
121                                 ;
122
123                         /*
124                          * cnt may be 0 above; always allocate at least
125                          * 3 entries so that we can at least fit "sh", bp, and
126                          * the NULL terminator.  We can rely on cnt to take into
127                          * account the NULL terminator in all other scenarios,
128                          * as we drop argv[0].
129                          */
130                         memp = alloca(MAX(3, cnt + 2) * sizeof (char *));
131                         if (memp == NULL) {
132                                 /* errno = ENOMEM; XXX override ENOEXEC? */
133                                 goto done;
134                         }
135                         if (cnt > 0) {
136                                 memp[0] = argv[0];
137                                 memp[1] = bp;
138                                 memcpy(memp + 2, argv + 1,
139                                     cnt * sizeof (char *));
140                         } else {
141                                 memp[0] = "sh";
142                                 memp[1] = bp;
143                                 memp[2] = NULL;
144                         }
145                         (void) execve(_PATH_BSHELL,
146                             __DECONST(char **, memp), envp);
147                         goto done;
148                 case ENOMEM:
149                         goto done;
150                 case ENOTDIR:
151                         break;
152                 case ETXTBSY:
153                         /*
154                          * We used to retry here, but sh(1) doesn't.
155                          */
156                         goto done;
157                 default:
158                         /*
159                          * EACCES may be for an inaccessible directory or
160                          * a non-executable file.  Call stat() to decide
161                          * which.  This also handles ambiguities for EFAULT
162                          * and EIO, and undocumented errors like ESTALE.
163                          * We hope that the race for a stat() is unimportant.
164                          */
165                         save_errno = errno;
166                         if (stat(bp, &sb) != 0)
167                                 break;
168                         if (save_errno == EACCES) {
169                                 eacces = 1;
170                                 continue;
171                         }
172                         errno = save_errno;
173                         goto done;
174                 }
175         }
176         if (eacces)
177                 errno = EACCES;
178         else
179                 errno = ENOENT;
180 done:
181         return (-1);
182 }
183
184 int
185 execvpe(const char *name, char * const argv[], char * const envp[])
186 {
187         const char *path;
188
189         /* Get the path we're searching. */
190         if ((path = getenv("PATH")) == NULL)
191                 path = _PATH_DEFPATH;
192
193         return (execvPe(name, path, argv, envp));
194 }
195
196 static __thread char errbuf[ERRBUFLEN];
197
198 const char *
199 libzfs_error_init(int error)
200 {
201         char *msg = errbuf;
202         size_t msglen = sizeof (errbuf);
203
204         if (modfind("zfs") < 0) {
205                 size_t len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN,
206                     "Failed to load %s module: "), ZFS_KMOD);
207                 msg += len;
208                 msglen -= len;
209         }
210
211         (void) snprintf(msg, msglen, "%s", strerror(error));
212
213         return (errbuf);
214 }
215
216 int
217 zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
218 {
219         return (lzc_ioctl_fd(hdl->libzfs_fd, request, zc));
220 }
221
222 /*
223  * Verify the required ZFS_DEV device is available and optionally attempt
224  * to load the ZFS modules.  Under normal circumstances the modules
225  * should already have been loaded by some external mechanism.
226  */
227 int
228 libzfs_load_module(void)
229 {
230         /*
231          * XXX: kldfind(ZFS_KMOD) would be nice here, but we retain
232          * modfind("zfs") so out-of-base openzfs userland works with the
233          * in-base module.
234          */
235         if (modfind("zfs") < 0) {
236                 /* Not present in kernel, try loading it. */
237                 if (kldload(ZFS_KMOD) < 0 && errno != EEXIST) {
238                         return (errno);
239                 }
240         }
241         return (0);
242 }
243
244 int
245 zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg)
246 {
247         (void) hdl, (void) path, (void) msg;
248         return (0);
249 }
250
251 int
252 zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
253 {
254         (void) hdl, (void) zhp, (void) name;
255         return (0);
256 }
257
258 int
259 find_shares_object(differ_info_t *di)
260 {
261         (void) di;
262         return (0);
263 }
264
265 int
266 zfs_destroy_snaps_nvl_os(libzfs_handle_t *hdl, nvlist_t *snaps)
267 {
268         (void) hdl, (void) snaps;
269         return (0);
270 }
271
272 /*
273  * Attach/detach the given filesystem to/from the given jail.
274  */
275 int
276 zfs_jail(zfs_handle_t *zhp, int jailid, int attach)
277 {
278         libzfs_handle_t *hdl = zhp->zfs_hdl;
279         zfs_cmd_t zc = {"\0"};
280         unsigned long cmd;
281         int ret;
282
283         if (attach) {
284                 (void) snprintf(errbuf, sizeof (errbuf),
285                     dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
286         } else {
287                 (void) snprintf(errbuf, sizeof (errbuf),
288                     dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name);
289         }
290
291         switch (zhp->zfs_type) {
292         case ZFS_TYPE_VOLUME:
293                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
294                     "volumes can not be jailed"));
295                 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
296         case ZFS_TYPE_SNAPSHOT:
297                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
298                     "snapshots can not be jailed"));
299                 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
300         case ZFS_TYPE_BOOKMARK:
301                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
302                     "bookmarks can not be jailed"));
303                 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
304         case ZFS_TYPE_VDEV:
305                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
306                     "vdevs can not be jailed"));
307                 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
308         case ZFS_TYPE_INVALID:
309                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
310                     "invalid zfs_type_t: ZFS_TYPE_INVALID"));
311                 return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
312         case ZFS_TYPE_POOL:
313         case ZFS_TYPE_FILESYSTEM:
314                 /* OK */
315                 ;
316         }
317         assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
318
319         (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
320         zc.zc_objset_type = DMU_OST_ZFS;
321         zc.zc_zoneid = jailid;
322
323         cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL;
324         if ((ret = zfs_ioctl(hdl, cmd, &zc)) != 0)
325                 zfs_standard_error(hdl, errno, errbuf);
326
327         return (ret);
328 }
329
330 /*
331  * Set loader options for next boot.
332  */
333 int
334 zpool_nextboot(libzfs_handle_t *hdl, uint64_t pool_guid, uint64_t dev_guid,
335     const char *command)
336 {
337         zfs_cmd_t zc = {"\0"};
338         nvlist_t *args;
339
340         args = fnvlist_alloc();
341         fnvlist_add_uint64(args, ZPOOL_CONFIG_POOL_GUID, pool_guid);
342         fnvlist_add_uint64(args, ZPOOL_CONFIG_GUID, dev_guid);
343         fnvlist_add_string(args, "command", command);
344         zcmd_write_src_nvlist(hdl, &zc, args);
345         int error = zfs_ioctl(hdl, ZFS_IOC_NEXTBOOT, &zc);
346         zcmd_free_nvlists(&zc);
347         nvlist_free(args);
348         return (error);
349 }
350
351 /*
352  * Return allocated loaded module version, or NULL on error (with errno set)
353  */
354 char *
355 zfs_version_kernel(void)
356 {
357         size_t l;
358         if (sysctlbyname("vfs.zfs.version.module",
359             NULL, &l, NULL, 0) == -1)
360                 return (NULL);
361         char *version = malloc(l);
362         if (version == NULL)
363                 return (NULL);
364         if (sysctlbyname("vfs.zfs.version.module",
365             version, &l, NULL, 0) == -1) {
366                 free(version);
367                 return (NULL);
368         }
369         return (version);
370 }