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