Home | History | Annotate | Line # | Download | only in procfs
procfs_vnops.c revision 1.1
      1 /*
      2  *	%W% (Erasmus) %G%	- pk (at) cs.few.eur.nl
      3  */
      4 
      5 #include "param.h"
      6 #include "systm.h"
      7 #include "time.h"
      8 #include "kernel.h"
      9 #include "ioctl.h"
     10 #include "file.h"
     11 #include "proc.h"
     12 #include "buf.h"
     13 #include "vnode.h"
     14 #include "namei.h"
     15 #include "resourcevar.h"
     16 #include "vm/vm.h"
     17 #include "kinfo.h"
     18 #include "kinfo_proc.h"
     19 
     20 #include "procfs.h"
     21 #include "pfsnode.h"
     22 
     23 #include "machine/vmparam.h"
     24 
     25 /*
     26  * procfs vnode operations.
     27  */
     28 struct vnodeops pfs_vnodeops = {
     29 	pfs_lookup,		/* lookup */
     30 	pfs_create,		/* create */
     31 	pfs_mknod,		/* mknod */
     32 	pfs_open,		/* open */
     33 	pfs_close,		/* close */
     34 	pfs_access,		/* access */
     35 	pfs_getattr,		/* getattr */
     36 	pfs_setattr,		/* setattr */
     37 	pfs_read,		/* read */
     38 	pfs_write,		/* write */
     39 	pfs_ioctl,		/* ioctl */
     40 	pfs_select,		/* select */
     41 	pfs_mmap,		/* mmap */
     42 	pfs_fsync,		/* fsync */
     43 	pfs_seek,		/* seek */
     44 	pfs_remove,		/* remove */
     45 	pfs_link,		/* link */
     46 	pfs_rename,		/* rename */
     47 	pfs_mkdir,		/* mkdir */
     48 	pfs_rmdir,		/* rmdir */
     49 	pfs_symlink,		/* symlink */
     50 	pfs_readdir,		/* readdir */
     51 	pfs_readlink,		/* readlink */
     52 	pfs_abortop,		/* abortop */
     53 	pfs_inactive,		/* inactive */
     54 	pfs_reclaim,		/* reclaim */
     55 	pfs_lock,		/* lock */
     56 	pfs_unlock,		/* unlock */
     57 	pfs_bmap,		/* bmap */
     58 	pfs_strategy,		/* strategy */
     59 	pfs_print,		/* print */
     60 	pfs_islocked,		/* islocked */
     61 	pfs_advlock,		/* advlock */
     62 };
     63 
     64 /*
     65  * Vnode Operations.
     66  *
     67  */
     68 /* ARGSUSED */
     69 int
     70 pfs_open(vp, mode, cred, p)
     71 	register struct vnode *vp;
     72 	int mode;
     73 	struct ucred *cred;
     74 	struct proc *p;
     75 {
     76 	struct pfsnode	*pfsp = VTOPFS(vp);
     77 
     78 #ifdef DEBUG
     79 	if (pfs_debug)
     80 		printf("pfs_open: vp 0x%x, proc %d\n", vp, p->p_pid);
     81 #endif
     82 
     83 	if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) == NULL)
     84 		return ESRCH;
     85 
     86 	if (	(pfsp->flags & FWRITE) && (mode & O_EXCL) ||
     87 		(pfsp->flags & O_EXCL) && (mode & FWRITE)	)
     88 		return EBUSY;
     89 
     90 
     91 	if (mode & FWRITE)
     92 		pfsp->flags = (mode & (FWRITE|O_EXCL));
     93 	return 0;
     94 }
     95 
     96 /*
     97  * /proc filesystem close routine
     98  */
     99 /* ARGSUSED */
    100 int
    101 pfs_close(vp, flag, cred, p)
    102 	register struct vnode *vp;
    103 	int flag;
    104 	struct ucred *cred;
    105 	struct proc *p;
    106 {
    107 	struct pfsnode	*pfsp = VTOPFS(vp);
    108 
    109 #ifdef DEBUG
    110 	if (pfs_debug)
    111 		printf("pfs_close: vp 0x%x proc %d\n", vp, p->p_pid);
    112 #endif
    113 	if ((flag & FWRITE) && (pfsp->flags & O_EXCL))
    114 		pfsp->flags &= ~(FWRITE|O_EXCL);
    115 
    116 	return (0);
    117 }
    118 
    119 /*
    120  * Ioctl operation.
    121  */
    122 /* ARGSUSED */
    123 int
    124 pfs_ioctl(vp, com, data, fflag, cred, p)
    125 	struct vnode *vp;
    126 	int com;
    127 	caddr_t data;
    128 	int fflag;
    129 	struct ucred *cred;
    130 	struct proc *p;
    131 {
    132 	int		error = 0;
    133 	struct proc	*procp;
    134 	struct pfsnode	*pfsp = VTOPFS(vp);
    135 
    136 	procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
    137 	if (!procp)
    138 		return ESRCH;
    139 
    140 	switch (com) {
    141 
    142 	case PIOCGPINFO: {
    143 		int copysize = sizeof(struct kinfo_proc), needed;
    144 		kinfo_doproc(KINFO_PROC_PID, data, &copysize,
    145 						pfsp->pfs_pid, &needed);
    146 		break;
    147 		}
    148 
    149 #ifdef notyet /* Changes to proc.h needed */
    150 	case PIOCGSIGSET:
    151 		procp->p_psigset = *(sigset_t *)data;
    152 		break;
    153 
    154 	case PIOCSSIGSET:
    155 		*(sigset_t *)data = procp->p_psigset;
    156 		break;
    157 
    158 	case PIOCGFLTSET:
    159 		procp->p_pfltset = *(sigflt_t *)data;
    160 		break;
    161 
    162 	case PIOCSFLTSET:
    163 		*(fltset_t *)data = procp->p_pfltset;
    164 		break;
    165 #endif
    166 
    167 	case PIOCGMAPFD:
    168 		error = pfs_vmfd(procp, pfsp, (struct vmfd *)data, p);
    169 		break;
    170 
    171 	case PIOCGNMAP:
    172 		*(int *)data = pfs_vm_nentries(procp, pfsp);
    173 		break;
    174 
    175 	case PIOCGMAP:
    176 		error = pfs_vmmap(procp, pfsp, *(struct procmap *)data);
    177 		break;
    178 
    179 	default:
    180 		error = EIO;
    181 		break;
    182 	}
    183 	return error;
    184 }
    185 
    186 /*
    187  * Pass I/O requests to the memory filesystem process.
    188  */
    189 int
    190 pfs_strategy(bp)
    191 	register struct buf *bp;
    192 {
    193 	struct vnode *vp;
    194 	struct proc *p = curproc;		/* XXX */
    195 
    196 	return (0);
    197 }
    198 
    199 /*
    200  * This is a noop, simply returning what one has been given.
    201  */
    202 int
    203 pfs_bmap(vp, bn, vpp, bnp)
    204 	struct vnode *vp;
    205 	daddr_t bn;
    206 	struct vnode **vpp;
    207 	daddr_t *bnp;
    208 {
    209 
    210 	if (vpp != NULL)
    211 		*vpp = vp;
    212 	if (bnp != NULL)
    213 		*bnp = bn;
    214 	return (0);
    215 }
    216 
    217 /*
    218  * /proc filesystem inactive routine
    219  */
    220 /* ARGSUSED */
    221 int
    222 pfs_inactive(vp, p)
    223 	struct vnode *vp;
    224 	struct proc *p;
    225 {
    226 	struct pfsnode	*pfsp = VTOPFS(vp);
    227 
    228 #if 0
    229 	if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) && vp->v_usecount == 0)
    230 		vgone(vp);
    231 #endif
    232 	if (vp->v_usecount == 0)
    233 		vgone(vp);
    234 	return 0;
    235 }
    236 
    237 /*
    238  * /proc filesystem reclaim routine
    239  */
    240 /* ARGSUSED */
    241 int
    242 pfs_reclaim(vp)
    243 	struct vnode *vp;
    244 {
    245 	struct pfsnode	**pp, *pfsp = VTOPFS(vp);
    246 
    247 	for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) {
    248 		if (*pp == pfsp) {
    249 			*pp = pfsp->pfs_next;
    250 			break;
    251 		}
    252 	}
    253 	return 0;
    254 }
    255 
    256 /*
    257  * Print out the contents of an pfsnode.
    258  */
    259 void
    260 pfs_print(vp)
    261 	struct vnode *vp;
    262 {
    263 	return;
    264 }
    265 
    266 /*
    267  * /proc bad operation
    268  */
    269 int
    270 pfs_badop()
    271 {
    272 	printf("pfs_badop called\n");
    273 	return EIO;
    274 }
    275 
    276 #if 0 /* Moved to pfs_subr.c */
    277 /*
    278  * Vnode op for reading/writing.
    279  */
    280 /* ARGSUSED */
    281 int
    282 pfs_doio(vp, uio, ioflag, cred)
    283 	struct vnode *vp;
    284 	register struct uio *uio;
    285 	int ioflag;
    286 	struct ucred *cred;
    287 {
    288 	struct pfsnode	*pfsp = VTOPFS(vp);
    289 	struct proc	*procp;
    290 	int		error = 0;
    291 	long		n, off;
    292 	caddr_t		kva;
    293 
    294 #ifdef DEBUG
    295 	if (pfs_debug)
    296 		printf("pfs_doio(%s): vp 0x%x, proc %x\n",
    297 			uio->uio_rw==UIO_READ?"R":"W", vp, uio->uio_procp);
    298 #endif
    299 
    300 #ifdef DIAGNOSTIC
    301 	if (vp->v_type != VPROC)
    302 		panic("pfs_doio vtype");
    303 #endif
    304 	procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
    305 	if (!procp)
    306 		return ESRCH;
    307 
    308 	if (uio->uio_resid == 0)
    309 		return (0);
    310 	if (uio->uio_offset < 0)
    311 		return (EINVAL);
    312 
    313 	do { /* One page at a time */
    314 		off = uio->uio_offset - trunc_page(uio->uio_offset);
    315 		n = MIN(PAGE_SIZE-off, uio->uio_resid);
    316 
    317 		/* Map page into kernel space */
    318 		error = pfs_map(procp, &kva, uio->uio_rw, uio->uio_offset);
    319 		if (error)
    320 			return error;
    321 
    322 		error = uiomove(kva + off, (int)n, uio);
    323 		pfs_unmap(procp, kva);
    324 
    325 	} while (error == 0 && uio->uio_resid > 0);
    326 
    327 	return (error);
    328 }
    329 #endif
    330 
    331 /*
    332  * Make up some attributes for a process file
    333  */
    334 int
    335 pfs_getattr (vp, vap, cred, p)
    336 	struct vnode *vp;
    337 	struct vattr *vap;
    338 	struct ucred *cred;
    339 	struct proc *p;
    340 {
    341 	struct pfsnode *pfsp = VTOPFS(vp);
    342 	struct proc *procp;
    343 
    344 	VATTR_NULL(vap);
    345 	vap->va_type = vp->v_type;
    346 
    347 	if (vp->v_flag & VROOT) {
    348 		vap->va_mode = 0755;
    349 		vap->va_nlink = 2;
    350 		vap->va_size =
    351 			roundup((2+nprocs)*sizeof(struct pfsdent), DIRBLKSIZ);
    352 		vap->va_size_rsv = 0;
    353 		vap->va_uid = 0;
    354 		vap->va_gid = 0;
    355 		vap->va_atime = vap->va_mtime = vap->va_ctime = time; /*XXX*/
    356 		return 0;
    357 	}
    358 
    359 	procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
    360 	if (!procp)
    361 		return ESRCH;
    362 
    363 	vap->va_mode = 0700;
    364 	vap->va_nlink = 1;
    365 	vap->va_size = ctob(	procp->p_vmspace->vm_tsize +
    366 				procp->p_vmspace->vm_dsize +
    367 				procp->p_vmspace->vm_ssize);
    368 	vap->va_size_rsv = 0;
    369 	vap->va_blocksize = page_size;
    370 	vap->va_uid = procp->p_ucred->cr_uid;
    371 	vap->va_gid = procp->p_ucred->cr_gid;
    372 	if (vap->va_uid != procp->p_cred->p_ruid)
    373 		vap->va_mode |= VSUID;
    374 	if (vap->va_gid != procp->p_cred->p_rgid)
    375 		vap->va_mode |= VSGID;
    376 	if (procp->p_flag & SLOAD) {
    377 		vap->va_atime = vap->va_mtime = vap->va_ctime =
    378 			procp->p_stats->p_start;
    379 	}
    380 
    381 	return 0;
    382 }
    383 
    384 int
    385 pfs_access (vp, mode, cred, p)
    386 	struct vnode *vp;
    387 	int mode;
    388 	struct ucred *cred;
    389 	struct proc *p;
    390 {
    391 	register struct vattr *vap;
    392 	register gid_t *gp;
    393 	struct vattr vattr;
    394 	register int i;
    395 	int error;
    396 
    397 	/*
    398 	 * If you're the super-user,
    399 	 * you always get access.
    400 	 */
    401 	if (cred->cr_uid == 0)
    402 		return (0);
    403 	vap = &vattr;
    404 	if (error = pfs_getattr(vp, vap, cred, p))
    405 		return (error);
    406 	/*
    407 	 * Access check is based on only one of owner, group, public.
    408 	 * If not owner, then check group. If not a member of the
    409 	 * group, then check public access.
    410 	 */
    411 	if (cred->cr_uid != vap->va_uid) {
    412 		mode >>= 3;
    413 		gp = cred->cr_groups;
    414 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
    415 			if (vap->va_gid == *gp)
    416 				goto found;
    417 		mode >>= 3;
    418 found:
    419 		;
    420 	}
    421 	if ((vap->va_mode & mode) != 0)
    422 		return (0);
    423 	return (EACCES);
    424 }
    425 
    426 /*
    427  * /proc lookup
    428  */
    429 int
    430 pfs_lookup(vp, ndp, p)
    431 	register struct vnode *vp;
    432 	register struct nameidata *ndp;
    433 	struct proc *p;
    434 {
    435 	int lockparent, wantparent, flag, error = 0;
    436 	pid_t pid;
    437 	struct vnode *nvp;
    438 	struct pfsnode *pfsp;
    439 	struct proc *procp;
    440 
    441 #ifdef DEBUG
    442 	if (pfs_debug)
    443 		printf("pfs_lookup: vp 0x%x name %s proc %d\n",
    444 			vp, ndp->ni_ptr, p->p_pid);
    445 #endif
    446 
    447 	ndp->ni_dvp = vp;
    448 	ndp->ni_vp = NULL;
    449 	if (vp->v_type != VDIR)
    450 		return (ENOTDIR);
    451 
    452 	lockparent = ndp->ni_nameiop & LOCKPARENT;
    453 	flag = ndp->ni_nameiop & OPMASK;
    454 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
    455 	if (flag != LOOKUP)
    456 		return EACCES;
    457 	if (ndp->ni_isdotdot) {
    458 		/* Should not happen */
    459 		printf("pfs_lookup: vp 0x%x: dotdot\n", vp);
    460 		return EIO;
    461 	}
    462 	if (ndp->ni_namelen == 1 && *ndp->ni_ptr == '.') {
    463 		VREF(vp);
    464 		ndp->ni_vp = vp;
    465 		return 0;
    466 	}
    467 
    468 	pid = (pid_t)atoi(ndp->ni_ptr, ndp->ni_namelen);
    469 	if (pid == (pid_t)-1)
    470 		return ENOENT;
    471 
    472 	if ((procp = pid?pfind(pid):&proc0) == NULL)
    473 		return ENOENT;
    474 
    475 	for (pfsp = pfshead; pfsp != NULL; pfsp = pfsp->pfs_next) {
    476 		if (pfsp->pfs_pid == pid)
    477 			break;
    478 	}
    479 
    480 	if (pfsp == NULL) {
    481 		struct pfsnode	**pp;
    482 		error = getnewvnode(VT_PROCFS, vp->v_mount, &pfs_vnodeops, &nvp);
    483 		if (error)
    484 			return error;
    485 
    486 		nvp->v_type = VPROC;
    487 		pfsp = VTOPFS(nvp);
    488 		pfsp->pfs_pid = pid;
    489 		pfsp->pfs_vnode = nvp;
    490 		for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next);
    491 		*pp = pfsp;
    492 
    493 	}
    494 	ndp->ni_vp = pfsp->pfs_vnode;
    495 
    496 	return (error);
    497 }
    498 
    499 int
    500 pfs_readdir(vp, uio, cred, eofflagp)
    501         struct vnode *vp;
    502         register struct uio *uio;
    503         struct ucred *cred;
    504         int *eofflagp;
    505 {
    506 	int	error = 0;
    507 	int	count, lost, pcnt, skipcnt, doingzomb = 0;
    508 	struct proc *p;
    509 	struct pfsdent dent;
    510 
    511 #ifdef DEBUG
    512 	if (pfs_debug)
    513 		printf("pfs_readdir: vp 0x%x proc %d\n",
    514 				vp, uio->uio_procp->p_pid);
    515 #endif
    516 	count = uio->uio_resid;
    517 	count &= ~(DIRBLKSIZ - 1);
    518 	lost = uio->uio_resid - count;
    519 	if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
    520 		return (EINVAL);
    521 	uio->uio_resid = count;
    522 	uio->uio_iov->iov_len = count;
    523 	*eofflagp = 1;
    524 	skipcnt = uio->uio_offset / sizeof(struct pfsdent);
    525 
    526 	count = 0;
    527 	if (skipcnt == 0) {
    528 		/* Fake "." and ".." entries? */
    529 #if 1
    530 		dent.d_fileno = 2;		/* XXX - Filesystem root */
    531 		dent.d_reclen = sizeof(struct pfsdent);
    532 
    533 		dent.d_namlen = 1;
    534 		dent.d_nam[0] = '.';
    535 		dent.d_nam[1] = '\0';
    536 		error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
    537 		if (error)
    538 			return error;
    539 
    540 		dent.d_fileno = 2;
    541 		dent.d_namlen = 2;
    542 		dent.d_nam[1] = '.';
    543 		dent.d_nam[2] = '\0';
    544 		error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
    545 		if (error)
    546 			return error;
    547 #endif
    548 		count += 2*dent.d_reclen;
    549 	}
    550 
    551 	p = allproc;
    552 	for (pcnt = 0; p && uio->uio_resid; pcnt++) {
    553 		if (pcnt < skipcnt) {
    554 			p = p->p_nxt;
    555 			if (p == NULL && doingzomb == 0) {
    556 				doingzomb = 1;
    557 				p = zombproc;
    558 			}
    559 			continue;
    560 		}
    561 		*eofflagp = 0;
    562 
    563 		/* "inode" is process slot (actually position on list) */
    564 		dent.d_fileno = (unsigned long)(pcnt+1);
    565 		dent.d_namlen = itos((unsigned int)p->p_pid, dent.d_nam);
    566 		dent.d_nam[dent.d_namlen] = '\0';
    567 
    568 		p = p->p_nxt;
    569 		if (p == NULL && doingzomb == 0) {
    570 			doingzomb = 1;
    571 			p = zombproc;
    572 		}
    573 		if (p == NULL) {
    574 			/* Extend 'reclen' to end of block */;
    575 			dent.d_reclen = DIRBLKSIZ - (count & (DIRBLKSIZ - 1));
    576 		} else
    577 			dent.d_reclen = sizeof(struct pfsdent);
    578 		count += dent.d_reclen;
    579 		error = uiomove((char *)&dent, dent.d_reclen, uio);
    580 		if (error)
    581 			break;
    582 	}
    583 	if (count == 0)
    584 		*eofflagp = 1;
    585 
    586 	uio->uio_resid += lost;
    587 	return error;
    588 }
    589 
    590 /*
    591  * convert n to decimal representation in character array b
    592  * return number of decimal digits produced.
    593  */
    594 int
    595 itos(n, b)
    596 unsigned int n;
    597 char *b;
    598 {
    599 #define BASE	10
    600 	int m = (n<BASE)?0:itos(n/BASE, b);
    601 
    602 	*(b+m) = "0123456789abcdef"[n%BASE];
    603 	return m+1;
    604 }
    605 
    606 /*
    607  * convert decimal ascii representation in b of length len to integer
    608  */
    609 int
    610 atoi(b, len)
    611 char *b;
    612 unsigned int len;
    613 {
    614 	int n = 0;
    615 
    616 	while (len--) {
    617 		register char c = *b++;
    618 		if (c < '0' || c > '9')
    619 			return -1;
    620 		n = 10 * n + (c - '0');
    621 	}
    622 	return n;
    623 }
    624