Annotation of src/sys/miscfs/procfs/procfs_subr.c, Revision 1.32
1.32 ! ad 1: /* $NetBSD: procfs_subr.c,v 1.31 2000/03/16 18:08:26 jdolecek Exp $ */
1.13 cgd 2:
1.1 pk 3: /*
1.20 thorpej 4: * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
1.5 cgd 5: * Copyright (c) 1993 Jan-Simon Pendry
1.11 mycroft 6: * Copyright (c) 1993
7: * The Regents of the University of California. All rights reserved.
1.2 pk 8: *
1.5 cgd 9: * This code is derived from software contributed to Berkeley by
10: * Jan-Simon Pendry.
11: *
1.2 pk 12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
1.5 cgd 22: * This product includes software developed by the University of
23: * California, Berkeley and its contributors.
24: * 4. Neither the name of the University nor the names of its contributors
25: * may be used to endorse or promote products derived from this software
26: * without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38: * SUCH DAMAGE.
1.2 pk 39: *
1.23 fvdl 40: * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
1.1 pk 41: */
1.5 cgd 42:
1.4 mycroft 43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/time.h>
46: #include <sys/kernel.h>
47: #include <sys/proc.h>
48: #include <sys/vnode.h>
1.11 mycroft 49: #include <sys/malloc.h>
1.18 mycroft 50: #include <sys/stat.h>
51:
1.5 cgd 52: #include <miscfs/procfs/procfs.h>
1.1 pk 53:
1.29 fvdl 54: void procfs_hashins __P((struct pfsnode *));
55: void procfs_hashrem __P((struct pfsnode *));
56: struct vnode *procfs_hashget __P((pid_t, pfstype, struct mount *));
57:
58: LIST_HEAD(pfs_hashhead, pfsnode) *pfs_hashtbl;
1.30 fvdl 59: u_long pfs_ihash; /* size of hash table - 1 */
60: #define PFSPIDHASH(pid) (&pfs_hashtbl[(pid) & pfs_ihash])
1.29 fvdl 61:
62: struct lock pfs_hashlock;
63: struct simplelock pfs_hash_slock;
1.1 pk 64:
1.20 thorpej 65: #define ISSET(t, f) ((t) & (f))
66:
1.1 pk 67: /*
1.5 cgd 68: * allocate a pfsnode/vnode pair. the vnode is
1.27 wrstuden 69: * referenced, and locked.
1.5 cgd 70: *
71: * the pid, pfs_type, and mount point uniquely
72: * identify a pfsnode. the mount point is needed
73: * because someone might mount this filesystem
74: * twice.
75: *
76: * all pfsnodes are maintained on a singly-linked
77: * list. new nodes are only allocated when they cannot
78: * be found on this list. entries on the list are
79: * removed when the vfs reclaim entry is called.
80: *
81: * a single lock is kept for the entire list. this is
82: * needed because the getnewvnode() function can block
83: * waiting for a vnode to become free, in which case there
84: * may be more than one process trying to get the same
85: * vnode. this lock is only taken if we are going to
86: * call getnewvnode, since the kernel itself is single-threaded.
87: *
88: * if an entry is found on the list, then call vget() to
89: * take a reference. this is done because there may be
90: * zero references to it and so it needs to removed from
91: * the vnode free list.
1.1 pk 92: */
1.11 mycroft 93: int
1.5 cgd 94: procfs_allocvp(mp, vpp, pid, pfs_type)
95: struct mount *mp;
96: struct vnode **vpp;
97: long pid;
98: pfstype pfs_type;
1.1 pk 99: {
1.12 mycroft 100: struct pfsnode *pfs;
101: struct vnode *vp;
1.5 cgd 102: int error;
103:
1.29 fvdl 104: do {
105: if ((*vpp = procfs_hashget(pid, pfs_type, mp)) != NULL)
1.5 cgd 106: return (0);
1.29 fvdl 107: } while (lockmgr(&pfs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
1.1 pk 108:
1.29 fvdl 109: if ((error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) != 0) {
110: *vpp = NULL;
111: lockmgr(&pfs_hashlock, LK_RELEASE, 0);
112: return (error);
1.5 cgd 113: }
1.11 mycroft 114: vp = *vpp;
1.5 cgd 115:
1.11 mycroft 116: MALLOC(pfs, void *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
117: vp->v_data = pfs;
1.5 cgd 118:
119: pfs->pfs_pid = (pid_t) pid;
120: pfs->pfs_type = pfs_type;
1.11 mycroft 121: pfs->pfs_vnode = vp;
1.5 cgd 122: pfs->pfs_flags = 0;
123: pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
124:
125: switch (pfs_type) {
1.11 mycroft 126: case Proot: /* /proc = dr-xr-xr-x */
1.17 mycroft 127: pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.11 mycroft 128: vp->v_type = VDIR;
129: vp->v_flag = VROOT;
130: break;
131:
1.22 mycroft 132: case Pcurproc: /* /proc/curproc = lr-xr-xr-x */
1.28 thorpej 133: case Pself: /* /proc/self = lr-xr-xr-x */
1.22 mycroft 134: pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.11 mycroft 135: vp->v_type = VLNK;
1.5 cgd 136: break;
137:
1.17 mycroft 138: case Pproc: /* /proc/N = dr-xr-xr-x */
139: pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.6 ws 140: vp->v_type = VDIR;
1.5 cgd 141: break;
142:
1.17 mycroft 143: case Pfile: /* /proc/N/file = -rw------- */
144: case Pmem: /* /proc/N/mem = -rw------- */
145: case Pregs: /* /proc/N/regs = -rw------- */
146: case Pfpregs: /* /proc/N/fpregs = -rw------- */
147: pfs->pfs_mode = S_IRUSR|S_IWUSR;
1.9 cgd 148: vp->v_type = VREG;
149: break;
150:
1.17 mycroft 151: case Pctl: /* /proc/N/ctl = --w------ */
152: case Pnote: /* /proc/N/note = --w------ */
153: case Pnotepg: /* /proc/N/notepg = --w------ */
154: pfs->pfs_mode = S_IWUSR;
1.6 ws 155: vp->v_type = VREG;
1.5 cgd 156: break;
157:
1.25 msaitoh 158: case Pmap: /* /proc/N/map = -r--r--r-- */
1.17 mycroft 159: case Pstatus: /* /proc/N/status = -r--r--r-- */
1.26 christos 160: case Pcmdline: /* /proc/N/cmdline = -r--r--r-- */
1.17 mycroft 161: pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
1.6 ws 162: vp->v_type = VREG;
1.5 cgd 163: break;
164:
165: default:
1.11 mycroft 166: panic("procfs_allocvp");
1.5 cgd 167: }
1.27 wrstuden 168:
1.29 fvdl 169: procfs_hashins(pfs);
170: lockmgr(&pfs_hashlock, LK_RELEASE, 0);
1.1 pk 171:
1.5 cgd 172: return (error);
1.1 pk 173: }
174:
1.11 mycroft 175: int
1.5 cgd 176: procfs_freevp(vp)
177: struct vnode *vp;
1.1 pk 178: {
1.5 cgd 179: struct pfsnode *pfs = VTOPFS(vp);
180:
1.29 fvdl 181: procfs_hashrem(pfs);
1.1 pk 182:
1.11 mycroft 183: FREE(vp->v_data, M_TEMP);
184: vp->v_data = 0;
1.5 cgd 185: return (0);
1.1 pk 186: }
187:
1.11 mycroft 188: int
1.15 christos 189: procfs_rw(v)
190: void *v;
1.1 pk 191: {
1.15 christos 192: struct vop_read_args *ap = v;
1.11 mycroft 193: struct vnode *vp = ap->a_vp;
194: struct uio *uio = ap->a_uio;
1.5 cgd 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)
1.1 pk 201: return (EINVAL);
1.19 mycroft 202:
203: switch (pfs->pfs_type) {
204: case Pregs:
205: case Pfpregs:
206: case Pmem:
207: /*
208: * Do not allow init to be modified while in secure mode; it
209: * could be duped into changing the security level.
210: */
211: if (uio->uio_rw == UIO_WRITE &&
212: p == initproc && securelevel > -1)
213: return (EPERM);
214: break;
215:
216: default:
217: break;
218: }
1.1 pk 219:
1.5 cgd 220: switch (pfs->pfs_type) {
221: case Pnote:
222: case Pnotepg:
1.11 mycroft 223: return (procfs_donote(curp, p, pfs, uio));
1.5 cgd 224:
225: case Pregs:
1.11 mycroft 226: return (procfs_doregs(curp, p, pfs, uio));
1.9 cgd 227:
228: case Pfpregs:
1.11 mycroft 229: return (procfs_dofpregs(curp, p, pfs, uio));
1.5 cgd 230:
231: case Pctl:
1.11 mycroft 232: return (procfs_doctl(curp, p, pfs, uio));
1.5 cgd 233:
234: case Pstatus:
1.11 mycroft 235: return (procfs_dostatus(curp, p, pfs, uio));
1.25 msaitoh 236:
237: case Pmap:
238: return (procfs_domap(curp, p, pfs, uio));
1.1 pk 239:
1.5 cgd 240: case Pmem:
1.11 mycroft 241: return (procfs_domem(curp, p, pfs, uio));
1.26 christos 242:
243: case Pcmdline:
244: return (procfs_docmdline(curp, p, pfs, uio));
1.1 pk 245:
1.5 cgd 246: default:
247: return (EOPNOTSUPP);
248: }
1.1 pk 249: }
250:
1.5 cgd 251: /*
252: * Get a string from userland into (buf). Strip a trailing
253: * nl character (to allow easy access from the shell).
1.11 mycroft 254: * The buffer should be *buflenp + 1 chars long. vfs_getuserstr
1.5 cgd 255: * will automatically add a nul char at the end.
256: *
257: * Returns 0 on success or the following errors
258: *
259: * EINVAL: file offset is non-zero.
260: * EMSGSIZE: message is longer than kernel buffer
261: * EFAULT: user i/o buffer is not addressable
262: */
1.11 mycroft 263: int
264: vfs_getuserstr(uio, buf, buflenp)
1.5 cgd 265: struct uio *uio;
266: char *buf;
267: int *buflenp;
1.1 pk 268: {
1.5 cgd 269: int xlen;
270: int error;
271:
1.11 mycroft 272: if (uio->uio_offset != 0)
273: return (EINVAL);
274:
1.5 cgd 275: xlen = *buflenp;
1.1 pk 276:
1.5 cgd 277: /* must be able to read the whole string in one go */
278: if (xlen < uio->uio_resid)
279: return (EMSGSIZE);
280: xlen = uio->uio_resid;
281:
1.14 christos 282: if ((error = uiomove(buf, xlen, uio)) != 0)
1.5 cgd 283: return (error);
284:
1.11 mycroft 285: /* allow multiple writes without seeks */
286: uio->uio_offset = 0;
287:
1.5 cgd 288: /* cleanup string and remove trailing newline */
289: buf[xlen] = '\0';
290: xlen = strlen(buf);
291: if (xlen > 0 && buf[xlen-1] == '\n')
292: buf[--xlen] = '\0';
293: *buflenp = xlen;
1.1 pk 294:
1.5 cgd 295: return (0);
1.1 pk 296: }
297:
1.11 mycroft 298: vfs_namemap_t *
299: vfs_findname(nm, buf, buflen)
300: vfs_namemap_t *nm;
1.5 cgd 301: char *buf;
302: int buflen;
1.1 pk 303: {
1.11 mycroft 304:
1.5 cgd 305: for (; nm->nm_name; nm++)
1.24 perry 306: if (memcmp(buf, nm->nm_name, buflen+1) == 0)
1.5 cgd 307: return (nm);
308:
309: return (0);
1.29 fvdl 310: }
311:
312: /*
313: * Initialize pfsnode hash table.
314: */
315: void
316: procfs_hashinit()
317: {
318: lockinit(&pfs_hashlock, PINOD, "pfs_hashlock", 0, 0);
1.32 ! ad 319: pfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT,
! 320: M_WAITOK, &pfs_ihash);
1.29 fvdl 321: simple_lock_init(&pfs_hash_slock);
1.31 jdolecek 322: }
323:
324: /*
325: * Free pfsnode hash table.
326: */
327: void
328: procfs_hashdone()
329: {
330: hashdone(pfs_hashtbl, M_UFSMNT);
1.29 fvdl 331: }
332:
333: struct vnode *
334: procfs_hashget(pid, type, mp)
335: pid_t pid;
336: pfstype type;
337: struct mount *mp;
338: {
339: struct pfsnode *pp;
340: struct vnode *vp;
341:
342: loop:
343: simple_lock(&pfs_hash_slock);
344: for (pp = PFSPIDHASH(pid)->lh_first; pp; pp = pp->pfs_hash.le_next) {
345: vp = PFSTOV(pp);
346: if (pid == pp->pfs_pid && pp->pfs_type == type &&
347: vp->v_mount == mp) {
348: simple_lock(&vp->v_interlock);
349: simple_unlock(&pfs_hash_slock);
350: if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
351: goto loop;
352: return (vp);
353: }
354: }
355: simple_unlock(&pfs_hash_slock);
356: return (NULL);
357: }
358:
359: /*
360: * Insert the pfsnode into the hash table and lock it.
361: */
362: void
363: procfs_hashins(pp)
364: struct pfsnode *pp;
365: {
366: struct pfs_hashhead *ppp;
367:
368: /* lock the pfsnode, then put it on the appropriate hash list */
369: lockmgr(&pp->pfs_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0);
370:
371: simple_lock(&pfs_hash_slock);
372: ppp = PFSPIDHASH(pp->pfs_pid);
373: LIST_INSERT_HEAD(ppp, pp, pfs_hash);
374: simple_unlock(&pfs_hash_slock);
375: }
376:
377: /*
378: * Remove the pfsnode from the hash table.
379: */
380: void
381: procfs_hashrem(pp)
382: struct pfsnode *pp;
383: {
384: simple_lock(&pfs_hash_slock);
385: LIST_REMOVE(pp, pfs_hash);
386: simple_unlock(&pfs_hash_slock);
387: }
388:
389: void
390: procfs_revoke_vnodes(p, arg)
391: struct proc *p;
392: void *arg;
393: {
394: struct pfsnode *pfs, *pnext;
395: struct vnode *vp;
396: struct mount *mp = (struct mount *)arg;
397:
398: if (!(p->p_flag & P_SUGID))
399: return;
400:
401: for (pfs = PFSPIDHASH(p->p_pid)->lh_first; pfs; pfs = pnext) {
402: vp = PFSTOV(pfs);
403: pnext = pfs->pfs_hash.le_next;
404: if (vp->v_usecount > 0 && pfs->pfs_pid == p->p_pid &&
405: vp->v_mount == mp)
406: VOP_REVOKE(vp, REVOKEALL);
407: }
1.1 pk 408: }
CVSweb <webmaster@jp.NetBSD.org>