1*65524Spendry /*
2*65524Spendry  * Copyright (c) 1993 The Regents of the University of California.
3*65524Spendry  * Copyright (c) 1993 Jan-Simon Pendry
4*65524Spendry  * All rights reserved.
5*65524Spendry  *
6*65524Spendry  * This code is derived from software contributed to Berkeley by
7*65524Spendry  * Jan-Simon Pendry.
8*65524Spendry  *
9*65524Spendry  * %sccs.include.redist.c%
10*65524Spendry  *
11*65524Spendry  *	@(#)procfs_vnops.c	8.1 (Berkeley) 01/05/94
12*65524Spendry  *
13*65524Spendry  * From:
14*65524Spendry  *	$Id: procfs_vnops.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
15*65524Spendry  */
16*65524Spendry 
17*65524Spendry /*
18*65524Spendry  * procfs vnode interface
19*65524Spendry  */
20*65524Spendry 
21*65524Spendry #include <sys/param.h>
22*65524Spendry #include <sys/systm.h>
23*65524Spendry #include <sys/time.h>
24*65524Spendry #include <sys/kernel.h>
25*65524Spendry #include <sys/file.h>
26*65524Spendry #include <sys/proc.h>
27*65524Spendry #include <sys/vnode.h>
28*65524Spendry #include <sys/namei.h>
29*65524Spendry #include <sys/malloc.h>
30*65524Spendry #include <sys/dirent.h>
31*65524Spendry #include <sys/resourcevar.h>
32*65524Spendry #include <miscfs/procfs/procfs.h>
33*65524Spendry #include <vm/vm.h>	/* for PAGE_SIZE */
34*65524Spendry 
35*65524Spendry /*
36*65524Spendry  * Vnode Operations.
37*65524Spendry  *
38*65524Spendry  */
39*65524Spendry 
40*65524Spendry /*
41*65524Spendry  * This is a list of the valid names in the
42*65524Spendry  * process-specific sub-directories.  It is
43*65524Spendry  * used in procfs_lookup and procfs_readdir
44*65524Spendry  */
45*65524Spendry static struct pfsnames {
46*65524Spendry 	u_short	d_namlen;
47*65524Spendry 	char	d_name[PROCFS_NAMELEN];
48*65524Spendry 	pfstype	d_pfstype;
49*65524Spendry } procent[] = {
50*65524Spendry #define N(s) sizeof(s)-1, s
51*65524Spendry 	/* namlen, nam, type */
52*65524Spendry 	{  N("file"),   Pfile },
53*65524Spendry 	{  N("mem"),    Pmem },
54*65524Spendry 	{  N("regs"),   Pregs },
55*65524Spendry 	{  N("ctl"),    Pctl },
56*65524Spendry 	{  N("status"), Pstatus },
57*65524Spendry 	{  N("note"),   Pnote },
58*65524Spendry 	{  N("notepg"), Pnotepg },
59*65524Spendry #undef N
60*65524Spendry };
61*65524Spendry #define Nprocent (sizeof(procent)/sizeof(procent[0]))
62*65524Spendry 
63*65524Spendry static pid_t atopid __P((const char *, u_int));
64*65524Spendry 
65*65524Spendry /*
66*65524Spendry  * set things up for doing i/o on
67*65524Spendry  * the pfsnode (vp).  (vp) is locked
68*65524Spendry  * on entry, and should be left locked
69*65524Spendry  * on exit.
70*65524Spendry  *
71*65524Spendry  * for procfs we don't need to do anything
72*65524Spendry  * in particular for i/o.  all that is done
73*65524Spendry  * is to support exclusive open on process
74*65524Spendry  * memory images.
75*65524Spendry  */
76*65524Spendry procfs_open(ap)
77*65524Spendry 	struct vop_open_args *ap;
78*65524Spendry {
79*65524Spendry 	struct pfsnode *pfs = VTOPFS(ap->a_vp);
80*65524Spendry 
81*65524Spendry 	switch (pfs->pfs_type) {
82*65524Spendry 	case Pmem:
83*65524Spendry 		if (PFIND(pfs->pfs_pid) == 0)
84*65524Spendry 			return (ENOENT);	/* was ESRCH, jsp */
85*65524Spendry 
86*65524Spendry 		if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) ||
87*65524Spendry 				(pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))
88*65524Spendry 			return (EBUSY);
89*65524Spendry 
90*65524Spendry 
91*65524Spendry 		if (ap->a_mode & FWRITE)
92*65524Spendry 			pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
93*65524Spendry 
94*65524Spendry 		return (0);
95*65524Spendry 
96*65524Spendry 	default:
97*65524Spendry 		break;
98*65524Spendry 	}
99*65524Spendry 
100*65524Spendry 	return (0);
101*65524Spendry }
102*65524Spendry 
103*65524Spendry /*
104*65524Spendry  * close the pfsnode (vp) after doing i/o.
105*65524Spendry  * (vp) is not locked on entry or exit.
106*65524Spendry  *
107*65524Spendry  * nothing to do for procfs other than undo
108*65524Spendry  * any exclusive open flag (see _open above).
109*65524Spendry  */
110*65524Spendry procfs_close(ap)
111*65524Spendry 	struct vop_close_args *ap;
112*65524Spendry {
113*65524Spendry 	struct pfsnode *pfs = VTOPFS(ap->a_vp);
114*65524Spendry 
115*65524Spendry 	switch (pfs->pfs_type) {
116*65524Spendry 	case Pmem:
117*65524Spendry 		if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
118*65524Spendry 			pfs->pfs_flags &= ~(FWRITE|O_EXCL);
119*65524Spendry 		break;
120*65524Spendry 	}
121*65524Spendry 
122*65524Spendry 	return (0);
123*65524Spendry }
124*65524Spendry 
125*65524Spendry /*
126*65524Spendry  * do an ioctl operation on pfsnode (vp).
127*65524Spendry  * (vp) is not locked on entry or exit.
128*65524Spendry  */
129*65524Spendry procfs_ioctl(ap)
130*65524Spendry 	struct vop_ioctl_args *ap;
131*65524Spendry {
132*65524Spendry 
133*65524Spendry 	return (ENOTTY);
134*65524Spendry }
135*65524Spendry 
136*65524Spendry /*
137*65524Spendry  * do block mapping for pfsnode (vp).
138*65524Spendry  * since we don't use the buffer cache
139*65524Spendry  * for procfs this function should never
140*65524Spendry  * be called.  in any case, it's not clear
141*65524Spendry  * what part of the kernel ever makes use
142*65524Spendry  * of this function.  for sanity, this is the
143*65524Spendry  * usual no-op bmap, although returning
144*65524Spendry  * (EIO) would be a reasonable alternative.
145*65524Spendry  */
146*65524Spendry procfs_bmap(ap)
147*65524Spendry 	struct vop_bmap_args *ap;
148*65524Spendry {
149*65524Spendry 
150*65524Spendry 	if (ap->a_vpp != NULL)
151*65524Spendry 		*ap->a_vpp = ap->a_vp;
152*65524Spendry 	if (ap->a_bnp != NULL)
153*65524Spendry 		*ap->a_bnp = ap->a_bn;
154*65524Spendry 	return (0);
155*65524Spendry }
156*65524Spendry 
157*65524Spendry /*
158*65524Spendry  * _inactive is called when the pfsnode
159*65524Spendry  * is vrele'd and the reference count goes
160*65524Spendry  * to zero.  (vp) will be on the vnode free
161*65524Spendry  * list, so to get it back vget() must be
162*65524Spendry  * used.
163*65524Spendry  *
164*65524Spendry  * for procfs, check if the process is still
165*65524Spendry  * alive and if it isn't then just throw away
166*65524Spendry  * the vnode by calling vgone().  this may
167*65524Spendry  * be overkill and a waste of time since the
168*65524Spendry  * chances are that the process will still be
169*65524Spendry  * there and PFIND is not free.
170*65524Spendry  *
171*65524Spendry  * (vp) is not locked on entry or exit.
172*65524Spendry  */
173*65524Spendry procfs_inactive(ap)
174*65524Spendry 	struct vop_inactive_args *ap;
175*65524Spendry {
176*65524Spendry 	struct pfsnode *pfs = VTOPFS(ap->a_vp);
177*65524Spendry 
178*65524Spendry 	if (PFIND(pfs->pfs_pid) == 0)
179*65524Spendry 		vgone(ap->a_vp);
180*65524Spendry 
181*65524Spendry 	return (0);
182*65524Spendry }
183*65524Spendry 
184*65524Spendry /*
185*65524Spendry  * _reclaim is called when getnewvnode()
186*65524Spendry  * wants to make use of an entry on the vnode
187*65524Spendry  * free list.  at this time the filesystem needs
188*65524Spendry  * to free any private data and remove the node
189*65524Spendry  * from any private lists.
190*65524Spendry  */
191*65524Spendry procfs_reclaim(ap)
192*65524Spendry 	struct vop_reclaim_args *ap;
193*65524Spendry {
194*65524Spendry 	int error;
195*65524Spendry 
196*65524Spendry 	error = procfs_freevp(ap->a_vp);
197*65524Spendry 	return (error);
198*65524Spendry }
199*65524Spendry 
200*65524Spendry /*
201*65524Spendry  * _print is used for debugging.
202*65524Spendry  * just print a readable description
203*65524Spendry  * of (vp).
204*65524Spendry  */
205*65524Spendry procfs_print(ap)
206*65524Spendry 	struct vop_print_args *ap;
207*65524Spendry {
208*65524Spendry 	struct pfsnode *pfs = VTOPFS(ap->a_vp);
209*65524Spendry 
210*65524Spendry 	printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n",
211*65524Spendry 		pfs->pfs_pid,
212*65524Spendry 		pfs->pfs_mode, pfs->pfs_flags);
213*65524Spendry }
214*65524Spendry 
215*65524Spendry /*
216*65524Spendry  * _abortop is called when operations such as
217*65524Spendry  * rename and create fail.  this entry is responsible
218*65524Spendry  * for undoing any side-effects caused by the lookup.
219*65524Spendry  * this will always include freeing the pathname buffer.
220*65524Spendry  */
221*65524Spendry procfs_abortop(ap)
222*65524Spendry 	struct vop_abortop_args *ap;
223*65524Spendry {
224*65524Spendry 
225*65524Spendry 	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
226*65524Spendry 		FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
227*65524Spendry 	return (0);
228*65524Spendry }
229*65524Spendry 
230*65524Spendry /*
231*65524Spendry  * generic entry point for unsupported operations
232*65524Spendry  */
233*65524Spendry procfs_badop()
234*65524Spendry {
235*65524Spendry 
236*65524Spendry 	return (EIO);
237*65524Spendry }
238*65524Spendry 
239*65524Spendry /*
240*65524Spendry  * Invent attributes for pfsnode (vp) and store
241*65524Spendry  * them in (vap).
242*65524Spendry  * Directories lengths are returned as zero since
243*65524Spendry  * any real length would require the genuine size
244*65524Spendry  * to be computed, and nothing cares anyway.
245*65524Spendry  *
246*65524Spendry  * this is relatively minimal for procfs.
247*65524Spendry  */
248*65524Spendry procfs_getattr(ap)
249*65524Spendry 	struct vop_getattr_args *ap;
250*65524Spendry {
251*65524Spendry 	struct pfsnode *pfs = VTOPFS(ap->a_vp);
252*65524Spendry 	struct proc *procp;
253*65524Spendry 	int error;
254*65524Spendry 
255*65524Spendry 	/* first check the process still exists */
256*65524Spendry 	procp = PFIND(pfs->pfs_pid);
257*65524Spendry 	if (procp == 0)
258*65524Spendry 		return (ENOENT);
259*65524Spendry 
260*65524Spendry 	error = 0;
261*65524Spendry 
262*65524Spendry 	/* start by zeroing out the attributes */
263*65524Spendry 	VATTR_NULL(ap->a_vap);
264*65524Spendry 
265*65524Spendry 	/* next do all the common fields */
266*65524Spendry 	(ap->a_vap)->va_type = ap->a_vp->v_type;
267*65524Spendry 	(ap->a_vap)->va_mode = pfs->pfs_mode;
268*65524Spendry 	(ap->a_vap)->va_fileid = pfs->pfs_fileno;
269*65524Spendry 	(ap->a_vap)->va_flags = 0;
270*65524Spendry 	(ap->a_vap)->va_blocksize = PAGE_SIZE;
271*65524Spendry 	(ap->a_vap)->va_bytes = ap->a_vap->va_size = 0;
272*65524Spendry 
273*65524Spendry 	/*
274*65524Spendry 	 * Make all times be current TOD.
275*65524Spendry 	 * It would be possible to get the process start
276*65524Spendry 	 * time from the p_stat structure, but there's
277*65524Spendry 	 * no "file creation" time stamp anyway, and the
278*65524Spendry 	 * p_stat structure is not addressible if u. gets
279*65524Spendry 	 * swapped out for that process.
280*65524Spendry 	 */
281*65524Spendry 	microtime(&(ap->a_vap)->va_ctime);
282*65524Spendry 	(ap->a_vap)->va_atime = ap->a_vap->va_mtime = ap->a_vap->va_ctime;
283*65524Spendry 
284*65524Spendry 	/*
285*65524Spendry 	 * now do the object specific fields
286*65524Spendry 	 *
287*65524Spendry 	 * The size could be set from struct reg, but it's hardly
288*65524Spendry 	 * worth the trouble, and it puts some (potentially) machine
289*65524Spendry 	 * dependent data into this machine-independent code.  If it
290*65524Spendry 	 * becomes important then this function should break out into
291*65524Spendry 	 * a per-file stat function in the corresponding .c file.
292*65524Spendry 	 */
293*65524Spendry 
294*65524Spendry 	switch (pfs->pfs_type) {
295*65524Spendry 	case Proot:
296*65524Spendry 		ap->a_vap->va_nlink = 2;
297*65524Spendry 		ap->a_vap->va_uid = 0;
298*65524Spendry 		ap->a_vap->va_gid = 0;
299*65524Spendry 		break;
300*65524Spendry 
301*65524Spendry 	case Pproc:
302*65524Spendry 		ap->a_vap->va_nlink = 2;
303*65524Spendry 		ap->a_vap->va_uid = procp->p_ucred->cr_uid;
304*65524Spendry 		ap->a_vap->va_gid = procp->p_ucred->cr_gid;
305*65524Spendry 		break;
306*65524Spendry 
307*65524Spendry 	case Pfile:
308*65524Spendry 		error = EOPNOTSUPP;
309*65524Spendry 		break;
310*65524Spendry 
311*65524Spendry 	case Pmem:
312*65524Spendry 		ap->a_vap->va_nlink = 1;
313*65524Spendry 		ap->a_vap->va_bytes = ap->a_vap->va_size =
314*65524Spendry 			ctob(procp->p_vmspace->vm_tsize +
315*65524Spendry 				    procp->p_vmspace->vm_dsize +
316*65524Spendry 				    procp->p_vmspace->vm_ssize);
317*65524Spendry 		ap->a_vap->va_uid = procp->p_ucred->cr_uid;
318*65524Spendry 		ap->a_vap->va_gid = procp->p_ucred->cr_gid;
319*65524Spendry 		break;
320*65524Spendry 
321*65524Spendry 	case Pregs:
322*65524Spendry 	case Pctl:
323*65524Spendry 	case Pstatus:
324*65524Spendry 	case Pnote:
325*65524Spendry 	case Pnotepg:
326*65524Spendry 		ap->a_vap->va_nlink = 1;
327*65524Spendry 		ap->a_vap->va_uid = procp->p_ucred->cr_uid;
328*65524Spendry 		ap->a_vap->va_gid = procp->p_ucred->cr_gid;
329*65524Spendry 		break;
330*65524Spendry 
331*65524Spendry 	default:
332*65524Spendry 		panic("procfs_getattr");
333*65524Spendry 	}
334*65524Spendry 
335*65524Spendry 	return (error);
336*65524Spendry }
337*65524Spendry 
338*65524Spendry procfs_setattr(ap)
339*65524Spendry 	struct vop_setattr_args *ap;
340*65524Spendry {
341*65524Spendry 	/*
342*65524Spendry 	 * just fake out attribute setting
343*65524Spendry 	 * it's not good to generate an error
344*65524Spendry 	 * return, otherwise things like creat()
345*65524Spendry 	 * will fail when they try to set the
346*65524Spendry 	 * file length to 0.  worse, this means
347*65524Spendry 	 * that echo $note > /proc/$pid/note will fail.
348*65524Spendry 	 */
349*65524Spendry 
350*65524Spendry 	return (0);
351*65524Spendry }
352*65524Spendry 
353*65524Spendry /*
354*65524Spendry  * implement access checking.
355*65524Spendry  *
356*65524Spendry  * something very similar to this code is duplicated
357*65524Spendry  * throughout the 4bsd kernel and should be moved
358*65524Spendry  * into kern/vfs_subr.c sometime.
359*65524Spendry  *
360*65524Spendry  * actually, the check for super-user is slightly
361*65524Spendry  * broken since it will allow read access to write-only
362*65524Spendry  * objects.  this doesn't cause any particular trouble
363*65524Spendry  * but does mean that the i/o entry points need to check
364*65524Spendry  * that the operation really does make sense.
365*65524Spendry  */
366*65524Spendry procfs_access(ap)
367*65524Spendry 	struct vop_access_args *ap;
368*65524Spendry {
369*65524Spendry 	struct vattr *vap;
370*65524Spendry 	struct vattr vattr;
371*65524Spendry 	int error;
372*65524Spendry 
373*65524Spendry 	/*
374*65524Spendry 	 * If you're the super-user,
375*65524Spendry 	 * you always get access.
376*65524Spendry 	 */
377*65524Spendry 	if (ap->a_cred->cr_uid == (uid_t) 0)
378*65524Spendry 		return (0);
379*65524Spendry 	vap = &vattr;
380*65524Spendry 	if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p))
381*65524Spendry 		return (error);
382*65524Spendry 
383*65524Spendry 	/*
384*65524Spendry 	 * Access check is based on only one of owner, group, public.
385*65524Spendry 	 * If not owner, then check group. If not a member of the
386*65524Spendry 	 * group, then check public access.
387*65524Spendry 	 */
388*65524Spendry 	if (ap->a_cred->cr_uid != vap->va_uid) {
389*65524Spendry 		gid_t *gp;
390*65524Spendry 		int i;
391*65524Spendry 
392*65524Spendry 		(ap->a_mode) >>= 3;
393*65524Spendry 		gp = ap->a_cred->cr_groups;
394*65524Spendry 		for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
395*65524Spendry 			if (vap->va_gid == *gp)
396*65524Spendry 				goto found;
397*65524Spendry 		ap->a_mode >>= 3;
398*65524Spendry found:
399*65524Spendry 		;
400*65524Spendry 	}
401*65524Spendry 
402*65524Spendry 	if ((vap->va_mode & ap->a_mode) == ap->a_mode)
403*65524Spendry 		return (0);
404*65524Spendry 
405*65524Spendry 	return (EACCES);
406*65524Spendry }
407*65524Spendry 
408*65524Spendry /*
409*65524Spendry  * lookup.  this is incredibly complicated in the
410*65524Spendry  * general case, however for most pseudo-filesystems
411*65524Spendry  * very little needs to be done.
412*65524Spendry  *
413*65524Spendry  * unless you want to get a migraine, just make sure your
414*65524Spendry  * filesystem doesn't do any locking of its own.  otherwise
415*65524Spendry  * read and inwardly digest ufs_lookup().
416*65524Spendry  */
417*65524Spendry procfs_lookup(ap)
418*65524Spendry 	struct vop_lookup_args *ap;
419*65524Spendry {
420*65524Spendry 	struct componentname *cnp = ap->a_cnp;
421*65524Spendry 	struct vnode **vpp = ap->a_vpp;
422*65524Spendry 	struct vnode *dvp = ap->a_dvp;
423*65524Spendry 	char *pname = cnp->cn_nameptr;
424*65524Spendry 	int error = 0;
425*65524Spendry 	int flag;
426*65524Spendry 	pid_t pid;
427*65524Spendry 	struct vnode *nvp;
428*65524Spendry 	struct pfsnode *pfs;
429*65524Spendry 	struct proc *procp;
430*65524Spendry 	int mode;
431*65524Spendry 	pfstype pfs_type;
432*65524Spendry 	int i;
433*65524Spendry 
434*65524Spendry 	if (cnp->cn_namelen == 1 && *pname == '.') {
435*65524Spendry 		*vpp = dvp;
436*65524Spendry 		VREF(dvp);
437*65524Spendry 		/*VOP_LOCK(dvp);*/
438*65524Spendry 		return (0);
439*65524Spendry 	}
440*65524Spendry 
441*65524Spendry 	*vpp = NULL;
442*65524Spendry 
443*65524Spendry 	pfs = VTOPFS(dvp);
444*65524Spendry 	switch (pfs->pfs_type) {
445*65524Spendry 	case Proot:
446*65524Spendry 		if (cnp->cn_flags & ISDOTDOT)
447*65524Spendry 			return (EIO);
448*65524Spendry 
449*65524Spendry 		if (CNEQ(cnp, "curproc", 7))
450*65524Spendry 			pid = cnp->cn_proc->p_pid;
451*65524Spendry 		else
452*65524Spendry 			pid = atopid(pname, cnp->cn_namelen);
453*65524Spendry 		if (pid == NO_PID)
454*65524Spendry 			return (ENOENT);
455*65524Spendry 
456*65524Spendry 		procp = PFIND(pid);
457*65524Spendry 		if (procp == 0)
458*65524Spendry 			return (ENOENT);
459*65524Spendry 
460*65524Spendry 		error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc);
461*65524Spendry 		if (error)
462*65524Spendry 			return (error);
463*65524Spendry 
464*65524Spendry 		nvp->v_type = VDIR;
465*65524Spendry 		pfs = VTOPFS(nvp);
466*65524Spendry 
467*65524Spendry 		*vpp = nvp;
468*65524Spendry 		return (0);
469*65524Spendry 
470*65524Spendry 	case Pproc:
471*65524Spendry 		if (cnp->cn_flags & ISDOTDOT) {
472*65524Spendry 			error = procfs_root(dvp->v_mount, vpp);
473*65524Spendry 			return (error);
474*65524Spendry 		}
475*65524Spendry 
476*65524Spendry 		procp = PFIND(pfs->pfs_pid);
477*65524Spendry 		if (procp == 0)
478*65524Spendry 			return (ENOENT);
479*65524Spendry 
480*65524Spendry 		for (i = 0; i < Nprocent; i++) {
481*65524Spendry 			struct pfsnames *dp = &procent[i];
482*65524Spendry 
483*65524Spendry 			if (cnp->cn_namelen == dp->d_namlen &&
484*65524Spendry 			    bcmp(pname, dp->d_name, dp->d_namlen) == 0) {
485*65524Spendry 			    	pfs_type = dp->d_pfstype;
486*65524Spendry 				goto found;
487*65524Spendry 			}
488*65524Spendry 		}
489*65524Spendry 		return (ENOENT);
490*65524Spendry 
491*65524Spendry 	found:
492*65524Spendry 		if (pfs_type == Pfile) {
493*65524Spendry 			nvp = procfs_findtextvp(procp);
494*65524Spendry 			if (nvp) {
495*65524Spendry 				VREF(nvp);
496*65524Spendry 				VOP_LOCK(nvp);
497*65524Spendry 			} else {
498*65524Spendry 				error = ENXIO;
499*65524Spendry 			}
500*65524Spendry 		} else {
501*65524Spendry 			error = procfs_allocvp(dvp->v_mount, &nvp,
502*65524Spendry 					pfs->pfs_pid, pfs_type);
503*65524Spendry 			if (error)
504*65524Spendry 				return (error);
505*65524Spendry 
506*65524Spendry 			nvp->v_type = VREG;
507*65524Spendry 			pfs = VTOPFS(nvp);
508*65524Spendry 		}
509*65524Spendry 		*vpp = nvp;
510*65524Spendry 		return (error);
511*65524Spendry 
512*65524Spendry 	default:
513*65524Spendry 		return (ENOTDIR);
514*65524Spendry 	}
515*65524Spendry }
516*65524Spendry 
517*65524Spendry /*
518*65524Spendry  * readdir returns directory entries from pfsnode (vp).
519*65524Spendry  *
520*65524Spendry  * the strategy here with procfs is to generate a single
521*65524Spendry  * directory entry at a time (struct pfsdent) and then
522*65524Spendry  * copy that out to userland using uiomove.  a more efficent
523*65524Spendry  * though more complex implementation, would try to minimize
524*65524Spendry  * the number of calls to uiomove().  for procfs, this is
525*65524Spendry  * hardly worth the added code complexity.
526*65524Spendry  *
527*65524Spendry  * this should just be done through read()
528*65524Spendry  */
529*65524Spendry procfs_readdir(ap)
530*65524Spendry 	struct vop_readdir_args *ap;
531*65524Spendry {
532*65524Spendry 	struct uio *uio = ap->a_uio;
533*65524Spendry 	struct pfsdent d;
534*65524Spendry 	struct pfsdent *dp = &d;
535*65524Spendry 	struct pfsnode *pfs;
536*65524Spendry 	int error;
537*65524Spendry 	int count;
538*65524Spendry 	int i;
539*65524Spendry 
540*65524Spendry 	pfs = VTOPFS(ap->a_vp);
541*65524Spendry 
542*65524Spendry 	if (uio->uio_resid < UIO_MX)
543*65524Spendry 		return (EINVAL);
544*65524Spendry 	if (uio->uio_offset & (UIO_MX-1))
545*65524Spendry 		return (EINVAL);
546*65524Spendry 	if (uio->uio_offset < 0)
547*65524Spendry 		return (EINVAL);
548*65524Spendry 
549*65524Spendry 	error = 0;
550*65524Spendry 	count = 0;
551*65524Spendry 	i = uio->uio_offset / UIO_MX;
552*65524Spendry 
553*65524Spendry 	switch (pfs->pfs_type) {
554*65524Spendry 	/*
555*65524Spendry 	 * this is for the process-specific sub-directories.
556*65524Spendry 	 * all that is needed to is copy out all the entries
557*65524Spendry 	 * from the procent[] table (top of this file).
558*65524Spendry 	 */
559*65524Spendry 	case Pproc: {
560*65524Spendry 		while (uio->uio_resid >= UIO_MX) {
561*65524Spendry 			struct pfsnames *dt;
562*65524Spendry 
563*65524Spendry 			if (i >= Nprocent)
564*65524Spendry 				break;
565*65524Spendry 
566*65524Spendry 			dt = &procent[i];
567*65524Spendry 
568*65524Spendry 			dp->d_reclen = UIO_MX;
569*65524Spendry 			dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype);
570*65524Spendry 			dp->d_type = DT_REG;
571*65524Spendry 			dp->d_namlen = dt->d_namlen;
572*65524Spendry 			bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1);
573*65524Spendry 			error = uiomove((caddr_t) dp, UIO_MX, uio);
574*65524Spendry 			if (error)
575*65524Spendry 				break;
576*65524Spendry 			count += UIO_MX;
577*65524Spendry 			i++;
578*65524Spendry 		}
579*65524Spendry 
580*65524Spendry 	    	break;
581*65524Spendry 
582*65524Spendry 	    }
583*65524Spendry 
584*65524Spendry 	/*
585*65524Spendry 	 * this is for the root of the procfs filesystem
586*65524Spendry 	 * what is needed is a special entry for "curproc"
587*65524Spendry 	 * followed by an entry for each process on allproc
588*65524Spendry #ifdef PROCFS_ZOMBIE
589*65524Spendry 	 * and zombproc.
590*65524Spendry #endif
591*65524Spendry 	 */
592*65524Spendry 
593*65524Spendry 	case Proot: {
594*65524Spendry 		int pcnt;
595*65524Spendry #ifdef PROCFS_ZOMBIE
596*65524Spendry 		int doingzomb = 0;
597*65524Spendry #endif
598*65524Spendry 		volatile struct proc *p;
599*65524Spendry 
600*65524Spendry 		p = allproc;
601*65524Spendry 
602*65524Spendry #define PROCFS_XFILES	1	/* number of other entries, like "curproc" */
603*65524Spendry 		pcnt = PROCFS_XFILES;
604*65524Spendry 
605*65524Spendry 		while (p && uio->uio_resid >= UIO_MX) {
606*65524Spendry 			bzero((char *) dp, UIO_MX);
607*65524Spendry 			dp->d_type = DT_DIR;
608*65524Spendry 			dp->d_reclen = UIO_MX;
609*65524Spendry 
610*65524Spendry 			switch (i) {
611*65524Spendry 			case 0:
612*65524Spendry 				/* ship out entry for "curproc" */
613*65524Spendry 				dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc);
614*65524Spendry 				dp->d_namlen = 7;
615*65524Spendry 				bcopy("curproc", dp->d_name, dp->d_namlen+1);
616*65524Spendry 				break;
617*65524Spendry 
618*65524Spendry 			default:
619*65524Spendry 				if (pcnt >= i) {
620*65524Spendry 					dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
621*65524Spendry 					dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid);
622*65524Spendry 				}
623*65524Spendry 
624*65524Spendry 				p = p->p_next;
625*65524Spendry 
626*65524Spendry #ifdef PROCFS_ZOMBIE
627*65524Spendry 				if (p == 0 && doingzomb == 0) {
628*65524Spendry 					doingzomb = 1;
629*65524Spendry 					p = zombproc;
630*65524Spendry 				}
631*65524Spendry #endif
632*65524Spendry 
633*65524Spendry 				if (pcnt++ < i)
634*65524Spendry 					continue;
635*65524Spendry 
636*65524Spendry 				break;
637*65524Spendry 			}
638*65524Spendry 			error = uiomove((caddr_t) dp, UIO_MX, uio);
639*65524Spendry 			if (error)
640*65524Spendry 				break;
641*65524Spendry 			count += UIO_MX;
642*65524Spendry 			i++;
643*65524Spendry 		}
644*65524Spendry 
645*65524Spendry 		break;
646*65524Spendry 
647*65524Spendry 	    }
648*65524Spendry 
649*65524Spendry 	default:
650*65524Spendry 		error = ENOTDIR;
651*65524Spendry 		break;
652*65524Spendry 	}
653*65524Spendry 
654*65524Spendry 	uio->uio_offset = i * UIO_MX;
655*65524Spendry 
656*65524Spendry 	return (error);
657*65524Spendry }
658*65524Spendry 
659*65524Spendry /*
660*65524Spendry  * convert decimal ascii to pid_t
661*65524Spendry  */
662*65524Spendry static pid_t
663*65524Spendry atopid(b, len)
664*65524Spendry 	const char *b;
665*65524Spendry 	u_int len;
666*65524Spendry {
667*65524Spendry 	pid_t p = 0;
668*65524Spendry 
669*65524Spendry 	while (len--) {
670*65524Spendry 		char c = *b++;
671*65524Spendry 		if (c < '0' || c > '9')
672*65524Spendry 			return (NO_PID);
673*65524Spendry 		p = 10 * p + (c - '0');
674*65524Spendry 		if (p > PID_MAX)
675*65524Spendry 			return (NO_PID);
676*65524Spendry 	}
677*65524Spendry 
678*65524Spendry 	return (p);
679*65524Spendry }
680*65524Spendry 
681*65524Spendry /*
682*65524Spendry  * procfs vnode operations.
683*65524Spendry  */
684*65524Spendry int (**procfs_vnodeop_p)();
685*65524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
686*65524Spendry 	{ &vop_default_desc, vn_default_error },
687*65524Spendry 	{ &vop_lookup_desc, procfs_lookup },		/* lookup */
688*65524Spendry 	{ &vop_create_desc, procfs_create },		/* create */
689*65524Spendry 	{ &vop_mknod_desc, procfs_mknod },		/* mknod */
690*65524Spendry 	{ &vop_open_desc, procfs_open },		/* open */
691*65524Spendry 	{ &vop_close_desc, procfs_close },		/* close */
692*65524Spendry 	{ &vop_access_desc, procfs_access },		/* access */
693*65524Spendry 	{ &vop_getattr_desc, procfs_getattr },		/* getattr */
694*65524Spendry 	{ &vop_setattr_desc, procfs_setattr },		/* setattr */
695*65524Spendry 	{ &vop_read_desc, procfs_read },		/* read */
696*65524Spendry 	{ &vop_write_desc, procfs_write },		/* write */
697*65524Spendry 	{ &vop_ioctl_desc, procfs_ioctl },		/* ioctl */
698*65524Spendry 	{ &vop_select_desc, procfs_select },		/* select */
699*65524Spendry 	{ &vop_mmap_desc, procfs_mmap },		/* mmap */
700*65524Spendry 	{ &vop_fsync_desc, procfs_fsync },		/* fsync */
701*65524Spendry 	{ &vop_seek_desc, procfs_seek },		/* seek */
702*65524Spendry 	{ &vop_remove_desc, procfs_remove },		/* remove */
703*65524Spendry 	{ &vop_link_desc, procfs_link },		/* link */
704*65524Spendry 	{ &vop_rename_desc, procfs_rename },		/* rename */
705*65524Spendry 	{ &vop_mkdir_desc, procfs_mkdir },		/* mkdir */
706*65524Spendry 	{ &vop_rmdir_desc, procfs_rmdir },		/* rmdir */
707*65524Spendry 	{ &vop_symlink_desc, procfs_symlink },		/* symlink */
708*65524Spendry 	{ &vop_readdir_desc, procfs_readdir },		/* readdir */
709*65524Spendry 	{ &vop_readlink_desc, procfs_readlink },	/* readlink */
710*65524Spendry 	{ &vop_abortop_desc, procfs_abortop },		/* abortop */
711*65524Spendry 	{ &vop_inactive_desc, procfs_inactive },	/* inactive */
712*65524Spendry 	{ &vop_reclaim_desc, procfs_reclaim },		/* reclaim */
713*65524Spendry 	{ &vop_lock_desc, procfs_lock },		/* lock */
714*65524Spendry 	{ &vop_unlock_desc, procfs_unlock },		/* unlock */
715*65524Spendry 	{ &vop_bmap_desc, procfs_bmap },		/* bmap */
716*65524Spendry 	{ &vop_strategy_desc, procfs_strategy },	/* strategy */
717*65524Spendry 	{ &vop_print_desc, procfs_print },		/* print */
718*65524Spendry 	{ &vop_islocked_desc, procfs_islocked },	/* islocked */
719*65524Spendry 	{ &vop_pathconf_desc, procfs_pathconf },	/* pathconf */
720*65524Spendry 	{ &vop_advlock_desc, procfs_advlock },		/* advlock */
721*65524Spendry 	{ &vop_blkatoff_desc, procfs_blkatoff },	/* blkatoff */
722*65524Spendry 	{ &vop_valloc_desc, procfs_valloc },		/* valloc */
723*65524Spendry 	{ &vop_vfree_desc, procfs_vfree },		/* vfree */
724*65524Spendry 	{ &vop_truncate_desc, procfs_truncate },	/* truncate */
725*65524Spendry 	{ &vop_update_desc, procfs_update },		/* update */
726*65524Spendry 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
727*65524Spendry };
728*65524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc =
729*65524Spendry 	{ &procfs_vnodeop_p, procfs_vnodeop_entries };
730