xref: /csrg-svn/sys/kern/sys_generic.c (revision 34473)
123384Smckusick /*
229104Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323384Smckusick  * All rights reserved.  The Berkeley software License Agreement
423384Smckusick  * specifies the terms and conditions for redistribution.
523384Smckusick  *
6*34473Smckusick  *	@(#)sys_generic.c	7.7 (Berkeley) 05/24/88
723384Smckusick  */
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"
1931653Smckusick #include "malloc.h"
207423Sroot 
217423Sroot /*
227423Sroot  * Read system call.
237423Sroot  */
247423Sroot read()
257423Sroot {
267423Sroot 	register struct a {
277423Sroot 		int	fdes;
287423Sroot 		char	*cbuf;
297423Sroot 		unsigned count;
307820Sroot 	} *uap = (struct a *)u.u_ap;
317746Sroot 	struct uio auio;
327746Sroot 	struct iovec aiov;
337423Sroot 
347820Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
357820Sroot 	aiov.iov_len = uap->count;
367820Sroot 	auio.uio_iov = &aiov;
377820Sroot 	auio.uio_iovcnt = 1;
387820Sroot 	rwuio(&auio, UIO_READ);
397820Sroot }
407820Sroot 
417820Sroot readv()
427820Sroot {
437820Sroot 	register struct a {
447820Sroot 		int	fdes;
457820Sroot 		struct	iovec *iovp;
4626474Skarels 		unsigned iovcnt;
477820Sroot 	} *uap = (struct a *)u.u_ap;
487820Sroot 	struct uio auio;
497820Sroot 	struct iovec aiov[16];		/* XXX */
507820Sroot 
5126474Skarels 	if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
527423Sroot 		u.u_error = EINVAL;
537423Sroot 		return;
547423Sroot 	}
557820Sroot 	auio.uio_iov = aiov;
567820Sroot 	auio.uio_iovcnt = uap->iovcnt;
579999Ssam 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
5826474Skarels 	    uap->iovcnt * sizeof (struct iovec));
599999Ssam 	if (u.u_error)
607423Sroot 		return;
617820Sroot 	rwuio(&auio, UIO_READ);
627423Sroot }
637423Sroot 
647423Sroot /*
657423Sroot  * Write system call
667423Sroot  */
677423Sroot write()
687423Sroot {
697423Sroot 	register struct a {
707423Sroot 		int	fdes;
717423Sroot 		char	*cbuf;
7226474Skarels 		unsigned count;
737820Sroot 	} *uap = (struct a *)u.u_ap;
747820Sroot 	struct uio auio;
757820Sroot 	struct iovec aiov;
767423Sroot 
777820Sroot 	auio.uio_iov = &aiov;
787820Sroot 	auio.uio_iovcnt = 1;
797820Sroot 	aiov.iov_base = uap->cbuf;
807820Sroot 	aiov.iov_len = uap->count;
817820Sroot 	rwuio(&auio, UIO_WRITE);
827820Sroot }
837820Sroot 
847820Sroot writev()
857820Sroot {
867820Sroot 	register struct a {
877820Sroot 		int	fdes;
887820Sroot 		struct	iovec *iovp;
8926474Skarels 		unsigned iovcnt;
907820Sroot 	} *uap = (struct a *)u.u_ap;
917820Sroot 	struct uio auio;
927820Sroot 	struct iovec aiov[16];		/* XXX */
937820Sroot 
9426474Skarels 	if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
957423Sroot 		u.u_error = EINVAL;
967423Sroot 		return;
977423Sroot 	}
987820Sroot 	auio.uio_iov = aiov;
997820Sroot 	auio.uio_iovcnt = uap->iovcnt;
1009999Ssam 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
10126474Skarels 	    uap->iovcnt * sizeof (struct iovec));
1029999Ssam 	if (u.u_error)
1037820Sroot 		return;
1047820Sroot 	rwuio(&auio, UIO_WRITE);
1057820Sroot }
1067820Sroot 
1077820Sroot rwuio(uio, rw)
1087820Sroot 	register struct uio *uio;
1097820Sroot 	enum uio_rw rw;
1107820Sroot {
1117820Sroot 	struct a {
1127820Sroot 		int	fdes;
1137820Sroot 	};
1147820Sroot 	register struct file *fp;
1157820Sroot 	register struct iovec *iov;
1167820Sroot 	int i, count;
1177820Sroot 
1187820Sroot 	GETF(fp, ((struct a *)u.u_ap)->fdes);
1197820Sroot 	if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
1207423Sroot 		u.u_error = EBADF;
1217423Sroot 		return;
1227423Sroot 	}
1237820Sroot 	uio->uio_resid = 0;
12416702Smckusick 	uio->uio_segflg = UIO_USERSPACE;
1257820Sroot 	iov = uio->uio_iov;
1267820Sroot 	for (i = 0; i < uio->uio_iovcnt; i++) {
1277820Sroot 		if (iov->iov_len < 0) {
1287820Sroot 			u.u_error = EINVAL;
1297820Sroot 			return;
1307820Sroot 		}
1317820Sroot 		uio->uio_resid += iov->iov_len;
1327820Sroot 		if (uio->uio_resid < 0) {
1337820Sroot 			u.u_error = EINVAL;
1347820Sroot 			return;
1357820Sroot 		}
13613270Ssam 		iov++;
1377820Sroot 	}
1387820Sroot 	count = uio->uio_resid;
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;
1497423Sroot }
1507423Sroot 
1517423Sroot /*
1527423Sroot  * Ioctl system call
1537423Sroot  */
1547423Sroot ioctl()
1557423Sroot {
1567423Sroot 	register struct file *fp;
1577624Ssam 	struct a {
1587423Sroot 		int	fdes;
1597423Sroot 		int	cmd;
1607423Sroot 		caddr_t	cmarg;
1617423Sroot 	} *uap;
1627820Sroot 	register int com;
1637820Sroot 	register u_int size;
16431653Smckusick 	caddr_t memp = 0;
16530530Skarels #define STK_PARAMS	128
16633480Skarels 	char stkbuf[STK_PARAMS];
16733480Skarels 	caddr_t data = stkbuf;
1687423Sroot 
1697423Sroot 	uap = (struct a *)u.u_ap;
17017004Smckusick 	GETF(fp, uap->fdes);
1717423Sroot 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
1727423Sroot 		u.u_error = EBADF;
1737423Sroot 		return;
1747423Sroot 	}
1757624Ssam 	com = uap->cmd;
1767624Ssam 
17713228Ssam #if defined(vax) && defined(COMPAT)
1787624Ssam 	/*
1797624Ssam 	 * Map old style ioctl's into new for the
1807624Ssam 	 * sake of backwards compatibility (sigh).
1817624Ssam 	 */
1827624Ssam 	if ((com&~0xffff) == 0) {
1837624Ssam 		com = mapioctl(com);
1847624Ssam 		if (com == 0) {
1857624Ssam 			u.u_error = EINVAL;
1867624Ssam 			return;
1877624Ssam 		}
1887624Ssam 	}
1897624Ssam #endif
1907624Ssam 	if (com == FIOCLEX) {
1919592Ssam 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
1927423Sroot 		return;
1937423Sroot 	}
1947624Ssam 	if (com == FIONCLEX) {
1959592Ssam 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
1967423Sroot 		return;
1977423Sroot 	}
1987624Ssam 
1997624Ssam 	/*
2007624Ssam 	 * Interpret high order word to find
2017624Ssam 	 * amount of data to be copied to/from the
2027624Ssam 	 * user's address space.
2037624Ssam 	 */
20430530Skarels 	size = IOCPARM_LEN(com);
20530530Skarels 	if (size > IOCPARM_MAX) {
2067624Ssam 		u.u_error = EFAULT;
2077423Sroot 		return;
2087423Sroot 	}
20933480Skarels 	if (size > sizeof (stkbuf)) {
210*34473Smckusick 		memp = (caddr_t)malloc((u_long)IOCPARM_MAX, M_IOCTLOPS,
211*34473Smckusick 		    M_WAITOK);
21231653Smckusick 		data = memp;
21330530Skarels 	}
21410601Ssam 	if (com&IOC_IN) {
21510601Ssam 		if (size) {
21610601Ssam 			u.u_error =
21730530Skarels 			    copyin(uap->cmarg, data, (u_int)size);
21831653Smckusick 			if (u.u_error) {
21931653Smckusick 				if (memp)
22031653Smckusick 					free(memp, M_IOCTLOPS);
22110601Ssam 				return;
22231653Smckusick 			}
22310601Ssam 		} else
22410601Ssam 			*(caddr_t *)data = uap->cmarg;
22510601Ssam 	} else if ((com&IOC_OUT) && size)
22610601Ssam 		/*
22710601Ssam 		 * Zero the buffer on the stack so the user
22810601Ssam 		 * always gets back something deterministic.
22910601Ssam 		 */
23030530Skarels 		bzero(data, size);
23111284Ssam 	else if (com&IOC_VOID)
23211284Ssam 		*(caddr_t *)data = uap->cmarg;
2337423Sroot 
23412751Ssam 	switch (com) {
2357624Ssam 
23612751Ssam 	case FIONBIO:
23712751Ssam 		u.u_error = fset(fp, FNDELAY, *(int *)data);
23830530Skarels 		break;
23912751Ssam 
24012751Ssam 	case FIOASYNC:
24112751Ssam 		u.u_error = fset(fp, FASYNC, *(int *)data);
24230530Skarels 		break;
24312751Ssam 
24412751Ssam 	case FIOSETOWN:
24512751Ssam 		u.u_error = fsetown(fp, *(int *)data);
24630530Skarels 		break;
24712751Ssam 
24812751Ssam 	case FIOGETOWN:
24912751Ssam 		u.u_error = fgetown(fp, (int *)data);
25030530Skarels 		break;
25130530Skarels 	default:
25230530Skarels 		if (setjmp(&u.u_qsave))
25330530Skarels 			u.u_error = EINTR;
25430530Skarels 		else
25530530Skarels 			u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
25630530Skarels 		/*
25730530Skarels 		 * Copy any data to user, size was
25830530Skarels 		 * already set and checked above.
25930530Skarels 		 */
26030530Skarels 		if (u.u_error == 0 && (com&IOC_OUT) && size)
26130530Skarels 			u.u_error = copyout(data, uap->cmarg, (u_int)size);
26230530Skarels 		break;
2637423Sroot 	}
26431653Smckusick 	if (memp)
26531653Smckusick 		free(memp, M_IOCTLOPS);
2667423Sroot }
2677423Sroot 
26812751Ssam int	unselect();
26912751Ssam int	nselcoll;
27017593Skarels 
2717423Sroot /*
27212751Ssam  * Select system call.
2737423Sroot  */
27412751Ssam select()
27512751Ssam {
27612751Ssam 	register struct uap  {
27712751Ssam 		int	nd;
27823523Skarels 		fd_set	*in, *ou, *ex;
27912751Ssam 		struct	timeval *tv;
28012751Ssam 	} *uap = (struct uap *)u.u_ap;
28123523Skarels 	fd_set ibits[3], obits[3];
28212751Ssam 	struct timeval atv;
28317593Skarels 	int s, ncoll, ni;
28412751Ssam 	label_t lqsave;
28512751Ssam 
28626277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
28726277Skarels 	bzero((caddr_t)obits, sizeof(obits));
28812751Ssam 	if (uap->nd > NOFILE)
28912751Ssam 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
29023523Skarels 	ni = howmany(uap->nd, NFDBITS);
29112751Ssam 
29212751Ssam #define	getbits(name, x) \
29312751Ssam 	if (uap->name) { \
29423523Skarels 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
29526277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
29612751Ssam 		if (u.u_error) \
29712751Ssam 			goto done; \
29817593Skarels 	}
29912751Ssam 	getbits(in, 0);
30012751Ssam 	getbits(ou, 1);
30112751Ssam 	getbits(ex, 2);
30212751Ssam #undef	getbits
30312751Ssam 
30412751Ssam 	if (uap->tv) {
30512751Ssam 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
30612751Ssam 			sizeof (atv));
30712751Ssam 		if (u.u_error)
30812751Ssam 			goto done;
30912751Ssam 		if (itimerfix(&atv)) {
31012751Ssam 			u.u_error = EINVAL;
31112751Ssam 			goto done;
31212751Ssam 		}
31317934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
31412751Ssam 	}
31512751Ssam retry:
31612751Ssam 	ncoll = nselcoll;
31712751Ssam 	u.u_procp->p_flag |= SSEL;
31817593Skarels 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
31912751Ssam 	if (u.u_error || u.u_r.r_val1)
32012751Ssam 		goto done;
32117934Skarels 	s = splhigh();
32212971Ssam 	/* this should be timercmp(&time, &atv, >=) */
32312971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
32412971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
32512751Ssam 		splx(s);
32612751Ssam 		goto done;
32712751Ssam 	}
32812751Ssam 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
32912751Ssam 		splx(s);
33012751Ssam 		goto retry;
33112751Ssam 	}
33212751Ssam 	u.u_procp->p_flag &= ~SSEL;
33312751Ssam 	if (uap->tv) {
33412751Ssam 		lqsave = u.u_qsave;
33512751Ssam 		if (setjmp(&u.u_qsave)) {
33612751Ssam 			untimeout(unselect, (caddr_t)u.u_procp);
33712751Ssam 			u.u_error = EINTR;
33812751Ssam 			splx(s);
33912751Ssam 			goto done;
34012751Ssam 		}
34112751Ssam 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
34212751Ssam 	}
34312751Ssam 	sleep((caddr_t)&selwait, PZERO+1);
34412751Ssam 	if (uap->tv) {
34512751Ssam 		u.u_qsave = lqsave;
34612751Ssam 		untimeout(unselect, (caddr_t)u.u_procp);
34712751Ssam 	}
34812751Ssam 	splx(s);
34912751Ssam 	goto retry;
35012751Ssam done:
35133712Skarels 	u.u_procp->p_flag &= ~SSEL;
35212751Ssam #define	putbits(name, x) \
35312751Ssam 	if (uap->name) { \
35423523Skarels 		int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
35526277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
35612751Ssam 		if (error) \
35712751Ssam 			u.u_error = error; \
35812751Ssam 	}
35926070Skarels 	if (u.u_error == 0) {
36021106Skarels 		putbits(in, 0);
36121106Skarels 		putbits(ou, 1);
36221106Skarels 		putbits(ex, 2);
36312751Ssam #undef putbits
36421106Skarels 	}
36512751Ssam }
36612751Ssam 
36712751Ssam unselect(p)
36812751Ssam 	register struct proc *p;
36912751Ssam {
37017934Skarels 	register int s = splhigh();
37112751Ssam 
37212751Ssam 	switch (p->p_stat) {
37312751Ssam 
37412751Ssam 	case SSLEEP:
37512751Ssam 		setrun(p);
37612751Ssam 		break;
37712751Ssam 
37812751Ssam 	case SSTOP:
37912751Ssam 		unsleep(p);
38012751Ssam 		break;
38112751Ssam 	}
38212751Ssam 	splx(s);
38312751Ssam }
38412751Ssam 
38517593Skarels selscan(ibits, obits, nfd)
38623523Skarels 	fd_set *ibits, *obits;
38712751Ssam {
38823523Skarels 	register int which, i, j;
38923523Skarels 	register fd_mask bits;
39012751Ssam 	int flag;
39112751Ssam 	struct file *fp;
39212751Ssam 	int n = 0;
39312751Ssam 
39412751Ssam 	for (which = 0; which < 3; which++) {
39512751Ssam 		switch (which) {
39612751Ssam 
39712751Ssam 		case 0:
39812751Ssam 			flag = FREAD; break;
39912751Ssam 
40012751Ssam 		case 1:
40112751Ssam 			flag = FWRITE; break;
40212751Ssam 
40312751Ssam 		case 2:
40412751Ssam 			flag = 0; break;
40512751Ssam 		}
40623523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
40723523Skarels 			bits = ibits[which].fds_bits[i/NFDBITS];
40817593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
40917593Skarels 				bits &= ~(1 << j);
41017593Skarels 				fp = u.u_ofile[i + j];
41117593Skarels 				if (fp == NULL) {
41217593Skarels 					u.u_error = EBADF;
41317593Skarels 					break;
41417593Skarels 				}
41517593Skarels 				if ((*fp->f_ops->fo_select)(fp, flag)) {
41623523Skarels 					FD_SET(i + j, &obits[which]);
41717593Skarels 					n++;
41817593Skarels 				}
41912751Ssam 			}
42012751Ssam 		}
42112751Ssam 	}
42212751Ssam 	return (n);
42312751Ssam }
42412751Ssam 
4257423Sroot /*ARGSUSED*/
42612751Ssam seltrue(dev, flag)
42712751Ssam 	dev_t dev;
42812751Ssam 	int flag;
4297423Sroot {
4307423Sroot 
43112751Ssam 	return (1);
4327423Sroot }
4338103Sroot 
43412751Ssam selwakeup(p, coll)
43512751Ssam 	register struct proc *p;
43612751Ssam 	int coll;
4378103Sroot {
4388103Sroot 
43912751Ssam 	if (coll) {
44012751Ssam 		nselcoll++;
44112751Ssam 		wakeup((caddr_t)&selwait);
44212751Ssam 	}
44312751Ssam 	if (p) {
44417934Skarels 		int s = splhigh();
44517270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
44617270Skarels 			if (p->p_stat == SSLEEP)
44717270Skarels 				setrun(p);
44817270Skarels 			else
44917270Skarels 				unsleep(p);
45017270Skarels 		} else if (p->p_flag & SSEL)
45112751Ssam 			p->p_flag &= ~SSEL;
45212751Ssam 		splx(s);
45312751Ssam 	}
4548103Sroot }
455