kernel/linprocfs: Implement /proc/devices.
[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, &fullpath, &freepath, 0);
566                 /* error = vn_fullpath(procp, NULL, &fullpath, &freepath); */
567                 if (error == 0) {
568                         vap->va_size = strlen(fullpath);
569                         kfree(freepath, M_TEMP);
570                 } else {
571                         vap->va_size = sizeof("unknown") - 1;
572                         error = 0;
573                 }
574                 vap->va_bytes = vap->va_size;
575                 break;
576         }
577         case Pcwd: {
578                 char *fullpath, *freepath;
579                 error = cache_fullpath(procp, &procp->p_fd->fd_ncdir, &fullpath, &freepath, 0);
580                 if (error == 0) {
581                         vap->va_size = strlen(fullpath);
582                         kfree(freepath, M_TEMP);
583                 } else {
584                         vap->va_size = sizeof("unknown") - 1;
585                         error = 0;
586                 }
587                 vap->va_bytes = vap->va_size;
588                 break;
589         }
590         case Pprocroot: {
591                 struct nchandle *nchp;
592                 char *fullpath, *freepath;
593                 nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
594                 error = cache_fullpath(procp, nchp, &fullpath, &freepath, 0);
595                 if (error == 0) {
596                         vap->va_size = strlen(fullpath);
597                         kfree(freepath, M_TEMP);
598                 } else {
599                         vap->va_size = sizeof("unknown") - 1;
600                         error = 0;
601                 }
602                 vap->va_bytes = vap->va_size;
603                 break;
604         }
605         case Pfd: {
606                 if (procp == curproc) {
607                         vap->va_size = sizeof("/dev/fd") - 1;
608                         error = 0;      
609                 } else {
610                         vap->va_size = sizeof("unknown") - 1;
611                         error = 0;
612                 }
613                 vap->va_bytes = vap->va_size;
614                 break;
615         }
616
617         case Pmeminfo:
618         case Pcpuinfo:
619         case Pmounts:
620         case Pstat:
621         case Puptime:
622         case Pversion:
623         case Ploadavg:
624         case Pnetdev:
625         case Pdevices:
626         case Posrelease:
627         case Postype:
628         case Ppidmax:
629                 vap->va_bytes = vap->va_size = 0;
630                 vap->va_uid = 0;
631                 vap->va_gid = 0;
632                 break;
633                 
634         case Pmem:
635                 /*
636                  * If we denied owner access earlier, then we have to
637                  * change the owner to root - otherwise 'ps' and friends
638                  * will break even though they are setgid kmem. *SIGH*
639                  */
640                 if (procp->p_flags & P_SUGID)
641                         vap->va_uid = 0;
642                 else
643                         vap->va_uid = procp->p_ucred->cr_uid;
644                 break;
645
646         case Pprocstat:
647         case Pprocstatus:
648         case Pcmdline:
649         case Penviron:
650         case Pmaps:
651         case Pstatm:
652                 vap->va_bytes = vap->va_size = 0;
653                 /* uid, gid are already set */
654                 break;
655
656         default:
657                 panic("linprocfs_getattr");
658         }
659 done:
660         if (procp)
661                 PRELE(procp);
662         return (error);
663 }
664
665 static int
666 linprocfs_setattr(struct vop_setattr_args *ap)
667 {
668
669         if (ap->a_vap->va_flags != VNOVAL)
670                 return (EOPNOTSUPP);
671
672         /*
673          * just fake out attribute setting
674          * it's not good to generate an error
675          * return, otherwise things like creat()
676          * will fail when they try to set the
677          * file length to 0.  worse, this means
678          * that echo $note > /proc/$pid/note will fail.
679          */
680
681         return (0);
682 }
683
684 /*
685  * implement access checking.
686  *
687  * something very similar to this code is duplicated
688  * throughout the 4bsd kernel and should be moved
689  * into kern/vfs_subr.c sometime.
690  *
691  * actually, the check for super-user is slightly
692  * broken since it will allow read access to write-only
693  * objects.  this doesn't cause any particular trouble
694  * but does mean that the i/o entry points need to check
695  * that the operation really does make sense.
696  */
697 static int
698 linprocfs_access(struct vop_access_args *ap)
699 {
700         struct vattr *vap;
701         struct vattr vattr;
702         int error;
703
704         /*
705          * If you're the super-user,
706          * you always get access.
707          */
708         if (ap->a_cred->cr_uid == 0)
709                 return (0);
710
711         vap = &vattr;
712         error = VOP_GETATTR(ap->a_vp, vap);
713         if (error)
714                 return (error);
715
716         /*
717          * Access check is based on only one of owner, group, public.
718          * If not owner, then check group. If not a member of the
719          * group, then check public access.
720          */
721         if (ap->a_cred->cr_uid != vap->va_uid) {
722                 gid_t *gp;
723                 int i;
724
725                 ap->a_mode >>= 3;
726                 gp = ap->a_cred->cr_groups;
727                 for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
728                         if (vap->va_gid == *gp)
729                                 goto found;
730                 ap->a_mode >>= 3;
731 found:
732                 ;
733         }
734
735         if ((vap->va_mode & ap->a_mode) == ap->a_mode)
736                 return (0);
737
738         return (EACCES);
739 }
740
741 /*
742  * lookup.  this is incredibly complicated in the general case, however
743  * for most pseudo-filesystems very little needs to be done.
744  */
745 static int
746 linprocfs_lookup(struct vop_old_lookup_args *ap)
747 {
748         struct componentname *cnp = ap->a_cnp;
749         struct vnode **vpp = ap->a_vpp;
750         struct vnode *dvp = ap->a_dvp;
751         char *pname = cnp->cn_nameptr;
752         struct proc_target *pt;
753         pid_t pid;
754         struct pfsnode *pfs;
755         struct proc *p;
756         int i;
757         int error;
758
759         *vpp = NULL;
760         p = NULL;
761
762         if (cnp->cn_nameiop == NAMEI_DELETE || 
763             cnp->cn_nameiop == NAMEI_RENAME ||
764             cnp->cn_nameiop == NAMEI_CREATE) {
765                 return (EROFS);
766         }
767
768         error = 0;
769
770         if (cnp->cn_namelen == 1 && *pname == '.') {
771                 *vpp = dvp;
772                 vref(*vpp);
773                 goto out;
774         }
775
776         pfs = VTOPFS(dvp);
777         switch (pfs->pfs_type) {
778         case Psys:
779                 if (cnp->cn_flags & CNP_ISDOTDOT) {
780                         error = linprocfs_root(dvp->v_mount, vpp);
781                         goto out;
782                 }
783                 if (CNEQ(cnp, "kernel", 6)) {
784                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Psyskernel);
785                         goto out;
786                 }               
787                 break;
788         case Pnet:
789                 if (cnp->cn_flags & CNP_ISDOTDOT) {
790                         error = linprocfs_root(dvp->v_mount, vpp);
791                         goto out;
792                 }
793                 if (CNEQ(cnp, "dev", 3)) {
794                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pnetdev);
795                         goto out;
796                 }               
797                 break;
798         case Psyskernel:
799                 if (cnp->cn_flags & CNP_ISDOTDOT) {
800                         /* XXX: this is wrong, wrong, wrong. */
801                         error = linprocfs_root(dvp->v_mount, vpp);
802                         goto out;
803                 }
804                 if (CNEQ(cnp, "osrelease", 9)) {
805                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Posrelease);
806                         goto out;
807                 }
808                 if (CNEQ(cnp, "ostype", 6)) {
809                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Postype);
810                         goto out;
811                 }
812                 if (CNEQ(cnp, "pid_max", 7)) {
813                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Ppidmax);
814                         goto out;
815                 }
816                 if (CNEQ(cnp, "version", 7)) {
817                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion);
818                         goto out;
819                 }
820                 break;
821                 
822         case Proot:
823                 if (cnp->cn_flags & CNP_ISDOTDOT)
824                         return (EIO);
825
826                 if (CNEQ(cnp, "self", 4)) {
827                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pself);
828                         goto out;
829                 }
830                 if (CNEQ(cnp, "meminfo", 7)) {
831                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmeminfo);
832                         goto out;
833                 }
834                 if (CNEQ(cnp, "cpuinfo", 7)) {
835                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pcpuinfo);
836                         goto out;
837                 }
838                 if (CNEQ(cnp, "mounts", 6)) {
839                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmounts);
840                         goto out;
841                 }
842                 if (CNEQ(cnp, "stat", 4)) {
843                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pstat);
844                         goto out;
845                 }
846                 if (CNEQ(cnp, "uptime", 6)) {
847                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Puptime);
848                         goto out;
849                 }
850                 if (CNEQ(cnp, "version", 7)) {
851                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion);
852                         goto out;
853                 }
854                 if (CNEQ(cnp, "loadavg", 7)) {
855                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Ploadavg);
856                         goto out;
857                 }
858                 if (CNEQ(cnp, "net", 3)) {
859                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pnet);
860                         goto out;
861                 }
862                 if (CNEQ(cnp, "sys", 3)) {
863                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Psys);
864                         goto out;
865                 }
866                 if (CNEQ(cnp, "devices", 7)) {
867                         error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pdevices);
868                         goto out;
869                 }
870
871                 pid = atopid(pname, cnp->cn_namelen);
872                 if (pid == NO_PID)
873                         break;
874
875                 p = linprocfs_pfind(pid);
876                 if (p == NULL)
877                         break;
878
879                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
880                         break;
881
882                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
883                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
884                         break;
885
886                 error = linprocfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
887                 goto out;
888
889         case Pproc:
890                 if (cnp->cn_flags & CNP_ISDOTDOT) {
891                         error = linprocfs_root(dvp->v_mount, vpp);
892                         goto out;
893                 }
894
895                 p = linprocfs_pfind(pfs->pfs_pid);
896                 if (p == NULL)
897                         break;
898
899                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
900                         break;
901
902                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
903                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
904                         break;
905
906                 for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
907                         if (cnp->cn_namelen == pt->pt_namlen &&
908                             bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
909                             (pt->pt_valid == NULL || (*pt->pt_valid)(p)))
910                                 goto found;
911                 }
912                 break;
913
914         found:
915                 error = linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
916                                         pt->pt_pfstype);
917                 goto out;
918
919         default:
920                 error = ENOTDIR;
921                 goto out;
922         }
923
924         if (cnp->cn_nameiop == NAMEI_LOOKUP)
925                 error = ENOENT;
926         else
927                 error = EROFS;
928
929         /*
930          * If no error occured *vpp will hold a referenced locked vnode.
931          * dvp was passed to us locked and *vpp must be returned locked
932          * so if dvp != *vpp and CNP_LOCKPARENT is not set, unlock dvp.
933          */
934 out:
935         if (p)
936                 PRELE(p);
937         if (error == 0) {
938                 if (*vpp != dvp && (cnp->cn_flags & CNP_LOCKPARENT) == 0) {
939                         cnp->cn_flags |= CNP_PDIRUNLOCK;
940                         vn_unlock(dvp);
941                 }
942         }
943         return (error);
944 }
945
946 /*
947  * Does this process have a text file?
948  */
949 int
950 linprocfs_validfile(struct proc *p)
951 {
952
953         return (procfs_findtextvp(p) != NULLVP);
954 }
955
956 /*
957  * readdir() returns directory entries from pfsnode (vp).
958  *
959  * We generate just one directory entry at a time, as it would probably
960  * not pay off to buffer several entries locally to save uiomove calls.
961  *
962  * linprocfs_readdir(struct vnode *a_vp, struct uio *a_uio,
963  *                   struct ucred *a_cred, int *a_eofflag,
964  *                   int *a_ncookies, off_t **a_cookies)
965  */
966 static int
967 linprocfs_readdir(struct vop_readdir_args *ap)
968 {
969         struct pfsnode *pfs;
970         int error;
971
972         if (ap->a_uio->uio_offset < 0 || ap->a_uio->uio_offset > INT_MAX)
973                 return (EINVAL);
974
975         pfs = VTOPFS(ap->a_vp);
976         if ((error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
977                 return (error);
978
979         switch (pfs->pfs_type) {
980         case Pproc:
981                 /*
982                  * This is for the process-specific sub-directories.
983                  * all that is needed to is copy out all the entries
984                  * from the procent[] table (top of this file).
985                  */
986                 error = linprocfs_readdir_proc(ap);
987                 break;
988         case Proot:
989                 /*
990                  * This is for the root of the procfs filesystem
991                  * what is needed is a special entry for "self"
992                  * followed by an entry for each process on allproc
993                  */
994                 error = linprocfs_readdir_root(ap);
995                 break;
996         case Pnet:
997                 error = linprocfs_readdir_net(ap);
998                 break;
999         case Psys:
1000                 error = linprocfs_readdir_sys(ap);
1001                 break;
1002         case Psyskernel:
1003                 error = linprocfs_readdir_syskernel(ap);
1004                 break;
1005         default:
1006                 error = ENOTDIR;
1007                 break;
1008         }
1009         vn_unlock(ap->a_vp);
1010
1011         return (error);
1012 }
1013
1014 static int
1015 linprocfs_readdir_proc(struct vop_readdir_args *ap)
1016 {
1017         struct pfsnode *pfs;
1018         int error, i, retval;
1019         struct proc *p;
1020         struct proc_target *pt;
1021         struct uio *uio = ap->a_uio;
1022
1023         pfs = VTOPFS(ap->a_vp);
1024         p = linprocfs_pfind(pfs->pfs_pid);
1025         if (p == NULL)
1026                 return(0);
1027         if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) {
1028                 PRELE(p);
1029                 return(0);
1030         }
1031
1032         error = 0;
1033         i = uio->uio_offset;
1034
1035         for (pt = &proc_targets[i];
1036              !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) {
1037                 if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
1038                         continue;
1039
1040                 retval = vop_write_dirent(&error, uio,
1041                     PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype), pt->pt_type,
1042                     pt->pt_namlen, pt->pt_name);
1043                 if (retval)
1044                         break;
1045         }
1046
1047         uio->uio_offset = i;
1048         PRELE(p);
1049
1050         return(error);
1051 }
1052
1053 struct linprocfs_readdir_root_info {
1054         int error;
1055         int pcnt;
1056         int i;
1057         struct uio *uio;
1058         struct ucred *cred;
1059 };
1060
1061 /*
1062  * Scan the root directory by scanning all process
1063  */
1064 static int linprocfs_readdir_root_callback(struct proc *p, void *data);
1065
1066 static int
1067 linprocfs_readdir_root(struct vop_readdir_args *ap)
1068 {
1069         struct linprocfs_readdir_root_info info;
1070         struct uio *uio = ap->a_uio;
1071         int res = 0;
1072
1073         info.error = 0;
1074         info.i = uio->uio_offset;
1075         info.pcnt = 0;
1076         info.uio = uio;
1077         info.cred = ap->a_cred;
1078
1079         while (info.pcnt < 13) {
1080                 res = linprocfs_readdir_root_callback(NULL, &info);
1081                 if (res < 0)
1082                         break;
1083         }
1084         if (res >= 0)
1085                 allproc_scan(linprocfs_readdir_root_callback, &info);
1086
1087         uio->uio_offset = info.i;
1088         return(info.error);
1089 }
1090
1091 static int
1092 linprocfs_readdir_root_callback(struct proc *p, void *data)
1093 {
1094         struct linprocfs_readdir_root_info *info = data;
1095         int retval;
1096         struct uio *uio = info->uio;
1097         ino_t d_ino;
1098         const char *d_name;
1099         char d_name_pid[20];
1100         size_t d_namlen;
1101         uint8_t d_type;
1102
1103         switch (info->pcnt) {
1104         case 0:         /* `.' */
1105                 d_ino = PROCFS_FILENO(0, Proot);
1106                 d_name = ".";
1107                 d_namlen = 1;
1108                 d_type = DT_DIR;
1109                 break;
1110         case 1:         /* `..' */
1111                 d_ino = PROCFS_FILENO(0, Proot);
1112                 d_name = "..";
1113                 d_namlen = 2;
1114                 d_type = DT_DIR;
1115                 break;
1116
1117         case 2:
1118                 d_ino = PROCFS_FILENO(0, Proot);
1119                 d_namlen = 4;
1120                 d_name = "self";
1121                 d_type = DT_LNK;
1122                 break;
1123
1124         case 3:
1125                 d_ino = PROCFS_FILENO(0, Pmeminfo);
1126                 d_namlen = 7;
1127                 d_name = "meminfo";
1128                 d_type = DT_REG;
1129                 break;
1130
1131         case 4:
1132                 d_ino = PROCFS_FILENO(0, Pcpuinfo);
1133                 d_namlen = 7;
1134                 d_name = "cpuinfo";
1135                 d_type = DT_REG;
1136                 break;
1137
1138         case 5:
1139                 d_ino = PROCFS_FILENO(0, Pstat);
1140                 d_namlen = 4;
1141                 d_name = "stat";
1142                 d_type = DT_REG;
1143                 break;
1144                     
1145         case 6:
1146                 d_ino = PROCFS_FILENO(0, Puptime);
1147                 d_namlen = 6;
1148                 d_name = "uptime";
1149                 d_type = DT_REG;
1150                 break;
1151
1152         case 7:
1153                 d_ino = PROCFS_FILENO(0, Pversion);
1154                 d_namlen = 7;
1155                 d_name = "version";
1156                 d_type = DT_REG;
1157                 break;
1158
1159         case 8:
1160                 d_ino = PROCFS_FILENO(0, Ploadavg);
1161                 d_namlen = 7;
1162                 d_name = "loadavg";
1163                 d_type = DT_REG;
1164                 break;
1165         case 9:
1166                 d_ino = PROCFS_FILENO(0, Pnet);
1167                 d_namlen = 3;
1168                 d_name = "net";
1169                 d_type = DT_DIR;
1170                 break;
1171         case 10:
1172                 d_ino = PROCFS_FILENO(0, Psys);
1173                 d_namlen = 3;
1174                 d_name = "sys";
1175                 d_type = DT_DIR;
1176                 break;
1177         case 11:
1178                 d_ino = PROCFS_FILENO(0, Pmounts);
1179                 d_namlen = 6;
1180                 d_name = "mounts";
1181                 d_type = DT_DIR;
1182                 break;
1183         case 12:
1184                 d_ino = PROCFS_FILENO(0, Pdevices);
1185                 d_namlen = 7;
1186                 d_name = "devices";
1187                 d_type = DT_REG;
1188                 break;          
1189         default:
1190                 /*
1191                  * Ignore processes that aren't in our prison
1192                  */
1193                 if (PRISON_CHECK(info->cred, p->p_ucred) == 0)
1194                         return(0);
1195
1196                 /*
1197                  * Ignore processes that we do not want to be visible.
1198                  */
1199                 if (ps_showallprocs == 0 && 
1200                     info->cred->cr_uid != 0 &&
1201                     info->cred->cr_uid != p->p_ucred->cr_uid) {
1202                         return(0);
1203                 }
1204
1205                 /*
1206                  * Skip processes we have already read (optimization)
1207                  */
1208                 if (info->pcnt < info->i) {
1209                         ++info->pcnt;
1210                         return(0);
1211                 }
1212                 d_ino = PROCFS_FILENO(p->p_pid, Pproc);
1213                 d_namlen = ksnprintf(d_name_pid, sizeof(d_name_pid),
1214                     "%ld", (long)p->p_pid);
1215                 d_name = d_name_pid;
1216                 d_type = DT_DIR;
1217                 break;
1218         }
1219
1220         /*
1221          * Skip processes we have already read
1222          */
1223         if (info->pcnt < info->i) {
1224                 ++info->pcnt;
1225                 return(0);
1226         }
1227         retval = vop_write_dirent(&info->error, info->uio, 
1228                                   d_ino, d_type, d_namlen, d_name);
1229         if (retval == 0) {
1230                 ++info->pcnt;   /* iterate proc candidates scanned */
1231                 ++info->i;      /* iterate entries written */
1232         }
1233         if (retval || info->error || uio->uio_resid <= 0)
1234                 return(-1);
1235         return(0);
1236 }
1237
1238 /*
1239  * Scan the root directory by scanning all process
1240  */
1241 static int linprocfs_readdir_net_callback(struct proc *p, void *data);
1242
1243 static int
1244 linprocfs_readdir_net(struct vop_readdir_args *ap)
1245 {
1246         struct linprocfs_readdir_root_info info;
1247         struct uio *uio = ap->a_uio;
1248         int res;
1249
1250         info.error = 0;
1251         info.i = uio->uio_offset;
1252         info.pcnt = 0;
1253         info.uio = uio;
1254         info.cred = ap->a_cred;
1255
1256         while (info.pcnt < 3) {
1257                 res = linprocfs_readdir_net_callback(NULL, &info);
1258                 if (res < 0)
1259                         break;
1260         }
1261
1262         uio->uio_offset = info.i;
1263         return(info.error);
1264 }
1265
1266 static int
1267 linprocfs_readdir_net_callback(struct proc *p, void *data)
1268 {
1269         struct linprocfs_readdir_root_info *info = data;
1270         int retval;
1271         struct uio *uio = info->uio;
1272         ino_t d_ino;
1273         const char *d_name;
1274         size_t d_namlen;
1275         uint8_t d_type;
1276
1277         switch (info->pcnt) {
1278         case 0:         /* `.' */
1279                 d_ino = PROCFS_FILENO(0, Pnet);
1280                 d_name = ".";
1281                 d_namlen = 1;
1282                 d_type = DT_DIR;
1283                 break;
1284         case 1:         /* `..' */
1285                 d_ino = PROCFS_FILENO(0, Proot);
1286                 d_name = "..";
1287                 d_namlen = 2;
1288                 d_type = DT_DIR;
1289                 break;
1290
1291         case 2:
1292                 d_ino = PROCFS_FILENO(0, Pnet);
1293                 d_namlen = 3;
1294                 d_name = "dev";
1295                 d_type = DT_REG;
1296                 break;
1297         default:
1298                 d_ino = 0;
1299                 d_namlen = 0;
1300                 d_name = NULL;
1301                 d_type = DT_REG;
1302                 break;
1303         }
1304
1305         /*
1306          * Skip processes we have already read
1307          */
1308         if (info->pcnt < info->i) {
1309                 ++info->pcnt;
1310                 return(0);
1311         }
1312         retval = vop_write_dirent(&info->error, info->uio, 
1313                                   d_ino, d_type, d_namlen, d_name);
1314         if (retval == 0) {
1315                 ++info->pcnt;   /* iterate proc candidates scanned */
1316                 ++info->i;      /* iterate entries written */
1317         }
1318         if (retval || info->error || uio->uio_resid <= 0)
1319                 return(-1);
1320         return(0);
1321 }
1322
1323
1324
1325
1326
1327
1328
1329 /*
1330  * Scan the root directory by scanning all process
1331  */
1332 static int linprocfs_readdir_sys_callback(struct proc *p, void *data);
1333
1334 static int
1335 linprocfs_readdir_sys(struct vop_readdir_args *ap)
1336 {
1337         struct linprocfs_readdir_root_info info;
1338         struct uio *uio = ap->a_uio;
1339         int res;
1340
1341         info.error = 0;
1342         info.i = uio->uio_offset;
1343         info.pcnt = 0;
1344         info.uio = uio;
1345         info.cred = ap->a_cred;
1346
1347         while (info.pcnt < 3) {
1348                 res = linprocfs_readdir_sys_callback(NULL, &info);
1349                 if (res < 0)
1350                         break;
1351         }
1352
1353         uio->uio_offset = info.i;
1354         return(info.error);
1355 }
1356
1357 static int
1358 linprocfs_readdir_sys_callback(struct proc *p, void *data)
1359 {
1360         struct linprocfs_readdir_root_info *info = data;
1361         int retval;
1362         struct uio *uio = info->uio;
1363         ino_t d_ino;
1364         const char *d_name;
1365         size_t d_namlen;
1366         uint8_t d_type;
1367
1368         switch (info->pcnt) {
1369         case 0:         /* `.' */
1370                 d_ino = PROCFS_FILENO(0, Psys);
1371                 d_name = ".";
1372                 d_namlen = 1;
1373                 d_type = DT_DIR;
1374                 break;
1375         case 1:         /* `..' */
1376                 d_ino = PROCFS_FILENO(0, Proot);
1377                 d_name = "..";
1378                 d_namlen = 2;
1379                 d_type = DT_DIR;
1380                 break;
1381
1382         case 2:
1383                 d_ino = PROCFS_FILENO(0, Psyskernel);
1384                 d_namlen = 6;
1385                 d_name = "kernel";
1386                 d_type = DT_DIR;
1387                 break;
1388         default:
1389                 d_ino = 0;
1390                 d_namlen = 0;
1391                 d_name = NULL;
1392                 d_type = DT_REG;
1393                 break;
1394         }
1395
1396         /*
1397          * Skip processes we have already read
1398          */
1399         if (info->pcnt < info->i) {
1400                 ++info->pcnt;
1401                 return(0);
1402         }
1403         retval = vop_write_dirent(&info->error, info->uio, 
1404                                   d_ino, d_type, d_namlen, d_name);
1405         if (retval == 0) {
1406                 ++info->pcnt;   /* iterate proc candidates scanned */
1407                 ++info->i;      /* iterate entries written */
1408         }
1409         if (retval || info->error || uio->uio_resid <= 0)
1410                 return(-1);
1411         return(0);
1412 }
1413
1414
1415
1416
1417
1418 /*
1419  * Scan the root directory by scanning all process
1420  */
1421 static int linprocfs_readdir_syskernel_callback(struct proc *p, void *data);
1422
1423 static int
1424 linprocfs_readdir_syskernel(struct vop_readdir_args *ap)
1425 {
1426         struct linprocfs_readdir_root_info info;
1427         struct uio *uio = ap->a_uio;
1428         int res;
1429
1430         info.error = 0;
1431         info.i = uio->uio_offset;
1432         info.pcnt = 0;
1433         info.uio = uio;
1434         info.cred = ap->a_cred;
1435
1436         while (info.pcnt < 6) {
1437                 res = linprocfs_readdir_syskernel_callback(NULL, &info);
1438                 if (res < 0)
1439                         break;
1440         }
1441
1442         uio->uio_offset = info.i;
1443         return(info.error);
1444 }
1445
1446 static int
1447 linprocfs_readdir_syskernel_callback(struct proc *p, void *data)
1448 {
1449         struct linprocfs_readdir_root_info *info = data;
1450         int retval;
1451         struct uio *uio = info->uio;
1452         ino_t d_ino;
1453         const char *d_name;
1454         size_t d_namlen;
1455         uint8_t d_type;
1456
1457         switch (info->pcnt) {
1458         case 0:         /* `.' */
1459                 d_ino = PROCFS_FILENO(0, Psyskernel);
1460                 d_name = ".";
1461                 d_namlen = 1;
1462                 d_type = DT_DIR;
1463                 break;
1464         case 1:         /* `..' */
1465                 d_ino = PROCFS_FILENO(0, Psys);
1466                 d_name = "..";
1467                 d_namlen = 2;
1468                 d_type = DT_DIR;
1469                 break;
1470
1471         case 2:
1472                 d_ino = PROCFS_FILENO(0, Posrelease);
1473                 d_namlen = 9;
1474                 d_name = "osrelease";
1475                 d_type = DT_REG;
1476                 break;
1477
1478         case 3:
1479                 d_ino = PROCFS_FILENO(0, Postype);
1480                 d_namlen = 4;
1481                 d_name = "ostype";
1482                 d_type = DT_REG;
1483                 break;
1484
1485         case 4:
1486                 d_ino = PROCFS_FILENO(0, Pversion);
1487                 d_namlen = 7;
1488                 d_name = "version";
1489                 d_type = DT_REG;
1490                 break;
1491
1492         case 5:
1493                 d_ino = PROCFS_FILENO(0, Ppidmax);
1494                 d_namlen = 7;
1495                 d_name = "pid_max";
1496                 d_type = DT_REG;
1497                 break;
1498         default:
1499                 d_ino = 0;
1500                 d_namlen = 0;
1501                 d_name = NULL;
1502                 d_type = DT_REG;
1503                 break;
1504         }
1505
1506         /*
1507          * Skip processes we have already read
1508          */
1509         if (info->pcnt < info->i) {
1510                 ++info->pcnt;
1511                 return(0);
1512         }
1513         retval = vop_write_dirent(&info->error, info->uio, 
1514                                   d_ino, d_type, d_namlen, d_name);
1515         if (retval == 0) {
1516                 ++info->pcnt;   /* iterate proc candidates scanned */
1517                 ++info->i;      /* iterate entries written */
1518         }
1519         if (retval || info->error || uio->uio_resid <= 0)
1520                 return(-1);
1521         return(0);
1522 }
1523
1524 /*
1525  * readlink reads the link of `self' or `exe'
1526  */
1527 static int
1528 linprocfs_readlink(struct vop_readlink_args *ap)
1529 {
1530         char buf[16];           /* should be enough */
1531         struct proc *procp;
1532         struct vnode *vp = ap->a_vp;
1533         struct nchandle *nchp;
1534         struct pfsnode *pfs = VTOPFS(vp);
1535         char *fullpath, *freepath;
1536         int error, len;
1537
1538         error = 0;
1539         procp = NULL;
1540
1541         switch (pfs->pfs_type) {
1542         case Pself:
1543                 if (pfs->pfs_fileno != PROCFS_FILENO(0, Pself))
1544                         return (EINVAL);
1545
1546                 len = ksnprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
1547
1548                 error = uiomove(buf, len, ap->a_uio);
1549                 break;
1550         /*
1551          * There _should_ be no way for an entire process to disappear
1552          * from under us...
1553          */
1554         case Pexe:
1555                 procp = linprocfs_pfind(pfs->pfs_pid);
1556                 if (procp == NULL || procp->p_ucred == NULL) {
1557                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1558                             pfs->pfs_pid);
1559                         error = uiomove("unknown", sizeof("unknown") - 1,
1560                                         ap->a_uio);
1561                         break;
1562                 }
1563                 error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0);
1564                 if (error != 0) {
1565                         error = uiomove("unknown", sizeof("unknown") - 1,
1566                                         ap->a_uio);
1567                         break;
1568                 }
1569                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1570                 kfree(freepath, M_TEMP);
1571                 break;
1572         case Pcwd:
1573                 procp = linprocfs_pfind(pfs->pfs_pid);
1574                 if (procp == NULL || procp->p_ucred == NULL) {
1575                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1576                                 pfs->pfs_pid);
1577                         error = uiomove("unknown", sizeof("unknown") - 1,
1578                                         ap->a_uio);
1579                         break;
1580                 }
1581                 error = cache_fullpath(procp, &procp->p_fd->fd_ncdir,
1582                                        &fullpath, &freepath, 0);
1583                 if (error != 0) {
1584                         error = uiomove("unknown", sizeof("unknown") - 1,
1585                                         ap->a_uio);
1586                         break;
1587                 }
1588                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1589                 kfree(freepath, M_TEMP);
1590                 break;
1591         case Pprocroot:
1592                 procp = linprocfs_pfind(pfs->pfs_pid);
1593                 if (procp == NULL || procp->p_ucred == NULL) {
1594                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1595                             pfs->pfs_pid);
1596                         error = uiomove("unknown", sizeof("unknown") - 1,
1597                                         ap->a_uio);
1598                         break;
1599                 }
1600                 nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
1601                 error = cache_fullpath(procp, nchp, &fullpath, &freepath, 0);
1602                 if (error != 0) {
1603                         error = uiomove("unknown", sizeof("unknown") - 1,
1604                                         ap->a_uio);
1605                         break;
1606                 }
1607                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1608                 kfree(freepath, M_TEMP);
1609                 break;
1610         case Pfd:
1611                 procp = linprocfs_pfind(pfs->pfs_pid);
1612                 if (procp == NULL || procp->p_ucred == NULL) {
1613                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1614                             pfs->pfs_pid);
1615                         error = uiomove("unknown", sizeof("unknown") - 1,
1616                                         ap->a_uio);
1617                         break;
1618                 }
1619                 if (procp == curproc) {
1620                         error = uiomove("/dev/fd", sizeof("/dev/fd") - 1,
1621                                         ap->a_uio);
1622                         break;
1623                 } else {
1624                         error = uiomove("unknown", sizeof("unknown") - 1,
1625                                         ap->a_uio);
1626                         break;
1627                 }
1628                 /* notreached */
1629                 break;
1630         default:
1631                 error = EINVAL;
1632                 break;
1633         }
1634         if (procp)
1635                 PRELE(procp);
1636         return error;
1637 }
1638
1639 /*
1640  * convert decimal ascii to pid_t
1641  */
1642 static pid_t
1643 atopid(const char *b, u_int len)
1644 {
1645         pid_t p = 0;
1646
1647         while (len--) {
1648                 char c = *b++;
1649                 if (c < '0' || c > '9')
1650                         return (NO_PID);
1651                 p = 10 * p + (c - '0');
1652                 if (p > PID_MAX)
1653                         return (NO_PID);
1654         }
1655
1656         return (p);
1657 }
1658