xref: /csrg-svn/sys/kern/sys_generic.c (revision 37127)
123384Smckusick /*
2*37127Skarels  * Copyright (c) 1982, 1986, 1988 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*37127Skarels  *	@(#)sys_generic.c	7.9 (Berkeley) 03/10/89
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"
20*37127Skarels #ifdef KTRACE
21*37127Skarels #include "ktrace.h"
22*37127Skarels #endif
237423Sroot 
247423Sroot /*
257423Sroot  * Read system call.
267423Sroot  */
277423Sroot read()
287423Sroot {
297423Sroot 	register struct a {
307423Sroot 		int	fdes;
317423Sroot 		char	*cbuf;
327423Sroot 		unsigned count;
337820Sroot 	} *uap = (struct a *)u.u_ap;
347746Sroot 	struct uio auio;
357746Sroot 	struct iovec aiov;
367423Sroot 
377820Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
387820Sroot 	aiov.iov_len = uap->count;
397820Sroot 	auio.uio_iov = &aiov;
407820Sroot 	auio.uio_iovcnt = 1;
417820Sroot 	rwuio(&auio, UIO_READ);
427820Sroot }
437820Sroot 
447820Sroot readv()
457820Sroot {
467820Sroot 	register struct a {
477820Sroot 		int	fdes;
487820Sroot 		struct	iovec *iovp;
4926474Skarels 		unsigned iovcnt;
507820Sroot 	} *uap = (struct a *)u.u_ap;
517820Sroot 	struct uio auio;
52*37127Skarels 	struct iovec aiov[UIO_SMALLIOV], *iov;
537820Sroot 
54*37127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
55*37127Skarels 		if (uap->iovcnt > UIO_MAXIOV) {
56*37127Skarels 			u.u_error = EINVAL;
57*37127Skarels 			return;
58*37127Skarels 		}
59*37127Skarels 		MALLOC(iov, struct iovec *,
60*37127Skarels 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
61*37127Skarels 		if (iov == NULL) {
62*37127Skarels 			u.u_error = ENOMEM;
63*37127Skarels 			return;
64*37127Skarels 		}
65*37127Skarels 	} else
66*37127Skarels 		iov = aiov;
67*37127Skarels 	auio.uio_iov = iov;
687820Sroot 	auio.uio_iovcnt = uap->iovcnt;
69*37127Skarels 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)auio.uio_iov,
7026474Skarels 	    uap->iovcnt * sizeof (struct iovec));
719999Ssam 	if (u.u_error)
72*37127Skarels 		goto done;
737820Sroot 	rwuio(&auio, UIO_READ);
74*37127Skarels done:
75*37127Skarels 	if (iov != aiov)
76*37127Skarels 		FREE(iov, M_IOV);
777423Sroot }
787423Sroot 
797423Sroot /*
807423Sroot  * Write system call
817423Sroot  */
827423Sroot write()
837423Sroot {
847423Sroot 	register struct a {
857423Sroot 		int	fdes;
867423Sroot 		char	*cbuf;
8726474Skarels 		unsigned count;
887820Sroot 	} *uap = (struct a *)u.u_ap;
897820Sroot 	struct uio auio;
907820Sroot 	struct iovec aiov;
917423Sroot 
927820Sroot 	auio.uio_iov = &aiov;
937820Sroot 	auio.uio_iovcnt = 1;
947820Sroot 	aiov.iov_base = uap->cbuf;
957820Sroot 	aiov.iov_len = uap->count;
967820Sroot 	rwuio(&auio, UIO_WRITE);
977820Sroot }
987820Sroot 
997820Sroot writev()
1007820Sroot {
1017820Sroot 	register struct a {
1027820Sroot 		int	fdes;
1037820Sroot 		struct	iovec *iovp;
10426474Skarels 		unsigned iovcnt;
1057820Sroot 	} *uap = (struct a *)u.u_ap;
1067820Sroot 	struct uio auio;
107*37127Skarels 	struct iovec aiov[UIO_SMALLIOV], *iov;
1087820Sroot 
109*37127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
110*37127Skarels 		if (uap->iovcnt > UIO_MAXIOV) {
111*37127Skarels 			u.u_error = EINVAL;
112*37127Skarels 			return;
113*37127Skarels 		}
114*37127Skarels 		MALLOC(iov, struct iovec *,
115*37127Skarels 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
116*37127Skarels 		if (iov == NULL) {
117*37127Skarels 			u.u_error = ENOMEM;
118*37127Skarels 			return;
119*37127Skarels 		}
120*37127Skarels 	} else
121*37127Skarels 		iov = aiov;
122*37127Skarels 	auio.uio_iov = iov;
1237820Sroot 	auio.uio_iovcnt = uap->iovcnt;
124*37127Skarels 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)auio.uio_iov,
12526474Skarels 	    uap->iovcnt * sizeof (struct iovec));
1269999Ssam 	if (u.u_error)
127*37127Skarels 		goto done;
1287820Sroot 	rwuio(&auio, UIO_WRITE);
129*37127Skarels done:
130*37127Skarels 	if (iov != aiov)
131*37127Skarels 		FREE(iov, M_IOV);
1327820Sroot }
1337820Sroot 
1347820Sroot rwuio(uio, rw)
1357820Sroot 	register struct uio *uio;
1367820Sroot 	enum uio_rw rw;
1377820Sroot {
1387820Sroot 	struct a {
1397820Sroot 		int	fdes;
1407820Sroot 	};
1417820Sroot 	register struct file *fp;
1427820Sroot 	register struct iovec *iov;
1437820Sroot 	int i, count;
144*37127Skarels #ifdef KTRACE
145*37127Skarels 	struct iovec *ktriov = NULL;
146*37127Skarels #endif
1477820Sroot 
148*37127Skarels 
1497820Sroot 	GETF(fp, ((struct a *)u.u_ap)->fdes);
1507820Sroot 	if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
1517423Sroot 		u.u_error = EBADF;
1527423Sroot 		return;
1537423Sroot 	}
1547820Sroot 	uio->uio_resid = 0;
15516702Smckusick 	uio->uio_segflg = UIO_USERSPACE;
1567820Sroot 	iov = uio->uio_iov;
1577820Sroot 	for (i = 0; i < uio->uio_iovcnt; i++) {
1587820Sroot 		if (iov->iov_len < 0) {
1597820Sroot 			u.u_error = EINVAL;
1607820Sroot 			return;
1617820Sroot 		}
1627820Sroot 		uio->uio_resid += iov->iov_len;
1637820Sroot 		if (uio->uio_resid < 0) {
1647820Sroot 			u.u_error = EINVAL;
1657820Sroot 			return;
1667820Sroot 		}
16713270Ssam 		iov++;
1687820Sroot 	}
1697820Sroot 	count = uio->uio_resid;
170*37127Skarels #ifdef KTRACE
171*37127Skarels 	/* if tracing, save a copy of iovec */
172*37127Skarels 	if (KTRPOINT(u.u_procp, KTR_GENIO))  {
173*37127Skarels 		int iovlen = uio->uio_iovcnt * sizeof (struct iovec);
174*37127Skarels 
175*37127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
176*37127Skarels 		if (ktriov != NULL)
177*37127Skarels 			bcopy((caddr_t)uio->uio_iov, (caddr_t)ktriov, iovlen);
178*37127Skarels 	}
179*37127Skarels #endif
18018309Smckusick 	if (setjmp(&u.u_qsave)) {
18118309Smckusick 		if (uio->uio_resid == count) {
18221009Smckusick 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
18318309Smckusick 				u.u_error = EINTR;
18418309Smckusick 			else
18518309Smckusick 				u.u_eosys = RESTARTSYS;
18618309Smckusick 		}
18712751Ssam 	} else
18812751Ssam 		u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio);
1897820Sroot 	u.u_r.r_val1 = count - uio->uio_resid;
190*37127Skarels #ifdef KTRACE
191*37127Skarels 	if (ktriov != NULL) {
192*37127Skarels 		ktrgenio(u.u_procp->p_tracep, ((struct a *)u.u_ap)->fdes,
193*37127Skarels 			rw, ktriov, u.u_r.r_val1);
194*37127Skarels 		FREE(ktriov, M_TEMP);
195*37127Skarels 	}
196*37127Skarels #endif
1977423Sroot }
1987423Sroot 
1997423Sroot /*
2007423Sroot  * Ioctl system call
2017423Sroot  */
2027423Sroot ioctl()
2037423Sroot {
2047423Sroot 	register struct file *fp;
2057624Ssam 	struct a {
2067423Sroot 		int	fdes;
2077423Sroot 		int	cmd;
2087423Sroot 		caddr_t	cmarg;
2097423Sroot 	} *uap;
2107820Sroot 	register int com;
2117820Sroot 	register u_int size;
21231653Smckusick 	caddr_t memp = 0;
21330530Skarels #define STK_PARAMS	128
21433480Skarels 	char stkbuf[STK_PARAMS];
21533480Skarels 	caddr_t data = stkbuf;
2167423Sroot 
2177423Sroot 	uap = (struct a *)u.u_ap;
21817004Smckusick 	GETF(fp, uap->fdes);
2197423Sroot 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
2207423Sroot 		u.u_error = EBADF;
2217423Sroot 		return;
2227423Sroot 	}
2237624Ssam 	com = uap->cmd;
2247624Ssam 
2257624Ssam 	if (com == FIOCLEX) {
2269592Ssam 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
2277423Sroot 		return;
2287423Sroot 	}
2297624Ssam 	if (com == FIONCLEX) {
2309592Ssam 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
2317423Sroot 		return;
2327423Sroot 	}
2337624Ssam 
2347624Ssam 	/*
2357624Ssam 	 * Interpret high order word to find
2367624Ssam 	 * amount of data to be copied to/from the
2377624Ssam 	 * user's address space.
2387624Ssam 	 */
23930530Skarels 	size = IOCPARM_LEN(com);
24030530Skarels 	if (size > IOCPARM_MAX) {
241*37127Skarels 		u.u_error = ENOTTY;
2427423Sroot 		return;
2437423Sroot 	}
24433480Skarels 	if (size > sizeof (stkbuf)) {
245*37127Skarels 		memp = (caddr_t)malloc((u_long)IOCPARM_LEN(com), M_IOCTLOPS,
24634473Smckusick 		    M_WAITOK);
24731653Smckusick 		data = memp;
24830530Skarels 	}
24910601Ssam 	if (com&IOC_IN) {
25010601Ssam 		if (size) {
251*37127Skarels 			u.u_error = copyin(uap->cmarg, data, (u_int)size);
25231653Smckusick 			if (u.u_error) {
25331653Smckusick 				if (memp)
25431653Smckusick 					free(memp, M_IOCTLOPS);
25510601Ssam 				return;
25631653Smckusick 			}
25710601Ssam 		} else
25810601Ssam 			*(caddr_t *)data = uap->cmarg;
25910601Ssam 	} else if ((com&IOC_OUT) && size)
26010601Ssam 		/*
261*37127Skarels 		 * Zero the buffer so the user always
262*37127Skarels 		 * gets back something deterministic.
26310601Ssam 		 */
26430530Skarels 		bzero(data, size);
26511284Ssam 	else if (com&IOC_VOID)
26611284Ssam 		*(caddr_t *)data = uap->cmarg;
2677423Sroot 
26812751Ssam 	switch (com) {
2697624Ssam 
27012751Ssam 	case FIONBIO:
27112751Ssam 		u.u_error = fset(fp, FNDELAY, *(int *)data);
27230530Skarels 		break;
27312751Ssam 
27412751Ssam 	case FIOASYNC:
27512751Ssam 		u.u_error = fset(fp, FASYNC, *(int *)data);
27630530Skarels 		break;
27712751Ssam 
27812751Ssam 	case FIOSETOWN:
27912751Ssam 		u.u_error = fsetown(fp, *(int *)data);
28030530Skarels 		break;
28112751Ssam 
28212751Ssam 	case FIOGETOWN:
28312751Ssam 		u.u_error = fgetown(fp, (int *)data);
28430530Skarels 		break;
28530530Skarels 	default:
28630530Skarels 		if (setjmp(&u.u_qsave))
28730530Skarels 			u.u_error = EINTR;
28830530Skarels 		else
28930530Skarels 			u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
29030530Skarels 		/*
29130530Skarels 		 * Copy any data to user, size was
29230530Skarels 		 * already set and checked above.
29330530Skarels 		 */
29430530Skarels 		if (u.u_error == 0 && (com&IOC_OUT) && size)
29530530Skarels 			u.u_error = copyout(data, uap->cmarg, (u_int)size);
29630530Skarels 		break;
2977423Sroot 	}
29831653Smckusick 	if (memp)
29931653Smckusick 		free(memp, M_IOCTLOPS);
3007423Sroot }
3017423Sroot 
30212751Ssam int	unselect();
30312751Ssam int	nselcoll;
30417593Skarels 
3057423Sroot /*
30612751Ssam  * Select system call.
3077423Sroot  */
30812751Ssam select()
30912751Ssam {
31012751Ssam 	register struct uap  {
31112751Ssam 		int	nd;
31223523Skarels 		fd_set	*in, *ou, *ex;
31312751Ssam 		struct	timeval *tv;
31412751Ssam 	} *uap = (struct uap *)u.u_ap;
31523523Skarels 	fd_set ibits[3], obits[3];
31612751Ssam 	struct timeval atv;
31717593Skarels 	int s, ncoll, ni;
31812751Ssam 	label_t lqsave;
31912751Ssam 
32026277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
32126277Skarels 	bzero((caddr_t)obits, sizeof(obits));
32212751Ssam 	if (uap->nd > NOFILE)
32312751Ssam 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
32423523Skarels 	ni = howmany(uap->nd, NFDBITS);
32512751Ssam 
32612751Ssam #define	getbits(name, x) \
32712751Ssam 	if (uap->name) { \
32823523Skarels 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
32926277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
33012751Ssam 		if (u.u_error) \
33112751Ssam 			goto done; \
33217593Skarels 	}
33312751Ssam 	getbits(in, 0);
33412751Ssam 	getbits(ou, 1);
33512751Ssam 	getbits(ex, 2);
33612751Ssam #undef	getbits
33712751Ssam 
33812751Ssam 	if (uap->tv) {
33912751Ssam 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
34012751Ssam 			sizeof (atv));
34112751Ssam 		if (u.u_error)
34212751Ssam 			goto done;
34312751Ssam 		if (itimerfix(&atv)) {
34412751Ssam 			u.u_error = EINVAL;
34512751Ssam 			goto done;
34612751Ssam 		}
34717934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
34812751Ssam 	}
34912751Ssam retry:
35012751Ssam 	ncoll = nselcoll;
35112751Ssam 	u.u_procp->p_flag |= SSEL;
35217593Skarels 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
35312751Ssam 	if (u.u_error || u.u_r.r_val1)
35412751Ssam 		goto done;
35517934Skarels 	s = splhigh();
35612971Ssam 	/* this should be timercmp(&time, &atv, >=) */
35712971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
35812971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
35912751Ssam 		splx(s);
36012751Ssam 		goto done;
36112751Ssam 	}
36212751Ssam 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
36312751Ssam 		splx(s);
36412751Ssam 		goto retry;
36512751Ssam 	}
36612751Ssam 	u.u_procp->p_flag &= ~SSEL;
36712751Ssam 	if (uap->tv) {
36812751Ssam 		lqsave = u.u_qsave;
36912751Ssam 		if (setjmp(&u.u_qsave)) {
37012751Ssam 			untimeout(unselect, (caddr_t)u.u_procp);
37112751Ssam 			u.u_error = EINTR;
37212751Ssam 			splx(s);
37312751Ssam 			goto done;
37412751Ssam 		}
37512751Ssam 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
37612751Ssam 	}
37712751Ssam 	sleep((caddr_t)&selwait, PZERO+1);
37812751Ssam 	if (uap->tv) {
37912751Ssam 		u.u_qsave = lqsave;
38012751Ssam 		untimeout(unselect, (caddr_t)u.u_procp);
38112751Ssam 	}
38212751Ssam 	splx(s);
38312751Ssam 	goto retry;
38412751Ssam done:
38533712Skarels 	u.u_procp->p_flag &= ~SSEL;
38612751Ssam #define	putbits(name, x) \
38712751Ssam 	if (uap->name) { \
38823523Skarels 		int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
38926277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
39012751Ssam 		if (error) \
39112751Ssam 			u.u_error = error; \
39212751Ssam 	}
39326070Skarels 	if (u.u_error == 0) {
39421106Skarels 		putbits(in, 0);
39521106Skarels 		putbits(ou, 1);
39621106Skarels 		putbits(ex, 2);
39712751Ssam #undef putbits
39821106Skarels 	}
39912751Ssam }
40012751Ssam 
40112751Ssam unselect(p)
40212751Ssam 	register struct proc *p;
40312751Ssam {
40417934Skarels 	register int s = splhigh();
40512751Ssam 
40612751Ssam 	switch (p->p_stat) {
40712751Ssam 
40812751Ssam 	case SSLEEP:
40912751Ssam 		setrun(p);
41012751Ssam 		break;
41112751Ssam 
41212751Ssam 	case SSTOP:
41312751Ssam 		unsleep(p);
41412751Ssam 		break;
41512751Ssam 	}
41612751Ssam 	splx(s);
41712751Ssam }
41812751Ssam 
41917593Skarels selscan(ibits, obits, nfd)
42023523Skarels 	fd_set *ibits, *obits;
42112751Ssam {
42223523Skarels 	register int which, i, j;
42323523Skarels 	register fd_mask bits;
42412751Ssam 	int flag;
42512751Ssam 	struct file *fp;
42612751Ssam 	int n = 0;
42712751Ssam 
42812751Ssam 	for (which = 0; which < 3; which++) {
42912751Ssam 		switch (which) {
43012751Ssam 
43112751Ssam 		case 0:
43212751Ssam 			flag = FREAD; break;
43312751Ssam 
43412751Ssam 		case 1:
43512751Ssam 			flag = FWRITE; break;
43612751Ssam 
43712751Ssam 		case 2:
43812751Ssam 			flag = 0; break;
43912751Ssam 		}
44023523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
44123523Skarels 			bits = ibits[which].fds_bits[i/NFDBITS];
44217593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
44317593Skarels 				bits &= ~(1 << j);
44417593Skarels 				fp = u.u_ofile[i + j];
44517593Skarels 				if (fp == NULL) {
44617593Skarels 					u.u_error = EBADF;
44717593Skarels 					break;
44817593Skarels 				}
44917593Skarels 				if ((*fp->f_ops->fo_select)(fp, flag)) {
45023523Skarels 					FD_SET(i + j, &obits[which]);
45117593Skarels 					n++;
45217593Skarels 				}
45312751Ssam 			}
45412751Ssam 		}
45512751Ssam 	}
45612751Ssam 	return (n);
45712751Ssam }
45812751Ssam 
4597423Sroot /*ARGSUSED*/
46012751Ssam seltrue(dev, flag)
46112751Ssam 	dev_t dev;
46212751Ssam 	int flag;
4637423Sroot {
4647423Sroot 
46512751Ssam 	return (1);
4667423Sroot }
4678103Sroot 
46812751Ssam selwakeup(p, coll)
46912751Ssam 	register struct proc *p;
47012751Ssam 	int coll;
4718103Sroot {
4728103Sroot 
47312751Ssam 	if (coll) {
47412751Ssam 		nselcoll++;
47512751Ssam 		wakeup((caddr_t)&selwait);
47612751Ssam 	}
47712751Ssam 	if (p) {
47817934Skarels 		int s = splhigh();
47917270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
48017270Skarels 			if (p->p_stat == SSLEEP)
48117270Skarels 				setrun(p);
48217270Skarels 			else
48317270Skarels 				unsleep(p);
48417270Skarels 		} else if (p->p_flag & SSEL)
48512751Ssam 			p->p_flag &= ~SSEL;
48612751Ssam 		splx(s);
48712751Ssam 	}
4888103Sroot }
489