1acb49b5bfcacce4dfe816c213a5484996763a91
[dragonfly.git] / sys / emulation / linux / i386 / linprocfs / linprocfs_vnops.c
1 /*
2  * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3  * Copyright (c) 1999 Pierre Beyssac
4  * Copyright (c) 1993, 1995 Jan-Simon Pendry
5  * Copyright (c) 1993, 1995
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *      @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
40  *
41  * $FreeBSD: src/sys/i386/linux/linprocfs/linprocfs_vnops.c,v 1.3.2.5 2001/08/12 14:29:19 rwatson Exp $
42  * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c,v 1.34 2006/08/19 17:27:22 dillon Exp $
43  */
44
45 /*
46  * procfs vnode interface
47  */
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/time.h>
52 #include <sys/kernel.h>
53 #include <sys/lock.h>
54 #include <sys/fcntl.h>
55 #include <sys/proc.h>
56 #include <sys/signalvar.h>
57 #include <sys/vnode.h>
58 #include <sys/mount.h>
59 #include <sys/namei.h>
60 #include <sys/dirent.h>
61 #include <sys/malloc.h>
62 #include <machine/reg.h>
63 #include <vm/vm_zone.h>
64 #include "linprocfs.h"
65 #include <sys/pioctl.h>
66
67 #include <machine/limits.h>
68
69 extern struct vnode *procfs_findtextvp (struct proc *);
70
71 static int      linprocfs_access (struct vop_access_args *);
72 static int      linprocfs_badop (struct vop_generic_args *);
73 static int      linprocfs_bmap (struct vop_bmap_args *);
74 static int      linprocfs_close (struct vop_close_args *);
75 static int      linprocfs_getattr (struct vop_getattr_args *);
76 static int      linprocfs_inactive (struct vop_inactive_args *);
77 static int      linprocfs_ioctl (struct vop_ioctl_args *);
78 static int      linprocfs_lookup (struct vop_old_lookup_args *);
79 static int      linprocfs_open (struct vop_open_args *);
80 static int      linprocfs_print (struct vop_print_args *);
81 static int      linprocfs_readdir (struct vop_readdir_args *);
82 static int      linprocfs_readlink (struct vop_readlink_args *);
83 static int      linprocfs_reclaim (struct vop_reclaim_args *);
84 static int      linprocfs_setattr (struct vop_setattr_args *);
85
86 static int      linprocfs_readdir_proc(struct vop_readdir_args *);
87 static int      linprocfs_readdir_root(struct vop_readdir_args *);
88
89 /*
90  * procfs vnode operations.
91  */
92 struct vop_ops linprocfs_vnode_vops = {
93         .vop_default =          vop_defaultop,
94         .vop_access =           linprocfs_access,
95         .vop_advlock =          (void *)linprocfs_badop,
96         .vop_bmap =             linprocfs_bmap,
97         .vop_close =            linprocfs_close,
98         .vop_old_create =       (void *)linprocfs_badop,
99         .vop_getattr =          linprocfs_getattr,
100         .vop_inactive =         linprocfs_inactive,
101         .vop_old_link =         (void *)linprocfs_badop,
102         .vop_old_lookup =       linprocfs_lookup,
103         .vop_old_mkdir =        (void *)linprocfs_badop,
104         .vop_old_mknod =        (void *)linprocfs_badop,
105         .vop_open =             linprocfs_open,
106         .vop_pathconf =         vop_stdpathconf,
107         .vop_print =            linprocfs_print,
108         .vop_read =             (void *)linprocfs_rw,
109         .vop_readdir =          linprocfs_readdir,
110         .vop_readlink =         linprocfs_readlink,
111         .vop_reclaim =          linprocfs_reclaim,
112         .vop_old_remove =       (void *)linprocfs_badop,
113         .vop_old_rename =       (void *)linprocfs_badop,
114         .vop_old_rmdir =        (void *)linprocfs_badop,
115         .vop_setattr =          linprocfs_setattr,
116         .vop_old_symlink =      (void *)linprocfs_badop,
117         .vop_write =            (void *)linprocfs_rw,
118         .vop_ioctl =            linprocfs_ioctl
119 };
120
121 /*
122  * This is a list of the valid names in the
123  * process-specific sub-directories.  It is
124  * used in linprocfs_lookup and linprocfs_readdir
125  */
126 static struct proc_target {
127         u_char  pt_type;
128         u_char  pt_namlen;
129         char    *pt_name;
130         pfstype pt_pfstype;
131         int     (*pt_valid) (struct proc *p);
132 } proc_targets[] = {
133 #define N(s) sizeof(s)-1, s
134         /*        name          type            validp */
135         { DT_DIR, N("."),       Pproc,          NULL },
136         { DT_DIR, N(".."),      Proot,          NULL },
137         { DT_REG, N("mem"),     Pmem,           NULL },
138         { DT_LNK, N("exe"),     Pexe,           NULL },
139         { DT_REG, N("stat"),    Pprocstat,      NULL },
140         { DT_REG, N("status"),  Pprocstatus,    NULL },
141 #undef N
142 };
143 static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
144
145 static pid_t atopid (const char *, u_int);
146
147 /*
148  * set things up for doing i/o on
149  * the pfsnode (vp).  (vp) is locked
150  * on entry, and should be left locked
151  * on exit.
152  *
153  * for procfs we don't need to do anything
154  * in particular for i/o.  all that is done
155  * is to support exclusive open on process
156  * memory images.
157  */
158 static int
159 linprocfs_open(struct vop_open_args *ap)
160 {
161         struct pfsnode *pfs = VTOPFS(ap->a_vp);
162         struct proc *p2;
163
164         p2 = PFIND(pfs->pfs_pid);
165         if (p2 == NULL)
166                 return (ENOENT);
167         if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred))
168                 return (ENOENT);
169
170         switch (pfs->pfs_type) {
171         case Pmem:
172                 if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
173                     ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
174                         return (EBUSY);
175
176                 if (p_trespass(ap->a_cred, p2->p_ucred))
177                         return (EPERM);
178
179                 if (ap->a_mode & FWRITE)
180                         pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
181
182                 break;
183         default:
184                 break;
185         }
186
187         return (vop_stdopen(ap));
188 }
189
190 /*
191  * close the pfsnode (vp) after doing i/o.
192  * (vp) is not locked on entry or exit.
193  *
194  * nothing to do for procfs other than undo
195  * any exclusive open flag (see _open above).
196  */
197 static int
198 linprocfs_close(struct vop_close_args *ap)
199 {
200         struct pfsnode *pfs = VTOPFS(ap->a_vp);
201         struct proc *p;
202
203         switch (pfs->pfs_type) {
204         case Pmem:
205                 if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
206                         pfs->pfs_flags &= ~(FWRITE|O_EXCL);
207                 /*
208                  * If this is the last close, then it checks to see if
209                  * the target process has PF_LINGER set in p_pfsflags,
210                  * if this is *not* the case, then the process' stop flags
211                  * are cleared, and the process is woken up.  This is
212                  * to help prevent the case where a process has been
213                  * told to stop on an event, but then the requesting process
214                  * has gone away or forgotten about it.
215                  */
216                 if ((ap->a_vp->v_usecount < 2)
217                     && (p = pfind(pfs->pfs_pid))
218                     && !(p->p_pfsflags & PF_LINGER)) {
219                         p->p_stops = 0;
220                         p->p_step = 0;
221                         wakeup(&p->p_step);
222                 }
223                 break;
224         default:
225                 break;
226         }
227         return (vop_stdclose(ap));
228 }
229
230 /*
231  * do an ioctl operation on a pfsnode (vp).
232  * (vp) is not locked on entry or exit.
233  */
234 static int
235 linprocfs_ioctl(struct vop_ioctl_args *ap)
236 {
237         struct pfsnode *pfs = VTOPFS(ap->a_vp);
238         struct proc *procp;
239         int error;
240         int signo;
241         struct procfs_status *psp;
242         unsigned char flags;
243
244         procp = pfind(pfs->pfs_pid);
245         if (procp == NULL) {
246                 return ENOTTY;
247         }
248
249         if (p_trespass(ap->a_cred, procp->p_ucred))
250                 return EPERM;
251
252         switch (ap->a_command) {
253         case PIOCBIS:
254           procp->p_stops |= *(unsigned int*)ap->a_data;
255           break;
256         case PIOCBIC:
257           procp->p_stops &= ~*(unsigned int*)ap->a_data;
258           break;
259         case PIOCSFL:
260           /*
261            * NFLAGS is "non-suser_xxx flags" -- currently, only
262            * PFS_ISUGID ("ignore set u/g id");
263            */
264 #define NFLAGS  (PF_ISUGID)
265           flags = (unsigned char)*(unsigned int*)ap->a_data;
266           if (flags & NFLAGS && (error = suser_cred(ap->a_cred, 0)))
267             return error;
268           procp->p_pfsflags = flags;
269           break;
270         case PIOCGFL:
271           *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags;
272         case PIOCSTATUS:
273           psp = (struct procfs_status *)ap->a_data;
274           psp->state = (procp->p_step == 0);
275           psp->flags = procp->p_pfsflags;
276           psp->events = procp->p_stops;
277           if (procp->p_step) {
278             psp->why = procp->p_stype;
279             psp->val = procp->p_xstat;
280           } else {
281             psp->why = psp->val = 0;    /* Not defined values */
282           }
283           break;
284         case PIOCWAIT:
285           psp = (struct procfs_status *)ap->a_data;
286           if (procp->p_step == 0) {
287             error = tsleep(&procp->p_stype, PCATCH, "piocwait", 0);
288             if (error)
289               return error;
290           }
291           psp->state = 1;       /* It stopped */
292           psp->flags = procp->p_pfsflags;
293           psp->events = procp->p_stops;
294           psp->why = procp->p_stype;    /* why it stopped */
295           psp->val = procp->p_xstat;    /* any extra info */
296           break;
297         case PIOCCONT:  /* Restart a proc */
298           if (procp->p_step == 0)
299             return EINVAL;      /* Can only start a stopped process */
300           if ((signo = *(int*)ap->a_data) != 0) {
301             if (signo >= NSIG || signo <= 0)
302               return EINVAL;
303             psignal(procp, signo);
304           }
305           procp->p_step = 0;
306           wakeup(&procp->p_step);
307           break;
308         default:
309           return (ENOTTY);
310         }
311         return 0;
312 }
313
314 /*
315  * do block mapping for pfsnode (vp).
316  * since we don't use the buffer cache
317  * for procfs this function should never
318  * be called.  in any case, it's not clear
319  * what part of the kernel ever makes use
320  * of this function.  for sanity, this is the
321  * usual no-op bmap, although returning
322  * (EIO) would be a reasonable alternative.
323  */
324 static int
325 linprocfs_bmap(struct vop_bmap_args *ap)
326 {
327         if (ap->a_vpp != NULL)
328                 *ap->a_vpp = ap->a_vp;
329         if (ap->a_doffsetp != NULL)
330                 *ap->a_doffsetp = ap->a_loffset;
331         if (ap->a_runp != NULL)
332                 *ap->a_runp = 0;
333         if (ap->a_runb != NULL)
334                 *ap->a_runb = 0;
335         return (0);
336 }
337
338 /*
339  * linprocfs_inactive is called when the pfsnode
340  * is vrele'd and the reference count is about
341  * to go to zero.  (vp) will be on the vnode free
342  * list, so to get it back vget() must be
343  * used.
344  *
345  * (vp) is locked on entry and must remain locked
346  *      on exit.
347  */
348 static int
349 linprocfs_inactive(struct vop_inactive_args *ap)
350 {
351         /*struct vnode *vp = ap->a_vp;*/
352
353         return (0);
354 }
355
356 /*
357  * _reclaim is called when getnewvnode()
358  * wants to make use of an entry on the vnode
359  * free list.  at this time the filesystem needs
360  * to free any private data and remove the node
361  * from any private lists.
362  */
363 static int
364 linprocfs_reclaim(struct vop_reclaim_args *ap)
365 {
366         return (linprocfs_freevp(ap->a_vp));
367 }
368
369 /*
370  * _print is used for debugging.
371  * just print a readable description
372  * of (vp).
373  */
374 static int
375 linprocfs_print(struct vop_print_args *ap)
376 {
377         struct pfsnode *pfs = VTOPFS(ap->a_vp);
378
379         printf("tag VT_PROCFS, type %d, pid %ld, mode %x, flags %lx\n",
380             pfs->pfs_type, (long)pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
381         return (0);
382 }
383
384 /*
385  * generic entry point for unsupported operations
386  */
387 static int
388 linprocfs_badop(struct vop_generic_args *ap __unused)
389 {
390
391         return (EIO);
392 }
393
394 /*
395  * Invent attributes for pfsnode (vp) and store
396  * them in (vap).
397  * Directories lengths are returned as zero since
398  * any real length would require the genuine size
399  * to be computed, and nothing cares anyway.
400  *
401  * this is relatively minimal for procfs.
402  */
403 static int
404 linprocfs_getattr(struct vop_getattr_args *ap)
405 {
406         struct pfsnode *pfs = VTOPFS(ap->a_vp);
407         struct vattr *vap = ap->a_vap;
408         struct proc *procp;
409         int error;
410
411         /*
412          * First make sure that the process and its credentials 
413          * still exist.
414          */
415         switch (pfs->pfs_type) {
416         case Proot:
417         case Pself:
418                 procp = 0;
419                 break;
420
421         default:
422                 procp = PFIND(pfs->pfs_pid);
423                 if (procp == 0 || procp->p_ucred == NULL)
424                         return (ENOENT);
425         }
426
427         error = 0;
428
429         /* start by zeroing out the attributes */
430         VATTR_NULL(vap);
431
432         /* next do all the common fields */
433         vap->va_type = ap->a_vp->v_type;
434         vap->va_mode = pfs->pfs_mode;
435         vap->va_fileid = pfs->pfs_fileno;
436         vap->va_flags = 0;
437         vap->va_blocksize = PAGE_SIZE;
438         vap->va_bytes = vap->va_size = 0;
439         vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
440
441         /*
442          * Make all times be current TOD.
443          * It would be possible to get the process start
444          * time from the p_stat structure, but there's
445          * no "file creation" time stamp anyway, and the
446          * p_stat structure is not addressible if u. gets
447          * swapped out for that process.
448          */
449         nanotime(&vap->va_ctime);
450         vap->va_atime = vap->va_mtime = vap->va_ctime;
451
452         /*
453          * now do the object specific fields
454          *
455          * The size could be set from struct reg, but it's hardly
456          * worth the trouble, and it puts some (potentially) machine
457          * dependent data into this machine-independent code.  If it
458          * becomes important then this function should break out into
459          * a per-file stat function in the corresponding .c file.
460          */
461
462         vap->va_nlink = 1;
463         if (procp) {
464                 vap->va_uid = procp->p_ucred->cr_uid;
465                 vap->va_gid = procp->p_ucred->cr_gid;
466         }
467
468         switch (pfs->pfs_type) {
469         case Proot:
470                 /*
471                  * Set nlink to 1 to tell fts(3) we don't actually know.
472                  */
473                 vap->va_nlink = 1;
474                 vap->va_uid = 0;
475                 vap->va_gid = 0;
476                 vap->va_size = vap->va_bytes = DEV_BSIZE;
477                 break;
478
479         case Pself: {
480                 char buf[16];           /* should be enough */
481                 vap->va_uid = 0;
482                 vap->va_gid = 0;
483                 vap->va_size = vap->va_bytes =
484                     snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
485                 break;
486         }
487
488         case Pproc:
489                 vap->va_nlink = nproc_targets;
490                 vap->va_size = vap->va_bytes = DEV_BSIZE;
491                 break;
492
493         case Pexe: {
494                 char *fullpath, *freepath;
495                 error = vn_fullpath(procp, NULL, &fullpath, &freepath);
496                 if (error == 0) {
497                         vap->va_size = strlen(fullpath);
498                         free(freepath, M_TEMP);
499                 } else {
500                         vap->va_size = sizeof("unknown") - 1;
501                         error = 0;
502                 }
503                 vap->va_bytes = vap->va_size;
504                 break;
505         }
506
507         case Pmeminfo:
508         case Pcpuinfo:
509         case Pstat:
510         case Puptime:
511         case Pversion:
512         case Ploadavg:
513                 vap->va_bytes = vap->va_size = 0;
514                 vap->va_uid = 0;
515                 vap->va_gid = 0;
516                 break;
517                 
518         case Pmem:
519                 /*
520                  * If we denied owner access earlier, then we have to
521                  * change the owner to root - otherwise 'ps' and friends
522                  * will break even though they are setgid kmem. *SIGH*
523                  */
524                 if (procp->p_flag & P_SUGID)
525                         vap->va_uid = 0;
526                 else
527                         vap->va_uid = procp->p_ucred->cr_uid;
528                 break;
529
530         case Pprocstat:
531         case Pprocstatus:
532                 vap->va_bytes = vap->va_size = 0;
533                 /* uid, gid are already set */
534                 break;
535
536         default:
537                 panic("linprocfs_getattr");
538         }
539
540         return (error);
541 }
542
543 static int
544 linprocfs_setattr(struct vop_setattr_args *ap)
545 {
546
547         if (ap->a_vap->va_flags != VNOVAL)
548                 return (EOPNOTSUPP);
549
550         /*
551          * just fake out attribute setting
552          * it's not good to generate an error
553          * return, otherwise things like creat()
554          * will fail when they try to set the
555          * file length to 0.  worse, this means
556          * that echo $note > /proc/$pid/note will fail.
557          */
558
559         return (0);
560 }
561
562 /*
563  * implement access checking.
564  *
565  * something very similar to this code is duplicated
566  * throughout the 4bsd kernel and should be moved
567  * into kern/vfs_subr.c sometime.
568  *
569  * actually, the check for super-user is slightly
570  * broken since it will allow read access to write-only
571  * objects.  this doesn't cause any particular trouble
572  * but does mean that the i/o entry points need to check
573  * that the operation really does make sense.
574  */
575 static int
576 linprocfs_access(struct vop_access_args *ap)
577 {
578         struct vattr *vap;
579         struct vattr vattr;
580         int error;
581
582         /*
583          * If you're the super-user,
584          * you always get access.
585          */
586         if (ap->a_cred->cr_uid == 0)
587                 return (0);
588
589         vap = &vattr;
590         error = VOP_GETATTR(ap->a_vp, vap);
591         if (error)
592                 return (error);
593
594         /*
595          * Access check is based on only one of owner, group, public.
596          * If not owner, then check group. If not a member of the
597          * group, then check public access.
598          */
599         if (ap->a_cred->cr_uid != vap->va_uid) {
600                 gid_t *gp;
601                 int i;
602
603                 ap->a_mode >>= 3;
604                 gp = ap->a_cred->cr_groups;
605                 for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
606                         if (vap->va_gid == *gp)
607                                 goto found;
608                 ap->a_mode >>= 3;
609 found:
610                 ;
611         }
612
613         if ((vap->va_mode & ap->a_mode) == ap->a_mode)
614                 return (0);
615
616         return (EACCES);
617 }
618
619 /*
620  * lookup.  this is incredibly complicated in the general case, however
621  * for most pseudo-filesystems very little needs to be done.
622  */
623 static int
624 linprocfs_lookup(struct vop_old_lookup_args *ap)
625 {
626         struct componentname *cnp = ap->a_cnp;
627         struct vnode **vpp = ap->a_vpp;
628         struct vnode *dvp = ap->a_dvp;
629         char *pname = cnp->cn_nameptr;
630         struct proc_target *pt;
631         pid_t pid;
632         struct pfsnode *pfs;
633         struct proc *p;
634         int i;
635         int error;
636
637         *vpp = NULL;
638
639         if (cnp->cn_nameiop == NAMEI_DELETE || 
640             cnp->cn_nameiop == NAMEI_RENAME ||
641             cnp->cn_nameiop == NAMEI_CREATE) {
642                 return (EROFS);
643         }
644
645         error = 0;
646
647         if (cnp->cn_namelen == 1 && *pname == '.') {
648                 *vpp = dvp;
649                 vref(*vpp);
650                 goto out;
651         }
652
653         pfs = VTOPFS(dvp);
654         switch (pfs->pfs_type) {
655         case Proot:
656                 if (cnp->cn_flags & CNP_ISDOTDOT)
657                         return (EIO);
658
659                 if (CNEQ(cnp, "self", 4)) {
660                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pself);
661                         goto out;
662                 }
663                 if (CNEQ(cnp, "meminfo", 7)) {
664                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmeminfo);
665                         goto out;
666                 }
667                 if (CNEQ(cnp, "cpuinfo", 7)) {
668                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pcpuinfo);
669                         goto out;
670                 }
671                 if (CNEQ(cnp, "stat", 4)) {
672                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pstat);
673                         goto out;
674                 }
675                 if (CNEQ(cnp, "uptime", 6)) {
676                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Puptime);
677                         goto out;
678                 }
679                 if (CNEQ(cnp, "version", 7)) {
680                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion);
681                         goto out;
682                 }
683                 if (CNEQ(cnp, "loadavg", 7)) {
684                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Ploadavg);
685                         goto out;
686                 }
687
688                 pid = atopid(pname, cnp->cn_namelen);
689                 if (pid == NO_PID)
690                         break;
691
692                 p = PFIND(pid);
693                 if (p == 0)
694                         break;
695
696                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
697                         break;
698
699                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
700                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
701                         break;
702
703                 error = linprocfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
704                 goto out;
705
706         case Pproc:
707                 if (cnp->cn_flags & CNP_ISDOTDOT) {
708                         error = linprocfs_root(dvp->v_mount, vpp);
709                         goto out;
710                 }
711
712                 p = PFIND(pfs->pfs_pid);
713                 if (p == 0)
714                         break;
715
716                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
717                         break;
718
719                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
720                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
721                         break;
722
723                 for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
724                         if (cnp->cn_namelen == pt->pt_namlen &&
725                             bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
726                             (pt->pt_valid == NULL || (*pt->pt_valid)(p)))
727                                 goto found;
728                 }
729                 break;
730
731         found:
732                 error = linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
733                                         pt->pt_pfstype);
734                 goto out;
735
736         default:
737                 error = ENOTDIR;
738                 goto out;
739         }
740
741         if (cnp->cn_nameiop == NAMEI_LOOKUP)
742                 error = ENOENT;
743         else
744                 error = EROFS;
745
746         /*
747          * If no error occured *vpp will hold a referenced locked vnode.
748          * dvp was passed to us locked and *vpp must be returned locked
749          * so if dvp != *vpp and CNP_LOCKPARENT is not set, unlock dvp.
750          */
751 out:
752         if (error == 0) {
753                 if (*vpp != dvp && (cnp->cn_flags & CNP_LOCKPARENT) == 0) {
754                         cnp->cn_flags |= CNP_PDIRUNLOCK;
755                         vn_unlock(dvp);
756                 }
757         }
758         return (error);
759 }
760
761 /*
762  * Does this process have a text file?
763  */
764 int
765 linprocfs_validfile(struct proc *p)
766 {
767
768         return (procfs_findtextvp(p) != NULLVP);
769 }
770
771 /*
772  * readdir() returns directory entries from pfsnode (vp).
773  *
774  * We generate just one directory entry at a time, as it would probably
775  * not pay off to buffer several entries locally to save uiomove calls.
776  *
777  * linprocfs_readdir(struct vnode *a_vp, struct uio *a_uio,
778  *                   struct ucred *a_cred, int *a_eofflag,
779  *                   int *a_ncookies, u_long **a_cookies)
780  */
781 static int
782 linprocfs_readdir(struct vop_readdir_args *ap)
783 {
784         struct pfsnode *pfs;
785         int error;
786
787         if (ap->a_uio->uio_offset < 0 || ap->a_uio->uio_offset > INT_MAX)
788                 return (EINVAL);
789
790         pfs = VTOPFS(ap->a_vp);
791         if ((error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
792                 return (error);
793
794         switch (pfs->pfs_type) {
795         case Pproc:
796                 /*
797                  * This is for the process-specific sub-directories.
798                  * all that is needed to is copy out all the entries
799                  * from the procent[] table (top of this file).
800                  */
801                 error = linprocfs_readdir_proc(ap);
802                 break;
803         case Proot:
804                 /*
805                  * This is for the root of the procfs filesystem
806                  * what is needed is a special entry for "self"
807                  * followed by an entry for each process on allproc
808                  */
809                 error = linprocfs_readdir_root(ap);
810                 break;
811         default:
812                 error = ENOTDIR;
813                 break;
814         }
815         vn_unlock(ap->a_vp);
816
817         return (error);
818 }
819
820 static int
821 linprocfs_readdir_proc(struct vop_readdir_args *ap)
822 {
823         struct pfsnode *pfs;
824         int error, i, retval;
825         struct proc *p;
826         struct proc_target *pt;
827         struct uio *uio = ap->a_uio;
828
829         pfs = VTOPFS(ap->a_vp);
830         p = PFIND(pfs->pfs_pid);
831         if (p == NULL)
832                 return(0);
833         if (!PRISON_CHECK(ap->a_cred, p->p_ucred))
834                 return(0);
835
836         error = 0;
837         i = uio->uio_offset;
838
839         for (pt = &proc_targets[i];
840              !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) {
841                 if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
842                         continue;
843
844                 retval = vop_write_dirent(&error, uio,
845                     PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype), pt->pt_type,
846                     pt->pt_namlen, pt->pt_name);
847                 if (retval)
848                         break;
849         }
850
851         uio->uio_offset = i;
852
853         return(error);
854 }
855
856 struct linprocfs_readdir_root_info {
857         int error;
858         int pcnt;
859         int i;
860         struct uio *uio;
861         struct ucred *cred;
862 };
863
864 /*
865  * Scan the root directory by scanning all process
866  */
867 static int linprocfs_readdir_root_callback(struct proc *p, void *data);
868
869 static int
870 linprocfs_readdir_root(struct vop_readdir_args *ap)
871 {
872         struct linprocfs_readdir_root_info info;
873         struct uio *uio = ap->a_uio;
874         int res;
875
876         info.error = 0;
877         info.i = uio->uio_offset;
878         info.pcnt = 0;
879         info.uio = uio;
880         info.cred = ap->a_cred;
881
882         while (info.pcnt < 9) {
883                 res = linprocfs_readdir_root_callback(NULL, &info);
884                 if (res < 0)
885                         break;
886         }
887         if (res >= 0)
888                 allproc_scan(linprocfs_readdir_root_callback, &info);
889
890         uio->uio_offset = info.i;
891         return(info.error);
892 }
893
894 static int
895 linprocfs_readdir_root_callback(struct proc *p, void *data)
896 {
897         struct linprocfs_readdir_root_info *info = data;
898         int retval;
899         struct uio *uio = info->uio;
900         ino_t d_ino;
901         const char *d_name;
902         char d_name_pid[20];
903         size_t d_namlen;
904         uint8_t d_type;
905
906         switch (info->pcnt) {
907         case 0:         /* `.' */
908                 d_ino = PROCFS_FILENO(0, Proot);
909                 d_name = ".";
910                 d_namlen = 1;
911                 d_type = DT_DIR;
912                 break;
913         case 1:         /* `..' */
914                 d_ino = PROCFS_FILENO(0, Proot);
915                 d_name = "..";
916                 d_namlen = 2;
917                 d_type = DT_DIR;
918                 break;
919
920         case 2:
921                 d_ino = PROCFS_FILENO(0, Proot);
922                 d_namlen = 4;
923                 d_name = "self";
924                 d_type = DT_LNK;
925                 break;
926
927         case 3:
928                 d_ino = PROCFS_FILENO(0, Pmeminfo);
929                 d_namlen = 7;
930                 d_name = "meminfo";
931                 d_type = DT_REG;
932                 break;
933
934         case 4:
935                 d_ino = PROCFS_FILENO(0, Pcpuinfo);
936                 d_namlen = 7;
937                 d_name = "cpuinfo";
938                 d_type = DT_REG;
939                 break;
940
941         case 5:
942                 d_ino = PROCFS_FILENO(0, Pstat);
943                 d_namlen = 4;
944                 d_name = "stat";
945                 d_type = DT_REG;
946                 break;
947                     
948         case 6:
949                 d_ino = PROCFS_FILENO(0, Puptime);
950                 d_namlen = 6;
951                 d_name = "uptime";
952                 d_type = DT_REG;
953                 break;
954
955         case 7:
956                 d_ino = PROCFS_FILENO(0, Pversion);
957                 d_namlen = 7;
958                 d_name = "version";
959                 d_type = DT_REG;
960                 break;
961
962         case 8:
963                 d_ino = PROCFS_FILENO(0, Ploadavg);
964                 d_namlen = 7;
965                 d_name = "loadavg";
966                 d_type = DT_REG;
967                 break;
968
969         default:
970                 /*
971                  * Ignore processes that aren't in our prison
972                  */
973                 if (PRISON_CHECK(info->cred, p->p_ucred) == 0)
974                         return(0);
975
976                 /*
977                  * Ignore processes that we do not want to be visible.
978                  */
979                 if (ps_showallprocs == 0 && 
980                     info->cred->cr_uid != 0 &&
981                     info->cred->cr_uid != p->p_ucred->cr_uid) {
982                         return(0);
983                 }
984
985                 /*
986                  * Skip processes we have already read (optimization)
987                  */
988                 if (info->pcnt < info->i) {
989                         ++info->pcnt;
990                         return(0);
991                 }
992                 d_ino = PROCFS_FILENO(p->p_pid, Pproc);
993                 d_namlen = snprintf(d_name_pid, sizeof(d_name_pid),
994                     "%ld", (long)p->p_pid);
995                 d_name = d_name_pid;
996                 d_type = DT_DIR;
997                 break;
998         }
999
1000         /*
1001          * Skip processes we have already read
1002          */
1003         if (info->pcnt < info->i) {
1004                 ++info->pcnt;
1005                 return(0);
1006         }
1007         retval = vop_write_dirent(&info->error, info->uio, 
1008                                   d_ino, d_type, d_namlen, d_name);
1009         if (retval == 0) {
1010                 ++info->pcnt;   /* iterate proc candidates scanned */
1011                 ++info->i;      /* iterate entries written */
1012         }
1013         if (retval || info->error || uio->uio_resid <= 0)
1014                 return(-1);
1015         return(0);
1016 }
1017
1018 /*
1019  * readlink reads the link of `self' or `exe'
1020  */
1021 static int
1022 linprocfs_readlink(struct vop_readlink_args *ap)
1023 {
1024         char buf[16];           /* should be enough */
1025         struct proc *procp;
1026         struct vnode *vp = ap->a_vp;
1027         struct pfsnode *pfs = VTOPFS(vp);
1028         char *fullpath, *freepath;
1029         int error, len;
1030
1031         switch (pfs->pfs_type) {
1032         case Pself:
1033                 if (pfs->pfs_fileno != PROCFS_FILENO(0, Pself))
1034                         return (EINVAL);
1035
1036                 len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
1037
1038                 return (uiomove(buf, len, ap->a_uio));
1039         /*
1040          * There _should_ be no way for an entire process to disappear
1041          * from under us...
1042          */
1043         case Pexe:
1044                 procp = PFIND(pfs->pfs_pid);
1045                 if (procp == NULL || procp->p_ucred == NULL) {
1046                         printf("linprocfs_readlink: pid %d disappeared\n",
1047                             pfs->pfs_pid);
1048                         return (uiomove("unknown", sizeof("unknown") - 1,
1049                             ap->a_uio));
1050                 }
1051                 error = vn_fullpath(procp, NULL, &fullpath, &freepath);
1052                 if (error != 0)
1053                         return (uiomove("unknown", sizeof("unknown") - 1,
1054                             ap->a_uio));
1055                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1056                 free(freepath, M_TEMP);
1057                 return (error);
1058         default:
1059                 return (EINVAL);
1060         }
1061 }
1062
1063 /*
1064  * convert decimal ascii to pid_t
1065  */
1066 static pid_t
1067 atopid(const char *b, u_int len)
1068 {
1069         pid_t p = 0;
1070
1071         while (len--) {
1072                 char c = *b++;
1073                 if (c < '0' || c > '9')
1074                         return (NO_PID);
1075                 p = 10 * p + (c - '0');
1076                 if (p > PID_MAX)
1077                         return (NO_PID);
1078         }
1079
1080         return (p);
1081 }
1082