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 | * | |
6fdd7e21 | 11 | * @(#)procfs_subr.c 8.4 (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 | { | |
62 | int error; | |
63 | struct pfsnode *pfs; | |
64 | struct pfsnode **pp; | |
65 | ||
66 | loop: | |
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 | ||
6fdd7e21 JSP |
129 | case Pfpregs: |
130 | pfs->pfs_mode = (VREAD|VWRITE); | |
131 | break; | |
132 | ||
a352e4ad JSP |
133 | case Pctl: |
134 | pfs->pfs_mode = (VWRITE); | |
135 | break; | |
136 | ||
137 | case Pstatus: | |
138 | pfs->pfs_mode = (VREAD) | | |
139 | (VREAD >> 3) | | |
140 | (VREAD >> 6); | |
141 | break; | |
142 | ||
143 | case Pnote: | |
144 | pfs->pfs_mode = (VWRITE); | |
145 | break; | |
146 | ||
147 | case Pnotepg: | |
148 | pfs->pfs_mode = (VWRITE); | |
149 | break; | |
150 | ||
151 | default: | |
152 | panic("procfs_allocvp"); | |
153 | } | |
154 | ||
155 | /* add to procfs vnode list */ | |
156 | for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) | |
157 | continue; | |
158 | *pp = pfs; | |
159 | ||
160 | out: | |
161 | pfsvplock &= ~PROCFS_LOCKED; | |
162 | ||
163 | if (pfsvplock & PROCFS_WANT) { | |
164 | pfsvplock &= ~PROCFS_WANT; | |
165 | wakeup((caddr_t) &pfsvplock); | |
166 | } | |
167 | ||
168 | return (error); | |
169 | } | |
170 | ||
171 | int | |
172 | procfs_freevp(vp) | |
173 | struct vnode *vp; | |
174 | { | |
175 | struct pfsnode **pfspp; | |
176 | struct pfsnode *pfs = VTOPFS(vp); | |
177 | ||
178 | for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) { | |
179 | if (*pfspp == pfs) { | |
180 | *pfspp = pfs->pfs_next; | |
181 | break; | |
182 | } | |
183 | } | |
184 | ||
185 | FREE(vp->v_data, M_TEMP); | |
186 | vp->v_data = 0; | |
187 | return (0); | |
188 | } | |
189 | ||
190 | int | |
191 | procfs_rw(ap) | |
192 | struct vop_read_args *ap; | |
193 | { | |
194 | struct vnode *vp = ap->a_vp; | |
195 | struct uio *uio = ap->a_uio; | |
196 | struct proc *curp = uio->uio_procp; | |
197 | struct pfsnode *pfs = VTOPFS(vp); | |
198 | struct proc *p; | |
199 | ||
200 | p = PFIND(pfs->pfs_pid); | |
201 | if (p == 0) | |
202 | return (EINVAL); | |
203 | ||
204 | switch (pfs->pfs_type) { | |
205 | case Pnote: | |
206 | case Pnotepg: | |
207 | return (procfs_donote(curp, p, pfs, uio)); | |
208 | ||
209 | case Pregs: | |
210 | return (procfs_doregs(curp, p, pfs, uio)); | |
211 | ||
6fdd7e21 JSP |
212 | case Pfpregs: |
213 | return (procfs_dofpregs(curp, p, pfs, uio)); | |
214 | ||
a352e4ad JSP |
215 | case Pctl: |
216 | return (procfs_doctl(curp, p, pfs, uio)); | |
217 | ||
218 | case Pstatus: | |
219 | return (procfs_dostatus(curp, p, pfs, uio)); | |
220 | ||
221 | case Pmem: | |
222 | return (procfs_domem(curp, p, pfs, uio)); | |
223 | ||
224 | default: | |
225 | return (EOPNOTSUPP); | |
226 | } | |
227 | } | |
228 | ||
229 | /* | |
230 | * Get a string from userland into (buf). Strip a trailing | |
231 | * nl character (to allow easy access from the shell). | |
232 | * The buffer should be *buflenp + 1 chars long. vfs_getuserstr | |
233 | * will automatically add a nul char at the end. | |
234 | * | |
235 | * Returns 0 on success or the following errors | |
236 | * | |
237 | * EINVAL: file offset is non-zero. | |
238 | * EMSGSIZE: message is longer than kernel buffer | |
239 | * EFAULT: user i/o buffer is not addressable | |
240 | */ | |
241 | int | |
242 | vfs_getuserstr(uio, buf, buflenp) | |
243 | struct uio *uio; | |
244 | char *buf; | |
245 | int *buflenp; | |
246 | { | |
247 | int xlen; | |
248 | int error; | |
249 | ||
250 | if (uio->uio_offset != 0) | |
251 | return (EINVAL); | |
252 | ||
253 | xlen = *buflenp; | |
254 | ||
255 | /* must be able to read the whole string in one go */ | |
256 | if (xlen < uio->uio_resid) | |
257 | return (EMSGSIZE); | |
258 | xlen = uio->uio_resid; | |
259 | ||
260 | error = uiomove(buf, xlen, uio); | |
261 | if (error) | |
262 | return (error); | |
263 | ||
264 | /* allow multiple writes without seeks */ | |
265 | uio->uio_offset = 0; | |
266 | ||
267 | /* cleanup string and remove trailing newline */ | |
268 | buf[xlen] = '\0'; | |
269 | xlen = strlen(buf); | |
270 | if (xlen > 0 && buf[xlen-1] == '\n') | |
271 | buf[--xlen] = '\0'; | |
272 | *buflenp = xlen; | |
273 | ||
274 | return (0); | |
275 | } | |
276 | ||
277 | vfs_namemap_t * | |
278 | vfs_findname(nm, buf, buflen) | |
279 | vfs_namemap_t *nm; | |
280 | char *buf; | |
281 | int buflen; | |
282 | { | |
283 | for (; nm->nm_name; nm++) | |
284 | if (bcmp(buf, (char *) nm->nm_name, buflen+1) == 0) | |
285 | return (nm); | |
286 | ||
287 | return (0); | |
288 | } |