xref: /netbsd-src/sys/miscfs/procfs/procfs_subr.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
1 /*
2  * Copyright (c) 1993 Jan-Simon Pendry
3  * Copyright (c) 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	from: @(#)procfs_subr.c	8.5 (Berkeley) 6/15/94
38  *	$Id: procfs_subr.c,v 1.12 1994/06/15 22:59:12 mycroft Exp $
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/time.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/vnode.h>
47 #include <sys/malloc.h>
48 #include <miscfs/procfs/procfs.h>
49 
50 static struct pfsnode *pfshead;
51 static int pfsvplock;
52 
53 /*
54  * allocate a pfsnode/vnode pair.  the vnode is
55  * referenced, but not locked.
56  *
57  * the pid, pfs_type, and mount point uniquely
58  * identify a pfsnode.  the mount point is needed
59  * because someone might mount this filesystem
60  * twice.
61  *
62  * all pfsnodes are maintained on a singly-linked
63  * list.  new nodes are only allocated when they cannot
64  * be found on this list.  entries on the list are
65  * removed when the vfs reclaim entry is called.
66  *
67  * a single lock is kept for the entire list.  this is
68  * needed because the getnewvnode() function can block
69  * waiting for a vnode to become free, in which case there
70  * may be more than one process trying to get the same
71  * vnode.  this lock is only taken if we are going to
72  * call getnewvnode, since the kernel itself is single-threaded.
73  *
74  * if an entry is found on the list, then call vget() to
75  * take a reference.  this is done because there may be
76  * zero references to it and so it needs to removed from
77  * the vnode free list.
78  */
79 int
80 procfs_allocvp(mp, vpp, pid, pfs_type)
81 	struct mount *mp;
82 	struct vnode **vpp;
83 	long pid;
84 	pfstype pfs_type;
85 {
86 	struct pfsnode *pfs;
87 	struct vnode *vp;
88 	struct pfsnode **pp;
89 	int error;
90 
91 loop:
92 	for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
93 		vp = PFSTOV(pfs);
94 		if (pfs->pfs_pid == pid &&
95 		    pfs->pfs_type == pfs_type &&
96 		    vp->v_mount == mp) {
97 			if (vget(vp, 0))
98 				goto loop;
99 			*vpp = vp;
100 			return (0);
101 		}
102 	}
103 
104 	/*
105 	 * otherwise lock the vp list while we call getnewvnode
106 	 * since that can block.
107 	 */
108 	if (pfsvplock & PROCFS_LOCKED) {
109 		pfsvplock |= PROCFS_WANT;
110 		sleep((caddr_t) &pfsvplock, PINOD);
111 		goto loop;
112 	}
113 	pfsvplock |= PROCFS_LOCKED;
114 
115 	if (error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp))
116 		goto out;
117 	vp = *vpp;
118 
119 	MALLOC(pfs, void *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
120 	vp->v_data = pfs;
121 
122 	pfs->pfs_next = 0;
123 	pfs->pfs_pid = (pid_t) pid;
124 	pfs->pfs_type = pfs_type;
125 	pfs->pfs_vnode = vp;
126 	pfs->pfs_flags = 0;
127 	pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
128 
129 	switch (pfs_type) {
130 	case Proot:	/* /proc = dr-xr-xr-x */
131 		pfs->pfs_mode = (VREAD|VEXEC) |
132 				(VREAD|VEXEC) >> 3 |
133 				(VREAD|VEXEC) >> 6;
134 		vp->v_type = VDIR;
135 		vp->v_flag = VROOT;
136 		break;
137 
138 	case Pcurproc:	/* /proc/curproc = lr--r--r-- */
139 		pfs->pfs_mode = (VREAD) |
140 				(VREAD >> 3) |
141 				(VREAD >> 6);
142 		vp->v_type = VLNK;
143 		break;
144 
145 	case Pproc:
146 		pfs->pfs_mode = (VREAD|VEXEC) |
147 				(VREAD|VEXEC) >> 3 |
148 				(VREAD|VEXEC) >> 6;
149 		vp->v_type = VDIR;
150 		break;
151 
152 	case Pfile:
153 	case Pmem:
154 	case Pregs:
155 	case Pfpregs:
156 		pfs->pfs_mode = (VREAD|VWRITE);
157 		vp->v_type = VREG;
158 		break;
159 
160 	case Pctl:
161 	case Pnote:
162 	case Pnotepg:
163 		pfs->pfs_mode = (VWRITE);
164 		vp->v_type = VREG;
165 		break;
166 
167 	case Pstatus:
168 		pfs->pfs_mode = (VREAD) |
169 				(VREAD >> 3) |
170 				(VREAD >> 6);
171 		vp->v_type = VREG;
172 		break;
173 
174 	default:
175 		panic("procfs_allocvp");
176 	}
177 
178 	/* add to procfs vnode list */
179 	for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next)
180 		continue;
181 	*pp = pfs;
182 
183 out:
184 	pfsvplock &= ~PROCFS_LOCKED;
185 
186 	if (pfsvplock & PROCFS_WANT) {
187 		pfsvplock &= ~PROCFS_WANT;
188 		wakeup((caddr_t) &pfsvplock);
189 	}
190 
191 	return (error);
192 }
193 
194 int
195 procfs_freevp(vp)
196 	struct vnode *vp;
197 {
198 	struct pfsnode **pfspp;
199 	struct pfsnode *pfs = VTOPFS(vp);
200 
201 	for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) {
202 		if (*pfspp == pfs) {
203 			*pfspp = pfs->pfs_next;
204 			break;
205 		}
206 	}
207 
208 	FREE(vp->v_data, M_TEMP);
209 	vp->v_data = 0;
210 	return (0);
211 }
212 
213 int
214 procfs_rw(ap)
215 	struct vop_read_args *ap;
216 {
217 	struct vnode *vp = ap->a_vp;
218 	struct uio *uio = ap->a_uio;
219 	struct proc *curp = uio->uio_procp;
220 	struct pfsnode *pfs = VTOPFS(vp);
221 	struct proc *p;
222 
223 	p = PFIND(pfs->pfs_pid);
224 	if (p == 0)
225 		return (EINVAL);
226 
227 	switch (pfs->pfs_type) {
228 	case Pnote:
229 	case Pnotepg:
230 		return (procfs_donote(curp, p, pfs, uio));
231 
232 	case Pregs:
233 		return (procfs_doregs(curp, p, pfs, uio));
234 
235 	case Pfpregs:
236 		return (procfs_dofpregs(curp, p, pfs, uio));
237 
238 	case Pctl:
239 		return (procfs_doctl(curp, p, pfs, uio));
240 
241 	case Pstatus:
242 		return (procfs_dostatus(curp, p, pfs, uio));
243 
244 	case Pmem:
245 		return (procfs_domem(curp, p, pfs, uio));
246 
247 	default:
248 		return (EOPNOTSUPP);
249 	}
250 }
251 
252 /*
253  * Get a string from userland into (buf).  Strip a trailing
254  * nl character (to allow easy access from the shell).
255  * The buffer should be *buflenp + 1 chars long.  vfs_getuserstr
256  * will automatically add a nul char at the end.
257  *
258  * Returns 0 on success or the following errors
259  *
260  * EINVAL:    file offset is non-zero.
261  * EMSGSIZE:  message is longer than kernel buffer
262  * EFAULT:    user i/o buffer is not addressable
263  */
264 int
265 vfs_getuserstr(uio, buf, buflenp)
266 	struct uio *uio;
267 	char *buf;
268 	int *buflenp;
269 {
270 	int xlen;
271 	int error;
272 
273 	if (uio->uio_offset != 0)
274 		return (EINVAL);
275 
276 	xlen = *buflenp;
277 
278 	/* must be able to read the whole string in one go */
279 	if (xlen < uio->uio_resid)
280 		return (EMSGSIZE);
281 	xlen = uio->uio_resid;
282 
283 	if (error = uiomove(buf, xlen, uio))
284 		return (error);
285 
286 	/* allow multiple writes without seeks */
287 	uio->uio_offset = 0;
288 
289 	/* cleanup string and remove trailing newline */
290 	buf[xlen] = '\0';
291 	xlen = strlen(buf);
292 	if (xlen > 0 && buf[xlen-1] == '\n')
293 		buf[--xlen] = '\0';
294 	*buflenp = xlen;
295 
296 	return (0);
297 }
298 
299 vfs_namemap_t *
300 vfs_findname(nm, buf, buflen)
301 	vfs_namemap_t *nm;
302 	char *buf;
303 	int buflen;
304 {
305 
306 	for (; nm->nm_name; nm++)
307 		if (bcmp(buf, (char *) nm->nm_name, buflen+1) == 0)
308 			return (nm);
309 
310 	return (0);
311 }
312