1*65523Spendry /*
2*65523Spendry  * Copyright (c) 1993 The Regents of the University of California.
3*65523Spendry  * Copyright (c) 1993 Jan-Simon Pendry
4*65523Spendry  * All rights reserved.
5*65523Spendry  *
6*65523Spendry  * This code is derived from software contributed to Berkeley by
7*65523Spendry  * Jan-Simon Pendry.
8*65523Spendry  *
9*65523Spendry  * %sccs.include.redist.c%
10*65523Spendry  *
11*65523Spendry  *	@(#)procfs_subr.c	8.1 (Berkeley) 01/05/94
12*65523Spendry  *
13*65523Spendry  * From:
14*65523Spendry  *	$Id: procfs_subr.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
15*65523Spendry  */
16*65523Spendry 
17*65523Spendry #include <sys/param.h>
18*65523Spendry #include <sys/systm.h>
19*65523Spendry #include <sys/time.h>
20*65523Spendry #include <sys/kernel.h>
21*65523Spendry #include <sys/proc.h>
22*65523Spendry #include <sys/vnode.h>
23*65523Spendry #include <sys/malloc.h>
24*65523Spendry #include <miscfs/procfs/procfs.h>
25*65523Spendry 
26*65523Spendry static struct pfsnode *pfshead;
27*65523Spendry static int pfsvplock;
28*65523Spendry 
29*65523Spendry /*
30*65523Spendry  * allocate a pfsnode/vnode pair.  the vnode is
31*65523Spendry  * referenced, but not locked.
32*65523Spendry  *
33*65523Spendry  * the pid, pfs_type, and mount point uniquely
34*65523Spendry  * identify a pfsnode.  the mount point is needed
35*65523Spendry  * because someone might mount this filesystem
36*65523Spendry  * twice.
37*65523Spendry  *
38*65523Spendry  * all pfsnodes are maintained on a singly-linked
39*65523Spendry  * list.  new nodes are only allocated when they cannot
40*65523Spendry  * be found on this list.  entries on the list are
41*65523Spendry  * removed when the vfs reclaim entry is called.
42*65523Spendry  *
43*65523Spendry  * a single lock is kept for the entire list.  this is
44*65523Spendry  * needed because the getnewvnode() function can block
45*65523Spendry  * waiting for a vnode to become free, in which case there
46*65523Spendry  * may be more than one process trying to get the same
47*65523Spendry  * vnode.  this lock is only taken if we are going to
48*65523Spendry  * call getnewvnode, since the kernel itself is single-threaded.
49*65523Spendry  *
50*65523Spendry  * if an entry is found on the list, then call vget() to
51*65523Spendry  * take a reference.  this is done because there may be
52*65523Spendry  * zero references to it and so it needs to removed from
53*65523Spendry  * the vnode free list.
54*65523Spendry  */
55*65523Spendry int
56*65523Spendry procfs_allocvp(mp, vpp, pid, pfs_type)
57*65523Spendry 	struct mount *mp;
58*65523Spendry 	struct vnode **vpp;
59*65523Spendry 	long pid;
60*65523Spendry 	pfstype pfs_type;
61*65523Spendry {
62*65523Spendry 	int error;
63*65523Spendry 	struct pfsnode *pfs;
64*65523Spendry 	struct pfsnode **pp;
65*65523Spendry 
66*65523Spendry loop:
67*65523Spendry 	for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
68*65523Spendry 		if (pfs->pfs_pid == pid &&
69*65523Spendry 		    pfs->pfs_type == pfs_type &&
70*65523Spendry 		    PFSTOV(pfs)->v_mount == mp) {
71*65523Spendry 			if (vget(pfs->pfs_vnode, 1))
72*65523Spendry 				goto loop;
73*65523Spendry 			VOP_UNLOCK(pfs->pfs_vnode);
74*65523Spendry 			*vpp = pfs->pfs_vnode;
75*65523Spendry 			return (0);
76*65523Spendry 		}
77*65523Spendry 	}
78*65523Spendry 
79*65523Spendry 	/*
80*65523Spendry 	 * otherwise lock the vp list while we call getnewvnode
81*65523Spendry 	 * since that can block.
82*65523Spendry 	 */
83*65523Spendry 	if (pfsvplock & PROCFS_LOCKED) {
84*65523Spendry 		pfsvplock |= PROCFS_WANT;
85*65523Spendry 		sleep((caddr_t) &pfsvplock, PINOD);
86*65523Spendry 		goto loop;
87*65523Spendry 	}
88*65523Spendry 	pfsvplock |= PROCFS_LOCKED;
89*65523Spendry 
90*65523Spendry 	error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp);
91*65523Spendry 	if (error)
92*65523Spendry 		goto out;
93*65523Spendry 
94*65523Spendry 	MALLOC((*vpp)->v_data, void *, sizeof(struct pfsnode),
95*65523Spendry 		M_TEMP, M_WAITOK);
96*65523Spendry 
97*65523Spendry 	pfs = VTOPFS(*vpp);
98*65523Spendry 	pfs->pfs_next = 0;
99*65523Spendry 	pfs->pfs_pid = (pid_t) pid;
100*65523Spendry 	pfs->pfs_type = pfs_type;
101*65523Spendry 	pfs->pfs_vnode = *vpp;
102*65523Spendry 	pfs->pfs_flags = 0;
103*65523Spendry 	pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
104*65523Spendry 
105*65523Spendry 	switch (pfs_type) {
106*65523Spendry 	case Proot:	/* /proc = dr-xr-xr-x */
107*65523Spendry 		pfs->pfs_mode = (VREAD|VEXEC) |
108*65523Spendry 				(VREAD|VEXEC) >> 3 |
109*65523Spendry 				(VREAD|VEXEC) >> 6;
110*65523Spendry 		break;
111*65523Spendry 
112*65523Spendry 	case Pproc:
113*65523Spendry 		pfs->pfs_mode = (VREAD|VEXEC) |
114*65523Spendry 				(VREAD|VEXEC) >> 3 |
115*65523Spendry 				(VREAD|VEXEC) >> 6;
116*65523Spendry 		break;
117*65523Spendry 
118*65523Spendry 	case Pfile:
119*65523Spendry 		pfs->pfs_mode = (VREAD|VWRITE);
120*65523Spendry 		break;
121*65523Spendry 
122*65523Spendry 	case Pmem:
123*65523Spendry 		pfs->pfs_mode = (VREAD|VWRITE);
124*65523Spendry 		break;
125*65523Spendry 
126*65523Spendry 	case Pregs:
127*65523Spendry 		pfs->pfs_mode = (VREAD|VWRITE);
128*65523Spendry 		break;
129*65523Spendry 
130*65523Spendry 	case Pctl:
131*65523Spendry 		pfs->pfs_mode = (VWRITE);
132*65523Spendry 		break;
133*65523Spendry 
134*65523Spendry 	case Pstatus:
135*65523Spendry 		pfs->pfs_mode = (VREAD) |
136*65523Spendry 				(VREAD >> 3) |
137*65523Spendry 				(VREAD >> 6);
138*65523Spendry 		break;
139*65523Spendry 
140*65523Spendry 	case Pnote:
141*65523Spendry 		pfs->pfs_mode = (VWRITE);
142*65523Spendry 		break;
143*65523Spendry 
144*65523Spendry 	case Pnotepg:
145*65523Spendry 		pfs->pfs_mode = (VWRITE);
146*65523Spendry 		break;
147*65523Spendry 
148*65523Spendry 	default:
149*65523Spendry 		panic("procfs_allocvp");
150*65523Spendry 	}
151*65523Spendry 
152*65523Spendry 	/* add to procfs vnode list */
153*65523Spendry 	for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next)
154*65523Spendry 		continue;
155*65523Spendry 	*pp = pfs;
156*65523Spendry 
157*65523Spendry out:
158*65523Spendry 	pfsvplock &= ~PROCFS_LOCKED;
159*65523Spendry 
160*65523Spendry 	if (pfsvplock & PROCFS_WANT) {
161*65523Spendry 		pfsvplock &= ~PROCFS_WANT;
162*65523Spendry 		wakeup((caddr_t) &pfsvplock);
163*65523Spendry 	}
164*65523Spendry 
165*65523Spendry 	return (error);
166*65523Spendry }
167*65523Spendry 
168*65523Spendry int
169*65523Spendry procfs_freevp(vp)
170*65523Spendry 	struct vnode *vp;
171*65523Spendry {
172*65523Spendry 	struct pfsnode **pfspp;
173*65523Spendry 	struct pfsnode *pfs = VTOPFS(vp);
174*65523Spendry 
175*65523Spendry 	for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) {
176*65523Spendry 		if (*pfspp == pfs) {
177*65523Spendry 			*pfspp = pfs->pfs_next;
178*65523Spendry 			break;
179*65523Spendry 		}
180*65523Spendry 	}
181*65523Spendry 
182*65523Spendry 	FREE(vp->v_data, M_TEMP);
183*65523Spendry 	vp->v_data = 0;
184*65523Spendry 	return (0);
185*65523Spendry }
186*65523Spendry 
187*65523Spendry int
188*65523Spendry procfs_rw(ap)
189*65523Spendry 	struct vop_read_args *ap;
190*65523Spendry {
191*65523Spendry 	struct vnode *vp = ap->a_vp;
192*65523Spendry 	struct uio *uio = ap->a_uio;
193*65523Spendry 	struct proc *curp = uio->uio_procp;
194*65523Spendry 	struct pfsnode *pfs = VTOPFS(vp);
195*65523Spendry 	struct proc *p;
196*65523Spendry 
197*65523Spendry 	p = PFIND(pfs->pfs_pid);
198*65523Spendry 	if (p == 0)
199*65523Spendry 		return (EINVAL);
200*65523Spendry 
201*65523Spendry 	switch (pfs->pfs_type) {
202*65523Spendry 	case Pnote:
203*65523Spendry 	case Pnotepg:
204*65523Spendry 		return (procfs_donote(curp, p, pfs, uio));
205*65523Spendry 
206*65523Spendry 	case Pregs:
207*65523Spendry 		return (procfs_doregs(curp, p, pfs, uio));
208*65523Spendry 
209*65523Spendry 	case Pctl:
210*65523Spendry 		return (procfs_doctl(curp, p, pfs, uio));
211*65523Spendry 
212*65523Spendry 	case Pstatus:
213*65523Spendry 		return (procfs_dostatus(curp, p, pfs, uio));
214*65523Spendry 
215*65523Spendry 	case Pmem:
216*65523Spendry 		return (procfs_domem(curp, p, pfs, uio));
217*65523Spendry 
218*65523Spendry 	default:
219*65523Spendry 		return (EOPNOTSUPP);
220*65523Spendry 	}
221*65523Spendry }
222*65523Spendry 
223*65523Spendry /*
224*65523Spendry  * Get a string from userland into (buf).  Strip a trailing
225*65523Spendry  * nl character (to allow easy access from the shell).
226*65523Spendry  * The buffer should be *buflenp + 1 chars long.  vfs_getuserstr
227*65523Spendry  * will automatically add a nul char at the end.
228*65523Spendry  *
229*65523Spendry  * Returns 0 on success or the following errors
230*65523Spendry  *
231*65523Spendry  * EINVAL:    file offset is non-zero.
232*65523Spendry  * EMSGSIZE:  message is longer than kernel buffer
233*65523Spendry  * EFAULT:    user i/o buffer is not addressable
234*65523Spendry  */
235*65523Spendry int
236*65523Spendry vfs_getuserstr(uio, buf, buflenp)
237*65523Spendry 	struct uio *uio;
238*65523Spendry 	char *buf;
239*65523Spendry 	int *buflenp;
240*65523Spendry {
241*65523Spendry 	int xlen;
242*65523Spendry 	int error;
243*65523Spendry 
244*65523Spendry 	if (uio->uio_offset != 0)
245*65523Spendry 		return (EINVAL);
246*65523Spendry 
247*65523Spendry 	xlen = *buflenp;
248*65523Spendry 
249*65523Spendry 	/* must be able to read the whole string in one go */
250*65523Spendry 	if (xlen < uio->uio_resid)
251*65523Spendry 		return (EMSGSIZE);
252*65523Spendry 	xlen = uio->uio_resid;
253*65523Spendry 
254*65523Spendry 	error = uiomove(buf, xlen, uio);
255*65523Spendry 	if (error)
256*65523Spendry 		return (error);
257*65523Spendry 
258*65523Spendry 	/* allow multiple writes without seeks */
259*65523Spendry 	uio->uio_offset = 0;
260*65523Spendry 
261*65523Spendry 	/* cleanup string and remove trailing newline */
262*65523Spendry 	buf[xlen] = '\0';
263*65523Spendry 	xlen = strlen(buf);
264*65523Spendry 	if (xlen > 0 && buf[xlen-1] == '\n')
265*65523Spendry 		buf[--xlen] = '\0';
266*65523Spendry 	*buflenp = xlen;
267*65523Spendry 
268*65523Spendry 	return (0);
269*65523Spendry }
270*65523Spendry 
271*65523Spendry vfs_namemap_t *
272*65523Spendry vfs_findname(nm, buf, buflen)
273*65523Spendry 	vfs_namemap_t *nm;
274*65523Spendry 	char *buf;
275*65523Spendry 	int buflen;
276*65523Spendry {
277*65523Spendry 	for (; nm->nm_name; nm++)
278*65523Spendry 		if (bcmp(buf, (char *) nm->nm_name, buflen+1) == 0)
279*65523Spendry 			return (nm);
280*65523Spendry 
281*65523Spendry 	return (0);
282*65523Spendry }
283