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 42void 43libzfs_set_pipe_max(int infd) 44{ 45 /* FreeBSD automatically resizes */ 46} 47 48static int 49execvPe(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 110retry: (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; 163done: 164 return (-1); 165} 166 167int 168execvpe(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 181static __thread char errbuf[ERRBUFLEN]; 182 183const char * 184libzfs_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 201int 202zfs_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 */ 212int 213libzfs_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 229int 230zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg) 231{ 232 return (0); 233} 234 235int 236zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name) 237{ 238 return (0); 239} 240 241int 242find_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 */ 250int 251zfs_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 */ 301int 302zpool_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 */ 325int 326zfs_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} 333