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