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