Esempio n. 1
0
/*
 * given an absolute pathname, convert it, if possible, to a devfs
 * name.  Examples:
 * /dev/rsd3a to /pci@1f,4000/glm@3/sd@0,0:a
 * /dev/dsk/c0t0d0s0 to /pci@1f,4000/glm@3/sd@0,0:a
 * /devices/pci@1f,4000/glm@3/sd@0,0:a to /pci@1f,4000/glm@3/sd@0,0:a
 * /pci@1f,4000/glm@3/sd@0,0:a unchanged
 *
 * This routine deals with symbolic links, physical pathname with and
 * without /devices stripped. Returns 0 on success or -1 on failure.
 */
static int
resolve_devfs_name(char *name, char *buffer)
{
	int error;
	char *fullname = NULL;
	struct pathname pn, rpn;

	/* if not a /dev or /device name, prepend /devices */
	if (strncmp(name, "/dev/", 5) != 0 &&
	    strncmp(name, "/devices/", 9) != 0) {
		fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
		(void) snprintf(fullname, MAXPATHLEN, "/devices%s", name);
		name = fullname;
	}

	if (pn_get(name, UIO_SYSSPACE, &pn) != 0) {
		if (fullname)
			kmem_free(fullname, MAXPATHLEN);
		return (-1);
	}

	pn_alloc(&rpn);
	error = lookuppn(&pn, &rpn, FOLLOW, NULL, NULL);
	if (error == 0)
		bcopy(rpn.pn_path, buffer, rpn.pn_pathlen);

	pn_free(&pn);
	pn_free(&rpn);
	if (fullname)
		kmem_free(fullname, MAXPATHLEN);

	return (error);
}
Esempio n. 2
0
static int
is_nonempty_dir(char *name, char *pathleft, struct sdev_node *dir)
{
	struct match_arg marg;
	struct pathname pn;
	struct vnode *gvp;
	struct sdev_node *gdir = dir->sdev_origin;

	if (VOP_LOOKUP(SDEVTOV(gdir), name, &gvp, NULL, 0, NULL, kcred,
	    NULL, NULL, NULL) != 0)
		return (0);

	if (gvp->v_type != VDIR) {
		VN_RELE(gvp);
		return (0);
	}

	if (pn_get(pathleft, UIO_SYSSPACE, &pn) != 0) {
		VN_RELE(gvp);
		return (0);
	}

	marg.expr = kmem_alloc(MAXNAMELEN, KM_SLEEP);
	(void) pn_getcomponent(&pn, marg.expr);
	marg.match = 0;

	walk_dir(gvp, &marg, match_name);
	VN_RELE(gvp);
	kmem_free(marg.expr, MAXNAMELEN);
	pn_free(&pn);

	return (marg.match);
}
Esempio n. 3
0
/*
 * Lookup the user file name,
 * Handle allocation and freeing of pathname buffer, return error.
 */
int
lookupnameatcred(
	char *fnamep,			/* user pathname */
	enum uio_seg seg,		/* addr space that name is in */
	int followlink,			/* follow sym links */
	vnode_t **dirvpp,		/* ret for ptr to parent dir vnode */
	vnode_t **compvpp,		/* ret for ptr to component vnode */
	vnode_t *startvp,		/* start path search from vp */
	cred_t *cr)			/* credential */
{
	char namebuf[TYPICALMAXPATHLEN];
	struct pathname lookpn;
	int error;

	error = pn_get_buf(fnamep, seg, &lookpn, namebuf, sizeof (namebuf));
	if (error == 0) {
		error = lookuppnatcred(&lookpn, NULL, followlink,
		    dirvpp, compvpp, startvp, cr);
	}
	if (error == ENAMETOOLONG) {
		/*
		 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
		 */
		if (error = pn_get(fnamep, seg, &lookpn))
			return (error);
		error = lookuppnatcred(&lookpn, NULL, followlink,
		    dirvpp, compvpp, startvp, cr);
		pn_free(&lookpn);
	}

	return (error);
}
Esempio n. 4
0
/*
 * Callback supporting lookup in a GFS XATTR directory.
 */
static int
xattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
    cred_t *cr, int flags, int *deflags, pathname_t *rpnp)
{
	vnode_t *pvp;
	struct pathname pn;
	int error;

	*vpp = NULL;
	*inop = 0;

	error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, NULL);

	/*
	 * Return ENOENT for EACCES requests during lookup.  Once an
	 * attribute create is attempted EACCES will be returned.
	 */
	if (error) {
		if (error == EACCES)
			return (ENOENT);
		return (error);
	}

	error = pn_get((char *)nm, UIO_SYSSPACE, &pn);
	if (error == 0) {
		error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, flags, rootvp,
		    cr, NULL, deflags, rpnp);
		pn_free(&pn);
	}

	return (error);
}
Esempio n. 5
0
/*
 * readdir_xattr_casecmp: given a system attribute name, see if there
 * is a real xattr with the same normalized name.
 */
static int
readdir_xattr_casecmp(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
    int *eflags)
{
	int error;
	vnode_t *vp;
	struct pathname pn;

	*eflags = 0;

	error = pn_get(nm, UIO_SYSSPACE, &pn);
	if (error == 0) {
		error = VOP_LOOKUP(dvp, nm, &vp, &pn,
		    FIGNORECASE, rootvp, cr, ct, NULL, NULL);
		if (error == 0) {
			*eflags = ED_CASE_CONFLICT;
			VN_RELE(vp);
		} else if (error == ENOENT) {
			error = 0;
		}
		pn_free(&pn);
	}

	return (error);
}
Esempio n. 6
0
/*
 * Given a global path (from rootdir), and a vnode that is the current root,
 * return the portion of the path that is beneath the current root or NULL on
 * failure.  The path MUST be a resolved path (no '..' entries or symlinks),
 * otherwise this function will fail.
 */
static char *
localpath(char *path, struct vnode *vrootp, cred_t *cr)
{
	vnode_t *vp;
	vnode_t *cvp;
	char component[MAXNAMELEN];
	char *ret = NULL;
	pathname_t pn;

	/*
	 * We use vn_compare() instead of VN_CMP() in order to detect lofs
	 * mounts and stacked vnodes.
	 */
	if (vn_compare(vrootp, rootdir))
		return (path);

	if (pn_get(path, UIO_SYSSPACE, &pn) != 0)
		return (NULL);

	vp = rootdir;
	VN_HOLD(vp);

	if (vn_ismntpt(vp) && traverse(&vp) != 0) {
		VN_RELE(vp);
		pn_free(&pn);
		return (NULL);
	}

	while (pn_pathleft(&pn)) {
		pn_skipslash(&pn);

		if (pn_getcomponent(&pn, component) != 0)
			break;

		if (VOP_LOOKUP(vp, component, &cvp, &pn, 0, rootdir, cr,
		    NULL, NULL, NULL) != 0)
			break;
		VN_RELE(vp);
		vp = cvp;

		if (vn_ismntpt(vp) && traverse(&vp) != 0)
			break;

		if (vn_compare(vp, vrootp)) {
			ret = path + (pn.pn_path - pn.pn_buf);
			break;
		}
	}

	VN_RELE(vp);
	pn_free(&pn);

	return (ret);
}
Esempio n. 7
0
/*
 * Look up a logical name in the global zone.
 * Provides the ability to map the global zone's device name
 * to an alternate name within a zone.  The primary example
 * is the virtual console device /dev/zcons/[zonename]/zconsole
 * mapped to /[zonename]/root/dev/zconsole.
 */
static void
prof_lookup_globaldev(struct sdev_node *dir, struct sdev_node *gdir,
    char *name, char *rename)
{
	int error;
	struct vnode *avp, *gdv, *gddv;
	struct sdev_node *newdv;
	struct vattr vattr = {0};
	struct pathname pn;

	/* check if node already exists */
	newdv = sdev_cache_lookup(dir, rename);
	if (newdv) {
		ASSERT(newdv->sdev_state != SDEV_ZOMBIE);
		SDEV_SIMPLE_RELE(newdv);
		return;
	}

	/* sanity check arguments */
	if (!gdir || pn_get(name, UIO_SYSSPACE, &pn))
		return;

	/* perform a relative lookup of the global /dev instance */
	gddv = SDEVTOV(gdir);
	VN_HOLD(gddv);
	error = lookuppnvp(&pn, NULL, FOLLOW, NULLVPP, &gdv,
	    rootdir, gddv, kcred);
	pn_free(&pn);
	if (error) {
		sdcmn_err10(("prof_lookup_globaldev: %s not found\n", name));
		return;
	}
	ASSERT(gdv && gdv->v_type != VLNK);

	/*
	 * Found the entry in global /dev, figure out attributes
	 * by looking at backing store. Call into devfs for default.
	 * Note, mapped device is persisted under the new name
	 */
	prof_getattr(dir, rename, gdv, &vattr, &avp, NULL);

	if (gdv->v_type != VDIR) {
		VN_RELE(gdv);
		gdir = NULL;
	} else
		gdir = VTOSDEV(gdv);

	if (prof_mknode(dir, rename, &newdv, &vattr, avp,
	    (void *)gdir, kcred) == 0) {
		ASSERT(newdv->sdev_state != SDEV_ZOMBIE);
		SDEV_SIMPLE_RELE(newdv);
	}
}
Esempio n. 8
0
/*
 * Last chance for a zone to see a node.  If our parent dir is
 * SDEV_ZONED, then we look up the "zone" property for the node.  If the
 * property is found and matches the current zone name, we allow it.
 * Note that this isn't quite correct for the global zone peeking inside
 * a zone's /dev - for that to work, we'd have to have a per-dev-mount
 * zone ref squirreled away.
 */
static int
prof_zone_matched(char *name, struct sdev_node *dir)
{
	vnode_t *gvn = SDEVTOV(dir->sdev_origin);
	struct pathname pn;
	vnode_t *vn = NULL;
	char zonename[ZONENAME_MAX];
	int znlen = ZONENAME_MAX;
	int ret;

	ASSERT((dir->sdev_flags & SDEV_ZONED) != 0);

	sdcmn_err10(("sdev_node %p is zoned, looking for %s\n",
	    (void *)dir, name));

	if (pn_get(name, UIO_SYSSPACE, &pn))
		return (0);

	VN_HOLD(gvn);

	ret = lookuppnvp(&pn, NULL, FOLLOW, NULLVPP, &vn, rootdir, gvn, kcred);

	pn_free(&pn);

	if (ret != 0) {
		sdcmn_err10(("prof_zone_matched: %s not found\n", name));
		return (0);
	}

	/*
	 * VBLK doesn't matter, and the property name is in fact treated
	 * as a const char *.
	 */
	ret = e_ddi_getlongprop_buf(vn->v_rdev, VBLK, (char *)"zone",
	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (caddr_t)zonename, &znlen);

	VN_RELE(vn);

	if (ret == DDI_PROP_NOT_FOUND) {
		sdcmn_err10(("vnode %p: no zone prop\n", (void *)vn));
		return (0);
	} else if (ret != DDI_PROP_SUCCESS) {
		sdcmn_err10(("vnode %p: zone prop error: %d\n",
		    (void *)vn, ret));
		return (0);
	}

	sdcmn_err10(("vnode %p zone prop: %s\n", (void *)vn, zonename));
	return (strcmp(zonename, curproc->p_zone->zone_name) == 0);
}
Esempio n. 9
0
/*
 * Parse path components and apply requested matching rule at
 * directory level.
 */
static void
process_rule(struct sdev_node *dir, struct sdev_node *gdir,
    char *path, char *tgt, int type)
{
	char *name;
	struct pathname	pn;
	int rv = 0;

	if ((strlen(path) > 5) && (strncmp(path, "/dev/", 5) == 0)) {
		path += 5;
	}

	if (pn_get(path, UIO_SYSSPACE, &pn) != 0)
		return;

	name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
	(void) pn_getcomponent(&pn, name);
	pn_skipslash(&pn);
	SDEV_HOLD(dir);

	while (pn_pathleft(&pn)) {
		/* If this is pattern, just add the pattern */
		if (strpbrk(name, "*?[]") != NULL &&
		    (type == PROFILE_TYPE_INCLUDE ||
		    type == PROFILE_TYPE_EXCLUDE)) {
			ASSERT(tgt == NULL);
			tgt = pn.pn_path;
			break;
		}
		if ((rv = prof_make_dir(name, &gdir, &dir)) != 0) {
			cmn_err(CE_CONT, "process_rule: %s error %d\n",
			    path, rv);
			break;
		}
		(void) pn_getcomponent(&pn, name);
		pn_skipslash(&pn);
	}

	/* process the leaf component */
	if (rv == 0) {
		prof_add_rule(name, tgt, dir, type);
		SDEV_SIMPLE_RELE(dir);
	}

	kmem_free(name, MAXPATHLEN);
	pn_free(&pn);
}
Esempio n. 10
0
static int
copen(int startfd, char *fname, int filemode, int createmode)
{
	struct pathname pn;
	vnode_t *vp, *sdvp;
	file_t *fp, *startfp;
	enum vtype type;
	int error;
	int fd, dupfd;
	vnode_t *startvp;
	proc_t *p = curproc;
	uio_seg_t seg = UIO_USERSPACE;
	char *open_filename = fname;
	uint32_t auditing = AU_AUDITING();
	char startchar;

	if (filemode & (FSEARCH|FEXEC)) {
		/*
		 * Must be one or the other and neither FREAD nor FWRITE
		 * Must not be any of FAPPEND FCREAT FTRUNC FXATTR FXATTRDIROPEN
		 * XXX: Should these just be silently ignored?
		 */
		if ((filemode & (FREAD|FWRITE)) ||
		    (filemode & (FSEARCH|FEXEC)) == (FSEARCH|FEXEC) ||
		    (filemode & (FAPPEND|FCREAT|FTRUNC|FXATTR|FXATTRDIROPEN)))
			return (set_errno(EINVAL));
	}

	if (startfd == AT_FDCWD) {
		/*
		 * Regular open()
		 */
		startvp = NULL;
	} else {
		/*
		 * We're here via openat()
		 */
		if (copyin(fname, &startchar, sizeof (char)))
			return (set_errno(EFAULT));

		/*
		 * if startchar is / then startfd is ignored
		 */
		if (startchar == '/')
			startvp = NULL;
		else {
			if ((startfp = getf(startfd)) == NULL)
				return (set_errno(EBADF));
			startvp = startfp->f_vnode;
			VN_HOLD(startvp);
			releasef(startfd);
		}
	}

	/*
	 * Handle __openattrdirat() requests
	 */
	if (filemode & FXATTRDIROPEN) {
		if (auditing && startvp != NULL)
			audit_setfsat_path(1);
		if (error = lookupnameat(fname, seg, FOLLOW,
		    NULLVPP, &vp, startvp))
			return (set_errno(error));
		if (startvp != NULL)
			VN_RELE(startvp);

		startvp = vp;
	}

	/*
	 * Do we need to go into extended attribute space?
	 */
	if (filemode & FXATTR) {
		if (startfd == AT_FDCWD) {
			if (copyin(fname, &startchar, sizeof (char)))
				return (set_errno(EFAULT));

			/*
			 * If startchar == '/' then no extended attributes
			 * are looked up.
			 */
			if (startchar == '/') {
				startvp = NULL;
			} else {
				mutex_enter(&p->p_lock);
				startvp = PTOU(p)->u_cdir;
				VN_HOLD(startvp);
				mutex_exit(&p->p_lock);
			}
		}

		/*
		 * Make sure we have a valid extended attribute request.
		 * We must either have a real fd or AT_FDCWD and a relative
		 * pathname.
		 */
		if (startvp == NULL) {
			goto noxattr;
		}
	}

	if (filemode & (FXATTR|FXATTRDIROPEN)) {
		vattr_t vattr;

		if (error = pn_get(fname, UIO_USERSPACE, &pn)) {
			goto out;
		}

		/*
		 * In order to access hidden attribute directory the
		 * user must be able to stat() the file
		 */
		vattr.va_mask = AT_ALL;
		if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) {
			pn_free(&pn);
			goto out;
		}

		if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 ||
		    vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) {
			error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
			    (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR :
			    LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(),
			    NULL, NULL, NULL);
		} else {
			error = EINVAL;
		}

		/*
		 * For __openattrdirat() use "." as filename to open
		 * as part of vn_openat()
		 */
		if (error == 0 && (filemode & FXATTRDIROPEN)) {
			open_filename = ".";
			seg = UIO_SYSSPACE;
		}

		pn_free(&pn);
		if (error != 0)
			goto out;

		VN_RELE(startvp);
		startvp = sdvp;
	}

noxattr:
	if ((filemode & (FREAD|FWRITE|FSEARCH|FEXEC|FXATTRDIROPEN)) != 0) {
		if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
			filemode &= ~FNDELAY;
		error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
		if (error == 0) {
			if (auditing && startvp != NULL)
				audit_setfsat_path(1);
			/*
			 * Last arg is a don't-care term if
			 * !(filemode & FCREAT).
			 */
			error = vn_openat(open_filename, seg, filemode,
			    (int)(createmode & MODEMASK),
			    &vp, CRCREAT, PTOU(curproc)->u_cmask,
			    startvp, fd);

			if (startvp != NULL)
				VN_RELE(startvp);
			if (error == 0) {
				if ((vp->v_flag & VDUP) == 0) {
					fp->f_vnode = vp;
					mutex_exit(&fp->f_tlock);
					/*
					 * We must now fill in the slot
					 * falloc reserved.
					 */
					setf(fd, fp);
					return (fd);
				} else {
					/*
					 * Special handling for /dev/fd.
					 * Give up the file pointer
					 * and dup the indicated file descriptor
					 * (in v_rdev). This is ugly, but I've
					 * seen worse.
					 */
					unfalloc(fp);
					dupfd = getminor(vp->v_rdev);
					type = vp->v_type;
					mutex_enter(&vp->v_lock);
					vp->v_flag &= ~VDUP;
					mutex_exit(&vp->v_lock);
					VN_RELE(vp);
					if (type != VCHR)
						return (set_errno(EINVAL));
					if ((fp = getf(dupfd)) == NULL) {
						setf(fd, NULL);
						return (set_errno(EBADF));
					}
					mutex_enter(&fp->f_tlock);
					fp->f_count++;
					mutex_exit(&fp->f_tlock);
					setf(fd, fp);
					releasef(dupfd);
				}
				return (fd);
			} else {
				setf(fd, NULL);
				unfalloc(fp);
				return (set_errno(error));
			}
		}
	} else {
		error = EINVAL;
	}
out:
	if (startvp != NULL)
		VN_RELE(startvp);
	return (set_errno(error));
}
Esempio n. 11
0
/*ARGSUSED3*/
static int
javaexec(vnode_t *vp, struct execa *uap, struct uarg *args,
    struct intpdata *idatap, int level, long *execsz, int setid,
    caddr_t execfile, cred_t *cred, int brand_action)
{
	struct intpdata idata;
	int error;
	ssize_t resid;
	vnode_t *nvp;
	off_t xoff, xoff_end;
	char lochdr[LOCHDRSIZ];
	struct pathname lookpn;
	struct pathname resolvepn;
	char *opath;

	if (level)
		return (ENOEXEC);	/* no recursion */

	/*
	 * Read in the full local file header, and validate
	 * the initial signature.
	 */
	if ((error = vn_rdwr(UIO_READ, vp, lochdr, sizeof (lochdr),
	    0, UIO_SYSSPACE, 0, (rlim64_t)0, cred, &resid)) != 0)
		return (error);
	if (resid != 0 || strncmp(lochdr, LOCSIG, SIGSIZ) != 0)
		return (ENOEXEC);

	/*
	 * Ok, so this -is- a ZIP file, and might even be a JAR file.
	 * Is it a Java executable?
	 */
	xoff = sizeof (lochdr) + LOCNAM(lochdr);
	xoff_end = xoff + LOCEXT(lochdr);

	while (xoff < xoff_end) {
		char xfhdr[XFHSIZ];

		if ((error = vn_rdwr(UIO_READ, vp, xfhdr, sizeof (xfhdr),
		    xoff, UIO_SYSSPACE, 0, (rlim64_t)0, cred, &resid)) != 0)
			return (error);
		if (resid != 0)
			return (ENOEXEC);
		if (XFHID(xfhdr) == XFJAVASIG)
			break;
		xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr);
	}

	if (xoff >= xoff_end)
		return (ENOEXEC);

	/*
	 * Note: If we ever make setid execution work, we need to ensure
	 * that we use /dev/fd to avoid the classic setuid shell script
	 * security hole.
	 */
	if (setid)
		return (EACCES);

	/*
	 * Find and invoke the Java runtime environment on the file
	 */
	idata.intp = NULL;
	idata.intp_name[0] = jexec;
	idata.intp_arg[0] = jexec_arg;
	if (error = pn_get(idata.intp_name[0], UIO_SYSSPACE, &lookpn))
		return (error);
	pn_alloc(&resolvepn);
	if (error = lookuppn(&lookpn, &resolvepn, FOLLOW, NULLVPP, &nvp)) {
		pn_free(&resolvepn);
		pn_free(&lookpn);
		return (ENOEXEC);
	}
	opath = args->pathname;
	args->pathname = resolvepn.pn_path;
	/* don't free resolvepn until we are done with args */
	pn_free(&lookpn);
	error = gexec(&nvp, uap, args, &idata, level + 1, execsz, execfile,
	    cred, EBA_NONE);

	if (!error) {
		/*
		 * Close this Java executable as the interpreter
		 * will open and close it later on.
		 */
		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, cred, NULL);
	}

	VN_RELE(nvp);
	args->pathname = opath;
	pn_free(&resolvepn);
	return (error);
}
Esempio n. 12
0
static int
VMBlockMount(struct vfs *vfsp,     // IN: file system to mount
             struct vnode *vnodep, // IN: Vnode that we are mounting on
             struct mounta *mntp,  // IN: Arguments to mount(2) from user
             struct cred *credp)   // IN: Credentials of caller
{
   VMBlockMountInfo *mip;
   int ret;

   Debug(VMBLOCK_ENTRY_LOGLEVEL, "VMBlockMount: entry\n");

   /*
    * These next few checks are done by all other Solaris file systems, so
    * let's follow their lead.
    */
   ret = secpolicy_fs_mount(credp, vnodep, vfsp);
   if (ret) {
      Warning("VMBlockMount: mounting security check failed.\n");
      return ret;
   }

   if (vnodep->v_type != VDIR) {
      Warning("VMBlockMount: not mounting on a directory.\n");
      return ENOTDIR;
   }

   mutex_enter(&vnodep->v_lock);
   if ((mntp->flags & MS_OVERLAY) == 0 &&
       (vnodep->v_count != 1 || (vnodep->v_flag & VROOT))) {
      mutex_exit(&vnodep->v_lock);
      Warning("VMBlockMount: cannot allow unrequested overlay mount.\n");
      return EBUSY;
   }
   mutex_exit(&vnodep->v_lock);

   /*
    * The directory we are redirecting to is specified as the special file
    * since we have no actual device to mount on.  We store that path in the
    * mount information structure (note that there's another allocation inside
    * pn_get() so we must pn_free() that path at unmount time). KM_SLEEP
    * guarantees our memory allocation will succeed (pn_get() uses this flag
    * too).
    */
   mip = kmem_zalloc(sizeof *mip, KM_SLEEP);
   ret = pn_get(mntp->spec,
                (mntp->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE,
                &mip->redirectPath);
   if (ret) {
      Warning("VMBlockMount: could not obtain redirecting directory.\n");
      kmem_free(mip, sizeof *mip);
      return ret;
   }

   /* Do a lookup on the specified path. */
   ret = lookupname(mntp->spec,
                    (mntp->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE,
                    FOLLOW,
                    NULLVPP,
                    &mip->redirectVnode);
   if (ret) {
      Warning("VMBlockMount: could not obtain redirecting directory.\n");
      goto error_lookup;
   }

   if (mip->redirectVnode->v_type != VDIR) {
      Warning("VMBlockMount: not redirecting to a directory.\n");
      ret = ENOTDIR;
      goto error;
   }

   /*
    * Initialize our vfs structure.
    */
   vfsp->vfs_vnodecovered = vnodep;
   vfsp->vfs_flag &= ~VFS_UNMOUNTED;
   vfsp->vfs_flag |= VMBLOCK_VFS_FLAGS;
   vfsp->vfs_bsize = PAGESIZE;
   vfsp->vfs_fstype = vmblockType;
   vfsp->vfs_bcount = 0;
   /* If we had mount options, we'd call vfs_setmntopt with vfsp->vfs_mntopts */

   /* Locate a unique device minor number for this mount. */
   mutex_enter(&vmblockMutex);
   do {
      vfsp->vfs_dev = makedevice(vmblockMajor, vmblockMinor);
      vmblockMinor = (vmblockMinor + 1) & L_MAXMIN32;
   } while (vfs_devismounted(vfsp->vfs_dev));
   mutex_exit(&vmblockMutex);

   vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, vmblockType);
   vfsp->vfs_data = (caddr_t)mip;

   /*
    * Now create the root vnode of the file system.
    */
   ret = VMBlockVnodeGet(&mip->root, mip->redirectVnode,
                         mip->redirectPath.pn_path,
                         mip->redirectPath.pn_pathlen,
                         NULL, vfsp, TRUE);
   if (ret) {
      Warning("VMBlockMount: couldn't create root vnode.\n");
      ret = EFAULT;
      goto error;
   }

   VN_HOLD(vfsp->vfs_vnodecovered);
   return 0;

error:
   /* lookupname() provides a held vnode. */
   VN_RELE(mip->redirectVnode);
error_lookup:
   pn_free(&mip->redirectPath);
   kmem_free(mip, sizeof *mip);
   return ret;
}
Esempio n. 13
0
static int
copen(int startfd, char *fname, int filemode, int createmode)
{
	struct pathname pn;
	vnode_t *vp, *sdvp;
	file_t *fp, *startfp;
	enum vtype type;
	int error;
	int fd, dupfd;
	vnode_t *startvp;
	proc_t *p = curproc;

	if (startfd == AT_FDCWD) {
		/*
		 * Regular open()
		 */
		startvp = NULL;
	} else {
		/*
		 * We're here via openat()
		 */
		char startchar;

		if (copyin(fname, &startchar, sizeof (char)))
			return (set_errno(EFAULT));

		/*
		 * if startchar is / then startfd is ignored
		 */
		if (startchar == '/')
			startvp = NULL;
		else {
			if ((startfp = getf(startfd)) == NULL)
				return (set_errno(EBADF));
			startvp = startfp->f_vnode;
			VN_HOLD(startvp);
			releasef(startfd);
		}
	}

	if (filemode & FXATTR) {

		/*
		 * Make sure we have a valid request.
		 * We must either have a real fd or AT_FDCWD
		 */

		if (startfd != AT_FDCWD && startvp == NULL) {
			error = EINVAL;
			goto out;
		}

		if (error = pn_get(fname, UIO_USERSPACE, &pn)) {
			goto out;
		}

		if (startfd == AT_FDCWD) {
			mutex_enter(&p->p_lock);
			startvp = PTOU(p)->u_cdir;
			VN_HOLD(startvp);
			mutex_exit(&p->p_lock);
		}

		/*
		 * Verify permission to put attributes on file
		 */

		if ((VOP_ACCESS(startvp, VREAD, 0, CRED()) != 0) &&
		    (VOP_ACCESS(startvp, VWRITE, 0, CRED()) != 0) &&
		    (VOP_ACCESS(startvp, VEXEC, 0, CRED()) != 0)) {
			error = EACCES;
			pn_free(&pn);
			goto out;
		}

		if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0) {
			error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
			    LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED());
		} else {
			error = EINVAL;
		}
		pn_free(&pn);
		if (error != 0)
			goto out;

		VN_RELE(startvp);
		startvp = sdvp;
	}

	if ((filemode & (FREAD|FWRITE)) != 0) {
		if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
			filemode &= ~FNDELAY;
		error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
		if (error == 0) {
#ifdef C2_AUDIT
			if (audit_active)
				audit_setfsat_path(1);
#endif /* C2_AUDIT */
			/*
			 * Last arg is a don't-care term if
			 * !(filemode & FCREAT).
			 */
			error = vn_openat(fname, UIO_USERSPACE, filemode,
			    (int)(createmode & MODEMASK), &vp, CRCREAT,
			    u.u_cmask, startvp);

			if (startvp != NULL)
				VN_RELE(startvp);
			if (error == 0) {
#ifdef C2_AUDIT
				if (audit_active)
					audit_copen(fd, fp, vp);
#endif /* C2_AUDIT */
				if ((vp->v_flag & VDUP) == 0) {
					fp->f_vnode = vp;
					mutex_exit(&fp->f_tlock);
					/*
					 * We must now fill in the slot
					 * falloc reserved.
					 */
					setf(fd, fp);
					return (fd);
				} else {
					/*
					 * Special handling for /dev/fd.
					 * Give up the file pointer
					 * and dup the indicated file descriptor
					 * (in v_rdev). This is ugly, but I've
					 * seen worse.
					 */
					unfalloc(fp);
					dupfd = getminor(vp->v_rdev);
					type = vp->v_type;
					mutex_enter(&vp->v_lock);
					vp->v_flag &= ~VDUP;
					mutex_exit(&vp->v_lock);
					VN_RELE(vp);
					if (type != VCHR)
						return (set_errno(EINVAL));
					if ((fp = getf(dupfd)) == NULL) {
						setf(fd, NULL);
						return (set_errno(EBADF));
					}
					mutex_enter(&fp->f_tlock);
					fp->f_count++;
					mutex_exit(&fp->f_tlock);
					setf(fd, fp);
					releasef(dupfd);
				}
				return (fd);
			} else {
				setf(fd, NULL);
				unfalloc(fp);
				return (set_errno(error));
			}
		}
	} else {
		error = EINVAL;
	}
out:
	if (startvp != NULL)
		VN_RELE(startvp);
	return (set_errno(error));
}
Esempio n. 14
0
/*ARGSUSED*/
static int
zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
{
	char		*osname;
	pathname_t	spn;
	int		error = 0;
	uio_seg_t	fromspace = (uap->flags & MS_SYSSPACE) ?
				UIO_SYSSPACE : UIO_USERSPACE;
	int		canwrite;

	if (mvp->v_type != VDIR)
		return (ENOTDIR);

	mutex_enter(&mvp->v_lock);
	if ((uap->flags & MS_REMOUNT) == 0 &&
	    (uap->flags & MS_OVERLAY) == 0 &&
	    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
		mutex_exit(&mvp->v_lock);
		return (EBUSY);
	}
	mutex_exit(&mvp->v_lock);

	/*
	 * ZFS does not support passing unparsed data in via MS_DATA.
	 * Users should use the MS_OPTIONSTR interface; this means
	 * that all option parsing is already done and the options struct
	 * can be interrogated.
	 */
	if ((uap->flags & MS_DATA) && uap->datalen > 0)
		return (EINVAL);

	/*
	 * When doing a remount, we simply refresh our temporary properties
	 * according to those options set in the current VFS options.
	 */
	if (uap->flags & MS_REMOUNT) {
		return (zfs_refresh_properties(vfsp));
	}

	/*
	 * Get the objset name (the "special" mount argument).
	 */
	if (error = pn_get(uap->spec, fromspace, &spn))
		return (error);

	osname = spn.pn_path;

	if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
		goto out;

	/*
	 * Refuse to mount a filesystem if we are in a local zone and the
	 * dataset is not visible.
	 */
	if (!INGLOBALZONE(curproc) &&
	    (!zone_dataset_visible(osname, &canwrite) || !canwrite)) {
		error = EPERM;
		goto out;
	}

	error = zfs_domount(vfsp, osname, cr);

out:
	pn_free(&spn);
	return (error);
}
Esempio n. 15
0
/*
 * Get the "real" XATTR directory associtated with the GFS XATTR directory.
 * Note: This does NOT take any additional hold on the returned real_vp,
 * because when this lookup succeeds we save the result in xattr_realvp
 * and keep that hold until the GFS XATTR directory goes inactive.
 */
static int
xattr_dir_realdir(vnode_t *gfs_dvp, vnode_t **ret_vpp, int flags,
    cred_t *cr, caller_context_t *ct)
{
	struct pathname pn;
	char *nm = "";
	xattr_dir_t *xattr_dir;
	vnode_t *realvp;
	int error;

	*ret_vpp = NULL;

	/*
	 * Usually, we've already found the underlying XATTR directory
	 * during some previous lookup and stored it in xattr_realvp.
	 */
	mutex_enter(&gfs_dvp->v_lock);
	xattr_dir = gfs_dvp->v_data;
	realvp = xattr_dir->xattr_realvp;
	mutex_exit(&gfs_dvp->v_lock);
	if (realvp != NULL) {
		*ret_vpp = realvp;
		return (0);
	}

	/*
	 * Lookup the XATTR dir in the underlying FS, relative to our
	 * "parent", which is the real object for which this GFS XATTR
	 * directory was created.  Set the LOOKUP_HAVE_SYSATTR_DIR flag
	 * so that we don't get into an infinite loop with fop_lookup
	 * calling back to xattr_dir_lookup.
	 */
	error = pn_get(nm, UIO_SYSSPACE, &pn);
	if (error != 0)
		return (error);
	error = VOP_LOOKUP(gfs_file_parent(gfs_dvp), nm, &realvp, &pn,
	    flags | LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, ct, NULL, NULL);
	pn_free(&pn);
	if (error != 0)
		return (error);

	/*
	 * Have the real XATTR directory.  Save it -- but first
	 * check whether we lost a race doing the lookup.
	 */
	mutex_enter(&gfs_dvp->v_lock);
	xattr_dir = gfs_dvp->v_data;
	if (xattr_dir->xattr_realvp == NULL) {
		/*
		 * Note that the hold taken by the VOP_LOOKUP above is
		 * retained from here until xattr_dir_inactive.
		 */
		xattr_dir->xattr_realvp = realvp;
	} else {
		/* We lost the race. */
		VN_RELE(realvp);
		realvp = xattr_dir->xattr_realvp;
	}
	mutex_exit(&gfs_dvp->v_lock);

	*ret_vpp = realvp;
	return (0);
}
Esempio n. 16
0
int
intpexec(
	struct vnode *vp,
	struct execa *uap,
	struct uarg *args,
	struct intpdata *idatap,
	int level,
	long *execsz,
	int setid,
	caddr_t exec_file,
	struct cred *cred,
	int brand_action)
{
	_NOTE(ARGUNUSED(brand_action))
	vnode_t *nvp;
	int error = 0;
	struct intpdata idata;
	struct pathname intppn;
	struct pathname resolvepn;
	char *opath;
	char devfd[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */
	int fd = -1;

	if (level) {		/* Can't recurse */
		error = ENOEXEC;
		goto bad;
	}

	ASSERT(idatap == (struct intpdata *)NULL);

	/*
	 * Allocate a buffer to read in the interpreter pathname.
	 */
	idata.intp = kmem_alloc(INTPSZ, KM_SLEEP);
	if (error = getintphead(vp, &idata))
		goto fail;

	/*
	 * Look the new vnode up.
	 */
	if (error = pn_get(idata.intp_name, UIO_SYSSPACE, &intppn))
		goto fail;
	pn_alloc(&resolvepn);
	if (error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp)) {
		pn_free(&resolvepn);
		pn_free(&intppn);
		goto fail;
	}
	opath = args->pathname;
	args->pathname = resolvepn.pn_path;
	/* don't free resolvepn until we are done with args */
	pn_free(&intppn);

	/*
	 * When we're executing a set-uid script resulting in uids
	 * mismatching or when we execute with additional privileges,
	 * we close the "replace script between exec and open by shell"
	 * hole by passing the script as /dev/fd parameter.
	 */
	if ((setid & EXECSETID_PRIVS) != 0 ||
	    (setid & (EXECSETID_UGIDS|EXECSETID_SETID)) ==
	    (EXECSETID_UGIDS|EXECSETID_SETID)) {
		(void) strcpy(devfd, "/dev/fd/");
		if (error = execopen(&vp, &fd))
			goto done;
		numtos(fd, &devfd[8]);
		args->fname = devfd;
	}

	error = gexec(&nvp, uap, args, &idata, ++level, execsz, exec_file, cred,
	    EBA_NONE);
done:
	VN_RELE(nvp);
	args->pathname = opath;
	pn_free(&resolvepn);
fail:
	kmem_free(idata.intp, INTPSZ);
	if (error && fd != -1)
		(void) execclose(fd);
bad:
	return (error);
}
Esempio n. 17
0
int
xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
{
	int error;
	vnode_t *pvp, *dvp;
	xattr_fid_t *xfidp;
	struct pathname pn;
	char *nm;
	uint16_t orig_len;

	*vpp = NULL;

	if (fidp->fid_len < XATTR_FIDSZ)
		return (EINVAL);

	xfidp = (xattr_fid_t *)fidp;
	orig_len = fidp->fid_len;
	fidp->fid_len = xfidp->parent_len;

	error = VFS_VGET(vfsp, &pvp, fidp);
	fidp->fid_len = orig_len;
	if (error)
		return (error);

	/*
	 * Start by getting the GFS sysattr directory.	We might need
	 * to recreate it during the VOP_LOOKUP.
	 */
	nm = "";
	error = pn_get(nm, UIO_SYSSPACE, &pn);
	if (error) {
		VN_RELE(pvp);
		return (EINVAL);
	}

	error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR,
	    rootvp, CRED(), NULL, NULL, NULL);
	pn_free(&pn);
	VN_RELE(pvp);
	if (error)
		return (error);

	if (xfidp->dir_offset == 0) {
		/*
		 * If we were looking for the directory, we're done.
		 */
		*vpp = dvp;
		return (0);
	}

	if (xfidp->dir_offset > XATTRDIR_NENTS) {
		VN_RELE(dvp);
		return (EINVAL);
	}

	nm = xattr_dirents[xfidp->dir_offset - 1].gfse_name;

	error = pn_get(nm, UIO_SYSSPACE, &pn);
	if (error) {
		VN_RELE(dvp);
		return (EINVAL);
	}

	error = VOP_LOOKUP(dvp, nm, vpp, &pn, 0, rootvp, CRED(), NULL,
	    NULL, NULL);

	pn_free(&pn);
	VN_RELE(dvp);

	return (error);
}
Esempio n. 18
0
/*
 * Get the XATTR dir for some file or directory.
 * See vnode.c: fop_lookup()
 *
 * Note this only gets the GFS XATTR directory.  We'll get the
 * real XATTR directory later, in xattr_dir_realdir.
 */
int
xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
{
	int error = 0;

	*vpp = NULL;

	if (dvp->v_type != VDIR && dvp->v_type != VREG)
		return (EINVAL);

	mutex_enter(&dvp->v_lock);

	/*
	 * If we're already in sysattr space, don't allow creation
	 * of another level of sysattrs.
	 */
	if (dvp->v_flag & V_SYSATTR) {
		mutex_exit(&dvp->v_lock);
		return (EINVAL);
	}

	if (dvp->v_xattrdir != NULL) {
		*vpp = dvp->v_xattrdir;
		VN_HOLD(*vpp);
	} else {
		ulong_t val;
		int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
		int sysattrs_allowed = 1;

		/*
		 * We have to drop the lock on dvp.  gfs_dir_create will
		 * grab it for a VN_HOLD.
		 */
		mutex_exit(&dvp->v_lock);

		/*
		 * If dvp allows xattr creation, but not sysattr
		 * creation, return the real xattr dir vp. We can't
		 * use the vfs feature mask here because _PC_SATTR_ENABLED
		 * has vnode-level granularity (e.g. .zfs).
		 */
		error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL);
		if (error != 0 || val == 0)
			sysattrs_allowed = 0;

		if (!xattrs_allowed && !sysattrs_allowed)
			return (EINVAL);

		if (!sysattrs_allowed) {
			struct pathname pn;
			char *nm = "";

			error = pn_get(nm, UIO_SYSSPACE, &pn);
			if (error)
				return (error);
			error = VOP_LOOKUP(dvp, nm, vpp, &pn,
			    flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
			    NULL, NULL);
			pn_free(&pn);
			return (error);
		}

		/*
		 * Note that we act as if we were given CREATE_XATTR_DIR,
		 * but only for creation of the GFS directory.
		 */
		*vpp = gfs_dir_create(
		    sizeof (xattr_dir_t), dvp, xattr_dir_ops, xattr_dirents,
		    xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
		mutex_enter(&dvp->v_lock);
		if (dvp->v_xattrdir != NULL) {
			/*
			 * We lost the race to create the xattr dir.
			 * Destroy this one, use the winner.  We can't
			 * just call VN_RELE(*vpp), because the vnode
			 * is only partially initialized.
			 */
			gfs_dir_t *dp = (*vpp)->v_data;

			ASSERT((*vpp)->v_count == 1);
			vn_free(*vpp);

			mutex_destroy(&dp->gfsd_lock);
			kmem_free(dp->gfsd_static,
			    dp->gfsd_nstatic * sizeof (gfs_dirent_t));
			kmem_free(dp, dp->gfsd_file.gfs_size);

			/*
			 * There is an implied VN_HOLD(dvp) here.  We should
			 * be doing a VN_RELE(dvp) to clean up the reference
			 * from *vpp, and then a VN_HOLD(dvp) for the new
			 * reference.  Instead, we just leave the count alone.
			 */

			*vpp = dvp->v_xattrdir;
			VN_HOLD(*vpp);
		} else {
			(*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR);
			dvp->v_xattrdir = *vpp;
		}
	}
	mutex_exit(&dvp->v_lock);

	return (error);
}
Esempio n. 19
0
static int
VMBlockIoctl(struct vnode *vp,     // IN:  Vnode of file to operate on
             int cmd,              // IN:  Requested command from user
             intptr_t arg,         // IN:  Arguments for command
             int flag,             // IN:  File pointer flags and data model
             struct cred *cr,      // IN:  Credentials of caller
             int *rvalp            // OUT: Return value on success
#if OS_VFS_VERSION >= 5
           , caller_context_t *ctx // IN: Caller's context
#endif
            )
{
   VMBlockMountInfo *mip;
   int ret;

   Debug(VMBLOCK_ENTRY_LOGLEVEL, "VMBlockIoctl: entry\n");

   mip = VPTOMIP(vp);
   if (vp != mip->root) {
      return ENOTSUP;
   }

   if (rvalp) {
      *rvalp = 0;
   }

   switch (cmd) {
   case VMBLOCK_ADD_FILEBLOCK:
   case VMBLOCK_DEL_FILEBLOCK:
   {
      struct pathname pn;

      ret = pn_get((char *)arg, UIO_USERSPACE, &pn);
      if (ret) {
         goto out;
      }

      /* Remove all trailing path separators. */
      while (pn.pn_pathlen > 0 && pn.pn_path[pn.pn_pathlen - 1] == '/') {
         pn.pn_path[pn.pn_pathlen - 1] = '\0';
         pn.pn_pathlen--;
      }

      ret = cmd == VMBLOCK_ADD_FILEBLOCK ?
               BlockAddFileBlock(pn.pn_path, curthread) :
               BlockRemoveFileBlock(pn.pn_path, curthread);
      pn_free(&pn);
      break;
   }
#ifdef VMX86_DEVEL
   case VMBLOCK_LIST_FILEBLOCKS:
      BlockListFileBlocks();
      ret = 0;
      break;
#endif
   default:
      Warning("VMBlockIoctl: unknown command (%d) received.\n", cmd);
      return ENOTSUP;
   }

out:
   return ret;
}
Esempio n. 20
0
int
dogetcwd(char *buf, size_t buflen)
{
	int ret;
	vnode_t *vp;
	vnode_t *compvp;
	refstr_t *cwd, *oldcwd;
	const char *value;
	pathname_t rpnp, pnp;
	proc_t *p = curproc;

	/*
	 * Check to see if there is a cached version of the cwd.  If so, lookup
	 * the cached value and make sure it is the same vnode.
	 */
	mutex_enter(&p->p_lock);
	if ((cwd = PTOU(p)->u_cwd) != NULL)
		refstr_hold(cwd);
	vp = PTOU(p)->u_cdir;
	VN_HOLD(vp);
	mutex_exit(&p->p_lock);

	/*
	 * Make sure we have permission to access the current directory.
	 */
	if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) != 0) {
		if (cwd != NULL)
			refstr_rele(cwd);
		VN_RELE(vp);
		return (ret);
	}

	if (cwd) {
		value = refstr_value(cwd);
		if ((ret = pn_get((char *)value, UIO_SYSSPACE, &pnp)) != 0) {
			refstr_rele(cwd);
			VN_RELE(vp);
			return (ret);
		}

		pn_alloc(&rpnp);

		if (lookuppn(&pnp, &rpnp, NO_FOLLOW, NULL, &compvp) == 0) {

			if (VN_CMP(vp, compvp) &&
			    strcmp(value, rpnp.pn_path) == 0) {
				VN_RELE(compvp);
				VN_RELE(vp);
				pn_free(&pnp);
				pn_free(&rpnp);
				if (strlen(value) + 1 > buflen) {
					refstr_rele(cwd);
					return (ENAMETOOLONG);
				}
				bcopy(value, buf, strlen(value) + 1);
				refstr_rele(cwd);
				return (0);
			}

			VN_RELE(compvp);
		}

		pn_free(&rpnp);
		pn_free(&pnp);

		refstr_rele(cwd);
	}

	ret = vnodetopath_common(NULL, vp, buf, buflen, CRED(),
	    LOOKUP_CHECKREAD);

	VN_RELE(vp);

	/*
	 * Store the new cwd and replace the existing cached copy.
	 */
	if (ret == 0)
		cwd = refstr_alloc(buf);
	else
		cwd = NULL;

	mutex_enter(&p->p_lock);
	oldcwd = PTOU(p)->u_cwd;
	PTOU(p)->u_cwd = cwd;
	mutex_exit(&p->p_lock);

	if (oldcwd)
		refstr_rele(oldcwd);

	return (ret);
}
Esempio n. 21
0
static int
zfs_vfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
{
	char	*osname = NULL;
	size_t  osnamelen = 0;
	int		error = 0;
	int		canwrite;
	/*
	 * Get the objset name (the "special" mount argument).
	 * The filesystem that we mount as root is defined in the
	 * "zfs-bootfs" property. 
	 */
	if (data) {
		user_addr_t fspec = USER_ADDR_NULL;
#ifndef __APPLE__
		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
		    DDI_PROP_DONTPASS, "zfs-bootfs", &zfs_bootpath) !=
		    DDI_SUCCESS)
			return (EIO);

		error = parse_bootpath(zfs_bootpath, rootfs.bo_name);
		ddi_prop_free(zfs_bootpath);
#endif
		osname = kmem_alloc(MAXPATHLEN, KM_SLEEP);

		if (vfs_context_is64bit(context)) {
			if ( (error = copyin(data, (caddr_t)&fspec, sizeof(fspec))) )
				goto out;	
		} else {
#ifdef ZFS_LEOPARD_ONLY
			char *tmp;
#else
			user32_addr_t tmp;
#endif
			if ( (error = copyin(data, (caddr_t)&tmp, sizeof(tmp))) )
				goto out;	
			/* munge into LP64 addr */
			fspec = CAST_USER_ADDR_T(tmp);
		}
		if ( (error = copyinstr(fspec, osname, MAXPATHLEN, &osnamelen)) )
			goto out;
	}

#if 0
	if (mvp->v_type != VDIR)
		return (ENOTDIR);

	mutex_enter(&mvp->v_lock);
	if ((uap->flags & MS_REMOUNT) == 0 &&
	    (uap->flags & MS_OVERLAY) == 0 &&
	    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
		mutex_exit(&mvp->v_lock);
		return (EBUSY);
	}
	mutex_exit(&mvp->v_lock);

	/*
	 * ZFS does not support passing unparsed data in via MS_DATA.
	 * Users should use the MS_OPTIONSTR interface; this means
	 * that all option parsing is already done and the options struct
	 * can be interrogated.
	 */
	if ((uap->flags & MS_DATA) && uap->datalen > 0)
		return (EINVAL);

	/*
	 * Get the objset name (the "special" mount argument).
	 */
	if (error = pn_get(uap->spec, fromspace, &spn))
		return (error);

	osname = spn.pn_path;
#endif
	/*
	 * Check for mount privilege?
	 *
	 * If we don't have privilege then see if
	 * we have local permission to allow it
	 */
#ifndef __APPLE__
	error = secpolicy_fs_mount(cr, mvp, vfsp);
	if (error) {
		error = dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr);
		if (error == 0) {
			vattr_t		vattr;

			/*
			 * Make sure user is the owner of the mount point
			 * or has sufficient privileges.
			 */

			vattr.va_mask = AT_UID;

			if (error = VOP_GETATTR(mvp, &vattr, 0, cr)) {
				goto out;
			}

			if (error = secpolicy_vnode_owner(cr, vattr.va_uid)) {
				goto out;
			}

			if (error = VOP_ACCESS(mvp, VWRITE, 0, cr)) {
				goto out;
			}

			secpolicy_fs_mount_clearopts(cr, vfsp);
		} else {
			goto out;
		}
	}
#endif

	error = zfs_domount(mp, 0, osname, context);
	if (error)
		printf("zfs_vfs_mount: error %d\n", error);
	if (error == 0) {
		zfsvfs_t *zfsvfs = NULL;

		/* Make the Finder treat sub file systems just like a folder */
		if (strpbrk(osname, "/"))
			vfs_setflags(mp, (u_int64_t)((unsigned int)MNT_DONTBROWSE));

		/* Indicate to VFS that we support ACLs. */
		vfs_setextendedsecurity(mp);

		/* Advisory locking should be handled at the VFS layer */
		vfs_setlocklocal(mp);

		/*
		 * Mac OS X needs a file system modify time
		 *
		 * We use the mtime of the "com.apple.system.mtime" 
		 * extended attribute, which is associated with the
		 * file system root directory.
		 *
		 * Here we need to take a ref on z_mtime_vp to keep it around.
		 * If the attribute isn't there, attempt to create it.
		 */
		zfsvfs = vfs_fsprivate(mp);
		if (zfsvfs->z_mtime_vp == NULL) {
			struct vnode * rvp;
			struct vnode *xdvp = NULLVP;
			struct vnode *xvp = NULLVP;
			znode_t *rootzp;
			timestruc_t modify_time;
			cred_t  *cr;
			timestruc_t  now;
			int flag;
			int result;

			if (zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp) != 0) {
				goto out;
			}
			rvp = ZTOV(rootzp);
			cr = (cred_t *)vfs_context_ucred(context);

			/* Grab the hidden attribute directory vnode. */
			result = zfs_get_xattrdir(rootzp, &xdvp, cr, CREATE_XATTR_DIR);
			vnode_put(rvp);	/* all done with root vnode */
			rvp = NULL;
			if (result) {
				goto out;
			}

			/*
			 * HACK - workaround missing vnode_setnoflush() KPI...
			 *
			 * We tag zfsvfs so that zfs_attach_vnode() can then set
			 * vnfs_marksystem when the vnode gets created.
			 */
			zfsvfs->z_last_unmount_time = 0xBADC0DE;
			zfsvfs->z_last_mtime_synced = VTOZ(xdvp)->z_id;
			flag = vfs_isrdonly(mp) ? 0 : ZEXISTS;
			/* Lookup or create the named attribute. */
			if ( zfs_obtain_xattr(VTOZ(xdvp), ZFS_MTIME_XATTR,
			                          S_IRUSR | S_IWUSR, cr, &xvp,
			                          flag) ) {
					zfsvfs->z_last_unmount_time = 0;
					zfsvfs->z_last_mtime_synced = 0;
					vnode_put(xdvp);
					goto out;
				}
				gethrestime(&now);
			ZFS_TIME_ENCODE(&now, VTOZ(xvp)->z_phys->zp_mtime);
			vnode_put(xdvp);
			vnode_ref(xvp);

			zfsvfs->z_mtime_vp = xvp;
			ZFS_TIME_DECODE(&modify_time, VTOZ(xvp)->z_phys->zp_mtime);
			zfsvfs->z_last_unmount_time = modify_time.tv_sec;
			zfsvfs->z_last_mtime_synced = modify_time.tv_sec;

			/*
			 * Keep this referenced vnode from impeding an unmount.
			 *
			 * XXX vnode_setnoflush() is MIA from KPI (see workaround above).
			 */
#if 0
			vnode_setnoflush(xvp);
#endif
			vnode_put(xvp);
		}
	}
out:
	if (osname) {
		kmem_free(osname, MAXPATHLEN);
	}
	return (error);
}