kernel/linprocfs: Fix accessing files in /proc (such as /proc/meminfo).
[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  */
43
44 /*
45  * procfs vnode interface
46  */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/time.h>
51 #include <sys/kernel.h>
52 #include <sys/lock.h>
53 #include <sys/fcntl.h>
54 #include <sys/proc.h>
55 #include <sys/priv.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 <sys/reg.h>
63 #include <sys/jail.h>
64 #include <vm/vm_zone.h>
65 #include "linprocfs.h"
66 #include <sys/pioctl.h>
67
68 #include <machine/limits.h>
69
70 extern struct vnode *procfs_findtextvp (struct proc *);
71
72 static int      linprocfs_access (struct vop_access_args *);
73 static int      linprocfs_badop (struct vop_generic_args *);
74 static int      linprocfs_bmap (struct vop_bmap_args *);
75 static int      linprocfs_close (struct vop_close_args *);
76 static int      linprocfs_getattr (struct vop_getattr_args *);
77 static int      linprocfs_inactive (struct vop_inactive_args *);
78 static int      linprocfs_ioctl (struct vop_ioctl_args *);
79 static int      linprocfs_lookup (struct vop_old_lookup_args *);
80 static int      linprocfs_open (struct vop_open_args *);
81 static int      linprocfs_print (struct vop_print_args *);
82 static int      linprocfs_readdir (struct vop_readdir_args *);
83 static int      linprocfs_readlink (struct vop_readlink_args *);
84 static int      linprocfs_reclaim (struct vop_reclaim_args *);
85 static int      linprocfs_setattr (struct vop_setattr_args *);
86
87 static int      linprocfs_readdir_proc(struct vop_readdir_args *);
88 static int      linprocfs_readdir_root(struct vop_readdir_args *);
89 static int      linprocfs_readdir_net(struct vop_readdir_args *ap);
90 static int      linprocfs_readdir_sys(struct vop_readdir_args *ap);
91 static int      linprocfs_readdir_syskernel(struct vop_readdir_args *ap);
92
93 /*
94  * procfs vnode operations.
95  */
96 struct vop_ops linprocfs_vnode_vops = {
97         .vop_default =          vop_defaultop,
98         .vop_access =           linprocfs_access,
99         .vop_advlock =          (void *)linprocfs_badop,
100         .vop_bmap =             linprocfs_bmap,
101         .vop_close =            linprocfs_close,
102         .vop_old_create =       (void *)linprocfs_badop,
103         .vop_getattr =          linprocfs_getattr,
104         .vop_inactive =         linprocfs_inactive,
105         .vop_old_link =         (void *)linprocfs_badop,
106         .vop_old_lookup =       linprocfs_lookup,
107         .vop_old_mkdir =        (void *)linprocfs_badop,
108         .vop_old_mknod =        (void *)linprocfs_badop,
109         .vop_open =             linprocfs_open,
110         .vop_pathconf =         vop_stdpathconf,
111         .vop_print =            linprocfs_print,
112         .vop_read =             (void *)linprocfs_rw,
113         .vop_readdir =          linprocfs_readdir,
114         .vop_readlink =         linprocfs_readlink,
115         .vop_reclaim =          linprocfs_reclaim,
116         .vop_old_remove =       (void *)linprocfs_badop,
117         .vop_old_rename =       (void *)linprocfs_badop,
118         .vop_old_rmdir =        (void *)linprocfs_badop,
119         .vop_setattr =          linprocfs_setattr,
120         .vop_old_symlink =      (void *)linprocfs_badop,
121         .vop_write =            (void *)linprocfs_rw,
122         .vop_ioctl =            linprocfs_ioctl
123 };
124
125 /*
126  * This is a list of the valid names in the
127  * process-specific sub-directories.  It is
128  * used in linprocfs_lookup and linprocfs_readdir
129  */
130 static struct proc_target {
131         u_char  pt_type;
132         u_char  pt_namlen;
133         char    *pt_name;
134         pfstype pt_pfstype;
135         int     (*pt_valid) (struct proc *p);
136 } proc_targets[] = {
137 #define N(s) sizeof(s)-1, s
138         /*        name          type            validp */
139         { DT_DIR, N("."),       Pproc,          NULL },
140         { DT_DIR, N(".."),      Proot,          NULL },
141         { DT_REG, N("mem"),     Pmem,           NULL },
142
143         { DT_LNK, N("exe"),     Pexe,           NULL },
144         { DT_LNK, N("cwd"),     Pcwd,           NULL },
145         { DT_LNK, N("root"),    Pprocroot,      NULL },
146         { DT_LNK, N("fd"),      Pfd,            NULL },
147
148         { DT_REG, N("stat"),    Pprocstat,      NULL },
149         { DT_REG, N("status"),  Pprocstatus,    NULL },
150         { DT_REG, N("maps"),    Pmaps,          NULL },
151         { DT_REG, N("statm"),   Pstatm,         NULL },
152 #if 0
153         { DT_REG, N("cmdline"), Pcmdline,       NULL },
154         { DT_REG, N("environ"), Penviron,       NULL },
155 #endif
156 #undef N
157 };
158 static const int nproc_targets = NELEM(proc_targets);
159
160 static pid_t atopid (const char *, u_int);
161
162 /*
163  * set things up for doing i/o on
164  * the pfsnode (vp).  (vp) is locked
165  * on entry, and should be left locked
166  * on exit.
167  *
168  * for procfs we don't need to do anything
169  * in particular for i/o.  all that is done
170  * is to support exclusive open on process
171  * memory images.
172  */
173 static int
174 linprocfs_open(struct vop_open_args *ap)
175 {
176         struct pfsnode *pfs = VTOPFS(ap->a_vp);
177         struct proc *p2;
178
179         p2 = linprocfs_pfind(pfs->pfs_pid);
180         if (p2 == NULL)
181                 return (ENOENT);
182         if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred))
183                 return (ENOENT);
184
185         switch (pfs->pfs_type) {
186         case Pmem:
187                 if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
188                     ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
189                         return (EBUSY);
190
191                 if (p_trespass(ap->a_cred, p2->p_ucred))
192                         return (EPERM);
193
194                 if (ap->a_mode & FWRITE)
195                         pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
196
197                 break;
198         default:
199                 break;
200         }
201
202         return (vop_stdopen(ap));
203 }
204
205 /*
206  * close the pfsnode (vp) after doing i/o.
207  * (vp) is not locked on entry or exit.
208  *
209  * nothing to do for procfs other than undo
210  * any exclusive open flag (see _open above).
211  */
212 static int
213 linprocfs_close(struct vop_close_args *ap)
214 {
215         struct pfsnode *pfs = VTOPFS(ap->a_vp);
216         struct proc *p;
217
218         switch (pfs->pfs_type) {
219         case Pmem:
220                 if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
221                         pfs->pfs_flags &= ~(FWRITE|O_EXCL);
222                 /*
223                  * If this is the last close, then it checks to see if
224                  * the target process has PF_LINGER set in p_pfsflags,
225                  * if this is *not* the case, then the process' stop flags
226                  * are cleared, and the process is woken up.  This is
227                  * to help prevent the case where a process has been
228                  * told to stop on an event, but then the requesting process
229                  * has gone away or forgotten about it.
230                  */
231                 p = NULL;
232                 if ((ap->a_vp->v_opencount < 2)
233                     && (p = linprocfs_pfind(pfs->pfs_pid))
234                     && !(p->p_pfsflags & PF_LINGER)) {
235                         p->p_stops = 0;
236                         p->p_step = 0;
237                         wakeup(&p->p_stype);
238                 }
239                 if (p)
240                         PRELE(p);
241                 break;
242         default:
243                 break;
244         }
245         return (vop_stdclose(ap));
246 }
247
248 /*
249  * do an ioctl operation on a pfsnode (vp).
250  * (vp) is not locked on entry or exit.
251  */
252 static int
253 linprocfs_ioctl(struct vop_ioctl_args *ap)
254 {
255         struct pfsnode *pfs = VTOPFS(ap->a_vp);
256         struct proc *procp;
257         int error;
258         int signo;
259         struct procfs_status *psp;
260         unsigned char flags;
261
262         procp = linprocfs_pfind(pfs->pfs_pid);
263         if (procp == NULL) {
264                 return ENOTTY;
265         }
266
267         if (p_trespass(ap->a_cred, procp->p_ucred)) {
268                 error = EPERM;
269                 goto done;
270         }
271
272         switch (ap->a_command) {
273         case PIOCBIS:
274           procp->p_stops |= *(unsigned int*)ap->a_data;
275           break;
276         case PIOCBIC:
277           procp->p_stops &= ~*(unsigned int*)ap->a_data;
278           break;
279         case PIOCSFL:
280           /*
281            * NFLAGS is "non-suser_xxx flags" -- currently, only
282            * PFS_ISUGID ("ignore set u/g id");
283            */
284 #define NFLAGS  (PF_ISUGID)
285           flags = (unsigned char)*(unsigned int*)ap->a_data;
286           if (flags & NFLAGS && (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)))
287             goto done;
288           procp->p_pfsflags = flags;
289           break;
290         case PIOCGFL:
291           *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags;
292         case PIOCSTATUS:
293           psp = (struct procfs_status *)ap->a_data;
294           psp->state = (procp->p_step == 0);
295           psp->flags = procp->p_pfsflags;
296           psp->events = procp->p_stops;
297           if (procp->p_step) {
298             psp->why = procp->p_stype;
299             psp->val = procp->p_xstat;
300           } else {
301             psp->why = psp->val = 0;    /* Not defined values */
302           }
303           break;
304         case PIOCWAIT:
305           psp = (struct procfs_status *)ap->a_data;
306           spin_lock(&procp->p_spin);
307           if (procp->p_step == 0) {
308             spin_unlock(&procp->p_spin);
309             tsleep_interlock(&procp->p_stype, PCATCH);
310             if (procp->p_stops == 0) {
311                 error = EINVAL;
312                 goto done;
313             }
314             if (procp->p_flags & P_POSTEXIT) {
315                 error = EINVAL;
316                 goto done;
317             }
318             if (procp->p_flags & P_INEXEC) {
319                 error = EAGAIN;
320                 goto done;
321             }
322             error = tsleep(&procp->p_stype, PCATCH | PINTERLOCKED,
323                            "piocwait", 0);
324             if (error)
325               goto done;
326           } else {
327             spin_unlock(&procp->p_spin);
328           }
329           psp->state = 1;       /* It stopped */
330           psp->flags = procp->p_pfsflags;
331           psp->events = procp->p_stops;
332           psp->why = procp->p_stype;    /* why it stopped */
333           psp->val = procp->p_xstat;    /* any extra info */
334           break;
335         case PIOCCONT:  /* Restart a proc */
336           if (procp->p_step == 0) {
337             error = EINVAL;     /* Can only start a stopped process */
338             goto done;
339           }
340           if ((signo = *(int*)ap->a_data) != 0) {
341             if (signo >= NSIG || signo <= 0) {
342               error = EINVAL;
343               goto done;
344             }
345             ksignal(procp, signo);
346           }
347           procp->p_step = 0;
348           wakeup(&procp->p_step);
349           break;
350         default:
351           error = ENOTTY;
352           goto done;
353         }
354         error = 0;
355 done:
356         if (procp)
357                 PRELE(procp);
358         return error;
359 }
360
361 /*
362  * do block mapping for pfsnode (vp).
363  * since we don't use the buffer cache
364  * for procfs this function should never
365  * be called.  in any case, it's not clear
366  * what part of the kernel ever makes use
367  * of this function.  for sanity, this is the
368  * usual no-op bmap, although returning
369  * (EIO) would be a reasonable alternative.
370  */
371 static int
372 linprocfs_bmap(struct vop_bmap_args *ap)
373 {
374         if (ap->a_doffsetp != NULL)
375                 *ap->a_doffsetp = ap->a_loffset;
376         if (ap->a_runp != NULL)
377                 *ap->a_runp = 0;
378         if (ap->a_runb != NULL)
379                 *ap->a_runb = 0;
380         return (0);
381 }
382
383 /*
384  * linprocfs_inactive is called when the pfsnode
385  * is vrele'd and the reference count is about
386  * to go to zero.  (vp) will be on the vnode free
387  * list, so to get it back vget() must be
388  * used.
389  *
390  * (vp) is locked on entry and must remain locked
391  *      on exit.
392  */
393 static int
394 linprocfs_inactive(struct vop_inactive_args *ap)
395 {
396         /*struct vnode *vp = ap->a_vp;*/
397
398         return (0);
399 }
400
401 /*
402  * _reclaim is called when getnewvnode()
403  * wants to make use of an entry on the vnode
404  * free list.  at this time the filesystem needs
405  * to free any private data and remove the node
406  * from any private lists.
407  */
408 static int
409 linprocfs_reclaim(struct vop_reclaim_args *ap)
410 {
411         return (linprocfs_freevp(ap->a_vp));
412 }
413
414 /*
415  * _print is used for debugging.
416  * just print a readable description
417  * of (vp).
418  */
419 static int
420 linprocfs_print(struct vop_print_args *ap)
421 {
422         struct pfsnode *pfs = VTOPFS(ap->a_vp);
423
424         kprintf("tag VT_PROCFS, type %d, pid %ld, mode %x, flags %lx\n",
425             pfs->pfs_type, (long)pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
426         return (0);
427 }
428
429 /*
430  * generic entry point for unsupported operations
431  */
432 static int
433 linprocfs_badop(struct vop_generic_args *ap __unused)
434 {
435
436         return (EIO);
437 }
438
439 /*
440  * Invent attributes for pfsnode (vp) and store
441  * them in (vap).
442  * Directories lengths are returned as zero since
443  * any real length would require the genuine size
444  * to be computed, and nothing cares anyway.
445  *
446  * this is relatively minimal for procfs.
447  */
448 static int
449 linprocfs_getattr(struct vop_getattr_args *ap)
450 {
451         struct pfsnode *pfs = VTOPFS(ap->a_vp);
452         struct vattr *vap = ap->a_vap;
453         struct proc *procp;
454         int error;
455
456         /*
457          * First make sure that the process and its credentials 
458          * still exist.
459          */
460         switch (pfs->pfs_type) {
461         case Proot:
462         case Pself:
463                 procp = NULL;
464                 break;
465
466         default:
467                 procp = linprocfs_pfind(pfs->pfs_pid);
468                 if (procp == NULL || procp->p_ucred == NULL)
469                         return (ENOENT);
470         }
471
472         error = 0;
473
474         /* start by zeroing out the attributes */
475         VATTR_NULL(vap);
476
477         /* next do all the common fields */
478         vap->va_type = ap->a_vp->v_type;
479         vap->va_mode = pfs->pfs_mode;
480         vap->va_fileid = pfs->pfs_fileno;
481         vap->va_flags = 0;
482         vap->va_blocksize = PAGE_SIZE;
483         vap->va_bytes = vap->va_size = 0;
484         vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
485
486         /*
487          * Make all times be current TOD.
488          * It would be possible to get the process start
489          * time from the p_stat structure, but there's
490          * no "file creation" time stamp anyway, and the
491          * p_stat structure is not addressible if u. gets
492          * swapped out for that process.
493          */
494         nanotime(&vap->va_ctime);
495         vap->va_atime = vap->va_mtime = vap->va_ctime;
496
497         /*
498          * now do the object specific fields
499          *
500          * The size could be set from struct reg, but it's hardly
501          * worth the trouble, and it puts some (potentially) machine
502          * dependent data into this machine-independent code.  If it
503          * becomes important then this function should break out into
504          * a per-file stat function in the corresponding .c file.
505          */
506
507         vap->va_nlink = 1;
508         if (procp) {
509                 vap->va_uid = procp->p_ucred->cr_uid;
510                 vap->va_gid = procp->p_ucred->cr_gid;
511         }
512
513         switch (pfs->pfs_type) {
514         case Proot:
515         case Pnet:
516         case Psys:
517         case Psyskernel:
518                 /*
519                  * Set nlink to 1 to tell fts(3) we don't actually know.
520                  */
521                 vap->va_nlink = 1;
522                 vap->va_uid = 0;
523                 vap->va_gid = 0;
524                 vap->va_size = vap->va_bytes = DEV_BSIZE;
525                 break;
526
527         case Pself: {
528                 char buf[16];           /* should be enough */
529                 vap->va_uid = 0;
530                 vap->va_gid = 0;
531                 vap->va_size = vap->va_bytes =
532                     ksnprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
533                 break;
534         }
535
536         case Pproc:
537                 vap->va_nlink = nproc_targets;
538                 vap->va_size = vap->va_bytes = DEV_BSIZE;
539                 break;
540
541         case Pexe: {
542                 char *fullpath, *freepath;
543                 error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0);
544                 /* error = vn_fullpath(procp, NULL, &fullpath, &freepath); */
545                 if (error == 0) {
546                         vap->va_size = strlen(fullpath);
547                         kfree(freepath, M_TEMP);
548                 } else {
549                         vap->va_size = sizeof("unknown") - 1;
550                         error = 0;
551                 }
552                 vap->va_bytes = vap->va_size;
553                 break;
554         }
555         case Pcwd: {
556                 char *fullpath, *freepath;
557                 error = cache_fullpath(procp, &procp->p_fd->fd_ncdir, &fullpath, &freepath, 0);
558                 if (error == 0) {
559                         vap->va_size = strlen(fullpath);
560                         kfree(freepath, M_TEMP);
561                 } else {
562                         vap->va_size = sizeof("unknown") - 1;
563                         error = 0;
564                 }
565                 vap->va_bytes = vap->va_size;
566                 break;
567         }
568         case Pprocroot: {
569                 struct nchandle *nchp;
570                 char *fullpath, *freepath;
571                 nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
572                 error = cache_fullpath(procp, nchp, &fullpath, &freepath, 0);
573                 if (error == 0) {
574                         vap->va_size = strlen(fullpath);
575                         kfree(freepath, M_TEMP);
576                 } else {
577                         vap->va_size = sizeof("unknown") - 1;
578                         error = 0;
579                 }
580                 vap->va_bytes = vap->va_size;
581                 break;
582         }
583         case Pfd: {
584                 if (procp == curproc) {
585                         vap->va_size = sizeof("/dev/fd") - 1;
586                         error = 0;      
587                 } else {
588                         vap->va_size = sizeof("unknown") - 1;
589                         error = 0;
590                 }
591                 vap->va_bytes = vap->va_size;
592                 break;
593         }
594
595         case Pmeminfo:
596         case Pcpuinfo:
597         case Pmounts:
598         case Pstat:
599         case Puptime:
600         case Pversion:
601         case Ploadavg:
602         case Pnetdev:
603         case Pdevices:
604         case Posrelease:
605         case Postype:
606         case Ppidmax:
607                 vap->va_bytes = vap->va_size = 0;
608                 vap->va_uid = 0;
609                 vap->va_gid = 0;
610                 break;
611                 
612         case Pmem:
613                 /*
614                  * If we denied owner access earlier, then we have to
615                  * change the owner to root - otherwise 'ps' and friends
616                  * will break even though they are setgid kmem. *SIGH*
617                  */
618                 if (procp->p_flags & P_SUGID)
619                         vap->va_uid = 0;
620                 else
621                         vap->va_uid = procp->p_ucred->cr_uid;
622                 break;
623
624         case Pprocstat:
625         case Pprocstatus:
626         case Pcmdline:
627         case Penviron:
628         case Pmaps:
629         case Pstatm:
630                 vap->va_bytes = vap->va_size = 0;
631                 /* uid, gid are already set */
632                 break;
633
634         default:
635                 panic("linprocfs_getattr");
636         }
637
638         return (error);
639 }
640
641 static int
642 linprocfs_setattr(struct vop_setattr_args *ap)
643 {
644
645         if (ap->a_vap->va_flags != VNOVAL)
646                 return (EOPNOTSUPP);
647
648         /*
649          * just fake out attribute setting
650          * it's not good to generate an error
651          * return, otherwise things like creat()
652          * will fail when they try to set the
653          * file length to 0.  worse, this means
654          * that echo $note > /proc/$pid/note will fail.
655          */
656
657         return (0);
658 }
659
660 /*
661  * implement access checking.
662  *
663  * something very similar to this code is duplicated
664  * throughout the 4bsd kernel and should be moved
665  * into kern/vfs_subr.c sometime.
666  *
667  * actually, the check for super-user is slightly
668  * broken since it will allow read access to write-only
669  * objects.  this doesn't cause any particular trouble
670  * but does mean that the i/o entry points need to check
671  * that the operation really does make sense.
672  */
673 static int
674 linprocfs_access(struct vop_access_args *ap)
675 {
676         struct vattr *vap;
677         struct vattr vattr;
678         int error;
679
680         /*
681          * If you're the super-user,
682          * you always get access.
683          */
684         if (ap->a_cred->cr_uid == 0)
685                 return (0);
686
687         vap = &vattr;
688         error = VOP_GETATTR(ap->a_vp, vap);
689         if (error)
690                 return (error);
691
692         /*
693          * Access check is based on only one of owner, group, public.
694          * If not owner, then check group. If not a member of the
695          * group, then check public access.
696          */
697         if (ap->a_cred->cr_uid != vap->va_uid) {
698                 gid_t *gp;
699                 int i;
700
701                 ap->a_mode >>= 3;
702                 gp = ap->a_cred->cr_groups;
703                 for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
704                         if (vap->va_gid == *gp)
705                                 goto found;
706                 ap->a_mode >>= 3;
707 found:
708                 ;
709         }
710
711         if ((vap->va_mode & ap->a_mode) == ap->a_mode)
712                 return (0);
713
714         return (EACCES);
715 }
716
717 /*
718  * lookup.  this is incredibly complicated in the general case, however
719  * for most pseudo-filesystems very little needs to be done.
720  */
721 static int
722 linprocfs_lookup(struct vop_old_lookup_args *ap)
723 {
724         struct componentname *cnp = ap->a_cnp;
725         struct vnode **vpp = ap->a_vpp;
726         struct vnode *dvp = ap->a_dvp;
727         char *pname = cnp->cn_nameptr;
728         struct proc_target *pt;
729         pid_t pid;
730         struct pfsnode *pfs;
731         struct proc *p;
732         int i;
733         int error;
734
735         *vpp = NULL;
736
737         if (cnp->cn_nameiop == NAMEI_DELETE || 
738             cnp->cn_nameiop == NAMEI_RENAME ||
739             cnp->cn_nameiop == NAMEI_CREATE) {
740                 return (EROFS);
741         }
742
743         error = 0;
744
745         if (cnp->cn_namelen == 1 && *pname == '.') {
746                 *vpp = dvp;
747                 vref(*vpp);
748                 goto out;
749         }
750
751         pfs = VTOPFS(dvp);
752         switch (pfs->pfs_type) {
753         case Psys:
754                 if (cnp->cn_flags & CNP_ISDOTDOT) {
755                         error = linprocfs_root(dvp->v_mount, vpp);
756                         goto out;
757                 }
758                 if (CNEQ(cnp, "kernel", 6)) {
759                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Psyskernel);
760                         goto out;
761                 }               
762                 break;
763         case Pnet:
764                 if (cnp->cn_flags & CNP_ISDOTDOT) {
765                         error = linprocfs_root(dvp->v_mount, vpp);
766                         goto out;
767                 }
768                 if (CNEQ(cnp, "dev", 3)) {
769                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pnetdev);
770                         goto out;
771                 }               
772                 break;
773         case Psyskernel:
774                 if (cnp->cn_flags & CNP_ISDOTDOT) {
775                         /* XXX: this is wrong, wrong, wrong. */
776                         error = linprocfs_root(dvp->v_mount, vpp);
777                         goto out;
778                 }
779                 if (CNEQ(cnp, "osrelease", 9)) {
780                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Posrelease);
781                         goto out;
782                 }
783                 if (CNEQ(cnp, "ostype", 6)) {
784                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Postype);
785                         goto out;
786                 }
787                 if (CNEQ(cnp, "pid_max", 7)) {
788                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Ppidmax);
789                         goto out;
790                 }
791                 if (CNEQ(cnp, "version", 7)) {
792                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion);
793                         goto out;
794                 }
795                 break;
796                 
797         case Proot:
798                 if (cnp->cn_flags & CNP_ISDOTDOT)
799                         return (EIO);
800
801                 if (CNEQ(cnp, "self", 4)) {
802                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pself);
803                         goto out;
804                 }
805                 if (CNEQ(cnp, "meminfo", 7)) {
806                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmeminfo);
807                         goto out;
808                 }
809                 if (CNEQ(cnp, "cpuinfo", 7)) {
810                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pcpuinfo);
811                         goto out;
812                 }
813                 if (CNEQ(cnp, "mounts", 6)) {
814                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmounts);
815                         goto out;
816                 }
817                 if (CNEQ(cnp, "stat", 4)) {
818                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pstat);
819                         goto out;
820                 }
821                 if (CNEQ(cnp, "uptime", 6)) {
822                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Puptime);
823                         goto out;
824                 }
825                 if (CNEQ(cnp, "version", 7)) {
826                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion);
827                         goto out;
828                 }
829                 if (CNEQ(cnp, "loadavg", 7)) {
830                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Ploadavg);
831                         goto out;
832                 }
833                 if (CNEQ(cnp, "net", 3)) {
834                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pnet);
835                         goto out;
836                 }
837                 if (CNEQ(cnp, "sys", 3)) {
838                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Psys);
839                         goto out;
840                 }
841
842                 pid = atopid(pname, cnp->cn_namelen);
843                 if (pid == NO_PID)
844                         break;
845
846                 p = linprocfs_pfind(pid);
847                 if (p == NULL)
848                         break;
849
850                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
851                         break;
852
853                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
854                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
855                         break;
856
857                 error = linprocfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
858                 goto out;
859
860         case Pproc:
861                 if (cnp->cn_flags & CNP_ISDOTDOT) {
862                         error = linprocfs_root(dvp->v_mount, vpp);
863                         goto out;
864                 }
865
866                 p = linprocfs_pfind(pfs->pfs_pid);
867                 if (p == NULL)
868                         break;
869
870                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
871                         break;
872
873                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
874                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
875                         break;
876
877                 for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
878                         if (cnp->cn_namelen == pt->pt_namlen &&
879                             bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
880                             (pt->pt_valid == NULL || (*pt->pt_valid)(p)))
881                                 goto found;
882                 }
883                 break;
884
885         found:
886                 error = linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
887                                         pt->pt_pfstype);
888                 goto out;
889
890         default:
891                 error = ENOTDIR;
892                 goto out;
893         }
894
895         if (cnp->cn_nameiop == NAMEI_LOOKUP)
896                 error = ENOENT;
897         else
898                 error = EROFS;
899
900         /*
901          * If no error occured *vpp will hold a referenced locked vnode.
902          * dvp was passed to us locked and *vpp must be returned locked
903          * so if dvp != *vpp and CNP_LOCKPARENT is not set, unlock dvp.
904          */
905 out:
906         if (error == 0) {
907                 if (*vpp != dvp && (cnp->cn_flags & CNP_LOCKPARENT) == 0) {
908                         cnp->cn_flags |= CNP_PDIRUNLOCK;
909                         vn_unlock(dvp);
910                 }
911         }
912         return (error);
913 }
914
915 /*
916  * Does this process have a text file?
917  */
918 int
919 linprocfs_validfile(struct proc *p)
920 {
921
922         return (procfs_findtextvp(p) != NULLVP);
923 }
924
925 /*
926  * readdir() returns directory entries from pfsnode (vp).
927  *
928  * We generate just one directory entry at a time, as it would probably
929  * not pay off to buffer several entries locally to save uiomove calls.
930  *
931  * linprocfs_readdir(struct vnode *a_vp, struct uio *a_uio,
932  *                   struct ucred *a_cred, int *a_eofflag,
933  *                   int *a_ncookies, off_t **a_cookies)
934  */
935 static int
936 linprocfs_readdir(struct vop_readdir_args *ap)
937 {
938         struct pfsnode *pfs;
939         int error;
940
941         if (ap->a_uio->uio_offset < 0 || ap->a_uio->uio_offset > INT_MAX)
942                 return (EINVAL);
943
944         pfs = VTOPFS(ap->a_vp);
945         if ((error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
946                 return (error);
947
948         switch (pfs->pfs_type) {
949         case Pproc:
950                 /*
951                  * This is for the process-specific sub-directories.
952                  * all that is needed to is copy out all the entries
953                  * from the procent[] table (top of this file).
954                  */
955                 error = linprocfs_readdir_proc(ap);
956                 break;
957         case Proot:
958                 /*
959                  * This is for the root of the procfs filesystem
960                  * what is needed is a special entry for "self"
961                  * followed by an entry for each process on allproc
962                  */
963                 error = linprocfs_readdir_root(ap);
964                 break;
965         case Pnet:
966                 error = linprocfs_readdir_net(ap);
967                 break;
968         case Psys:
969                 error = linprocfs_readdir_sys(ap);
970                 break;
971         case Psyskernel:
972                 error = linprocfs_readdir_syskernel(ap);
973                 break;
974         default:
975                 error = ENOTDIR;
976                 break;
977         }
978         vn_unlock(ap->a_vp);
979
980         return (error);
981 }
982
983 static int
984 linprocfs_readdir_proc(struct vop_readdir_args *ap)
985 {
986         struct pfsnode *pfs;
987         int error, i, retval;
988         struct proc *p;
989         struct proc_target *pt;
990         struct uio *uio = ap->a_uio;
991
992         pfs = VTOPFS(ap->a_vp);
993         p = linprocfs_pfind(pfs->pfs_pid);
994         if (p == NULL)
995                 return(0);
996         if (!PRISON_CHECK(ap->a_cred, p->p_ucred))
997                 return(0);
998
999         error = 0;
1000         i = uio->uio_offset;
1001
1002         for (pt = &proc_targets[i];
1003              !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) {
1004                 if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
1005                         continue;
1006
1007                 retval = vop_write_dirent(&error, uio,
1008                     PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype), pt->pt_type,
1009                     pt->pt_namlen, pt->pt_name);
1010                 if (retval)
1011                         break;
1012         }
1013
1014         uio->uio_offset = i;
1015
1016         return(error);
1017 }
1018
1019 struct linprocfs_readdir_root_info {
1020         int error;
1021         int pcnt;
1022         int i;
1023         struct uio *uio;
1024         struct ucred *cred;
1025 };
1026
1027 /*
1028  * Scan the root directory by scanning all process
1029  */
1030 static int linprocfs_readdir_root_callback(struct proc *p, void *data);
1031
1032 static int
1033 linprocfs_readdir_root(struct vop_readdir_args *ap)
1034 {
1035         struct linprocfs_readdir_root_info info;
1036         struct uio *uio = ap->a_uio;
1037         int res = 0;
1038
1039         info.error = 0;
1040         info.i = uio->uio_offset;
1041         info.pcnt = 0;
1042         info.uio = uio;
1043         info.cred = ap->a_cred;
1044
1045         while (info.pcnt < 12) {
1046                 res = linprocfs_readdir_root_callback(NULL, &info);
1047                 if (res < 0)
1048                         break;
1049         }
1050         if (res >= 0)
1051                 allproc_scan(linprocfs_readdir_root_callback, &info);
1052
1053         uio->uio_offset = info.i;
1054         return(info.error);
1055 }
1056
1057 static int
1058 linprocfs_readdir_root_callback(struct proc *p, void *data)
1059 {
1060         struct linprocfs_readdir_root_info *info = data;
1061         int retval;
1062         struct uio *uio = info->uio;
1063         ino_t d_ino;
1064         const char *d_name;
1065         char d_name_pid[20];
1066         size_t d_namlen;
1067         uint8_t d_type;
1068
1069         switch (info->pcnt) {
1070         case 0:         /* `.' */
1071                 d_ino = PROCFS_FILENO(0, Proot);
1072                 d_name = ".";
1073                 d_namlen = 1;
1074                 d_type = DT_DIR;
1075                 break;
1076         case 1:         /* `..' */
1077                 d_ino = PROCFS_FILENO(0, Proot);
1078                 d_name = "..";
1079                 d_namlen = 2;
1080                 d_type = DT_DIR;
1081                 break;
1082
1083         case 2:
1084                 d_ino = PROCFS_FILENO(0, Proot);
1085                 d_namlen = 4;
1086                 d_name = "self";
1087                 d_type = DT_LNK;
1088                 break;
1089
1090         case 3:
1091                 d_ino = PROCFS_FILENO(0, Pmeminfo);
1092                 d_namlen = 7;
1093                 d_name = "meminfo";
1094                 d_type = DT_REG;
1095                 break;
1096
1097         case 4:
1098                 d_ino = PROCFS_FILENO(0, Pcpuinfo);
1099                 d_namlen = 7;
1100                 d_name = "cpuinfo";
1101                 d_type = DT_REG;
1102                 break;
1103
1104         case 5:
1105                 d_ino = PROCFS_FILENO(0, Pstat);
1106                 d_namlen = 4;
1107                 d_name = "stat";
1108                 d_type = DT_REG;
1109                 break;
1110                     
1111         case 6:
1112                 d_ino = PROCFS_FILENO(0, Puptime);
1113                 d_namlen = 6;
1114                 d_name = "uptime";
1115                 d_type = DT_REG;
1116                 break;
1117
1118         case 7:
1119                 d_ino = PROCFS_FILENO(0, Pversion);
1120                 d_namlen = 7;
1121                 d_name = "version";
1122                 d_type = DT_REG;
1123                 break;
1124
1125         case 8:
1126                 d_ino = PROCFS_FILENO(0, Ploadavg);
1127                 d_namlen = 7;
1128                 d_name = "loadavg";
1129                 d_type = DT_REG;
1130                 break;
1131         case 9:
1132                 d_ino = PROCFS_FILENO(0, Pnet);
1133                 d_namlen = 3;
1134                 d_name = "net";
1135                 d_type = DT_DIR;
1136                 break;
1137         case 10:
1138                 d_ino = PROCFS_FILENO(0, Psys);
1139                 d_namlen = 3;
1140                 d_name = "sys";
1141                 d_type = DT_DIR;
1142                 break;
1143         case 11:
1144                 d_ino = PROCFS_FILENO(0, Pmounts);
1145                 d_namlen = 6;
1146                 d_name = "mounts";
1147                 d_type = DT_DIR;
1148                 break;
1149 #if 0
1150         case 11:
1151                 d_ino = PROCFS_FILENO(0, Pdevices);
1152                 d_namlen = 7;
1153                 d_name = "devices";
1154                 d_type = DT_REG;
1155                 break;          
1156 #endif
1157         default:
1158                 /*
1159                  * Ignore processes that aren't in our prison
1160                  */
1161                 if (PRISON_CHECK(info->cred, p->p_ucred) == 0)
1162                         return(0);
1163
1164                 /*
1165                  * Ignore processes that we do not want to be visible.
1166                  */
1167                 if (ps_showallprocs == 0 && 
1168                     info->cred->cr_uid != 0 &&
1169                     info->cred->cr_uid != p->p_ucred->cr_uid) {
1170                         return(0);
1171                 }
1172
1173                 /*
1174                  * Skip processes we have already read (optimization)
1175                  */
1176                 if (info->pcnt < info->i) {
1177                         ++info->pcnt;
1178                         return(0);
1179                 }
1180                 d_ino = PROCFS_FILENO(p->p_pid, Pproc);
1181                 d_namlen = ksnprintf(d_name_pid, sizeof(d_name_pid),
1182                     "%ld", (long)p->p_pid);
1183                 d_name = d_name_pid;
1184                 d_type = DT_DIR;
1185                 break;
1186         }
1187
1188         /*
1189          * Skip processes we have already read
1190          */
1191         if (info->pcnt < info->i) {
1192                 ++info->pcnt;
1193                 return(0);
1194         }
1195         retval = vop_write_dirent(&info->error, info->uio, 
1196                                   d_ino, d_type, d_namlen, d_name);
1197         if (retval == 0) {
1198                 ++info->pcnt;   /* iterate proc candidates scanned */
1199                 ++info->i;      /* iterate entries written */
1200         }
1201         if (retval || info->error || uio->uio_resid <= 0)
1202                 return(-1);
1203         return(0);
1204 }
1205
1206 /*
1207  * Scan the root directory by scanning all process
1208  */
1209 static int linprocfs_readdir_net_callback(struct proc *p, void *data);
1210
1211 static int
1212 linprocfs_readdir_net(struct vop_readdir_args *ap)
1213 {
1214         struct linprocfs_readdir_root_info info;
1215         struct uio *uio = ap->a_uio;
1216         int res;
1217
1218         info.error = 0;
1219         info.i = uio->uio_offset;
1220         info.pcnt = 0;
1221         info.uio = uio;
1222         info.cred = ap->a_cred;
1223
1224         while (info.pcnt < 3) {
1225                 res = linprocfs_readdir_net_callback(NULL, &info);
1226                 if (res < 0)
1227                         break;
1228         }
1229
1230         uio->uio_offset = info.i;
1231         return(info.error);
1232 }
1233
1234 static int
1235 linprocfs_readdir_net_callback(struct proc *p, void *data)
1236 {
1237         struct linprocfs_readdir_root_info *info = data;
1238         int retval;
1239         struct uio *uio = info->uio;
1240         ino_t d_ino;
1241         const char *d_name;
1242         size_t d_namlen;
1243         uint8_t d_type;
1244
1245         switch (info->pcnt) {
1246         case 0:         /* `.' */
1247                 d_ino = PROCFS_FILENO(0, Pnet);
1248                 d_name = ".";
1249                 d_namlen = 1;
1250                 d_type = DT_DIR;
1251                 break;
1252         case 1:         /* `..' */
1253                 d_ino = PROCFS_FILENO(0, Proot);
1254                 d_name = "..";
1255                 d_namlen = 2;
1256                 d_type = DT_DIR;
1257                 break;
1258
1259         case 2:
1260                 d_ino = PROCFS_FILENO(0, Pnet);
1261                 d_namlen = 3;
1262                 d_name = "dev";
1263                 d_type = DT_REG;
1264                 break;
1265         default:
1266                 d_ino = 0;
1267                 d_namlen = 0;
1268                 d_name = NULL;
1269                 d_type = DT_REG;
1270                 break;
1271         }
1272
1273         /*
1274          * Skip processes we have already read
1275          */
1276         if (info->pcnt < info->i) {
1277                 ++info->pcnt;
1278                 return(0);
1279         }
1280         retval = vop_write_dirent(&info->error, info->uio, 
1281                                   d_ino, d_type, d_namlen, d_name);
1282         if (retval == 0) {
1283                 ++info->pcnt;   /* iterate proc candidates scanned */
1284                 ++info->i;      /* iterate entries written */
1285         }
1286         if (retval || info->error || uio->uio_resid <= 0)
1287                 return(-1);
1288         return(0);
1289 }
1290
1291
1292
1293
1294
1295
1296
1297 /*
1298  * Scan the root directory by scanning all process
1299  */
1300 static int linprocfs_readdir_sys_callback(struct proc *p, void *data);
1301
1302 static int
1303 linprocfs_readdir_sys(struct vop_readdir_args *ap)
1304 {
1305         struct linprocfs_readdir_root_info info;
1306         struct uio *uio = ap->a_uio;
1307         int res;
1308
1309         info.error = 0;
1310         info.i = uio->uio_offset;
1311         info.pcnt = 0;
1312         info.uio = uio;
1313         info.cred = ap->a_cred;
1314
1315         while (info.pcnt < 3) {
1316                 res = linprocfs_readdir_sys_callback(NULL, &info);
1317                 if (res < 0)
1318                         break;
1319         }
1320
1321         uio->uio_offset = info.i;
1322         return(info.error);
1323 }
1324
1325 static int
1326 linprocfs_readdir_sys_callback(struct proc *p, void *data)
1327 {
1328         struct linprocfs_readdir_root_info *info = data;
1329         int retval;
1330         struct uio *uio = info->uio;
1331         ino_t d_ino;
1332         const char *d_name;
1333         size_t d_namlen;
1334         uint8_t d_type;
1335
1336         switch (info->pcnt) {
1337         case 0:         /* `.' */
1338                 d_ino = PROCFS_FILENO(0, Psys);
1339                 d_name = ".";
1340                 d_namlen = 1;
1341                 d_type = DT_DIR;
1342                 break;
1343         case 1:         /* `..' */
1344                 d_ino = PROCFS_FILENO(0, Proot);
1345                 d_name = "..";
1346                 d_namlen = 2;
1347                 d_type = DT_DIR;
1348                 break;
1349
1350         case 2:
1351                 d_ino = PROCFS_FILENO(0, Psyskernel);
1352                 d_namlen = 6;
1353                 d_name = "kernel";
1354                 d_type = DT_DIR;
1355                 break;
1356         default:
1357                 d_ino = 0;
1358                 d_namlen = 0;
1359                 d_name = NULL;
1360                 d_type = DT_REG;
1361                 break;
1362         }
1363
1364         /*
1365          * Skip processes we have already read
1366          */
1367         if (info->pcnt < info->i) {
1368                 ++info->pcnt;
1369                 return(0);
1370         }
1371         retval = vop_write_dirent(&info->error, info->uio, 
1372                                   d_ino, d_type, d_namlen, d_name);
1373         if (retval == 0) {
1374                 ++info->pcnt;   /* iterate proc candidates scanned */
1375                 ++info->i;      /* iterate entries written */
1376         }
1377         if (retval || info->error || uio->uio_resid <= 0)
1378                 return(-1);
1379         return(0);
1380 }
1381
1382
1383
1384
1385
1386 /*
1387  * Scan the root directory by scanning all process
1388  */
1389 static int linprocfs_readdir_syskernel_callback(struct proc *p, void *data);
1390
1391 static int
1392 linprocfs_readdir_syskernel(struct vop_readdir_args *ap)
1393 {
1394         struct linprocfs_readdir_root_info info;
1395         struct uio *uio = ap->a_uio;
1396         int res;
1397
1398         info.error = 0;
1399         info.i = uio->uio_offset;
1400         info.pcnt = 0;
1401         info.uio = uio;
1402         info.cred = ap->a_cred;
1403
1404         while (info.pcnt < 6) {
1405                 res = linprocfs_readdir_syskernel_callback(NULL, &info);
1406                 if (res < 0)
1407                         break;
1408         }
1409
1410         uio->uio_offset = info.i;
1411         return(info.error);
1412 }
1413
1414 static int
1415 linprocfs_readdir_syskernel_callback(struct proc *p, void *data)
1416 {
1417         struct linprocfs_readdir_root_info *info = data;
1418         int retval;
1419         struct uio *uio = info->uio;
1420         ino_t d_ino;
1421         const char *d_name;
1422         size_t d_namlen;
1423         uint8_t d_type;
1424
1425         switch (info->pcnt) {
1426         case 0:         /* `.' */
1427                 d_ino = PROCFS_FILENO(0, Psyskernel);
1428                 d_name = ".";
1429                 d_namlen = 1;
1430                 d_type = DT_DIR;
1431                 break;
1432         case 1:         /* `..' */
1433                 d_ino = PROCFS_FILENO(0, Psys);
1434                 d_name = "..";
1435                 d_namlen = 2;
1436                 d_type = DT_DIR;
1437                 break;
1438
1439         case 2:
1440                 d_ino = PROCFS_FILENO(0, Posrelease);
1441                 d_namlen = 9;
1442                 d_name = "osrelease";
1443                 d_type = DT_REG;
1444                 break;
1445
1446         case 3:
1447                 d_ino = PROCFS_FILENO(0, Postype);
1448                 d_namlen = 4;
1449                 d_name = "ostype";
1450                 d_type = DT_REG;
1451                 break;
1452
1453         case 4:
1454                 d_ino = PROCFS_FILENO(0, Pversion);
1455                 d_namlen = 7;
1456                 d_name = "version";
1457                 d_type = DT_REG;
1458                 break;
1459
1460         case 5:
1461                 d_ino = PROCFS_FILENO(0, Ppidmax);
1462                 d_namlen = 7;
1463                 d_name = "pid_max";
1464                 d_type = DT_REG;
1465                 break;
1466         default:
1467                 d_ino = 0;
1468                 d_namlen = 0;
1469                 d_name = NULL;
1470                 d_type = DT_REG;
1471                 break;
1472         }
1473
1474         /*
1475          * Skip processes we have already read
1476          */
1477         if (info->pcnt < info->i) {
1478                 ++info->pcnt;
1479                 return(0);
1480         }
1481         retval = vop_write_dirent(&info->error, info->uio, 
1482                                   d_ino, d_type, d_namlen, d_name);
1483         if (retval == 0) {
1484                 ++info->pcnt;   /* iterate proc candidates scanned */
1485                 ++info->i;      /* iterate entries written */
1486         }
1487         if (retval || info->error || uio->uio_resid <= 0)
1488                 return(-1);
1489         return(0);
1490 }
1491
1492 /*
1493  * readlink reads the link of `self' or `exe'
1494  */
1495 static int
1496 linprocfs_readlink(struct vop_readlink_args *ap)
1497 {
1498         char buf[16];           /* should be enough */
1499         struct proc *procp;
1500         struct vnode *vp = ap->a_vp;
1501         struct nchandle *nchp;
1502         struct pfsnode *pfs = VTOPFS(vp);
1503         char *fullpath, *freepath;
1504         int error, len;
1505
1506         switch (pfs->pfs_type) {
1507         case Pself:
1508                 if (pfs->pfs_fileno != PROCFS_FILENO(0, Pself))
1509                         return (EINVAL);
1510
1511                 len = ksnprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
1512
1513                 return (uiomove(buf, len, ap->a_uio));
1514         /*
1515          * There _should_ be no way for an entire process to disappear
1516          * from under us...
1517          */
1518         case Pexe:
1519                 procp = linprocfs_pfind(pfs->pfs_pid);
1520                 if (procp == NULL || procp->p_ucred == NULL) {
1521                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1522                             pfs->pfs_pid);
1523                         return (uiomove("unknown", sizeof("unknown") - 1,
1524                             ap->a_uio));
1525                 }
1526                 error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0);
1527                 if (error != 0)
1528                         return (uiomove("unknown", sizeof("unknown") - 1,
1529                             ap->a_uio));
1530                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1531                 kfree(freepath, M_TEMP);
1532                 return (error);
1533         case Pcwd:
1534                 procp = linprocfs_pfind(pfs->pfs_pid);
1535                 if (procp == NULL || procp->p_ucred == NULL) {
1536                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1537                             pfs->pfs_pid);
1538                         return (uiomove("unknown", sizeof("unknown") - 1,
1539                             ap->a_uio));
1540                 }
1541                 error = cache_fullpath(procp, &procp->p_fd->fd_ncdir, &fullpath, &freepath, 0);
1542                 if (error != 0)
1543                         return (uiomove("unknown", sizeof("unknown") - 1,
1544                             ap->a_uio));
1545                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1546                 kfree(freepath, M_TEMP);
1547                 return (error);
1548         case Pprocroot:
1549                 procp = linprocfs_pfind(pfs->pfs_pid);
1550                 if (procp == NULL || procp->p_ucred == NULL) {
1551                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1552                             pfs->pfs_pid);
1553                         return (uiomove("unknown", sizeof("unknown") - 1,
1554                             ap->a_uio));
1555                 }
1556                 nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
1557                 error = cache_fullpath(procp, nchp, &fullpath, &freepath, 0);
1558                 if (error != 0)
1559                         return (uiomove("unknown", sizeof("unknown") - 1,
1560                             ap->a_uio));
1561                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1562                 kfree(freepath, M_TEMP);
1563                 return (error);
1564         case Pfd:
1565                 procp = linprocfs_pfind(pfs->pfs_pid);
1566                 if (procp == NULL || procp->p_ucred == NULL) {
1567                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1568                             pfs->pfs_pid);
1569                         return (uiomove("unknown", sizeof("unknown") - 1,
1570                             ap->a_uio));
1571                 }
1572                 if (procp == curproc) {
1573                         return (uiomove("/dev/fd", sizeof("/dev/fd") - 1,
1574                             ap->a_uio));
1575                 } else {
1576                         return (uiomove("unknown", sizeof("unknown") - 1,
1577                             ap->a_uio));
1578                 }
1579                 /* notreached */
1580                 break;
1581         default:
1582                 return (EINVAL);
1583         }
1584 }
1585
1586 /*
1587  * convert decimal ascii to pid_t
1588  */
1589 static pid_t
1590 atopid(const char *b, u_int len)
1591 {
1592         pid_t p = 0;
1593
1594         while (len--) {
1595                 char c = *b++;
1596                 if (c < '0' || c > '9')
1597                         return (NO_PID);
1598                 p = 10 * p + (c - '0');
1599                 if (p > PID_MAX)
1600                         return (NO_PID);
1601         }
1602
1603         return (p);
1604 }
1605