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 | * | |
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 | ||
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 | ||
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 | ||
156 | out: | |
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 | ||
167 | int | |
168 | procfs_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 | ||
186 | int | |
187 | procfs_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 | */ | |
234 | int | |
235 | vfs_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 | ||
270 | vfs_namemap_t * | |
271 | vfs_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 | } |