Annotation of sys/miscfs/procfs/procfs_vnops.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: procfs_vnops.c,v 1.40 2007/06/18 08:30:07 jasper Exp $ */
2: /* $NetBSD: procfs_vnops.c,v 1.40 1996/03/16 23:52:55 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1993 Jan-Simon Pendry
6: * Copyright (c) 1993
7: * The Regents of the University of California. All rights reserved.
8: *
9: * This code is derived from software contributed to Berkeley by
10: * Jan-Simon Pendry.
11: *
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. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)procfs_vnops.c 8.8 (Berkeley) 6/15/94
37: */
38:
39: /*
40: * procfs vnode interface
41: */
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/time.h>
46: #include <sys/kernel.h>
47: #include <sys/file.h>
48: #include <sys/proc.h>
49: #include <sys/mount.h>
50: #include <sys/vnode.h>
51: #include <sys/namei.h>
52: #include <sys/malloc.h>
53: #include <sys/dirent.h>
54: #include <sys/resourcevar.h>
55: #include <sys/poll.h>
56: #include <sys/ptrace.h>
57: #include <sys/stat.h>
58:
59: #include <uvm/uvm_extern.h> /* for PAGE_SIZE */
60:
61: #include <machine/reg.h>
62:
63: #include <miscfs/procfs/procfs.h>
64:
65: /*
66: * Vnode Operations.
67: *
68: */
69: static int procfs_validfile_linux(struct proc *, struct mount *);
70:
71: /*
72: * This is a list of the valid names in the
73: * process-specific sub-directories. It is
74: * used in procfs_lookup and procfs_readdir
75: */
76: struct proc_target {
77: u_char pt_type;
78: u_char pt_namlen;
79: char *pt_name;
80: pfstype pt_pfstype;
81: int (*pt_valid)(struct proc *p, struct mount *mp);
82: } proc_targets[] = {
83: #define N(s) sizeof(s)-1, s
84: /* name type validp */
85: { DT_DIR, N("."), Pproc, NULL },
86: { DT_DIR, N(".."), Proot, NULL },
87: { DT_REG, N("file"), Pfile, procfs_validfile },
88: { DT_REG, N("mem"), Pmem, NULL },
89: { DT_REG, N("ctl"), Pctl, NULL },
90: { DT_REG, N("status"), Pstatus, NULL },
91: { DT_REG, N("note"), Pnote, NULL },
92: { DT_REG, N("notepg"), Pnotepg, NULL },
93: { DT_REG, N("cmdline"), Pcmdline, NULL },
94: { DT_REG, N("exe"), Pfile, procfs_validfile_linux },
95: #undef N
96: };
97: static int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
98:
99: /*
100: * List of files in the root directory. Note: the validate function
101: * will be called with p == NULL for these
102: */
103: struct proc_target proc_root_targets[] = {
104: #define N(s) sizeof(s)-1, s
105: /* name type validp */
106: { DT_REG, N("meminfo"), Pmeminfo, procfs_validfile_linux },
107: { DT_REG, N("cpuinfo"), Pcpuinfo, procfs_validfile_linux },
108: #undef N
109: };
110: static int nproc_root_targets =
111: sizeof(proc_root_targets) / sizeof(proc_root_targets[0]);
112:
113: static pid_t atopid(const char *, u_int);
114:
115: /*
116: * Prototypes for procfs vnode ops
117: */
118: int procfs_badop(void *);
119:
120: int procfs_lookup(void *);
121: #define procfs_create procfs_badop
122: #define procfs_mknod procfs_badop
123: int procfs_open(void *);
124: int procfs_close(void *);
125: int procfs_access(void *);
126: int procfs_getattr(void *);
127: int procfs_setattr(void *);
128: #define procfs_read procfs_rw
129: #define procfs_write procfs_rw
130: int procfs_ioctl(void *);
131: #define procfs_fsync procfs_badop
132: #define procfs_remove procfs_badop
133: int procfs_link(void *);
134: #define procfs_rename procfs_badop
135: #define procfs_mkdir procfs_badop
136: #define procfs_rmdir procfs_badop
137: int procfs_symlink(void *);
138: int procfs_readdir(void *);
139: int procfs_readlink(void *);
140: int procfs_inactive(void *);
141: int procfs_reclaim(void *);
142: #define procfs_lock nullop
143: #define procfs_unlock nullop
144: int procfs_bmap(void *);
145: #define procfs_strategy procfs_badop
146: int procfs_print(void *);
147: int procfs_pathconf(void *);
148: #define procfs_islocked nullop
149: #define procfs_advlock procfs_badop
150:
151: static pid_t atopid(const char *, u_int);
152:
153: /*
154: * procfs vnode operations.
155: */
156: int (**procfs_vnodeop_p)(void *);
157: struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
158: { &vop_default_desc, vn_default_error },
159: { &vop_lookup_desc, procfs_lookup }, /* lookup */
160: { &vop_create_desc, procfs_create }, /* create */
161: { &vop_mknod_desc, procfs_mknod }, /* mknod */
162: { &vop_open_desc, procfs_open }, /* open */
163: { &vop_close_desc, procfs_close }, /* close */
164: { &vop_access_desc, procfs_access }, /* access */
165: { &vop_getattr_desc, procfs_getattr }, /* getattr */
166: { &vop_setattr_desc, procfs_setattr }, /* setattr */
167: { &vop_read_desc, procfs_read }, /* read */
168: { &vop_write_desc, procfs_write }, /* write */
169: { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */
170: { &vop_poll_desc, procfs_poll }, /* poll */
171: { &vop_fsync_desc, procfs_fsync }, /* fsync */
172: { &vop_remove_desc, procfs_remove }, /* remove */
173: { &vop_link_desc, procfs_link }, /* link */
174: { &vop_rename_desc, procfs_rename }, /* rename */
175: { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */
176: { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */
177: { &vop_symlink_desc, procfs_symlink }, /* symlink */
178: { &vop_readdir_desc, procfs_readdir }, /* readdir */
179: { &vop_readlink_desc, procfs_readlink }, /* readlink */
180: { &vop_abortop_desc, vop_generic_abortop }, /* abortop */
181: { &vop_inactive_desc, procfs_inactive }, /* inactive */
182: { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */
183: { &vop_lock_desc, procfs_lock }, /* lock */
184: { &vop_unlock_desc, procfs_unlock }, /* unlock */
185: { &vop_bmap_desc, procfs_bmap }, /* bmap */
186: { &vop_strategy_desc, procfs_strategy }, /* strategy */
187: { &vop_print_desc, procfs_print }, /* print */
188: { &vop_islocked_desc, procfs_islocked }, /* islocked */
189: { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */
190: { &vop_advlock_desc, procfs_advlock }, /* advlock */
191: { NULL, NULL }
192: };
193: struct vnodeopv_desc procfs_vnodeop_opv_desc =
194: { &procfs_vnodeop_p, procfs_vnodeop_entries };
195: /*
196: * set things up for doing i/o on
197: * the pfsnode (vp). (vp) is locked
198: * on entry, and should be left locked
199: * on exit.
200: *
201: * for procfs we don't need to do anything
202: * in particular for i/o. all that is done
203: * is to support exclusive open on process
204: * memory images.
205: */
206: int
207: procfs_open(void *v)
208: {
209: struct vop_open_args *ap = v;
210: struct pfsnode *pfs = VTOPFS(ap->a_vp);
211: struct proc *p1 = ap->a_p; /* tracer */
212: struct proc *p2; /* traced */
213: int error;
214:
215: if ((p2 = pfind(pfs->pfs_pid)) == 0)
216: return (ENOENT); /* was ESRCH, jsp */
217:
218: switch (pfs->pfs_type) {
219: case Pmem:
220: if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
221: ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
222: return (EBUSY);
223:
224: if ((error = process_checkioperm(p1, p2)) != 0)
225: return (error);
226:
227: if (ap->a_mode & FWRITE)
228: pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
229:
230: return (0);
231:
232: default:
233: break;
234: }
235:
236: return (0);
237: }
238:
239: /*
240: * close the pfsnode (vp) after doing i/o.
241: * (vp) is not locked on entry or exit.
242: *
243: * nothing to do for procfs other than undo
244: * any exclusive open flag (see _open above).
245: */
246: int
247: procfs_close(void *v)
248: {
249: struct vop_close_args *ap = v;
250: struct pfsnode *pfs = VTOPFS(ap->a_vp);
251:
252: switch (pfs->pfs_type) {
253: case Pmem:
254: if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
255: pfs->pfs_flags &= ~(FWRITE|O_EXCL);
256: break;
257: case Pctl:
258: case Pstatus:
259: case Pnotepg:
260: case Pnote:
261: case Proot:
262: case Pcurproc:
263: case Pself:
264: case Pproc:
265: case Pfile:
266: case Pregs:
267: case Pfpregs:
268: case Pcmdline:
269: case Pmeminfo:
270: case Pcpuinfo:
271: break;
272: }
273:
274: return (0);
275: }
276:
277: /*
278: * do an ioctl operation on pfsnode (vp).
279: * (vp) is not locked on entry or exit.
280: */
281: /*ARGSUSED*/
282: int
283: procfs_ioctl(void *v)
284: {
285:
286: return (ENOTTY);
287: }
288:
289: /*
290: * do block mapping for pfsnode (vp).
291: * since we don't use the buffer cache
292: * for procfs this function should never
293: * be called. in any case, it's not clear
294: * what part of the kernel ever makes use
295: * of this function. for sanity, this is the
296: * usual no-op bmap, although returning
297: * (EIO) would be a reasonable alternative.
298: */
299: int
300: procfs_bmap(void *v)
301: {
302: struct vop_bmap_args *ap = v;
303:
304: if (ap->a_vpp != NULL)
305: *ap->a_vpp = ap->a_vp;
306: if (ap->a_bnp != NULL)
307: *ap->a_bnp = ap->a_bn;
308: return (0);
309: }
310:
311: /*
312: * _inactive is called when the pfsnode
313: * is vrele'd and the reference count goes
314: * to zero. (vp) will be on the vnode free
315: * list, so to get it back vget() must be
316: * used.
317: *
318: * for procfs, check if the process is still
319: * alive and if it isn't then just throw away
320: * the vnode by calling vgone(). this may
321: * be overkill and a waste of time since the
322: * chances are that the process will still be
323: * there and pfind is not free.
324: *
325: * (vp) is not locked on entry or exit.
326: */
327: int
328: procfs_inactive(void *v)
329: {
330: struct vop_inactive_args *ap = v;
331: struct vnode *vp = ap->a_vp;
332: struct pfsnode *pfs = VTOPFS(vp);
333:
334: if (pfind(pfs->pfs_pid) == NULL && !(vp->v_flag & VXLOCK))
335: vgone(vp);
336:
337: return (0);
338: }
339:
340: /*
341: * _reclaim is called when getnewvnode()
342: * wants to make use of an entry on the vnode
343: * free list. at this time the filesystem needs
344: * to free any private data and remove the node
345: * from any private lists.
346: */
347: int
348: procfs_reclaim(void *v)
349: {
350: struct vop_reclaim_args *ap = v;
351:
352: return (procfs_freevp(ap->a_vp));
353: }
354:
355: /*
356: * Return POSIX pathconf information applicable to special devices.
357: */
358: int
359: procfs_pathconf(void *v)
360: {
361: struct vop_pathconf_args *ap = v;
362:
363: switch (ap->a_name) {
364: case _PC_LINK_MAX:
365: *ap->a_retval = LINK_MAX;
366: return (0);
367: case _PC_MAX_CANON:
368: *ap->a_retval = MAX_CANON;
369: return (0);
370: case _PC_MAX_INPUT:
371: *ap->a_retval = MAX_INPUT;
372: return (0);
373: case _PC_PIPE_BUF:
374: *ap->a_retval = PIPE_BUF;
375: return (0);
376: case _PC_CHOWN_RESTRICTED:
377: *ap->a_retval = 1;
378: return (0);
379: case _PC_VDISABLE:
380: *ap->a_retval = _POSIX_VDISABLE;
381: return (0);
382: default:
383: return (EINVAL);
384: }
385: /* NOTREACHED */
386: }
387:
388: /*
389: * _print is used for debugging.
390: * just print a readable description
391: * of (vp).
392: */
393: int
394: procfs_print(void *v)
395: {
396: struct vop_print_args *ap = v;
397: struct pfsnode *pfs = VTOPFS(ap->a_vp);
398:
399: printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n",
400: pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
401: return 0;
402: }
403:
404: int
405: procfs_link(void *v)
406: {
407: struct vop_link_args *ap = v;
408:
409: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
410: vput(ap->a_dvp);
411: return (EROFS);
412: }
413:
414: int
415: procfs_symlink(void *v)
416: {
417: struct vop_symlink_args *ap = v;
418:
419: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
420: vput(ap->a_dvp);
421: return (EROFS);
422: }
423:
424:
425: /*
426: * generic entry point for unsupported operations
427: */
428: /*ARGSUSED*/
429: int
430: procfs_badop(void *v)
431: {
432:
433: return (EIO);
434: }
435:
436: /*
437: * Invent attributes for pfsnode (vp) and store
438: * them in (vap).
439: * Directories lengths are returned as zero since
440: * any real length would require the genuine size
441: * to be computed, and nothing cares anyway.
442: *
443: * this is relatively minimal for procfs.
444: */
445: int
446: procfs_getattr(void *v)
447: {
448: struct vop_getattr_args *ap = v;
449: struct pfsnode *pfs = VTOPFS(ap->a_vp);
450: struct vattr *vap = ap->a_vap;
451: struct proc *procp;
452: int error;
453:
454: /* first check the process still exists */
455: switch (pfs->pfs_type) {
456: case Proot:
457: case Pcurproc:
458: case Pcpuinfo:
459: case Pmeminfo:
460: procp = 0;
461: break;
462:
463: default:
464: procp = pfind(pfs->pfs_pid);
465: if (procp == 0)
466: return (ENOENT);
467: }
468:
469: error = 0;
470:
471: /* start by zeroing out the attributes */
472: VATTR_NULL(vap);
473:
474: /* next do all the common fields */
475: vap->va_type = ap->a_vp->v_type;
476: vap->va_mode = pfs->pfs_mode;
477: vap->va_fileid = pfs->pfs_fileno;
478: vap->va_flags = 0;
479: vap->va_blocksize = PAGE_SIZE;
480: vap->va_bytes = vap->va_size = 0;
481:
482: /*
483: * Make all times be current TOD.
484: * It would be possible to get the process start
485: * time from the p_stat structure, but there's
486: * no "file creation" time stamp anyway, and the
487: * p_stat structure is not addressible if u. gets
488: * swapped out for that process.
489: */
490: getnanotime(&vap->va_ctime);
491: vap->va_atime = vap->va_mtime = vap->va_ctime;
492:
493: switch (pfs->pfs_type) {
494: case Pregs:
495: case Pfpregs:
496: #ifndef PTRACE
497: break;
498: #endif
499: case Pmem:
500: /*
501: * If the process has exercised some setuid or setgid
502: * privilege, then rip away read/write permission so
503: * that only root can gain access.
504: */
505: if (procp->p_flag & P_SUGID)
506: vap->va_mode &= ~(S_IRUSR|S_IWUSR);
507: /* FALLTHROUGH */
508: case Pctl:
509: case Pstatus:
510: case Pnote:
511: case Pnotepg:
512: case Pcmdline:
513: vap->va_nlink = 1;
514: vap->va_uid = procp->p_ucred->cr_uid;
515: vap->va_gid = procp->p_ucred->cr_gid;
516: break;
517: case Pmeminfo:
518: case Pcpuinfo:
519: vap->va_nlink = 1;
520: vap->va_uid = vap->va_gid = 0;
521: break;
522: case Pproc:
523: case Pfile:
524: case Proot:
525: case Pcurproc:
526: case Pself:
527: break;
528: }
529:
530: /*
531: * now do the object specific fields
532: *
533: * The size could be set from struct reg, but it's hardly
534: * worth the trouble, and it puts some (potentially) machine
535: * dependent data into this machine-independent code. If it
536: * becomes important then this function should break out into
537: * a per-file stat function in the corresponding .c file.
538: */
539:
540: switch (pfs->pfs_type) {
541: case Proot:
542: /*
543: * Set nlink to 1 to tell fts(3) we don't actually know.
544: */
545: vap->va_nlink = 1;
546: vap->va_uid = 0;
547: vap->va_gid = 0;
548: vap->va_size = vap->va_bytes = DEV_BSIZE;
549: break;
550:
551: case Pcurproc: {
552: char buf[16]; /* should be enough */
553: int len;
554:
555: len = snprintf(buf, sizeof buf, "%ld", (long)curproc->p_pid);
556: if (len == -1 || len >= sizeof buf) {
557: error = EINVAL;
558: break;
559: }
560: vap->va_nlink = 1;
561: vap->va_uid = 0;
562: vap->va_gid = 0;
563: vap->va_size = vap->va_bytes = len;
564: break;
565: }
566:
567: case Pself:
568: vap->va_nlink = 1;
569: vap->va_uid = 0;
570: vap->va_gid = 0;
571: vap->va_size = vap->va_bytes = sizeof("curproc");
572: break;
573:
574: case Pproc:
575: vap->va_nlink = 2;
576: vap->va_uid = procp->p_ucred->cr_uid;
577: vap->va_gid = procp->p_ucred->cr_gid;
578: vap->va_size = vap->va_bytes = DEV_BSIZE;
579: break;
580:
581: case Pfile:
582: error = EOPNOTSUPP;
583: break;
584:
585: case Pmem:
586: vap->va_bytes = vap->va_size =
587: ctob(procp->p_vmspace->vm_tsize +
588: procp->p_vmspace->vm_dsize +
589: procp->p_vmspace->vm_ssize);
590: break;
591:
592: case Pregs:
593: #ifdef PTRACE
594: vap->va_bytes = vap->va_size = sizeof(struct reg);
595: #endif
596: break;
597:
598: case Pfpregs:
599: #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
600: #ifdef PTRACE
601: vap->va_bytes = vap->va_size = sizeof(struct fpreg);
602: #endif
603: #endif
604: break;
605:
606: case Pctl:
607: case Pstatus:
608: case Pnote:
609: case Pnotepg:
610: case Pcmdline:
611: case Pmeminfo:
612: case Pcpuinfo:
613: vap->va_bytes = vap->va_size = 0;
614: break;
615:
616: #ifdef DIAGNOSTIC
617: default:
618: panic("procfs_getattr");
619: #endif
620: }
621:
622: return (error);
623: }
624:
625: /*ARGSUSED*/
626: int
627: procfs_setattr(void *v)
628: {
629: /*
630: * just fake out attribute setting
631: * it's not good to generate an error
632: * return, otherwise things like creat()
633: * will fail when they try to set the
634: * file length to 0. worse, this means
635: * that echo $note > /proc/$pid/note will fail.
636: */
637:
638: return (0);
639: }
640:
641: /*
642: * implement access checking.
643: *
644: * actually, the check for super-user is slightly
645: * broken since it will allow read access to write-only
646: * objects. this doesn't cause any particular trouble
647: * but does mean that the i/o entry points need to check
648: * that the operation really does make sense.
649: */
650: int
651: procfs_access(void *v)
652: {
653: struct vop_access_args *ap = v;
654: struct vattr va;
655: int error;
656:
657: if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p)) != 0)
658: return (error);
659:
660: return (vaccess(va.va_mode, va.va_uid, va.va_gid, ap->a_mode,
661: ap->a_cred));
662: }
663:
664: /*
665: * lookup. this is incredibly complicated in the
666: * general case, however for most pseudo-filesystems
667: * very little needs to be done.
668: *
669: * unless you want to get a migraine, just make sure your
670: * filesystem doesn't do any locking of its own. otherwise
671: * read and inwardly digest ufs_lookup().
672: */
673: int
674: procfs_lookup(void *v)
675: {
676: struct vop_lookup_args *ap = v;
677: struct componentname *cnp = ap->a_cnp;
678: struct vnode **vpp = ap->a_vpp;
679: struct vnode *dvp = ap->a_dvp;
680: char *pname = cnp->cn_nameptr;
681: struct proc *curp = curproc;
682: struct proc_target *pt;
683: struct vnode *fvp;
684: pid_t pid;
685: struct pfsnode *pfs;
686: struct proc *p = NULL;
687: int i, error, wantpunlock, iscurproc = 0, isself = 0;
688:
689: *vpp = NULL;
690: cnp->cn_flags &= ~PDIRUNLOCK;
691:
692: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
693: return (EROFS);
694:
695: if (cnp->cn_namelen == 1 && *pname == '.') {
696: *vpp = dvp;
697: VREF(dvp);
698: return (0);
699: }
700:
701: wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN));
702: pfs = VTOPFS(dvp);
703: switch (pfs->pfs_type) {
704: case Proot:
705: if (cnp->cn_flags & ISDOTDOT)
706: return (EIO);
707:
708: iscurproc = CNEQ(cnp, "curproc", 7);
709: isself = CNEQ(cnp, "self", 4);
710:
711: if (iscurproc || isself) {
712: error = procfs_allocvp(dvp->v_mount, vpp, 0,
713: iscurproc ? Pcurproc : Pself);
714: if ((error == 0) && (wantpunlock)) {
715: VOP_UNLOCK(dvp, 0, curp);
716: cnp->cn_flags |= PDIRUNLOCK;
717: }
718: return (error);
719: }
720:
721: for (i = 0; i < nproc_root_targets; i++) {
722: pt = &proc_root_targets[i];
723: if (cnp->cn_namelen == pt->pt_namlen &&
724: memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
725: (pt->pt_valid == NULL ||
726: (*pt->pt_valid)(p, dvp->v_mount)))
727: break;
728: }
729:
730: if (i != nproc_root_targets) {
731: error = procfs_allocvp(dvp->v_mount, vpp, 0,
732: pt->pt_pfstype);
733: if ((error == 0) && (wantpunlock)) {
734: VOP_UNLOCK(dvp, 0, curp);
735: cnp->cn_flags |= PDIRUNLOCK;
736: }
737: return (error);
738: }
739:
740: pid = atopid(pname, cnp->cn_namelen);
741: if (pid == NO_PID)
742: break;
743:
744: p = pfind(pid);
745: if (p == 0)
746: break;
747:
748: error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
749: if ((error == 0) && wantpunlock) {
750: VOP_UNLOCK(dvp, 0, curp);
751: cnp->cn_flags |= PDIRUNLOCK;
752: }
753: return (error);
754:
755: case Pproc:
756: /*
757: * do the .. dance. We unlock the directory, and then
758: * get the root dir. That will automatically return ..
759: * locked. Then if the caller wanted dvp locked, we
760: * re-lock.
761: */
762: if (cnp->cn_flags & ISDOTDOT) {
763: VOP_UNLOCK(dvp, 0, p);
764: cnp->cn_flags |= PDIRUNLOCK;
765: error = procfs_root(dvp->v_mount, vpp);
766: if ((error == 0) && (wantpunlock == 0) &&
767: ((error = vn_lock(dvp, LK_EXCLUSIVE, curp)) == 0))
768: cnp->cn_flags &= ~PDIRUNLOCK;
769: return (error);
770: }
771:
772: p = pfind(pfs->pfs_pid);
773: if (p == 0)
774: break;
775:
776: for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
777: if (cnp->cn_namelen == pt->pt_namlen &&
778: bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
779: (pt->pt_valid == NULL ||
780: (*pt->pt_valid)(p, dvp->v_mount)))
781: goto found;
782: }
783: break;
784:
785: found:
786: if (pt->pt_pfstype == Pfile) {
787: fvp = p->p_textvp;
788: /* We already checked that it exists. */
789: VREF(fvp);
790: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp);
791: if (wantpunlock) {
792: VOP_UNLOCK(dvp, 0, curp);
793: cnp->cn_flags |= PDIRUNLOCK;
794: }
795: *vpp = fvp;
796: return (0);
797: }
798:
799: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
800: pt->pt_pfstype);
801: if ((error == 0) && (wantpunlock)) {
802: VOP_UNLOCK(dvp, 0, curp);
803: cnp->cn_flags |= PDIRUNLOCK;
804: }
805: return (error);
806:
807: default:
808: return (ENOTDIR);
809: }
810:
811: return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
812: }
813:
814: int
815: procfs_validfile(struct proc *p, struct mount *mp)
816: {
817:
818: return (p->p_textvp != NULLVP);
819: }
820:
821: int
822: procfs_validfile_linux(struct proc *p, struct mount *mp)
823: {
824: int flags;
825:
826: flags = VFSTOPROC(mp)->pmnt_flags;
827: return ((flags & PROCFSMNT_LINUXCOMPAT) &&
828: (p == NULL || procfs_validfile(p, mp)));
829: }
830:
831: /*
832: * readdir returns directory entries from pfsnode (vp).
833: *
834: * the strategy here with procfs is to generate a single
835: * directory entry at a time (struct dirent) and then
836: * copy that out to userland using uiomove. a more efficent
837: * though more complex implementation, would try to minimize
838: * the number of calls to uiomove(). for procfs, this is
839: * hardly worth the added code complexity.
840: *
841: * this should just be done through read()
842: */
843: int
844: procfs_readdir(void *v)
845: {
846: struct vop_readdir_args *ap = v;
847: struct uio *uio = ap->a_uio;
848: struct dirent d;
849: struct pfsnode *pfs;
850: struct vnode *vp;
851: int i;
852: int error;
853:
854: vp = ap->a_vp;
855: pfs = VTOPFS(vp);
856:
857: if (uio->uio_resid < UIO_MX)
858: return (EINVAL);
859:
860: error = 0;
861: i = uio->uio_offset;
862: if (i < 0)
863: return (EINVAL);
864: bzero(&d, UIO_MX);
865: d.d_reclen = UIO_MX;
866:
867: switch (pfs->pfs_type) {
868: /*
869: * this is for the process-specific sub-directories.
870: * all that is needed to is copy out all the entries
871: * from the procent[] table (top of this file).
872: */
873: case Pproc: {
874: struct proc *p;
875: struct proc_target *pt;
876:
877: p = pfind(pfs->pfs_pid);
878: if (p == NULL)
879: break;
880:
881: for (pt = &proc_targets[i];
882: uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
883: if (pt->pt_valid &&
884: (*pt->pt_valid)(p, vp->v_mount) == 0)
885: continue;
886:
887: d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype);
888: d.d_namlen = pt->pt_namlen;
889: bcopy(pt->pt_name, d.d_name, pt->pt_namlen + 1);
890: d.d_type = pt->pt_type;
891:
892: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
893: break;
894: }
895:
896: break;
897: }
898:
899: /*
900: * this is for the root of the procfs filesystem
901: * what is needed is a special entry for "curproc"
902: * followed by an entry for each process on allproc
903: #ifdef PROCFS_ZOMBIE
904: * and zombproc.
905: #endif
906: */
907:
908: case Proot: {
909: #ifdef PROCFS_ZOMBIE
910: int doingzomb = 0;
911: #endif
912: int pcnt = i;
913: volatile struct proc *p = LIST_FIRST(&allproc);
914:
915: if (pcnt > 3)
916: pcnt = 3;
917: #ifdef PROCFS_ZOMBIE
918: again:
919: #endif
920: for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) {
921: switch (i) {
922: case 0: /* `.' */
923: case 1: /* `..' */
924: d.d_fileno = PROCFS_FILENO(0, Proot);
925: d.d_namlen = i + 1;
926: bcopy("..", d.d_name, d.d_namlen);
927: d.d_name[i + 1] = '\0';
928: d.d_type = DT_DIR;
929: break;
930:
931: case 2:
932: d.d_fileno = PROCFS_FILENO(0, Pcurproc);
933: d.d_namlen = 7;
934: bcopy("curproc", d.d_name, 8);
935: d.d_type = DT_LNK;
936: break;
937:
938: case 3:
939: d.d_fileno = PROCFS_FILENO(0, Pself);
940: d.d_namlen = 4;
941: bcopy("self", d.d_name, 5);
942: d.d_type = DT_LNK;
943: break;
944:
945: case 4:
946: if (VFSTOPROC(vp->v_mount)->pmnt_flags &
947: PROCFSMNT_LINUXCOMPAT) {
948: d.d_fileno = PROCFS_FILENO(0, Pcpuinfo);
949: d.d_namlen = 7;
950: bcopy("cpuinfo", d.d_name, 8);
951: d.d_type = DT_REG;
952: break;
953: }
954: /* fall through */
955:
956: case 5:
957: if (VFSTOPROC(vp->v_mount)->pmnt_flags &
958: PROCFSMNT_LINUXCOMPAT) {
959: d.d_fileno = PROCFS_FILENO(0, Pmeminfo);
960: d.d_namlen = 7;
961: bcopy("meminfo", d.d_name, 8);
962: d.d_type = DT_REG;
963: break;
964: }
965: /* fall through */
966:
967: default:
968: while (pcnt < i) {
969: pcnt++;
970: p = LIST_NEXT(p, p_list);
971: if (!p)
972: goto done;
973: }
974: d.d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
975: d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
976: "%ld", (long)p->p_pid);
977: d.d_type = DT_REG;
978: p = LIST_NEXT(p, p_list);
979: break;
980: }
981:
982: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
983: break;
984: }
985: done:
986:
987: #ifdef PROCFS_ZOMBIE
988: if (p == 0 && doingzomb == 0) {
989: doingzomb = 1;
990: p = LIST_FIRST(&zombproc);
991: goto again;
992: }
993: #endif
994:
995: break;
996:
997: }
998:
999: default:
1000: error = ENOTDIR;
1001: break;
1002: }
1003:
1004: uio->uio_offset = i;
1005: return (error);
1006: }
1007:
1008: /*
1009: * readlink reads the link of `curproc'
1010: */
1011: int
1012: procfs_readlink(void *v)
1013: {
1014: struct vop_readlink_args *ap = v;
1015: char buf[16]; /* should be enough */
1016: int len;
1017:
1018: if (VTOPFS(ap->a_vp)->pfs_fileno == PROCFS_FILENO(0, Pcurproc))
1019: len = snprintf(buf, sizeof buf, "%ld", (long)curproc->p_pid);
1020: else if (VTOPFS(ap->a_vp)->pfs_fileno == PROCFS_FILENO(0, Pself))
1021: len = strlcpy(buf, "curproc", sizeof buf);
1022: else
1023: return (EINVAL);
1024: if (len == -1 || len >= sizeof buf)
1025: return (EINVAL);
1026:
1027: return (uiomove(buf, len, ap->a_uio));
1028: }
1029:
1030: /*
1031: * convert decimal ascii to pid_t
1032: */
1033: static pid_t
1034: atopid(const char *b, u_int len)
1035: {
1036: pid_t p = 0;
1037:
1038: while (len--) {
1039: char c = *b++;
1040: if (c < '0' || c > '9')
1041: return (NO_PID);
1042: p = 10 * p + (c - '0');
1043: if (p > PID_MAX)
1044: return (NO_PID);
1045: }
1046:
1047: return (p);
1048: }
1049: int
1050: procfs_poll(void *v)
1051: {
1052: struct vop_poll_args *ap = v;
1053:
1054: return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
1055: }
CVSweb