Home | History | Annotate | Line # | Download | only in procfs
procfs_vnops.c revision 1.12
      1   1.1       pk /*
      2   1.9      cgd  * Copyright (c) 1993 The Regents of the University of California.
      3   1.9      cgd  * Copyright (c) 1993 Jan-Simon Pendry
      4   1.2       pk  * All rights reserved.
      5   1.2       pk  *
      6   1.9      cgd  * This code is derived from software contributed to Berkeley by
      7   1.9      cgd  * Jan-Simon Pendry.
      8   1.9      cgd  *
      9   1.2       pk  * Redistribution and use in source and binary forms, with or without
     10   1.2       pk  * modification, are permitted provided that the following conditions
     11   1.2       pk  * are met:
     12   1.2       pk  * 1. Redistributions of source code must retain the above copyright
     13   1.2       pk  *    notice, this list of conditions and the following disclaimer.
     14   1.2       pk  * 2. Redistributions in binary form must reproduce the above copyright
     15   1.2       pk  *    notice, this list of conditions and the following disclaimer in the
     16   1.2       pk  *    documentation and/or other materials provided with the distribution.
     17   1.2       pk  * 3. All advertising materials mentioning features or use of this software
     18   1.2       pk  *    must display the following acknowledgement:
     19   1.9      cgd  *	This product includes software developed by the University of
     20   1.9      cgd  *	California, Berkeley and its contributors.
     21   1.9      cgd  * 4. Neither the name of the University nor the names of its contributors
     22   1.9      cgd  *    may be used to endorse or promote products derived from this software
     23   1.9      cgd  *    without specific prior written permission.
     24   1.9      cgd  *
     25   1.9      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26   1.9      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27   1.9      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28   1.9      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29   1.9      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30   1.9      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31   1.9      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32   1.9      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33   1.9      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34   1.9      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35   1.9      cgd  * SUCH DAMAGE.
     36   1.2       pk  *
     37   1.9      cgd  * From:
     38   1.9      cgd  *	Id: procfs_vnops.c,v 4.2 1994/01/02 15:28:44 jsp Exp
     39   1.9      cgd  *
     40  1.12       ws  *	$Id: procfs_vnops.c,v 1.12 1994/01/09 19:44:10 ws Exp $
     41   1.2       pk  */
     42   1.2       pk 
     43   1.2       pk /*
     44   1.9      cgd  * procfs vnode interface
     45   1.1       pk  */
     46   1.1       pk 
     47   1.8  mycroft #include <sys/param.h>
     48   1.8  mycroft #include <sys/systm.h>
     49   1.8  mycroft #include <sys/time.h>
     50   1.8  mycroft #include <sys/kernel.h>
     51   1.8  mycroft #include <sys/file.h>
     52   1.8  mycroft #include <sys/proc.h>
     53   1.8  mycroft #include <sys/vnode.h>
     54   1.8  mycroft #include <sys/namei.h>
     55   1.9      cgd #include <sys/malloc.h>
     56   1.8  mycroft #include <sys/resourcevar.h>
     57   1.9      cgd #include <miscfs/procfs/procfs.h>
     58   1.9      cgd #include <vm/vm.h>	/* for page_size */
     59   1.1       pk 
     60  1.11      cgd #include <machine/reg.h>
     61  1.11      cgd 
     62   1.9      cgd /*
     63   1.9      cgd  * Vnode Operations.
     64   1.9      cgd  *
     65   1.9      cgd  */
     66   1.1       pk 
     67   1.1       pk /*
     68   1.9      cgd  * This is a list of the valid names in the
     69   1.9      cgd  * process-specific sub-directories.  It is
     70   1.9      cgd  * used in procfs_lookup and procfs_readdir
     71   1.9      cgd  */
     72   1.9      cgd static struct pfsnames {
     73   1.9      cgd 	u_short	d_namlen;
     74   1.9      cgd 	char	d_name[PROCFS_NAMELEN];
     75   1.9      cgd 	pfstype	d_pfstype;
     76   1.9      cgd } procent[] = {
     77   1.9      cgd #define N(s) sizeof(s)-1, s
     78   1.9      cgd 	/* namlen, nam, type */
     79  1.12       ws 	{  N("."),	Pproc },
     80  1.12       ws 	{  N(".."),	Proot },
     81   1.9      cgd 	{  N("file"),   Pfile },
     82   1.9      cgd 	{  N("mem"),    Pmem },
     83   1.9      cgd 	{  N("regs"),   Pregs },
     84   1.9      cgd 	{  N("ctl"),    Pctl },
     85   1.9      cgd 	{  N("status"), Pstatus },
     86   1.9      cgd 	{  N("note"),   Pnote },
     87   1.9      cgd 	{  N("notepg"), Pnotepg },
     88   1.9      cgd #undef N
     89   1.1       pk };
     90   1.9      cgd #define Nprocent (sizeof(procent)/sizeof(procent[0]))
     91   1.9      cgd 
     92  1.12       ws #define	PROCFS_XFILES	3	/* number of other entries, like "curproc" */
     93  1.12       ws 
     94   1.9      cgd static pid_t atopid __P((const char *, u_int));
     95   1.1       pk 
     96   1.1       pk /*
     97   1.9      cgd  * set things up for doing i/o on
     98   1.9      cgd  * the pfsnode (vp).  (vp) is locked
     99   1.9      cgd  * on entry, and should be left locked
    100   1.9      cgd  * on exit.
    101   1.1       pk  *
    102   1.9      cgd  * for procfs we don't need to do anything
    103   1.9      cgd  * in particular for i/o.  all that is done
    104   1.9      cgd  * is to support exclusive open on process
    105   1.9      cgd  * memory images.
    106   1.1       pk  */
    107   1.9      cgd procfs_open(vp, mode, cred, p)
    108   1.9      cgd 	struct vnode *vp;
    109   1.1       pk 	int mode;
    110   1.1       pk 	struct ucred *cred;
    111   1.1       pk 	struct proc *p;
    112   1.1       pk {
    113   1.9      cgd 	struct pfsnode *pfs = VTOPFS(vp);
    114   1.9      cgd 
    115   1.9      cgd 	switch (pfs->pfs_type) {
    116   1.9      cgd 	case Pmem:
    117   1.9      cgd 		if (PFIND(pfs->pfs_pid) == 0)
    118   1.9      cgd 			return (ENOENT);	/* was ESRCH, jsp */
    119   1.9      cgd 
    120   1.9      cgd 		if ((pfs->pfs_flags & FWRITE) && (mode & O_EXCL) ||
    121   1.9      cgd 				(pfs->pfs_flags & O_EXCL) && (mode & FWRITE))
    122   1.9      cgd 			return (EBUSY);
    123   1.1       pk 
    124   1.1       pk 
    125   1.9      cgd 		if (mode & FWRITE)
    126   1.9      cgd 			pfs->pfs_flags = (mode & (FWRITE|O_EXCL));
    127   1.1       pk 
    128   1.9      cgd 		return (0);
    129   1.1       pk 
    130   1.9      cgd 	default:
    131   1.9      cgd 		break;
    132   1.9      cgd 	}
    133   1.1       pk 
    134   1.9      cgd 	return (0);
    135   1.1       pk }
    136   1.1       pk 
    137   1.1       pk /*
    138   1.9      cgd  * close the pfsnode (vp) after doing i/o.
    139   1.9      cgd  * (vp) is not locked on entry or exit.
    140   1.9      cgd  *
    141   1.9      cgd  * nothing to do for procfs other than undo
    142   1.9      cgd  * any exclusive open flag (see _open above).
    143   1.1       pk  */
    144   1.9      cgd procfs_close(vp, flag, cred, p)
    145   1.9      cgd 	struct vnode *vp;
    146   1.1       pk 	int flag;
    147   1.1       pk 	struct ucred *cred;
    148   1.1       pk 	struct proc *p;
    149   1.1       pk {
    150   1.9      cgd 	struct pfsnode *pfs = VTOPFS(vp);
    151   1.1       pk 
    152   1.9      cgd 	switch (pfs->pfs_type) {
    153   1.9      cgd 	case Pmem:
    154   1.9      cgd 		if ((flag & FWRITE) && (pfs->pfs_flags & O_EXCL))
    155   1.9      cgd 			pfs->pfs_flags &= ~(FWRITE|O_EXCL);
    156   1.9      cgd 		break;
    157   1.9      cgd 	}
    158   1.1       pk 
    159   1.1       pk 	return (0);
    160   1.1       pk }
    161   1.1       pk 
    162   1.1       pk /*
    163   1.9      cgd  * do an ioctl operation on pfsnode (vp).
    164   1.9      cgd  * (vp) is not locked on entry or exit.
    165   1.1       pk  */
    166   1.9      cgd procfs_ioctl(vp, com, data, fflag, cred, p)
    167   1.1       pk 	struct vnode *vp;
    168   1.1       pk 	int com;
    169   1.1       pk 	caddr_t data;
    170   1.1       pk 	int fflag;
    171   1.1       pk 	struct ucred *cred;
    172   1.1       pk 	struct proc *p;
    173   1.1       pk {
    174   1.1       pk 
    175   1.9      cgd 	return (ENOTTY);
    176   1.1       pk }
    177   1.1       pk 
    178   1.1       pk /*
    179   1.9      cgd  * do block mapping for pfsnode (vp).
    180   1.9      cgd  * since we don't use the buffer cache
    181   1.9      cgd  * for procfs this function should never
    182   1.9      cgd  * be called.  in any case, it's not clear
    183   1.9      cgd  * what part of the kernel ever makes use
    184   1.9      cgd  * of this function.  for sanity, this is the
    185   1.9      cgd  * usual no-op bmap, although returning
    186   1.9      cgd  * (EIO) would be a reasonable alternative.
    187   1.1       pk  */
    188   1.9      cgd procfs_bmap(vp, bn, vpp, bnp)
    189   1.1       pk 	struct vnode *vp;
    190   1.1       pk 	daddr_t bn;
    191   1.1       pk 	struct vnode **vpp;
    192   1.1       pk 	daddr_t *bnp;
    193   1.1       pk {
    194   1.1       pk 
    195   1.1       pk 	if (vpp != NULL)
    196   1.1       pk 		*vpp = vp;
    197   1.1       pk 	if (bnp != NULL)
    198   1.1       pk 		*bnp = bn;
    199   1.1       pk 	return (0);
    200   1.1       pk }
    201   1.1       pk 
    202   1.1       pk /*
    203   1.9      cgd  * _inactive is called when the pfsnode
    204   1.9      cgd  * is vrele'd and the reference count goes
    205   1.9      cgd  * to zero.  (vp) will be on the vnode free
    206   1.9      cgd  * list, so to get it back vget() must be
    207   1.9      cgd  * used.
    208   1.9      cgd  *
    209   1.9      cgd  * for procfs, check if the process is still
    210   1.9      cgd  * alive and if it isn't then just throw away
    211   1.9      cgd  * the vnode by calling vgone().  this may
    212   1.9      cgd  * be overkill and a waste of time since the
    213   1.9      cgd  * chances are that the process will still be
    214   1.9      cgd  * there and PFIND is not free.
    215   1.9      cgd  *
    216   1.9      cgd  * (vp) is not locked on entry or exit.
    217   1.1       pk  */
    218   1.9      cgd procfs_inactive(vp, p)
    219   1.1       pk 	struct vnode *vp;
    220   1.1       pk 	struct proc *p;
    221   1.1       pk {
    222   1.9      cgd 	struct pfsnode *pfs = VTOPFS(vp);
    223   1.1       pk 
    224   1.9      cgd 	if (PFIND(pfs->pfs_pid) == 0)
    225   1.1       pk 		vgone(vp);
    226   1.5       pk 
    227   1.9      cgd 	return (0);
    228   1.1       pk }
    229   1.1       pk 
    230   1.1       pk /*
    231   1.9      cgd  * _reclaim is called when getnewvnode()
    232   1.9      cgd  * wants to make use of an entry on the vnode
    233   1.9      cgd  * free list.  at this time the filesystem needs
    234   1.9      cgd  * to free any private data and remove the node
    235   1.9      cgd  * from any private lists.
    236   1.1       pk  */
    237   1.9      cgd procfs_reclaim(vp)
    238   1.1       pk 	struct vnode *vp;
    239   1.1       pk {
    240   1.9      cgd 	int error;
    241   1.1       pk 
    242   1.9      cgd 	error = procfs_freevp(vp);
    243   1.9      cgd 	return (error);
    244   1.1       pk }
    245   1.1       pk 
    246   1.1       pk /*
    247   1.9      cgd  * _print is used for debugging.
    248   1.9      cgd  * just print a readable description
    249   1.9      cgd  * of (vp).
    250   1.1       pk  */
    251   1.9      cgd procfs_print(vp)
    252   1.1       pk 	struct vnode *vp;
    253   1.1       pk {
    254   1.9      cgd 	struct pfsnode *pfs = VTOPFS(vp);
    255   1.5       pk 
    256   1.9      cgd 	printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n",
    257   1.9      cgd 		pfs->pfs_pid,
    258   1.9      cgd 		pfs->pfs_mode, pfs->pfs_flags);
    259   1.1       pk }
    260   1.1       pk 
    261   1.1       pk /*
    262   1.9      cgd  * _abortop is called when operations such as
    263   1.9      cgd  * rename and create fail.  this entry is responsible
    264   1.9      cgd  * for undoing any side-effects caused by the lookup.
    265   1.9      cgd  * this will always include freeing the pathname buffer.
    266   1.1       pk  */
    267   1.9      cgd procfs_abortop(ndp)
    268   1.9      cgd 	struct nameidata *ndp;
    269   1.1       pk {
    270   1.9      cgd 
    271   1.9      cgd 	if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
    272   1.9      cgd 		FREE(ndp->ni_pnbuf, M_NAMEI);
    273   1.9      cgd 	return (0);
    274   1.1       pk }
    275   1.1       pk 
    276   1.1       pk /*
    277   1.9      cgd  * generic entry point for unsupported operations
    278   1.1       pk  */
    279   1.9      cgd procfs_badop()
    280   1.1       pk {
    281   1.1       pk 
    282   1.9      cgd 	return (EIO);
    283   1.1       pk }
    284   1.1       pk 
    285   1.1       pk /*
    286   1.9      cgd  * Invent attributes for pfsnode (vp) and store
    287   1.9      cgd  * them in (vap).
    288   1.9      cgd  * Directories lengths are returned as zero since
    289   1.9      cgd  * any real length would require the genuine size
    290   1.9      cgd  * to be computed, and nothing cares anyway.
    291   1.9      cgd  *
    292   1.9      cgd  * this is relatively minimal for procfs.
    293   1.1       pk  */
    294   1.9      cgd procfs_getattr(vp, vap, cred, p)
    295   1.1       pk 	struct vnode *vp;
    296   1.1       pk 	struct vattr *vap;
    297   1.1       pk 	struct ucred *cred;
    298   1.1       pk 	struct proc *p;
    299   1.1       pk {
    300   1.9      cgd 	struct pfsnode *pfs = VTOPFS(vp);
    301   1.1       pk 	struct proc *procp;
    302   1.9      cgd 	int error;
    303   1.1       pk 
    304   1.9      cgd 	/* start by zeroing out the attributes */
    305   1.1       pk 	VATTR_NULL(vap);
    306   1.9      cgd 
    307   1.9      cgd 	/* next do all the common fields */
    308   1.1       pk 	vap->va_type = vp->v_type;
    309   1.9      cgd 	vap->va_mode = pfs->pfs_mode;
    310   1.9      cgd 	vap->va_fileid = pfs->pfs_fileno;
    311   1.9      cgd 	vap->va_flags = 0;
    312   1.9      cgd 	vap->va_blocksize = page_size;
    313   1.9      cgd 	vap->va_bytes = vap->va_size = 0;
    314   1.9      cgd 
    315   1.9      cgd 	/*
    316   1.9      cgd 	 * Make all times be current TOD.
    317   1.9      cgd 	 * It would be possible to get the process start
    318   1.9      cgd 	 * time from the p_stat structure, but there's
    319   1.9      cgd 	 * no "file creation" time stamp anyway, and the
    320   1.9      cgd 	 * p_stat structure is not addressible if u. gets
    321   1.9      cgd 	 * swapped out for that process.
    322   1.9      cgd 	 */
    323   1.9      cgd 	microtime(&vap->va_ctime);
    324   1.9      cgd 	vap->va_atime = vap->va_mtime = vap->va_ctime;
    325   1.9      cgd 
    326  1.12       ws 	error = 0;
    327  1.12       ws 
    328  1.12       ws 	if (pfs->pfs_type != Proot) {
    329  1.12       ws 		/* check the process still exists */
    330  1.12       ws 		procp = PFIND(pfs->pfs_pid);
    331  1.12       ws 		if (procp == 0)
    332  1.12       ws 			return (ENOENT);
    333  1.12       ws 		/* most of the time we want these values */
    334  1.12       ws 		vap->va_nlink = 1;
    335  1.12       ws 		vap->va_uid = procp->p_ucred->cr_uid;
    336  1.12       ws 		vap->va_gid = procp->p_ucred->cr_gid;
    337  1.12       ws 	}
    338  1.12       ws 
    339   1.9      cgd 	/*
    340   1.9      cgd 	 * now do the object specific fields
    341   1.9      cgd 	 *
    342   1.9      cgd 	 * The size could be set from struct reg, but it's hardly
    343   1.9      cgd 	 * worth the trouble, and it puts some (potentially) machine
    344   1.9      cgd 	 * dependent data into this machine-independent code.  If it
    345   1.9      cgd 	 * becomes important then this function should break out into
    346   1.9      cgd 	 * a per-file stat function in the corresponding .c file.
    347   1.9      cgd 	 */
    348   1.1       pk 
    349   1.9      cgd 	switch (pfs->pfs_type) {
    350   1.9      cgd 	case Proot:
    351  1.12       ws 		switch ((int)pfs->pfs_pid) {
    352  1.12       ws 		case 0:		/* /proc */
    353  1.12       ws 			vap->va_nlink = 2;
    354  1.12       ws 			vap->va_uid = 0;
    355  1.12       ws 			vap->va_gid = 0;
    356  1.12       ws 			vap->va_bytes = vap->va_size
    357  1.12       ws 				= (maxproc + 1 + PROCFS_XFILES) * UIO_MX;
    358  1.12       ws 			break;
    359  1.12       ws 		case 1:		/* /proc/curproc */
    360  1.12       ws 			vap->va_nlink = 1;
    361  1.12       ws 			vap->va_uid = 0;
    362  1.12       ws 			vap->va_gid = 0;
    363  1.12       ws 			break;
    364  1.12       ws 		default:
    365  1.12       ws 			panic("procfs_getattr root");
    366  1.12       ws 		}
    367   1.9      cgd 		break;
    368   1.9      cgd 
    369   1.9      cgd 	case Pproc:
    370   1.9      cgd 		vap->va_nlink = 2;
    371  1.12       ws 		vap->va_bytes = vap->va_size = Nprocent * UIO_MX;
    372   1.9      cgd 		break;
    373   1.9      cgd 
    374   1.9      cgd 	case Pmem:
    375   1.9      cgd 		vap->va_bytes = vap->va_size =
    376   1.9      cgd 			ctob(procp->p_vmspace->vm_tsize +
    377   1.9      cgd 				    procp->p_vmspace->vm_dsize +
    378   1.9      cgd 				    procp->p_vmspace->vm_ssize);
    379   1.9      cgd 		break;
    380   1.9      cgd 
    381   1.9      cgd 	case Pregs:
    382  1.11      cgd 		vap->va_bytes = vap->va_size = sizeof(struct reg);
    383  1.12       ws 		break;
    384  1.12       ws 
    385  1.12       ws 	case Pstatus:
    386  1.12       ws 		vap->va_bytes = vap->va_size = 256;	/* only a maximum */
    387  1.12       ws 		break;
    388  1.12       ws 
    389   1.9      cgd 	case Pctl:
    390  1.12       ws 		break;
    391  1.12       ws 
    392   1.9      cgd 	case Pnote:
    393   1.9      cgd 	case Pnotepg:
    394   1.9      cgd 		break;
    395   1.1       pk 
    396   1.9      cgd 	default:
    397  1.12       ws 		panic("procfs_getattr type");
    398   1.1       pk 	}
    399   1.1       pk 
    400   1.9      cgd 	return (error);
    401   1.1       pk }
    402   1.1       pk 
    403   1.9      cgd procfs_setattr(vp, vap, cred, p)
    404   1.5       pk 	struct vnode *vp;
    405   1.5       pk 	struct vattr *vap;
    406   1.5       pk 	struct ucred *cred;
    407   1.5       pk 	struct proc *p;
    408   1.5       pk {
    409   1.5       pk 	/*
    410   1.9      cgd 	 * just fake out attribute setting
    411   1.9      cgd 	 * it's not good to generate an error
    412   1.9      cgd 	 * return, otherwise things like creat()
    413   1.9      cgd 	 * will fail when they try to set the
    414   1.9      cgd 	 * file length to 0.  worse, this means
    415   1.9      cgd 	 * that echo $note > /proc/$pid/note will fail.
    416   1.5       pk 	 */
    417   1.5       pk 
    418   1.9      cgd 	return (0);
    419   1.5       pk }
    420   1.5       pk 
    421   1.9      cgd /*
    422   1.9      cgd  * implement access checking.
    423   1.9      cgd  *
    424   1.9      cgd  * something very similar to this code is duplicated
    425   1.9      cgd  * throughout the 4bsd kernel and should be moved
    426   1.9      cgd  * into kern/vfs_subr.c sometime.
    427   1.9      cgd  *
    428   1.9      cgd  * actually, the check for super-user is slightly
    429   1.9      cgd  * broken since it will allow read access to write-only
    430   1.9      cgd  * objects.  this doesn't cause any particular trouble
    431   1.9      cgd  * but does mean that the i/o entry points need to check
    432   1.9      cgd  * that the operation really does make sense.
    433   1.9      cgd  */
    434   1.9      cgd procfs_access(vp, mode, cred, p)
    435   1.1       pk 	struct vnode *vp;
    436   1.1       pk 	int mode;
    437   1.1       pk 	struct ucred *cred;
    438   1.1       pk 	struct proc *p;
    439   1.1       pk {
    440   1.9      cgd 	struct vattr *vap;
    441   1.1       pk 	struct vattr vattr;
    442   1.1       pk 	int error;
    443   1.1       pk 
    444   1.1       pk 	/*
    445   1.1       pk 	 * If you're the super-user,
    446   1.1       pk 	 * you always get access.
    447   1.1       pk 	 */
    448   1.9      cgd 	if (cred->cr_uid == (uid_t) 0)
    449   1.1       pk 		return (0);
    450   1.1       pk 	vap = &vattr;
    451   1.9      cgd 	if (error = VOP_GETATTR(vp, vap, cred, p))
    452   1.1       pk 		return (error);
    453   1.9      cgd 
    454   1.1       pk 	/*
    455   1.1       pk 	 * Access check is based on only one of owner, group, public.
    456   1.1       pk 	 * If not owner, then check group. If not a member of the
    457   1.1       pk 	 * group, then check public access.
    458   1.1       pk 	 */
    459   1.1       pk 	if (cred->cr_uid != vap->va_uid) {
    460   1.9      cgd 		gid_t *gp;
    461   1.9      cgd 		int i;
    462   1.9      cgd 
    463   1.1       pk 		mode >>= 3;
    464   1.1       pk 		gp = cred->cr_groups;
    465   1.1       pk 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
    466   1.1       pk 			if (vap->va_gid == *gp)
    467   1.1       pk 				goto found;
    468   1.1       pk 		mode >>= 3;
    469   1.1       pk found:
    470   1.1       pk 		;
    471   1.1       pk 	}
    472   1.9      cgd 
    473   1.9      cgd 	if ((vap->va_mode & mode) == mode)
    474   1.1       pk 		return (0);
    475   1.9      cgd 
    476   1.1       pk 	return (EACCES);
    477   1.1       pk }
    478   1.1       pk 
    479   1.1       pk /*
    480   1.9      cgd  * lookup.  this is incredibly complicated in the
    481   1.9      cgd  * general case, however for most pseudo-filesystems
    482   1.9      cgd  * very little needs to be done.
    483   1.9      cgd  *
    484   1.9      cgd  * (dvp) is the directory in which the lookup takes place.
    485   1.9      cgd  * (ndp) contains all the information about the type of
    486   1.9      cgd  *       lookup being done.
    487   1.9      cgd  *
    488   1.9      cgd  * (dvp) is locked on entry.
    489   1.9      cgd  * the job of lookup is to set ndp->ni_dvp, and ndp->ni_vp.
    490   1.9      cgd  * (this changes in 4.4 where all we want is the equivalent
    491   1.9      cgd  * of ndp->ni_vp.)
    492   1.9      cgd  *
    493   1.9      cgd  * unless you want to get a migraine, just make sure your
    494   1.9      cgd  * filesystem doesn't do any locking of its own.  otherwise
    495   1.9      cgd  * read and inwardly digest ufs_lookup().
    496   1.9      cgd  */
    497   1.9      cgd procfs_lookup(dvp, ndp, p)
    498   1.9      cgd 	struct vnode *dvp;
    499   1.9      cgd 	struct nameidata *ndp;
    500   1.1       pk 	struct proc *p;
    501   1.1       pk {
    502   1.9      cgd 	char *pname = ndp->ni_ptr;
    503   1.9      cgd 	int error = 0;
    504   1.9      cgd 	int flag;
    505   1.1       pk 	pid_t pid;
    506   1.1       pk 	struct vnode *nvp;
    507   1.9      cgd 	struct pfsnode *pfs;
    508   1.1       pk 	struct proc *procp;
    509   1.9      cgd 	int mode;
    510   1.9      cgd 	pfstype pfs_type;
    511   1.9      cgd 	int i;
    512   1.1       pk 
    513   1.9      cgd 	if (ndp->ni_namelen == 1 && *pname == '.') {
    514   1.9      cgd 		ndp->ni_vp = dvp;
    515   1.9      cgd 		ndp->ni_dvp = dvp;
    516   1.9      cgd 		VREF(dvp);
    517   1.9      cgd 		return (0);
    518   1.9      cgd 	}
    519   1.1       pk 
    520   1.9      cgd 	ndp->ni_dvp = dvp;
    521   1.1       pk 	ndp->ni_vp = NULL;
    522   1.1       pk 
    523   1.9      cgd 	pfs = VTOPFS(dvp);
    524   1.9      cgd 	switch (pfs->pfs_type) {
    525   1.9      cgd 	case Proot:
    526   1.9      cgd 		if (ndp->ni_isdotdot)
    527   1.9      cgd 			return (EIO);
    528   1.9      cgd 
    529  1.12       ws 		if (NDEQ(ndp, "curproc", 7)) {
    530  1.12       ws 			if (error = procfs_allocvp(dvp->v_mount, &nvp, 1, Proot))
    531  1.12       ws 				return error;
    532  1.12       ws 			ndp->ni_vp = nvp;
    533  1.12       ws 			return 0;
    534  1.12       ws 		}
    535  1.12       ws 
    536  1.12       ws 		pid = atopid(pname, ndp->ni_namelen);
    537   1.9      cgd 		if (pid == NO_PID)
    538   1.9      cgd 			return (ENOENT);
    539   1.9      cgd 
    540   1.9      cgd 		procp = PFIND(pid);
    541   1.9      cgd 		if (procp == 0)
    542   1.9      cgd 			return (ENOENT);
    543   1.9      cgd 
    544   1.9      cgd 		error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc);
    545   1.9      cgd 		if (error)
    546   1.9      cgd 			return (error);
    547   1.9      cgd 
    548   1.9      cgd 		ndp->ni_vp = nvp;
    549   1.9      cgd 		return (0);
    550   1.9      cgd 
    551   1.9      cgd 	case Pproc:
    552   1.9      cgd 		if (ndp->ni_isdotdot) {
    553   1.9      cgd 			ndp->ni_dvp = dvp;
    554   1.9      cgd 			error = procfs_root(dvp->v_mount, &ndp->ni_vp);
    555   1.9      cgd 			return (error);
    556   1.9      cgd 		}
    557   1.1       pk 
    558   1.9      cgd 		procp = PFIND(pfs->pfs_pid);
    559   1.9      cgd 		if (procp == 0)
    560   1.9      cgd 			return (ENOENT);
    561   1.9      cgd 
    562   1.9      cgd 		for (i = 0; i < Nprocent; i++) {
    563   1.9      cgd 			struct pfsnames *dp = &procent[i];
    564   1.9      cgd 
    565   1.9      cgd 			if (ndp->ni_namelen == dp->d_namlen &&
    566   1.9      cgd 			    bcmp(pname, dp->d_name, dp->d_namlen) == 0) {
    567   1.9      cgd 			    	pfs_type = dp->d_pfstype;
    568   1.9      cgd 				goto found;
    569   1.9      cgd 			}
    570   1.9      cgd 		}
    571   1.9      cgd 		return (ENOENT);
    572   1.1       pk 
    573   1.9      cgd 	found:
    574   1.9      cgd 		if (pfs_type == Pfile) {
    575   1.9      cgd 			nvp = procfs_findtextvp(procp);
    576   1.9      cgd 			if (nvp) {
    577   1.9      cgd 				VREF(nvp);
    578   1.9      cgd 				VOP_LOCK(nvp);
    579   1.9      cgd 			} else {
    580   1.9      cgd 				error = ENXIO;
    581   1.9      cgd 			}
    582   1.9      cgd 		} else {
    583   1.9      cgd 			error = procfs_allocvp(dvp->v_mount, &nvp,
    584   1.9      cgd 					pfs->pfs_pid, pfs_type);
    585   1.9      cgd 			if (error)
    586   1.9      cgd 				return (error);
    587   1.1       pk 
    588   1.9      cgd 			pfs = VTOPFS(nvp);
    589   1.9      cgd 		}
    590   1.9      cgd 		ndp->ni_vp = nvp;
    591   1.9      cgd 		return (error);
    592   1.1       pk 
    593   1.9      cgd 	default:
    594   1.9      cgd 		return (ENOTDIR);
    595   1.1       pk 	}
    596   1.1       pk }
    597   1.1       pk 
    598   1.9      cgd /*
    599   1.9      cgd  * readdir returns directory entries from pfsnode (vp).
    600   1.9      cgd  *
    601   1.9      cgd  * the strategy here with procfs is to generate a single
    602   1.9      cgd  * directory entry at a time (struct pfsdent) and then
    603   1.9      cgd  * copy that out to userland using uiomove.  a more efficent
    604   1.9      cgd  * though more complex implementation, would try to minimize
    605   1.9      cgd  * the number of calls to uiomove().  for procfs, this is
    606   1.9      cgd  * hardly worth the added code complexity.
    607   1.9      cgd  *
    608   1.9      cgd  * this should just be done through read()
    609   1.9      cgd  */
    610   1.9      cgd procfs_readdir(vp, uio, cred, eofflagp, cookies, ncookies)
    611   1.1       pk         struct vnode *vp;
    612   1.9      cgd         struct uio *uio;
    613   1.1       pk         struct ucred *cred;
    614   1.1       pk         int *eofflagp;
    615   1.6       ws 	u_int *cookies;
    616   1.6       ws 	int ncookies;
    617   1.1       pk {
    618   1.9      cgd 	struct pfsdent d;
    619   1.9      cgd 	struct pfsdent *dp = &d;
    620   1.9      cgd 	struct pfsnode *pfs;
    621   1.9      cgd 	int error;
    622   1.9      cgd 	int count;
    623   1.9      cgd 	int i;
    624   1.9      cgd 
    625   1.9      cgd 	pfs = VTOPFS(vp);
    626   1.1       pk 
    627   1.9      cgd 	if (uio->uio_resid < UIO_MX)
    628   1.9      cgd 		return (EINVAL);
    629   1.9      cgd 	if (uio->uio_offset & (UIO_MX-1))
    630   1.9      cgd 		return (EINVAL);
    631   1.9      cgd 	if (uio->uio_offset < 0)
    632   1.1       pk 		return (EINVAL);
    633   1.1       pk 
    634   1.9      cgd 	error = 0;
    635   1.1       pk 	count = 0;
    636   1.9      cgd 	i = uio->uio_offset / UIO_MX;
    637   1.9      cgd 
    638   1.9      cgd 	switch (pfs->pfs_type) {
    639   1.9      cgd 	/*
    640   1.9      cgd 	 * this is for the process-specific sub-directories.
    641   1.9      cgd 	 * all that is needed to is copy out all the entries
    642   1.9      cgd 	 * from the procent[] table (top of this file).
    643   1.9      cgd 	 */
    644   1.9      cgd 	case Pproc: {
    645  1.12       ws 		while (uio->uio_resid >= UIO_MX && (!cookies || ncookies > 0)) {
    646   1.9      cgd 			struct pfsnames *dt;
    647  1.12       ws 			pid_t pid = pfs->pfs_pid;
    648   1.9      cgd 
    649   1.9      cgd 			if (i >= Nprocent) {
    650   1.9      cgd 				*eofflagp = 1;
    651   1.9      cgd 				break;
    652   1.9      cgd 			}
    653   1.9      cgd 
    654   1.9      cgd 			dt = &procent[i];
    655   1.9      cgd 			dp->d_reclen = UIO_MX;
    656  1.12       ws 
    657  1.12       ws 			if (dt->d_pfstype == Proot)
    658  1.12       ws 				pid = 0;
    659  1.12       ws 			dp->d_fileno = PROCFS_FILENO(pid, dt->d_pfstype);
    660   1.9      cgd 			dp->d_namlen = dt->d_namlen;
    661   1.9      cgd 			bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1);
    662   1.9      cgd 			error = uiomove((caddr_t) dp, UIO_MX, uio);
    663   1.9      cgd 			if (error)
    664   1.9      cgd 				break;
    665   1.9      cgd 			count += UIO_MX;
    666   1.9      cgd 			i++;
    667  1.12       ws 			if (cookies) {
    668  1.12       ws 				*cookies++ = i * UIO_MX;
    669  1.12       ws 				ncookies--;
    670  1.12       ws 			}
    671   1.6       ws 		}
    672   1.9      cgd 
    673   1.9      cgd 	    	break;
    674   1.9      cgd 
    675   1.9      cgd 	    }
    676   1.9      cgd 
    677   1.9      cgd 	/*
    678   1.9      cgd 	 * this is for the root of the procfs filesystem
    679   1.9      cgd 	 * what is needed is a special entry for "curproc"
    680   1.9      cgd 	 * followed by an entry for each process on allproc
    681   1.9      cgd #ifdef PROCFS_ZOMBIE
    682   1.9      cgd 	 * and zombproc.
    683   1.9      cgd #endif
    684   1.9      cgd 	 */
    685   1.9      cgd 
    686   1.9      cgd 	case Proot: {
    687   1.9      cgd 		int pcnt;
    688   1.9      cgd #ifdef PROCFS_ZOMBIE
    689   1.9      cgd 		int doingzomb = 0;
    690   1.9      cgd #endif
    691   1.9      cgd 		struct proc *p;
    692   1.9      cgd 
    693  1.10      cgd 		p = (struct proc *) allproc;
    694   1.9      cgd 
    695   1.9      cgd 		pcnt = PROCFS_XFILES;
    696   1.9      cgd 
    697  1.12       ws 		while (p && uio->uio_resid >= UIO_MX && (!cookies || ncookies > 0)) {
    698   1.9      cgd 			bzero((char *) dp, UIO_MX);
    699   1.9      cgd 			dp->d_reclen = UIO_MX;
    700   1.9      cgd 
    701   1.9      cgd 			switch (i) {
    702  1.12       ws 			case 0:		/* `.' */
    703  1.12       ws 			case 1:		/* `..' */
    704  1.12       ws 				dp->d_fileno = PROCFS_FILENO(0, Proot);
    705  1.12       ws 				bcopy("..",dp->d_name,3);
    706  1.12       ws 				dp->d_namlen = i + 1;
    707  1.12       ws 				dp->d_name[i + 1] = 0;
    708  1.12       ws 				break;
    709  1.12       ws 			case 2:
    710   1.9      cgd 				/* ship out entry for "curproc" */
    711  1.12       ws 				dp->d_fileno = PROCFS_FILENO(1, Proot);
    712   1.9      cgd 				dp->d_namlen = 7;
    713   1.9      cgd 				bcopy("curproc", dp->d_name, dp->d_namlen+1);
    714   1.9      cgd 				break;
    715   1.9      cgd 
    716   1.9      cgd 			default:
    717   1.9      cgd 				if (pcnt >= i) {
    718   1.9      cgd 					dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
    719   1.9      cgd 					dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid);
    720   1.9      cgd 				}
    721   1.9      cgd 
    722   1.9      cgd 				p = p->p_nxt;
    723   1.9      cgd 
    724   1.9      cgd #ifdef PROCFS_ZOMBIE
    725   1.9      cgd 				if (p == 0 && doingzomb == 0) {
    726   1.9      cgd 					doingzomb = 1;
    727   1.9      cgd 					p = zombproc;
    728   1.9      cgd 				}
    729   1.1       pk #endif
    730   1.1       pk 
    731   1.9      cgd 				if (pcnt++ < i)
    732   1.9      cgd 					continue;
    733   1.9      cgd 
    734   1.9      cgd 				break;
    735   1.1       pk 			}
    736   1.9      cgd 			error = uiomove((caddr_t) dp, UIO_MX, uio);
    737   1.9      cgd 			if (error)
    738   1.9      cgd 				break;
    739   1.9      cgd 			count += UIO_MX;
    740   1.9      cgd 			i++;
    741  1.12       ws 			if (cookies) {
    742  1.12       ws 				*cookies++ = i * UIO_MX;
    743  1.12       ws 				ncookies--;
    744  1.12       ws 			}
    745   1.1       pk 		}
    746   1.1       pk 
    747   1.9      cgd 		break;
    748   1.9      cgd 
    749   1.9      cgd 	    }
    750   1.9      cgd 
    751   1.9      cgd 	default:
    752   1.9      cgd 		error = ENOTDIR;
    753   1.9      cgd 		break;
    754   1.1       pk 	}
    755   1.9      cgd 
    756   1.9      cgd 	uio->uio_offset = i * UIO_MX;
    757   1.1       pk 	if (count == 0)
    758   1.1       pk 		*eofflagp = 1;
    759   1.1       pk 
    760   1.9      cgd 	return (error);
    761  1.12       ws }
    762  1.12       ws 
    763  1.12       ws /*
    764  1.12       ws  * readlink reads the link of "curproc"
    765  1.12       ws  */
    766  1.12       ws procfs_readlink(vp, uio, cred)
    767  1.12       ws 	struct vnode *vp;
    768  1.12       ws 	struct uio *uio;
    769  1.12       ws 	struct ucred *cred;
    770  1.12       ws {
    771  1.12       ws 	struct pfsnode *pfs = VTOPFS(vp);
    772  1.12       ws 	char buf[16];		/* should be enough */
    773  1.12       ws 	int len;
    774  1.12       ws 
    775  1.12       ws 	if (pfs->pfs_fileno != PROCFS_FILENO(1,Proot))
    776  1.12       ws 		return EINVAL;
    777  1.12       ws 
    778  1.12       ws 	len = sprintf(buf,"%ld",(long)curproc->p_pid);
    779  1.12       ws 
    780  1.12       ws 	return uiomove(buf, len, uio);
    781   1.1       pk }
    782   1.1       pk 
    783   1.1       pk /*
    784   1.9      cgd  * convert decimal ascii to pid_t
    785   1.1       pk  */
    786   1.9      cgd static pid_t
    787   1.9      cgd atopid(b, len)
    788   1.9      cgd 	const char *b;
    789   1.9      cgd 	u_int len;
    790   1.1       pk {
    791   1.9      cgd 	pid_t p = 0;
    792   1.1       pk 
    793   1.1       pk 	while (len--) {
    794   1.9      cgd 		char c = *b++;
    795   1.1       pk 		if (c < '0' || c > '9')
    796   1.9      cgd 			return (NO_PID);
    797   1.9      cgd 		p = 10 * p + (c - '0');
    798   1.9      cgd 		if (p > PID_MAX)
    799   1.9      cgd 			return (NO_PID);
    800   1.1       pk 	}
    801   1.9      cgd 
    802   1.9      cgd 	return (p);
    803   1.1       pk }
    804   1.9      cgd 
    805   1.9      cgd /*
    806   1.9      cgd  * procfs vnode operations.
    807   1.9      cgd  */
    808   1.9      cgd struct vnodeops procfs_vnodeops = {
    809   1.9      cgd 	procfs_lookup,		/* lookup */
    810   1.9      cgd 	procfs_create,		/* create */
    811   1.9      cgd 	procfs_mknod,		/* mknod */
    812   1.9      cgd 	procfs_open,		/* open */
    813   1.9      cgd 	procfs_close,		/* close */
    814   1.9      cgd 	procfs_access,		/* access */
    815   1.9      cgd 	procfs_getattr,		/* getattr */
    816   1.9      cgd 	procfs_setattr,		/* setattr */
    817   1.9      cgd 	procfs_read,		/* read */
    818   1.9      cgd 	procfs_write,		/* write */
    819   1.9      cgd 	procfs_ioctl,		/* ioctl */
    820   1.9      cgd 	procfs_select,		/* select */
    821   1.9      cgd 	procfs_mmap,		/* mmap */
    822   1.9      cgd 	procfs_fsync,		/* fsync */
    823   1.9      cgd 	procfs_seek,		/* seek */
    824   1.9      cgd 	procfs_remove,		/* remove */
    825   1.9      cgd 	procfs_link,		/* link */
    826   1.9      cgd 	procfs_rename,		/* rename */
    827   1.9      cgd 	procfs_mkdir,		/* mkdir */
    828   1.9      cgd 	procfs_rmdir,		/* rmdir */
    829   1.9      cgd 	procfs_symlink,		/* symlink */
    830   1.9      cgd 	procfs_readdir,		/* readdir */
    831   1.9      cgd 	procfs_readlink,	/* readlink */
    832   1.9      cgd 	procfs_abortop,		/* abortop */
    833   1.9      cgd 	procfs_inactive,	/* inactive */
    834   1.9      cgd 	procfs_reclaim,		/* reclaim */
    835   1.9      cgd 	procfs_lock,		/* lock */
    836   1.9      cgd 	procfs_unlock,		/* unlock */
    837   1.9      cgd 	procfs_bmap,		/* bmap */
    838   1.9      cgd 	procfs_strategy,	/* strategy */
    839   1.9      cgd 	procfs_print,		/* print */
    840   1.9      cgd 	procfs_islocked,	/* islocked */
    841   1.9      cgd 	procfs_advlock,		/* advlock */
    842   1.9      cgd };
    843