예제 #1
0
int
procfs_validfile_linux(struct proc *p, struct mount *mp)
{
	int flags;

	flags = VFSTOPROC(mp)->pmnt_flags;
	return ((flags & PROCFSMNT_LINUXCOMPAT) &&
	    (p == NULL || procfs_validfile(p, mp)));
}
예제 #2
0
/* ARGSUSED */
int
procfs_mount(
    struct mount *mp,
    const char *path,
    void *data,
    size_t *data_len)
{
	struct lwp *l = curlwp;
	struct procfsmount *pmnt;
	struct procfs_args *args = data;
	int error;

	if (args == NULL)
		return EINVAL;

	if (UIO_MX & (UIO_MX-1)) {
		log(LOG_ERR, "procfs: invalid directory entry size");
		return (EINVAL);
	}

	if (mp->mnt_flag & MNT_GETARGS) {
		if (*data_len < sizeof *args)
			return EINVAL;

		pmnt = VFSTOPROC(mp);
		if (pmnt == NULL)
			return EIO;
		args->version = PROCFS_ARGSVERSION;
		args->flags = pmnt->pmnt_flags;
		*data_len = sizeof *args;
		return 0;
	}

	if (mp->mnt_flag & MNT_UPDATE)
		return (EOPNOTSUPP);

	if (*data_len >= sizeof *args && args->version != PROCFS_ARGSVERSION)
		return EINVAL;

	pmnt = kmem_zalloc(sizeof(struct procfsmount), KM_SLEEP);

	mp->mnt_stat.f_namemax = PROCFS_MAXNAMLEN;
	mp->mnt_flag |= MNT_LOCAL;
	mp->mnt_data = pmnt;
	vfs_getnewfsid(mp);

	error = set_statvfs_info(path, UIO_USERSPACE, "procfs", UIO_SYSSPACE,
	    mp->mnt_op->vfs_name, mp, l);
	pmnt->pmnt_exechook = exechook_establish(procfs_revoke_vnodes, mp);
	if (*data_len >= sizeof *args)
		pmnt->pmnt_flags = args->flags;
	else
		pmnt->pmnt_flags = 0;

	mp->mnt_iflag |= IMNT_MPSAFE;
	return error;
}
예제 #3
0
/*
 * unmount system call
 */
int
procfs_unmount(struct mount *mp, int mntflags)
{
	int error;
	int flags = 0;

	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;

	if ((error = vflush(mp, 0, flags)) != 0)
		return (error);

	exechook_disestablish(VFSTOPROC(mp)->pmnt_exechook);

	kmem_free(mp->mnt_data, sizeof(struct procfsmount));
	mp->mnt_data = NULL;

	return 0;
}
예제 #4
0
/*
 * unmount system call
 */
int
procfs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
	int error;
	extern int doforce;
	int flags = 0;

	if (mntflags & MNT_FORCE) {
		/* procfs can never be rootfs so don't check for it */
		if (!doforce)
			return (EINVAL);
		flags |= FORCECLOSE;
	}

	if ((error = vflush(mp, 0, flags)) != 0)
		return (error);

	free(VFSTOPROC(mp), M_MISCFSMNT);
	mp->mnt_data = 0;

	return (0);
}
예제 #5
0
/*
 * readdir returns directory entries from pfsnode (vp).
 *
 * the strategy here with procfs is to generate a single
 * directory entry at a time (struct dirent) and then
 * copy that out to userland using uiomove.  a more efficent
 * though more complex implementation, would try to minimize
 * the number of calls to uiomove().  for procfs, this is
 * hardly worth the added code complexity.
 *
 * this should just be done through read()
 */
int
procfs_readdir(void *v)
{
	struct vop_readdir_args *ap = v;
	struct uio *uio = ap->a_uio;
	struct dirent d;
	struct pfsnode *pfs;
	struct vnode *vp;
	int i;
	int error;

	vp = ap->a_vp;
	pfs = VTOPFS(vp);

	if (uio->uio_resid < UIO_MX)
		return (EINVAL);

	error = 0;
	i = uio->uio_offset;
	if (i < 0)
		return (EINVAL);
	bzero(&d, UIO_MX);
	d.d_reclen = UIO_MX;

	switch (pfs->pfs_type) {
	/*
	 * this is for the process-specific sub-directories.
	 * all that is needed to is copy out all the entries
	 * from the procent[] table (top of this file).
	 */
	case Pproc: {
		struct proc *p;
		const struct proc_target *pt;

		p = pfind(pfs->pfs_pid);
		if (p == NULL)
			break;

		for (pt = &proc_targets[i];
		     uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
			if (pt->pt_valid &&
			    (*pt->pt_valid)(p, vp->v_mount) == 0)
				continue;
			
			d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype);
			d.d_namlen = pt->pt_namlen;
			bcopy(pt->pt_name, d.d_name, pt->pt_namlen + 1);
			d.d_type = pt->pt_type;

			if ((error = uiomove(&d, UIO_MX, uio)) != 0)
				break;
		}

	    	break;
	}

	/*
	 * this is for the root of the procfs filesystem
	 * what is needed is a special entry for "curproc"
	 * followed by an entry for each process on allproc
#ifdef PROCFS_ZOMBIE
	 * and zombproc.
#endif
	 */

	case Proot: {
#ifdef PROCFS_ZOMBIE
		int doingzomb = 0;
#endif
		int pcnt = i;
		volatile struct proc *p = LIST_FIRST(&allproc);

		if (pcnt > 3)
			pcnt = 3;
#ifdef PROCFS_ZOMBIE
	again:
#endif
		for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) {
			switch (i) {
			case 0:		/* `.' */
			case 1:		/* `..' */
				d.d_fileno = PROCFS_FILENO(0, Proot);
				d.d_namlen = i + 1;
				bcopy("..", d.d_name, d.d_namlen);
				d.d_name[i + 1] = '\0';
				d.d_type = DT_DIR;
				break;

			case 2:
				d.d_fileno = PROCFS_FILENO(0, Pcurproc);
				d.d_namlen = 7;
				bcopy("curproc", d.d_name, 8);
				d.d_type = DT_LNK;
				break;

			case 3:
				d.d_fileno = PROCFS_FILENO(0, Pself);
				d.d_namlen = 4;
				bcopy("self", d.d_name, 5);
				d.d_type = DT_LNK;
				break;

			case 4:
				if (VFSTOPROC(vp->v_mount)->pmnt_flags &
				    PROCFSMNT_LINUXCOMPAT) {
					d.d_fileno = PROCFS_FILENO(0, Pcpuinfo);
					d.d_namlen = 7;
					bcopy("cpuinfo", d.d_name, 8);
					d.d_type = DT_REG;
					break;
				}
				/* fall through */

			case 5:
				if (VFSTOPROC(vp->v_mount)->pmnt_flags &
				    PROCFSMNT_LINUXCOMPAT) {
					d.d_fileno = PROCFS_FILENO(0, Pmeminfo);
					d.d_namlen = 7;
					bcopy("meminfo", d.d_name, 8);
					d.d_type = DT_REG;
					break;
				}
				/* fall through */

			default:
				while (pcnt < i) {
					pcnt++;
					p = LIST_NEXT(p, p_list);
					if (!p)
						goto done;
				}
				d.d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
				d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
				    "%ld", (long)p->p_pid);
				d.d_type = DT_REG;
				p = LIST_NEXT(p, p_list);
				break;
			}

			if ((error = uiomove(&d, UIO_MX, uio)) != 0)
				break;
		}
	done:

#ifdef PROCFS_ZOMBIE
		if (p == 0 && doingzomb == 0) {
			doingzomb = 1;
			p = LIST_FIRST(&zombproc);
			goto again;
		}
#endif

		break;

	}

	default:
		error = ENOTDIR;
		break;
	}

	uio->uio_offset = i;
	return (error);
}