linprocfs - Fix process exit / procfs vnode access race & stepping races
[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
867                 pid = atopid(pname, cnp->cn_namelen);
868                 if (pid == NO_PID)
869                         break;
870
871                 p = linprocfs_pfind(pid);
872                 if (p == NULL)
873                         break;
874
875                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
876                         break;
877
878                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
879                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
880                         break;
881
882                 error = linprocfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
883                 goto out;
884
885         case Pproc:
886                 if (cnp->cn_flags & CNP_ISDOTDOT) {
887                         error = linprocfs_root(dvp->v_mount, vpp);
888                         goto out;
889                 }
890
891                 p = linprocfs_pfind(pfs->pfs_pid);
892                 if (p == NULL)
893                         break;
894
895                 if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred))
896                         break;
897
898                 if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 &&
899                     ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid)
900                         break;
901
902                 for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
903                         if (cnp->cn_namelen == pt->pt_namlen &&
904                             bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
905                             (pt->pt_valid == NULL || (*pt->pt_valid)(p)))
906                                 goto found;
907                 }
908                 break;
909
910         found:
911                 error = linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
912                                         pt->pt_pfstype);
913                 goto out;
914
915         default:
916                 error = ENOTDIR;
917                 goto out;
918         }
919
920         if (cnp->cn_nameiop == NAMEI_LOOKUP)
921                 error = ENOENT;
922         else
923                 error = EROFS;
924
925         /*
926          * If no error occured *vpp will hold a referenced locked vnode.
927          * dvp was passed to us locked and *vpp must be returned locked
928          * so if dvp != *vpp and CNP_LOCKPARENT is not set, unlock dvp.
929          */
930 out:
931         if (p)
932                 PRELE(p);
933         if (error == 0) {
934                 if (*vpp != dvp && (cnp->cn_flags & CNP_LOCKPARENT) == 0) {
935                         cnp->cn_flags |= CNP_PDIRUNLOCK;
936                         vn_unlock(dvp);
937                 }
938         }
939         return (error);
940 }
941
942 /*
943  * Does this process have a text file?
944  */
945 int
946 linprocfs_validfile(struct proc *p)
947 {
948
949         return (procfs_findtextvp(p) != NULLVP);
950 }
951
952 /*
953  * readdir() returns directory entries from pfsnode (vp).
954  *
955  * We generate just one directory entry at a time, as it would probably
956  * not pay off to buffer several entries locally to save uiomove calls.
957  *
958  * linprocfs_readdir(struct vnode *a_vp, struct uio *a_uio,
959  *                   struct ucred *a_cred, int *a_eofflag,
960  *                   int *a_ncookies, off_t **a_cookies)
961  */
962 static int
963 linprocfs_readdir(struct vop_readdir_args *ap)
964 {
965         struct pfsnode *pfs;
966         int error;
967
968         if (ap->a_uio->uio_offset < 0 || ap->a_uio->uio_offset > INT_MAX)
969                 return (EINVAL);
970
971         pfs = VTOPFS(ap->a_vp);
972         if ((error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
973                 return (error);
974
975         switch (pfs->pfs_type) {
976         case Pproc:
977                 /*
978                  * This is for the process-specific sub-directories.
979                  * all that is needed to is copy out all the entries
980                  * from the procent[] table (top of this file).
981                  */
982                 error = linprocfs_readdir_proc(ap);
983                 break;
984         case Proot:
985                 /*
986                  * This is for the root of the procfs filesystem
987                  * what is needed is a special entry for "self"
988                  * followed by an entry for each process on allproc
989                  */
990                 error = linprocfs_readdir_root(ap);
991                 break;
992         case Pnet:
993                 error = linprocfs_readdir_net(ap);
994                 break;
995         case Psys:
996                 error = linprocfs_readdir_sys(ap);
997                 break;
998         case Psyskernel:
999                 error = linprocfs_readdir_syskernel(ap);
1000                 break;
1001         default:
1002                 error = ENOTDIR;
1003                 break;
1004         }
1005         vn_unlock(ap->a_vp);
1006
1007         return (error);
1008 }
1009
1010 static int
1011 linprocfs_readdir_proc(struct vop_readdir_args *ap)
1012 {
1013         struct pfsnode *pfs;
1014         int error, i, retval;
1015         struct proc *p;
1016         struct proc_target *pt;
1017         struct uio *uio = ap->a_uio;
1018
1019         pfs = VTOPFS(ap->a_vp);
1020         p = linprocfs_pfind(pfs->pfs_pid);
1021         if (p == NULL)
1022                 return(0);
1023         if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) {
1024                 PRELE(p);
1025                 return(0);
1026         }
1027
1028         error = 0;
1029         i = uio->uio_offset;
1030
1031         for (pt = &proc_targets[i];
1032              !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) {
1033                 if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
1034                         continue;
1035
1036                 retval = vop_write_dirent(&error, uio,
1037                     PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype), pt->pt_type,
1038                     pt->pt_namlen, pt->pt_name);
1039                 if (retval)
1040                         break;
1041         }
1042
1043         uio->uio_offset = i;
1044         PRELE(p);
1045
1046         return(error);
1047 }
1048
1049 struct linprocfs_readdir_root_info {
1050         int error;
1051         int pcnt;
1052         int i;
1053         struct uio *uio;
1054         struct ucred *cred;
1055 };
1056
1057 /*
1058  * Scan the root directory by scanning all process
1059  */
1060 static int linprocfs_readdir_root_callback(struct proc *p, void *data);
1061
1062 static int
1063 linprocfs_readdir_root(struct vop_readdir_args *ap)
1064 {
1065         struct linprocfs_readdir_root_info info;
1066         struct uio *uio = ap->a_uio;
1067         int res = 0;
1068
1069         info.error = 0;
1070         info.i = uio->uio_offset;
1071         info.pcnt = 0;
1072         info.uio = uio;
1073         info.cred = ap->a_cred;
1074
1075         while (info.pcnt < 12) {
1076                 res = linprocfs_readdir_root_callback(NULL, &info);
1077                 if (res < 0)
1078                         break;
1079         }
1080         if (res >= 0)
1081                 allproc_scan(linprocfs_readdir_root_callback, &info);
1082
1083         uio->uio_offset = info.i;
1084         return(info.error);
1085 }
1086
1087 static int
1088 linprocfs_readdir_root_callback(struct proc *p, void *data)
1089 {
1090         struct linprocfs_readdir_root_info *info = data;
1091         int retval;
1092         struct uio *uio = info->uio;
1093         ino_t d_ino;
1094         const char *d_name;
1095         char d_name_pid[20];
1096         size_t d_namlen;
1097         uint8_t d_type;
1098
1099         switch (info->pcnt) {
1100         case 0:         /* `.' */
1101                 d_ino = PROCFS_FILENO(0, Proot);
1102                 d_name = ".";
1103                 d_namlen = 1;
1104                 d_type = DT_DIR;
1105                 break;
1106         case 1:         /* `..' */
1107                 d_ino = PROCFS_FILENO(0, Proot);
1108                 d_name = "..";
1109                 d_namlen = 2;
1110                 d_type = DT_DIR;
1111                 break;
1112
1113         case 2:
1114                 d_ino = PROCFS_FILENO(0, Proot);
1115                 d_namlen = 4;
1116                 d_name = "self";
1117                 d_type = DT_LNK;
1118                 break;
1119
1120         case 3:
1121                 d_ino = PROCFS_FILENO(0, Pmeminfo);
1122                 d_namlen = 7;
1123                 d_name = "meminfo";
1124                 d_type = DT_REG;
1125                 break;
1126
1127         case 4:
1128                 d_ino = PROCFS_FILENO(0, Pcpuinfo);
1129                 d_namlen = 7;
1130                 d_name = "cpuinfo";
1131                 d_type = DT_REG;
1132                 break;
1133
1134         case 5:
1135                 d_ino = PROCFS_FILENO(0, Pstat);
1136                 d_namlen = 4;
1137                 d_name = "stat";
1138                 d_type = DT_REG;
1139                 break;
1140                     
1141         case 6:
1142                 d_ino = PROCFS_FILENO(0, Puptime);
1143                 d_namlen = 6;
1144                 d_name = "uptime";
1145                 d_type = DT_REG;
1146                 break;
1147
1148         case 7:
1149                 d_ino = PROCFS_FILENO(0, Pversion);
1150                 d_namlen = 7;
1151                 d_name = "version";
1152                 d_type = DT_REG;
1153                 break;
1154
1155         case 8:
1156                 d_ino = PROCFS_FILENO(0, Ploadavg);
1157                 d_namlen = 7;
1158                 d_name = "loadavg";
1159                 d_type = DT_REG;
1160                 break;
1161         case 9:
1162                 d_ino = PROCFS_FILENO(0, Pnet);
1163                 d_namlen = 3;
1164                 d_name = "net";
1165                 d_type = DT_DIR;
1166                 break;
1167         case 10:
1168                 d_ino = PROCFS_FILENO(0, Psys);
1169                 d_namlen = 3;
1170                 d_name = "sys";
1171                 d_type = DT_DIR;
1172                 break;
1173         case 11:
1174                 d_ino = PROCFS_FILENO(0, Pmounts);
1175                 d_namlen = 6;
1176                 d_name = "mounts";
1177                 d_type = DT_DIR;
1178                 break;
1179 #if 0
1180         case 11:
1181                 d_ino = PROCFS_FILENO(0, Pdevices);
1182                 d_namlen = 7;
1183                 d_name = "devices";
1184                 d_type = DT_REG;
1185                 break;          
1186 #endif
1187         default:
1188                 /*
1189                  * Ignore processes that aren't in our prison
1190                  */
1191                 if (PRISON_CHECK(info->cred, p->p_ucred) == 0)
1192                         return(0);
1193
1194                 /*
1195                  * Ignore processes that we do not want to be visible.
1196                  */
1197                 if (ps_showallprocs == 0 && 
1198                     info->cred->cr_uid != 0 &&
1199                     info->cred->cr_uid != p->p_ucred->cr_uid) {
1200                         return(0);
1201                 }
1202
1203                 /*
1204                  * Skip processes we have already read (optimization)
1205                  */
1206                 if (info->pcnt < info->i) {
1207                         ++info->pcnt;
1208                         return(0);
1209                 }
1210                 d_ino = PROCFS_FILENO(p->p_pid, Pproc);
1211                 d_namlen = ksnprintf(d_name_pid, sizeof(d_name_pid),
1212                     "%ld", (long)p->p_pid);
1213                 d_name = d_name_pid;
1214                 d_type = DT_DIR;
1215                 break;
1216         }
1217
1218         /*
1219          * Skip processes we have already read
1220          */
1221         if (info->pcnt < info->i) {
1222                 ++info->pcnt;
1223                 return(0);
1224         }
1225         retval = vop_write_dirent(&info->error, info->uio, 
1226                                   d_ino, d_type, d_namlen, d_name);
1227         if (retval == 0) {
1228                 ++info->pcnt;   /* iterate proc candidates scanned */
1229                 ++info->i;      /* iterate entries written */
1230         }
1231         if (retval || info->error || uio->uio_resid <= 0)
1232                 return(-1);
1233         return(0);
1234 }
1235
1236 /*
1237  * Scan the root directory by scanning all process
1238  */
1239 static int linprocfs_readdir_net_callback(struct proc *p, void *data);
1240
1241 static int
1242 linprocfs_readdir_net(struct vop_readdir_args *ap)
1243 {
1244         struct linprocfs_readdir_root_info info;
1245         struct uio *uio = ap->a_uio;
1246         int res;
1247
1248         info.error = 0;
1249         info.i = uio->uio_offset;
1250         info.pcnt = 0;
1251         info.uio = uio;
1252         info.cred = ap->a_cred;
1253
1254         while (info.pcnt < 3) {
1255                 res = linprocfs_readdir_net_callback(NULL, &info);
1256                 if (res < 0)
1257                         break;
1258         }
1259
1260         uio->uio_offset = info.i;
1261         return(info.error);
1262 }
1263
1264 static int
1265 linprocfs_readdir_net_callback(struct proc *p, void *data)
1266 {
1267         struct linprocfs_readdir_root_info *info = data;
1268         int retval;
1269         struct uio *uio = info->uio;
1270         ino_t d_ino;
1271         const char *d_name;
1272         size_t d_namlen;
1273         uint8_t d_type;
1274
1275         switch (info->pcnt) {
1276         case 0:         /* `.' */
1277                 d_ino = PROCFS_FILENO(0, Pnet);
1278                 d_name = ".";
1279                 d_namlen = 1;
1280                 d_type = DT_DIR;
1281                 break;
1282         case 1:         /* `..' */
1283                 d_ino = PROCFS_FILENO(0, Proot);
1284                 d_name = "..";
1285                 d_namlen = 2;
1286                 d_type = DT_DIR;
1287                 break;
1288
1289         case 2:
1290                 d_ino = PROCFS_FILENO(0, Pnet);
1291                 d_namlen = 3;
1292                 d_name = "dev";
1293                 d_type = DT_REG;
1294                 break;
1295         default:
1296                 d_ino = 0;
1297                 d_namlen = 0;
1298                 d_name = NULL;
1299                 d_type = DT_REG;
1300                 break;
1301         }
1302
1303         /*
1304          * Skip processes we have already read
1305          */
1306         if (info->pcnt < info->i) {
1307                 ++info->pcnt;
1308                 return(0);
1309         }
1310         retval = vop_write_dirent(&info->error, info->uio, 
1311                                   d_ino, d_type, d_namlen, d_name);
1312         if (retval == 0) {
1313                 ++info->pcnt;   /* iterate proc candidates scanned */
1314                 ++info->i;      /* iterate entries written */
1315         }
1316         if (retval || info->error || uio->uio_resid <= 0)
1317                 return(-1);
1318         return(0);
1319 }
1320
1321
1322
1323
1324
1325
1326
1327 /*
1328  * Scan the root directory by scanning all process
1329  */
1330 static int linprocfs_readdir_sys_callback(struct proc *p, void *data);
1331
1332 static int
1333 linprocfs_readdir_sys(struct vop_readdir_args *ap)
1334 {
1335         struct linprocfs_readdir_root_info info;
1336         struct uio *uio = ap->a_uio;
1337         int res;
1338
1339         info.error = 0;
1340         info.i = uio->uio_offset;
1341         info.pcnt = 0;
1342         info.uio = uio;
1343         info.cred = ap->a_cred;
1344
1345         while (info.pcnt < 3) {
1346                 res = linprocfs_readdir_sys_callback(NULL, &info);
1347                 if (res < 0)
1348                         break;
1349         }
1350
1351         uio->uio_offset = info.i;
1352         return(info.error);
1353 }
1354
1355 static int
1356 linprocfs_readdir_sys_callback(struct proc *p, void *data)
1357 {
1358         struct linprocfs_readdir_root_info *info = data;
1359         int retval;
1360         struct uio *uio = info->uio;
1361         ino_t d_ino;
1362         const char *d_name;
1363         size_t d_namlen;
1364         uint8_t d_type;
1365
1366         switch (info->pcnt) {
1367         case 0:         /* `.' */
1368                 d_ino = PROCFS_FILENO(0, Psys);
1369                 d_name = ".";
1370                 d_namlen = 1;
1371                 d_type = DT_DIR;
1372                 break;
1373         case 1:         /* `..' */
1374                 d_ino = PROCFS_FILENO(0, Proot);
1375                 d_name = "..";
1376                 d_namlen = 2;
1377                 d_type = DT_DIR;
1378                 break;
1379
1380         case 2:
1381                 d_ino = PROCFS_FILENO(0, Psyskernel);
1382                 d_namlen = 6;
1383                 d_name = "kernel";
1384                 d_type = DT_DIR;
1385                 break;
1386         default:
1387                 d_ino = 0;
1388                 d_namlen = 0;
1389                 d_name = NULL;
1390                 d_type = DT_REG;
1391                 break;
1392         }
1393
1394         /*
1395          * Skip processes we have already read
1396          */
1397         if (info->pcnt < info->i) {
1398                 ++info->pcnt;
1399                 return(0);
1400         }
1401         retval = vop_write_dirent(&info->error, info->uio, 
1402                                   d_ino, d_type, d_namlen, d_name);
1403         if (retval == 0) {
1404                 ++info->pcnt;   /* iterate proc candidates scanned */
1405                 ++info->i;      /* iterate entries written */
1406         }
1407         if (retval || info->error || uio->uio_resid <= 0)
1408                 return(-1);
1409         return(0);
1410 }
1411
1412
1413
1414
1415
1416 /*
1417  * Scan the root directory by scanning all process
1418  */
1419 static int linprocfs_readdir_syskernel_callback(struct proc *p, void *data);
1420
1421 static int
1422 linprocfs_readdir_syskernel(struct vop_readdir_args *ap)
1423 {
1424         struct linprocfs_readdir_root_info info;
1425         struct uio *uio = ap->a_uio;
1426         int res;
1427
1428         info.error = 0;
1429         info.i = uio->uio_offset;
1430         info.pcnt = 0;
1431         info.uio = uio;
1432         info.cred = ap->a_cred;
1433
1434         while (info.pcnt < 6) {
1435                 res = linprocfs_readdir_syskernel_callback(NULL, &info);
1436                 if (res < 0)
1437                         break;
1438         }
1439
1440         uio->uio_offset = info.i;
1441         return(info.error);
1442 }
1443
1444 static int
1445 linprocfs_readdir_syskernel_callback(struct proc *p, void *data)
1446 {
1447         struct linprocfs_readdir_root_info *info = data;
1448         int retval;
1449         struct uio *uio = info->uio;
1450         ino_t d_ino;
1451         const char *d_name;
1452         size_t d_namlen;
1453         uint8_t d_type;
1454
1455         switch (info->pcnt) {
1456         case 0:         /* `.' */
1457                 d_ino = PROCFS_FILENO(0, Psyskernel);
1458                 d_name = ".";
1459                 d_namlen = 1;
1460                 d_type = DT_DIR;
1461                 break;
1462         case 1:         /* `..' */
1463                 d_ino = PROCFS_FILENO(0, Psys);
1464                 d_name = "..";
1465                 d_namlen = 2;
1466                 d_type = DT_DIR;
1467                 break;
1468
1469         case 2:
1470                 d_ino = PROCFS_FILENO(0, Posrelease);
1471                 d_namlen = 9;
1472                 d_name = "osrelease";
1473                 d_type = DT_REG;
1474                 break;
1475
1476         case 3:
1477                 d_ino = PROCFS_FILENO(0, Postype);
1478                 d_namlen = 4;
1479                 d_name = "ostype";
1480                 d_type = DT_REG;
1481                 break;
1482
1483         case 4:
1484                 d_ino = PROCFS_FILENO(0, Pversion);
1485                 d_namlen = 7;
1486                 d_name = "version";
1487                 d_type = DT_REG;
1488                 break;
1489
1490         case 5:
1491                 d_ino = PROCFS_FILENO(0, Ppidmax);
1492                 d_namlen = 7;
1493                 d_name = "pid_max";
1494                 d_type = DT_REG;
1495                 break;
1496         default:
1497                 d_ino = 0;
1498                 d_namlen = 0;
1499                 d_name = NULL;
1500                 d_type = DT_REG;
1501                 break;
1502         }
1503
1504         /*
1505          * Skip processes we have already read
1506          */
1507         if (info->pcnt < info->i) {
1508                 ++info->pcnt;
1509                 return(0);
1510         }
1511         retval = vop_write_dirent(&info->error, info->uio, 
1512                                   d_ino, d_type, d_namlen, d_name);
1513         if (retval == 0) {
1514                 ++info->pcnt;   /* iterate proc candidates scanned */
1515                 ++info->i;      /* iterate entries written */
1516         }
1517         if (retval || info->error || uio->uio_resid <= 0)
1518                 return(-1);
1519         return(0);
1520 }
1521
1522 /*
1523  * readlink reads the link of `self' or `exe'
1524  */
1525 static int
1526 linprocfs_readlink(struct vop_readlink_args *ap)
1527 {
1528         char buf[16];           /* should be enough */
1529         struct proc *procp;
1530         struct vnode *vp = ap->a_vp;
1531         struct nchandle *nchp;
1532         struct pfsnode *pfs = VTOPFS(vp);
1533         char *fullpath, *freepath;
1534         int error, len;
1535
1536         error = 0;
1537         procp = NULL;
1538
1539         switch (pfs->pfs_type) {
1540         case Pself:
1541                 if (pfs->pfs_fileno != PROCFS_FILENO(0, Pself))
1542                         return (EINVAL);
1543
1544                 len = ksnprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
1545
1546                 error = uiomove(buf, len, ap->a_uio);
1547                 break;
1548         /*
1549          * There _should_ be no way for an entire process to disappear
1550          * from under us...
1551          */
1552         case Pexe:
1553                 procp = linprocfs_pfind(pfs->pfs_pid);
1554                 if (procp == NULL || procp->p_ucred == NULL) {
1555                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1556                             pfs->pfs_pid);
1557                         error = uiomove("unknown", sizeof("unknown") - 1,
1558                                         ap->a_uio);
1559                         break;
1560                 }
1561                 error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0);
1562                 if (error != 0) {
1563                         error = uiomove("unknown", sizeof("unknown") - 1,
1564                                         ap->a_uio);
1565                         break;
1566                 }
1567                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1568                 kfree(freepath, M_TEMP);
1569                 break;
1570         case Pcwd:
1571                 procp = linprocfs_pfind(pfs->pfs_pid);
1572                 if (procp == NULL || procp->p_ucred == NULL) {
1573                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1574                                 pfs->pfs_pid);
1575                         error = uiomove("unknown", sizeof("unknown") - 1,
1576                                         ap->a_uio);
1577                         break;
1578                 }
1579                 error = cache_fullpath(procp, &procp->p_fd->fd_ncdir,
1580                                        &fullpath, &freepath, 0);
1581                 if (error != 0) {
1582                         error = uiomove("unknown", sizeof("unknown") - 1,
1583                                         ap->a_uio);
1584                         break;
1585                 }
1586                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1587                 kfree(freepath, M_TEMP);
1588                 break;
1589         case Pprocroot:
1590                 procp = linprocfs_pfind(pfs->pfs_pid);
1591                 if (procp == NULL || procp->p_ucred == NULL) {
1592                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1593                             pfs->pfs_pid);
1594                         error = uiomove("unknown", sizeof("unknown") - 1,
1595                                         ap->a_uio);
1596                         break;
1597                 }
1598                 nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
1599                 error = cache_fullpath(procp, nchp, &fullpath, &freepath, 0);
1600                 if (error != 0) {
1601                         error = uiomove("unknown", sizeof("unknown") - 1,
1602                                         ap->a_uio);
1603                         break;
1604                 }
1605                 error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
1606                 kfree(freepath, M_TEMP);
1607                 break;
1608         case Pfd:
1609                 procp = linprocfs_pfind(pfs->pfs_pid);
1610                 if (procp == NULL || procp->p_ucred == NULL) {
1611                         kprintf("linprocfs_readlink: pid %d disappeared\n",
1612                             pfs->pfs_pid);
1613                         error = uiomove("unknown", sizeof("unknown") - 1,
1614                                         ap->a_uio);
1615                         break;
1616                 }
1617                 if (procp == curproc) {
1618                         error = uiomove("/dev/fd", sizeof("/dev/fd") - 1,
1619                                         ap->a_uio);
1620                         break;
1621                 } else {
1622                         error = uiomove("unknown", sizeof("unknown") - 1,
1623                                         ap->a_uio);
1624                         break;
1625                 }
1626                 /* notreached */
1627                 break;
1628         default:
1629                 error = EINVAL;
1630                 break;
1631         }
1632         if (procp)
1633                 PRELE(procp);
1634         return error;
1635 }
1636
1637 /*
1638  * convert decimal ascii to pid_t
1639  */
1640 static pid_t
1641 atopid(const char *b, u_int len)
1642 {
1643         pid_t p = 0;
1644
1645         while (len--) {
1646                 char c = *b++;
1647                 if (c < '0' || c > '9')
1648                         return (NO_PID);
1649                 p = 10 * p + (c - '0');
1650                 if (p > PID_MAX)
1651                         return (NO_PID);
1652         }
1653
1654         return (p);
1655 }
1656