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