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