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