Commit | Line | Data |
---|---|---|
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 | ||
26 | static struct pfsnode *pfshead; | |
27 | static 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 | */ | |
55 | int | |
56 | procfs_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 | |
67 | loop: | |
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 | ||
159 | out: | |
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 | ||
170 | int | |
171 | procfs_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 | ||
189 | int | |
190 | procfs_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 | */ | |
240 | int | |
241 | vfs_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 | ||
275 | vfs_namemap_t * | |
276 | vfs_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 | } |