Exemple #1
0
/*
 * readlink reads the link of `curproc' or `file'
 */
static int
procfs_readlink(struct vop_readlink_args *ap)
{
	char buf[16];		/* should be enough */
	struct proc *procp;
	struct vnode *vp = ap->a_vp;
	struct pfsnode *pfs = VTOPFS(vp);
	char *fullpath, *freepath;
	int error, len;

	switch (pfs->pfs_type) {
	case Pcurproc:
		if (pfs->pfs_fileno != PROCFS_FILENO(0, Pcurproc))
			return (EINVAL);

		len = ksnprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);

		return (uiomove(buf, len, ap->a_uio));
	/*
	 * There _should_ be no way for an entire process to disappear
	 * from under us...
	 */
	case Pfile:
		procp = pfs_pfind(pfs->pfs_pid);
		if (procp == NULL || procp->p_ucred == NULL) {
			kprintf("procfs_readlink: pid %d disappeared\n",
			    pfs->pfs_pid);
			if (procp)
				PRELE(procp);
			return (uiomove("unknown", sizeof("unknown") - 1,
			    ap->a_uio));
		}
		error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0);
		if (error != 0) {
			if (procp)
				PRELE(procp);
			return (uiomove("unknown", sizeof("unknown") - 1,
			    ap->a_uio));
		}
		error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
		kfree(freepath, M_TEMP);
		if (procp)
			PRELE(procp);
		return (error);
	default:
		return (EINVAL);
	}
}
Exemple #2
0
static int
procfs_readdir_proc(struct vop_readdir_args *ap)
{
	struct pfsnode *pfs;
	int error, i, retval;
	struct proc *p;
	struct lwp *lp;
	struct proc_target *pt;
	struct uio *uio = ap->a_uio;

	pfs = VTOPFS(ap->a_vp);
	p = pfs_pfind(pfs->pfs_pid);
	if (p == NULL)
		return(0);
	if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) {
		error = 0;
		goto done;
	}
	/* XXX lwp, not MPSAFE */
	lp = FIRST_LWP_IN_PROC(p);

	error = 0;
	i = (int)uio->uio_offset;
	if (i < 0) {
		error = EINVAL;
		goto done;
	}

	for (pt = &proc_targets[i];
	     !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) {
		if (pt->pt_valid && (*pt->pt_valid)(lp) == 0)
			continue;

		retval = vop_write_dirent(&error, uio,
		    PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype), pt->pt_type,
		    pt->pt_namlen, pt->pt_name);
		if (retval)
			break;
	}

	uio->uio_offset = (off_t)i;
	error = 0;
done:
	PRELE(p);
	return error;
}
/*
 * 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);
}
int
procfs_loadvnode(struct mount *mp, struct vnode *vp,
    const void *key, size_t key_len, const void **new_key)
{
	int error;
	struct pfskey pfskey;
	struct pfsnode *pfs;

	KASSERT(key_len == sizeof(pfskey));
	memcpy(&pfskey, key, key_len);

	pfs = kmem_alloc(sizeof(*pfs), KM_SLEEP);
	pfs->pfs_pid = pfskey.pk_pid;
	pfs->pfs_type = pfskey.pk_type;
	pfs->pfs_fd = pfskey.pk_fd;
	pfs->pfs_vnode = vp;
	pfs->pfs_flags = 0;
	pfs->pfs_fileno =
	    PROCFS_FILENO(pfs->pfs_pid, pfs->pfs_type, pfs->pfs_fd);
	vp->v_tag = VT_PROCFS;
	vp->v_op = procfs_vnodeop_p;
	vp->v_data = pfs;

	switch (pfs->pfs_type) {
	case PFSroot:	/* /proc = dr-xr-xr-x */
		vp->v_vflag |= VV_ROOT;
		/*FALLTHROUGH*/
	case PFSproc:	/* /proc/N = dr-xr-xr-x */
		pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
		vp->v_type = VDIR;
		break;

	case PFStask:	/* /proc/N/task = dr-xr-xr-x */
		if (pfs->pfs_fd == -1) {
			pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|
			    S_IROTH|S_IXOTH;
			vp->v_type = VDIR;
			break;
		}
		/*FALLTHROUGH*/
	case PFScurproc:	/* /proc/curproc = lr-xr-xr-x */
	case PFSself:	/* /proc/self    = lr-xr-xr-x */
	case PFScwd:	/* /proc/N/cwd = lr-xr-xr-x */
	case PFSchroot:	/* /proc/N/chroot = lr-xr-xr-x */
	case PFSexe:	/* /proc/N/exe = lr-xr-xr-x */
		pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
		vp->v_type = VLNK;
		break;

	case PFSfd:
		if (pfs->pfs_fd == -1) {	/* /proc/N/fd = dr-x------ */
			pfs->pfs_mode = S_IRUSR|S_IXUSR;
			vp->v_type = VDIR;
		} else {	/* /proc/N/fd/M = [ps-]rw------- */
			file_t *fp;
			vnode_t *vxp;
			struct proc *p;

			mutex_enter(proc_lock);
			p = proc_find(pfs->pfs_pid);
			mutex_exit(proc_lock);
			if (p == NULL) {
				error = ENOENT;
				goto bad;
			}
			KASSERT(rw_read_held(&p->p_reflock));
			if ((fp = fd_getfile2(p, pfs->pfs_fd)) == NULL) {
				error = EBADF;
				goto bad;
			}

			pfs->pfs_mode = S_IRUSR|S_IWUSR;
			switch (fp->f_type) {
			case DTYPE_VNODE:
				vxp = fp->f_vnode;

				/*
				 * We make symlinks for directories
				 * to avoid cycles.
				 */
				if (vxp->v_type == VDIR)
					goto symlink;
				vp->v_type = vxp->v_type;
				break;
			case DTYPE_PIPE:
				vp->v_type = VFIFO;
				break;
			case DTYPE_SOCKET:
				vp->v_type = VSOCK;
				break;
			case DTYPE_KQUEUE:
			case DTYPE_MISC:
			case DTYPE_SEM:
			symlink:
				pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|
				    S_IXGRP|S_IROTH|S_IXOTH;
				vp->v_type = VLNK;
				break;
			default:
				error = EOPNOTSUPP;
				closef(fp);
				goto bad;
			}
			closef(fp);
		}
		break;

	case PFSfile:	/* /proc/N/file = -rw------- */
	case PFSmem:	/* /proc/N/mem = -rw------- */
	case PFSregs:	/* /proc/N/regs = -rw------- */
	case PFSfpregs:	/* /proc/N/fpregs = -rw------- */
		pfs->pfs_mode = S_IRUSR|S_IWUSR;
		vp->v_type = VREG;
		break;

	case PFSctl:	/* /proc/N/ctl = --w------ */
	case PFSnote:	/* /proc/N/note = --w------ */
	case PFSnotepg:	/* /proc/N/notepg = --w------ */
		pfs->pfs_mode = S_IWUSR;
		vp->v_type = VREG;
		break;

	case PFSmap:	/* /proc/N/map = -r--r--r-- */
	case PFSmaps:	/* /proc/N/maps = -r--r--r-- */
	case PFSstatus:	/* /proc/N/status = -r--r--r-- */
	case PFSstat:	/* /proc/N/stat = -r--r--r-- */
	case PFScmdline:	/* /proc/N/cmdline = -r--r--r-- */
	case PFSemul:	/* /proc/N/emul = -r--r--r-- */
	case PFSmeminfo:	/* /proc/meminfo = -r--r--r-- */
	case PFScpustat:	/* /proc/stat = -r--r--r-- */
	case PFSdevices:	/* /proc/devices = -r--r--r-- */
	case PFScpuinfo:	/* /proc/cpuinfo = -r--r--r-- */
	case PFSuptime:	/* /proc/uptime = -r--r--r-- */
	case PFSmounts:	/* /proc/mounts = -r--r--r-- */
	case PFSloadavg:	/* /proc/loadavg = -r--r--r-- */
	case PFSstatm:	/* /proc/N/statm = -r--r--r-- */
	case PFSversion:	/* /proc/version = -r--r--r-- */
		pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
		vp->v_type = VREG;
		break;

#ifdef __HAVE_PROCFS_MACHDEP
	PROCFS_MACHDEP_NODETYPE_CASES
		procfs_machdep_allocvp(vp);
		break;
#endif

	default:
		panic("procfs_allocvp");
	}

	uvm_vnp_setsize(vp, 0);
	*new_key = &pfs->pfs_key;

	return 0;

bad:
	vp->v_tag =VT_NON;
	vp->v_type = VNON;
	vp->v_op = NULL;
	vp->v_data = NULL;
	kmem_free(pfs, sizeof(*pfs));
	return error;
}
Exemple #5
0
static int
procfs_readdir_root_callback(struct proc *p, void *data)
{
	struct procfs_readdir_root_info *info = data;
	struct uio *uio;
	int retval;
	ino_t d_ino;
	const char *d_name;
	char d_name_pid[20];
	size_t d_namlen;
	uint8_t d_type;

	uio = info->uio;

	if (uio->uio_resid <= 0 || info->error)
		return(-1);

	switch (info->pcnt) {
	case 0:		/* `.' */
		d_ino = PROCFS_FILENO(0, Proot);
		d_name = ".";
		d_namlen = 1;
		d_type = DT_DIR;
		break;
	case 1:		/* `..' */
		d_ino = PROCFS_FILENO(0, Proot);
		d_name = "..";
		d_namlen = 2;
		d_type = DT_DIR;
		break;

	case 2:
		d_ino = PROCFS_FILENO(0, Pcurproc);
		d_namlen = 7;
		d_name = "curproc";
		d_type = DT_LNK;
		break;


	default:
		if (!PRISON_CHECK(info->cred, p->p_ucred))
			return(0);
		if (ps_showallprocs == 0 && 
		    info->cred->cr_uid != 0 &&
		    info->cred->cr_uid != p->p_ucred->cr_uid) {
			return(0);
		}

		/*
		 * Skip entries we have already returned (optimization)
		 */
		if (info->pcnt < info->i) {
			++info->pcnt;
			return(0);
		}

		d_ino = PROCFS_FILENO(p->p_pid, Pproc);
		d_namlen = ksnprintf(d_name_pid, sizeof(d_name_pid),
		    "%ld", (long)p->p_pid);
		d_name = d_name_pid;
		d_type = DT_DIR;
		break;
	}

	/*
	 * Skip entries we have already returned (optimization)
	 */
	if (info->pcnt < info->i) {
		++info->pcnt;
		return(0);
	}

	retval = vop_write_dirent(&info->error, uio,
				  d_ino, d_type, d_namlen, d_name);
	if (retval)
		return(-1);
	++info->pcnt;
	++info->i;
	return(0);
}