xref: /csrg-svn/sys/kern/sys_generic.c (revision 23384)
1*23384Smckusick /*
2*23384Smckusick  * Copyright (c) 1982 Regents of the University of California.
3*23384Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*23384Smckusick  * specifies the terms and conditions for redistribution.
5*23384Smckusick  *
6*23384Smckusick  *	@(#)sys_generic.c	6.11 (Berkeley) 06/08/85
7*23384Smckusick  */
87423Sroot 
917094Sbloom #include "param.h"
1017094Sbloom #include "systm.h"
1117094Sbloom #include "dir.h"
1217094Sbloom #include "user.h"
1317094Sbloom #include "ioctl.h"
1417094Sbloom #include "file.h"
1517094Sbloom #include "proc.h"
1617094Sbloom #include "uio.h"
1717094Sbloom #include "kernel.h"
1817094Sbloom #include "stat.h"
197423Sroot 
207423Sroot /*
217423Sroot  * Read system call.
227423Sroot  */
237423Sroot read()
247423Sroot {
257423Sroot 	register struct a {
267423Sroot 		int	fdes;
277423Sroot 		char	*cbuf;
287423Sroot 		unsigned count;
297820Sroot 	} *uap = (struct a *)u.u_ap;
307746Sroot 	struct uio auio;
317746Sroot 	struct iovec aiov;
327423Sroot 
337820Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
347820Sroot 	aiov.iov_len = uap->count;
357820Sroot 	auio.uio_iov = &aiov;
367820Sroot 	auio.uio_iovcnt = 1;
377820Sroot 	rwuio(&auio, UIO_READ);
387820Sroot }
397820Sroot 
407820Sroot readv()
417820Sroot {
427820Sroot 	register struct a {
437820Sroot 		int	fdes;
447820Sroot 		struct	iovec *iovp;
457820Sroot 		int	iovcnt;
467820Sroot 	} *uap = (struct a *)u.u_ap;
477820Sroot 	struct uio auio;
487820Sroot 	struct iovec aiov[16];		/* XXX */
497820Sroot 
507820Sroot 	if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
517423Sroot 		u.u_error = EINVAL;
527423Sroot 		return;
537423Sroot 	}
547820Sroot 	auio.uio_iov = aiov;
557820Sroot 	auio.uio_iovcnt = uap->iovcnt;
569999Ssam 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
579999Ssam 	    (unsigned)(uap->iovcnt * sizeof (struct iovec)));
589999Ssam 	if (u.u_error)
597423Sroot 		return;
607820Sroot 	rwuio(&auio, UIO_READ);
617423Sroot }
627423Sroot 
637423Sroot /*
647423Sroot  * Write system call
657423Sroot  */
667423Sroot write()
677423Sroot {
687423Sroot 	register struct a {
697423Sroot 		int	fdes;
707423Sroot 		char	*cbuf;
717820Sroot 		int	count;
727820Sroot 	} *uap = (struct a *)u.u_ap;
737820Sroot 	struct uio auio;
747820Sroot 	struct iovec aiov;
757423Sroot 
767820Sroot 	auio.uio_iov = &aiov;
777820Sroot 	auio.uio_iovcnt = 1;
787820Sroot 	aiov.iov_base = uap->cbuf;
797820Sroot 	aiov.iov_len = uap->count;
807820Sroot 	rwuio(&auio, UIO_WRITE);
817820Sroot }
827820Sroot 
837820Sroot writev()
847820Sroot {
857820Sroot 	register struct a {
867820Sroot 		int	fdes;
877820Sroot 		struct	iovec *iovp;
887820Sroot 		int	iovcnt;
897820Sroot 	} *uap = (struct a *)u.u_ap;
907820Sroot 	struct uio auio;
917820Sroot 	struct iovec aiov[16];		/* XXX */
927820Sroot 
937820Sroot 	if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
947423Sroot 		u.u_error = EINVAL;
957423Sroot 		return;
967423Sroot 	}
977820Sroot 	auio.uio_iov = aiov;
987820Sroot 	auio.uio_iovcnt = uap->iovcnt;
999999Ssam 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
1009999Ssam 	    (unsigned)(uap->iovcnt * sizeof (struct iovec)));
1019999Ssam 	if (u.u_error)
1027820Sroot 		return;
1037820Sroot 	rwuio(&auio, UIO_WRITE);
1047820Sroot }
1057820Sroot 
1067820Sroot rwuio(uio, rw)
1077820Sroot 	register struct uio *uio;
1087820Sroot 	enum uio_rw rw;
1097820Sroot {
1107820Sroot 	struct a {
1117820Sroot 		int	fdes;
1127820Sroot 	};
1137820Sroot 	register struct file *fp;
1147820Sroot 	register struct iovec *iov;
1157820Sroot 	int i, count;
1167820Sroot 
1177820Sroot 	GETF(fp, ((struct a *)u.u_ap)->fdes);
1187820Sroot 	if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
1197423Sroot 		u.u_error = EBADF;
1207423Sroot 		return;
1217423Sroot 	}
1227820Sroot 	uio->uio_resid = 0;
12316702Smckusick 	uio->uio_segflg = UIO_USERSPACE;
1247820Sroot 	iov = uio->uio_iov;
1257820Sroot 	for (i = 0; i < uio->uio_iovcnt; i++) {
1267820Sroot 		if (iov->iov_len < 0) {
1277820Sroot 			u.u_error = EINVAL;
1287820Sroot 			return;
1297820Sroot 		}
1307820Sroot 		uio->uio_resid += iov->iov_len;
1317820Sroot 		if (uio->uio_resid < 0) {
1327820Sroot 			u.u_error = EINVAL;
1337820Sroot 			return;
1347820Sroot 		}
13513270Ssam 		iov++;
1367820Sroot 	}
1377820Sroot 	count = uio->uio_resid;
13812751Ssam 	uio->uio_offset = fp->f_offset;
13918309Smckusick 	if (setjmp(&u.u_qsave)) {
14018309Smckusick 		if (uio->uio_resid == count) {
14121009Smckusick 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
14218309Smckusick 				u.u_error = EINTR;
14318309Smckusick 			else
14418309Smckusick 				u.u_eosys = RESTARTSYS;
14518309Smckusick 		}
14612751Ssam 	} else
14712751Ssam 		u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio);
1487820Sroot 	u.u_r.r_val1 = count - uio->uio_resid;
14912751Ssam 	fp->f_offset += u.u_r.r_val1;
1507423Sroot }
1517423Sroot 
1527423Sroot /*
1537423Sroot  * Ioctl system call
1547423Sroot  */
1557423Sroot ioctl()
1567423Sroot {
1577423Sroot 	register struct file *fp;
1587624Ssam 	struct a {
1597423Sroot 		int	fdes;
1607423Sroot 		int	cmd;
1617423Sroot 		caddr_t	cmarg;
1627423Sroot 	} *uap;
1637820Sroot 	register int com;
1647820Sroot 	register u_int size;
1657624Ssam 	char data[IOCPARM_MASK+1];
1667423Sroot 
1677423Sroot 	uap = (struct a *)u.u_ap;
16817004Smckusick 	GETF(fp, uap->fdes);
1697423Sroot 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
1707423Sroot 		u.u_error = EBADF;
1717423Sroot 		return;
1727423Sroot 	}
1737624Ssam 	com = uap->cmd;
1747624Ssam 
17513228Ssam #if defined(vax) && defined(COMPAT)
1767624Ssam 	/*
1777624Ssam 	 * Map old style ioctl's into new for the
1787624Ssam 	 * sake of backwards compatibility (sigh).
1797624Ssam 	 */
1807624Ssam 	if ((com&~0xffff) == 0) {
1817624Ssam 		com = mapioctl(com);
1827624Ssam 		if (com == 0) {
1837624Ssam 			u.u_error = EINVAL;
1847624Ssam 			return;
1857624Ssam 		}
1867624Ssam 	}
1877624Ssam #endif
1887624Ssam 	if (com == FIOCLEX) {
1899592Ssam 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
1907423Sroot 		return;
1917423Sroot 	}
1927624Ssam 	if (com == FIONCLEX) {
1939592Ssam 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
1947423Sroot 		return;
1957423Sroot 	}
1967624Ssam 
1977624Ssam 	/*
1987624Ssam 	 * Interpret high order word to find
1997624Ssam 	 * amount of data to be copied to/from the
2007624Ssam 	 * user's address space.
2017624Ssam 	 */
2027624Ssam 	size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
2037624Ssam 	if (size > sizeof (data)) {
2047624Ssam 		u.u_error = EFAULT;
2057423Sroot 		return;
2067423Sroot 	}
20710601Ssam 	if (com&IOC_IN) {
20810601Ssam 		if (size) {
20910601Ssam 			u.u_error =
21010601Ssam 			    copyin(uap->cmarg, (caddr_t)data, (u_int)size);
21110601Ssam 			if (u.u_error)
21210601Ssam 				return;
21310601Ssam 		} else
21410601Ssam 			*(caddr_t *)data = uap->cmarg;
21510601Ssam 	} else if ((com&IOC_OUT) && size)
21610601Ssam 		/*
21710601Ssam 		 * Zero the buffer on the stack so the user
21810601Ssam 		 * always gets back something deterministic.
21910601Ssam 		 */
2207624Ssam 		bzero((caddr_t)data, size);
22111284Ssam 	else if (com&IOC_VOID)
22211284Ssam 		*(caddr_t *)data = uap->cmarg;
2237423Sroot 
22412751Ssam 	switch (com) {
2257624Ssam 
22612751Ssam 	case FIONBIO:
22712751Ssam 		u.u_error = fset(fp, FNDELAY, *(int *)data);
22812751Ssam 		return;
22912751Ssam 
23012751Ssam 	case FIOASYNC:
23112751Ssam 		u.u_error = fset(fp, FASYNC, *(int *)data);
23212751Ssam 		return;
23312751Ssam 
23412751Ssam 	case FIOSETOWN:
23512751Ssam 		u.u_error = fsetown(fp, *(int *)data);
23612751Ssam 		return;
23712751Ssam 
23812751Ssam 	case FIOGETOWN:
23912751Ssam 		u.u_error = fgetown(fp, (int *)data);
24012751Ssam 		return;
2417423Sroot 	}
24212751Ssam 	u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
2437624Ssam 	/*
2447624Ssam 	 * Copy any data to user, size was
2457624Ssam 	 * already set and checked above.
2467624Ssam 	 */
2479999Ssam 	if (u.u_error == 0 && (com&IOC_OUT) && size)
2489999Ssam 		u.u_error = copyout(data, uap->cmarg, (u_int)size);
2497423Sroot }
2507423Sroot 
25112751Ssam int	unselect();
25212751Ssam int	nselcoll;
25317593Skarels 
2547423Sroot /*
25517593Skarels  * Select uses bit masks of file descriptors in ints.
25617593Skarels  * These macros manipulate such bit fields (the filesystem macros use chars).
25717593Skarels  */
25817593Skarels #define NBI		(sizeof(int) * NBBY)		/* bits per int */
25917593Skarels #define	NI		howmany(NOFILE, NBI)
26017593Skarels #define	tbit(p, n)	((p)[(n)/NBI] & (1 << ((n) % NBI)))
26117593Skarels #define	sbit(p, n)	((p)[(n)/NBI] |= (1 << ((n) % NBI)))
26217593Skarels #define	cbit(p, n)	((p)[(n)/NBI] &= ~(1 << ((n) % NBI)))
26317593Skarels 
26417593Skarels /*
26512751Ssam  * Select system call.
2667423Sroot  */
26712751Ssam select()
26812751Ssam {
26912751Ssam 	register struct uap  {
27012751Ssam 		int	nd;
27117593Skarels 		int	*in, *ou, *ex;
27212751Ssam 		struct	timeval *tv;
27312751Ssam 	} *uap = (struct uap *)u.u_ap;
27417593Skarels 	int ibits[3][NI], obits[3][NI];
27512751Ssam 	struct timeval atv;
27617593Skarels 	int s, ncoll, ni;
27712751Ssam 	label_t lqsave;
27812751Ssam 
27917593Skarels 	bzero(ibits, sizeof(ibits));
28017593Skarels 	bzero(obits, sizeof(obits));
28112751Ssam 	if (uap->nd > NOFILE)
28212751Ssam 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
28317593Skarels 	ni = howmany(uap->nd, NBI);
28412751Ssam 
28512751Ssam #define	getbits(name, x) \
28612751Ssam 	if (uap->name) { \
28717593Skarels 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)ibits[x], \
28817593Skarels 		    ni * sizeof(int)); \
28912751Ssam 		if (u.u_error) \
29012751Ssam 			goto done; \
29117593Skarels 	}
29212751Ssam 	getbits(in, 0);
29312751Ssam 	getbits(ou, 1);
29412751Ssam 	getbits(ex, 2);
29512751Ssam #undef	getbits
29612751Ssam 
29712751Ssam 	if (uap->tv) {
29812751Ssam 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
29912751Ssam 			sizeof (atv));
30012751Ssam 		if (u.u_error)
30112751Ssam 			goto done;
30212751Ssam 		if (itimerfix(&atv)) {
30312751Ssam 			u.u_error = EINVAL;
30412751Ssam 			goto done;
30512751Ssam 		}
30617934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
30712751Ssam 	}
30812751Ssam retry:
30912751Ssam 	ncoll = nselcoll;
31012751Ssam 	u.u_procp->p_flag |= SSEL;
31117593Skarels 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
31212751Ssam 	if (u.u_error || u.u_r.r_val1)
31312751Ssam 		goto done;
31417934Skarels 	s = splhigh();
31512971Ssam 	/* this should be timercmp(&time, &atv, >=) */
31612971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
31712971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
31812751Ssam 		splx(s);
31912751Ssam 		goto done;
32012751Ssam 	}
32112751Ssam 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
32212751Ssam 		u.u_procp->p_flag &= ~SSEL;
32312751Ssam 		splx(s);
32412751Ssam 		goto retry;
32512751Ssam 	}
32612751Ssam 	u.u_procp->p_flag &= ~SSEL;
32712751Ssam 	if (uap->tv) {
32812751Ssam 		lqsave = u.u_qsave;
32912751Ssam 		if (setjmp(&u.u_qsave)) {
33012751Ssam 			untimeout(unselect, (caddr_t)u.u_procp);
33112751Ssam 			u.u_error = EINTR;
33212751Ssam 			splx(s);
33312751Ssam 			goto done;
33412751Ssam 		}
33512751Ssam 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
33612751Ssam 	}
33712751Ssam 	sleep((caddr_t)&selwait, PZERO+1);
33812751Ssam 	if (uap->tv) {
33912751Ssam 		u.u_qsave = lqsave;
34012751Ssam 		untimeout(unselect, (caddr_t)u.u_procp);
34112751Ssam 	}
34212751Ssam 	splx(s);
34312751Ssam 	goto retry;
34412751Ssam done:
34512751Ssam #define	putbits(name, x) \
34612751Ssam 	if (uap->name) { \
34717593Skarels 		int error = copyout((caddr_t)obits[x], (caddr_t)uap->name, \
34817593Skarels 		    ni * sizeof(int)); \
34912751Ssam 		if (error) \
35012751Ssam 			u.u_error = error; \
35112751Ssam 	}
35221106Skarels 	if (u.u_error != EINTR) {
35321106Skarels 		putbits(in, 0);
35421106Skarels 		putbits(ou, 1);
35521106Skarels 		putbits(ex, 2);
35612751Ssam #undef putbits
35721106Skarels 	}
35812751Ssam }
35912751Ssam 
36012751Ssam unselect(p)
36112751Ssam 	register struct proc *p;
36212751Ssam {
36317934Skarels 	register int s = splhigh();
36412751Ssam 
36512751Ssam 	switch (p->p_stat) {
36612751Ssam 
36712751Ssam 	case SSLEEP:
36812751Ssam 		setrun(p);
36912751Ssam 		break;
37012751Ssam 
37112751Ssam 	case SSTOP:
37212751Ssam 		unsleep(p);
37312751Ssam 		break;
37412751Ssam 	}
37512751Ssam 	splx(s);
37612751Ssam }
37712751Ssam 
37817593Skarels selscan(ibits, obits, nfd)
37917593Skarels 	int (*ibits)[NI], (*obits)[NI];
38012751Ssam {
38117593Skarels 	register int which, bits, i, j;
38212751Ssam 	int flag;
38312751Ssam 	struct file *fp;
38412751Ssam 	int n = 0;
38512751Ssam 
38612751Ssam 	for (which = 0; which < 3; which++) {
38712751Ssam 		switch (which) {
38812751Ssam 
38912751Ssam 		case 0:
39012751Ssam 			flag = FREAD; break;
39112751Ssam 
39212751Ssam 		case 1:
39312751Ssam 			flag = FWRITE; break;
39412751Ssam 
39512751Ssam 		case 2:
39612751Ssam 			flag = 0; break;
39712751Ssam 		}
39817593Skarels 		for (i = 0; i < nfd; i += NBI) {
39917593Skarels 			bits = ibits[which][i/NBI];
40017593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
40117593Skarels 				bits &= ~(1 << j);
40217593Skarels 				fp = u.u_ofile[i + j];
40317593Skarels 				if (fp == NULL) {
40417593Skarels 					u.u_error = EBADF;
40517593Skarels 					break;
40617593Skarels 				}
40717593Skarels 				if ((*fp->f_ops->fo_select)(fp, flag)) {
40817593Skarels 					sbit(obits[which], i + j);
40917593Skarels 					n++;
41017593Skarels 				}
41112751Ssam 			}
41212751Ssam 		}
41312751Ssam 	}
41412751Ssam 	return (n);
41512751Ssam }
41612751Ssam 
4177423Sroot /*ARGSUSED*/
41812751Ssam seltrue(dev, flag)
41912751Ssam 	dev_t dev;
42012751Ssam 	int flag;
4217423Sroot {
4227423Sroot 
42312751Ssam 	return (1);
4247423Sroot }
4258103Sroot 
42612751Ssam selwakeup(p, coll)
42712751Ssam 	register struct proc *p;
42812751Ssam 	int coll;
4298103Sroot {
4308103Sroot 
43112751Ssam 	if (coll) {
43212751Ssam 		nselcoll++;
43312751Ssam 		wakeup((caddr_t)&selwait);
43412751Ssam 	}
43512751Ssam 	if (p) {
43617934Skarels 		int s = splhigh();
43717270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
43817270Skarels 			if (p->p_stat == SSLEEP)
43917270Skarels 				setrun(p);
44017270Skarels 			else
44117270Skarels 				unsleep(p);
44217270Skarels 		} else if (p->p_flag & SSEL)
44312751Ssam 			p->p_flag &= ~SSEL;
44412751Ssam 		splx(s);
44512751Ssam 	}
4468103Sroot }
447