date and time created 94/01/27 11:30:30 by pendry
[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 *
1611db1e 11 * @(#)procfs_subr.c 8.3 (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{
62 int error;
63 struct pfsnode *pfs;
64 struct pfsnode **pp;
65
66loop:
67 for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
68 if (pfs->pfs_pid == pid &&
69 pfs->pfs_type == pfs_type &&
70 PFSTOV(pfs)->v_mount == mp) {
ce173ae2 71 if (vget(pfs->pfs_vnode, 0))
a352e4ad 72 goto loop;
a352e4ad
JSP
73 *vpp = pfs->pfs_vnode;
74 return (0);
75 }
76 }
77
78 /*
79 * otherwise lock the vp list while we call getnewvnode
80 * since that can block.
81 */
82 if (pfsvplock & PROCFS_LOCKED) {
83 pfsvplock |= PROCFS_WANT;
84 sleep((caddr_t) &pfsvplock, PINOD);
85 goto loop;
86 }
87 pfsvplock |= PROCFS_LOCKED;
88
89 error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp);
90 if (error)
91 goto out;
92
93 MALLOC((*vpp)->v_data, void *, sizeof(struct pfsnode),
94 M_TEMP, M_WAITOK);
95
96 pfs = VTOPFS(*vpp);
97 pfs->pfs_next = 0;
98 pfs->pfs_pid = (pid_t) pid;
99 pfs->pfs_type = pfs_type;
100 pfs->pfs_vnode = *vpp;
101 pfs->pfs_flags = 0;
102 pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
103
104 switch (pfs_type) {
105 case Proot: /* /proc = dr-xr-xr-x */
106 pfs->pfs_mode = (VREAD|VEXEC) |
107 (VREAD|VEXEC) >> 3 |
108 (VREAD|VEXEC) >> 6;
109 break;
110
111 case Pproc:
112 pfs->pfs_mode = (VREAD|VEXEC) |
113 (VREAD|VEXEC) >> 3 |
114 (VREAD|VEXEC) >> 6;
115 break;
116
117 case Pfile:
118 pfs->pfs_mode = (VREAD|VWRITE);
119 break;
120
121 case Pmem:
122 pfs->pfs_mode = (VREAD|VWRITE);
123 break;
124
125 case Pregs:
126 pfs->pfs_mode = (VREAD|VWRITE);
127 break;
128
129 case Pctl:
130 pfs->pfs_mode = (VWRITE);
131 break;
132
133 case Pstatus:
134 pfs->pfs_mode = (VREAD) |
135 (VREAD >> 3) |
136 (VREAD >> 6);
137 break;
138
139 case Pnote:
140 pfs->pfs_mode = (VWRITE);
141 break;
142
143 case Pnotepg:
144 pfs->pfs_mode = (VWRITE);
145 break;
146
147 default:
148 panic("procfs_allocvp");
149 }
150
151 /* add to procfs vnode list */
152 for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next)
153 continue;
154 *pp = pfs;
155
156out:
157 pfsvplock &= ~PROCFS_LOCKED;
158
159 if (pfsvplock & PROCFS_WANT) {
160 pfsvplock &= ~PROCFS_WANT;
161 wakeup((caddr_t) &pfsvplock);
162 }
163
164 return (error);
165}
166
167int
168procfs_freevp(vp)
169 struct vnode *vp;
170{
171 struct pfsnode **pfspp;
172 struct pfsnode *pfs = VTOPFS(vp);
173
174 for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) {
175 if (*pfspp == pfs) {
176 *pfspp = pfs->pfs_next;
177 break;
178 }
179 }
180
181 FREE(vp->v_data, M_TEMP);
182 vp->v_data = 0;
183 return (0);
184}
185
186int
187procfs_rw(ap)
188 struct vop_read_args *ap;
189{
190 struct vnode *vp = ap->a_vp;
191 struct uio *uio = ap->a_uio;
192 struct proc *curp = uio->uio_procp;
193 struct pfsnode *pfs = VTOPFS(vp);
194 struct proc *p;
195
196 p = PFIND(pfs->pfs_pid);
197 if (p == 0)
198 return (EINVAL);
199
200 switch (pfs->pfs_type) {
201 case Pnote:
202 case Pnotepg:
203 return (procfs_donote(curp, p, pfs, uio));
204
205 case Pregs:
206 return (procfs_doregs(curp, p, pfs, uio));
207
208 case Pctl:
209 return (procfs_doctl(curp, p, pfs, uio));
210
211 case Pstatus:
212 return (procfs_dostatus(curp, p, pfs, uio));
213
214 case Pmem:
215 return (procfs_domem(curp, p, pfs, uio));
216
217 default:
218 return (EOPNOTSUPP);
219 }
220}
221
222/*
223 * Get a string from userland into (buf). Strip a trailing
224 * nl character (to allow easy access from the shell).
225 * The buffer should be *buflenp + 1 chars long. vfs_getuserstr
226 * will automatically add a nul char at the end.
227 *
228 * Returns 0 on success or the following errors
229 *
230 * EINVAL: file offset is non-zero.
231 * EMSGSIZE: message is longer than kernel buffer
232 * EFAULT: user i/o buffer is not addressable
233 */
234int
235vfs_getuserstr(uio, buf, buflenp)
236 struct uio *uio;
237 char *buf;
238 int *buflenp;
239{
240 int xlen;
241 int error;
242
243 if (uio->uio_offset != 0)
244 return (EINVAL);
245
246 xlen = *buflenp;
247
248 /* must be able to read the whole string in one go */
249 if (xlen < uio->uio_resid)
250 return (EMSGSIZE);
251 xlen = uio->uio_resid;
252
253 error = uiomove(buf, xlen, uio);
254 if (error)
255 return (error);
256
257 /* allow multiple writes without seeks */
258 uio->uio_offset = 0;
259
260 /* cleanup string and remove trailing newline */
261 buf[xlen] = '\0';
262 xlen = strlen(buf);
263 if (xlen > 0 && buf[xlen-1] == '\n')
264 buf[--xlen] = '\0';
265 *buflenp = xlen;
266
267 return (0);
268}
269
270vfs_namemap_t *
271vfs_findname(nm, buf, buflen)
272 vfs_namemap_t *nm;
273 char *buf;
274 int buflen;
275{
276 for (; nm->nm_name; nm++)
277 if (bcmp(buf, (char *) nm->nm_name, buflen+1) == 0)
278 return (nm);
279
280 return (0);
281}