xref: /csrg-svn/sys/kern/sys_generic.c (revision 30530)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)sys_generic.c	7.2 (Berkeley) 02/19/87
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "dir.h"
12 #include "user.h"
13 #include "ioctl.h"
14 #include "file.h"
15 #include "proc.h"
16 #include "uio.h"
17 #include "kernel.h"
18 #include "stat.h"
19 #include "buf.h"				/* XXX */
20 
21 /*
22  * Read system call.
23  */
24 read()
25 {
26 	register struct a {
27 		int	fdes;
28 		char	*cbuf;
29 		unsigned count;
30 	} *uap = (struct a *)u.u_ap;
31 	struct uio auio;
32 	struct iovec aiov;
33 
34 	aiov.iov_base = (caddr_t)uap->cbuf;
35 	aiov.iov_len = uap->count;
36 	auio.uio_iov = &aiov;
37 	auio.uio_iovcnt = 1;
38 	rwuio(&auio, UIO_READ);
39 }
40 
41 readv()
42 {
43 	register struct a {
44 		int	fdes;
45 		struct	iovec *iovp;
46 		unsigned iovcnt;
47 	} *uap = (struct a *)u.u_ap;
48 	struct uio auio;
49 	struct iovec aiov[16];		/* XXX */
50 
51 	if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
52 		u.u_error = EINVAL;
53 		return;
54 	}
55 	auio.uio_iov = aiov;
56 	auio.uio_iovcnt = uap->iovcnt;
57 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
58 	    uap->iovcnt * sizeof (struct iovec));
59 	if (u.u_error)
60 		return;
61 	rwuio(&auio, UIO_READ);
62 }
63 
64 /*
65  * Write system call
66  */
67 write()
68 {
69 	register struct a {
70 		int	fdes;
71 		char	*cbuf;
72 		unsigned count;
73 	} *uap = (struct a *)u.u_ap;
74 	struct uio auio;
75 	struct iovec aiov;
76 
77 	auio.uio_iov = &aiov;
78 	auio.uio_iovcnt = 1;
79 	aiov.iov_base = uap->cbuf;
80 	aiov.iov_len = uap->count;
81 	rwuio(&auio, UIO_WRITE);
82 }
83 
84 writev()
85 {
86 	register struct a {
87 		int	fdes;
88 		struct	iovec *iovp;
89 		unsigned iovcnt;
90 	} *uap = (struct a *)u.u_ap;
91 	struct uio auio;
92 	struct iovec aiov[16];		/* XXX */
93 
94 	if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
95 		u.u_error = EINVAL;
96 		return;
97 	}
98 	auio.uio_iov = aiov;
99 	auio.uio_iovcnt = uap->iovcnt;
100 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
101 	    uap->iovcnt * sizeof (struct iovec));
102 	if (u.u_error)
103 		return;
104 	rwuio(&auio, UIO_WRITE);
105 }
106 
107 rwuio(uio, rw)
108 	register struct uio *uio;
109 	enum uio_rw rw;
110 {
111 	struct a {
112 		int	fdes;
113 	};
114 	register struct file *fp;
115 	register struct iovec *iov;
116 	int i, count;
117 
118 	GETF(fp, ((struct a *)u.u_ap)->fdes);
119 	if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
120 		u.u_error = EBADF;
121 		return;
122 	}
123 	uio->uio_resid = 0;
124 	uio->uio_segflg = UIO_USERSPACE;
125 	iov = uio->uio_iov;
126 	for (i = 0; i < uio->uio_iovcnt; i++) {
127 		if (iov->iov_len < 0) {
128 			u.u_error = EINVAL;
129 			return;
130 		}
131 		uio->uio_resid += iov->iov_len;
132 		if (uio->uio_resid < 0) {
133 			u.u_error = EINVAL;
134 			return;
135 		}
136 		iov++;
137 	}
138 	count = uio->uio_resid;
139 	uio->uio_offset = fp->f_offset;
140 	if (setjmp(&u.u_qsave)) {
141 		if (uio->uio_resid == count) {
142 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
143 				u.u_error = EINTR;
144 			else
145 				u.u_eosys = RESTARTSYS;
146 		}
147 	} else
148 		u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio);
149 	u.u_r.r_val1 = count - uio->uio_resid;
150 	fp->f_offset += u.u_r.r_val1;
151 }
152 
153 /*
154  * Ioctl system call
155  */
156 ioctl()
157 {
158 	register struct file *fp;
159 	struct a {
160 		int	fdes;
161 		int	cmd;
162 		caddr_t	cmarg;
163 	} *uap;
164 	register int com;
165 	register u_int size;
166 	struct buf *bp = 0;
167 #define STK_PARAMS	128
168 	char buf[STK_PARAMS];
169 	caddr_t data = buf;
170 
171 	uap = (struct a *)u.u_ap;
172 	GETF(fp, uap->fdes);
173 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
174 		u.u_error = EBADF;
175 		return;
176 	}
177 	com = uap->cmd;
178 
179 #if defined(vax) && defined(COMPAT)
180 	/*
181 	 * Map old style ioctl's into new for the
182 	 * sake of backwards compatibility (sigh).
183 	 */
184 	if ((com&~0xffff) == 0) {
185 		com = mapioctl(com);
186 		if (com == 0) {
187 			u.u_error = EINVAL;
188 			return;
189 		}
190 	}
191 #endif
192 	if (com == FIOCLEX) {
193 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
194 		return;
195 	}
196 	if (com == FIONCLEX) {
197 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
198 		return;
199 	}
200 
201 	/*
202 	 * Interpret high order word to find
203 	 * amount of data to be copied to/from the
204 	 * user's address space.
205 	 */
206 	size = IOCPARM_LEN(com);
207 	if (size > IOCPARM_MAX) {
208 		u.u_error = EFAULT;
209 		return;
210 	}
211 	if (size > sizeof (buf)) {
212 		bp = geteblk(IOCPARM_MAX);		/* XXX */
213 		data = bp->b_un.b_addr;
214 	}
215 	if (com&IOC_IN) {
216 		if (size) {
217 			u.u_error =
218 			    copyin(uap->cmarg, data, (u_int)size);
219 			if (u.u_error)
220 				return;
221 		} else
222 			*(caddr_t *)data = uap->cmarg;
223 	} else if ((com&IOC_OUT) && size)
224 		/*
225 		 * Zero the buffer on the stack so the user
226 		 * always gets back something deterministic.
227 		 */
228 		bzero(data, size);
229 	else if (com&IOC_VOID)
230 		*(caddr_t *)data = uap->cmarg;
231 
232 	switch (com) {
233 
234 	case FIONBIO:
235 		u.u_error = fset(fp, FNDELAY, *(int *)data);
236 		break;
237 
238 	case FIOASYNC:
239 		u.u_error = fset(fp, FASYNC, *(int *)data);
240 		break;
241 
242 	case FIOSETOWN:
243 		u.u_error = fsetown(fp, *(int *)data);
244 		break;
245 
246 	case FIOGETOWN:
247 		u.u_error = fgetown(fp, (int *)data);
248 		break;
249 	default:
250 		if (setjmp(&u.u_qsave))
251 			u.u_error = EINTR;
252 		else
253 			u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
254 		/*
255 		 * Copy any data to user, size was
256 		 * already set and checked above.
257 		 */
258 		if (u.u_error == 0 && (com&IOC_OUT) && size)
259 			u.u_error = copyout(data, uap->cmarg, (u_int)size);
260 		break;
261 	}
262 	if (bp)
263 		brelse(bp);
264 }
265 
266 int	unselect();
267 int	nselcoll;
268 
269 /*
270  * Select system call.
271  */
272 select()
273 {
274 	register struct uap  {
275 		int	nd;
276 		fd_set	*in, *ou, *ex;
277 		struct	timeval *tv;
278 	} *uap = (struct uap *)u.u_ap;
279 	fd_set ibits[3], obits[3];
280 	struct timeval atv;
281 	int s, ncoll, ni;
282 	label_t lqsave;
283 
284 	bzero((caddr_t)ibits, sizeof(ibits));
285 	bzero((caddr_t)obits, sizeof(obits));
286 	if (uap->nd > NOFILE)
287 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
288 	ni = howmany(uap->nd, NFDBITS);
289 
290 #define	getbits(name, x) \
291 	if (uap->name) { \
292 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
293 		    (unsigned)(ni * sizeof(fd_mask))); \
294 		if (u.u_error) \
295 			goto done; \
296 	}
297 	getbits(in, 0);
298 	getbits(ou, 1);
299 	getbits(ex, 2);
300 #undef	getbits
301 
302 	if (uap->tv) {
303 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
304 			sizeof (atv));
305 		if (u.u_error)
306 			goto done;
307 		if (itimerfix(&atv)) {
308 			u.u_error = EINVAL;
309 			goto done;
310 		}
311 		s = splhigh(); timevaladd(&atv, &time); splx(s);
312 	}
313 retry:
314 	ncoll = nselcoll;
315 	u.u_procp->p_flag |= SSEL;
316 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
317 	if (u.u_error || u.u_r.r_val1)
318 		goto done;
319 	s = splhigh();
320 	/* this should be timercmp(&time, &atv, >=) */
321 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
322 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
323 		splx(s);
324 		goto done;
325 	}
326 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
327 		u.u_procp->p_flag &= ~SSEL;
328 		splx(s);
329 		goto retry;
330 	}
331 	u.u_procp->p_flag &= ~SSEL;
332 	if (uap->tv) {
333 		lqsave = u.u_qsave;
334 		if (setjmp(&u.u_qsave)) {
335 			untimeout(unselect, (caddr_t)u.u_procp);
336 			u.u_error = EINTR;
337 			splx(s);
338 			goto done;
339 		}
340 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
341 	}
342 	sleep((caddr_t)&selwait, PZERO+1);
343 	if (uap->tv) {
344 		u.u_qsave = lqsave;
345 		untimeout(unselect, (caddr_t)u.u_procp);
346 	}
347 	splx(s);
348 	goto retry;
349 done:
350 #define	putbits(name, x) \
351 	if (uap->name) { \
352 		int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
353 		    (unsigned)(ni * sizeof(fd_mask))); \
354 		if (error) \
355 			u.u_error = error; \
356 	}
357 	if (u.u_error == 0) {
358 		putbits(in, 0);
359 		putbits(ou, 1);
360 		putbits(ex, 2);
361 #undef putbits
362 	}
363 }
364 
365 unselect(p)
366 	register struct proc *p;
367 {
368 	register int s = splhigh();
369 
370 	switch (p->p_stat) {
371 
372 	case SSLEEP:
373 		setrun(p);
374 		break;
375 
376 	case SSTOP:
377 		unsleep(p);
378 		break;
379 	}
380 	splx(s);
381 }
382 
383 selscan(ibits, obits, nfd)
384 	fd_set *ibits, *obits;
385 {
386 	register int which, i, j;
387 	register fd_mask bits;
388 	int flag;
389 	struct file *fp;
390 	int n = 0;
391 
392 	for (which = 0; which < 3; which++) {
393 		switch (which) {
394 
395 		case 0:
396 			flag = FREAD; break;
397 
398 		case 1:
399 			flag = FWRITE; break;
400 
401 		case 2:
402 			flag = 0; break;
403 		}
404 		for (i = 0; i < nfd; i += NFDBITS) {
405 			bits = ibits[which].fds_bits[i/NFDBITS];
406 			while ((j = ffs(bits)) && i + --j < nfd) {
407 				bits &= ~(1 << j);
408 				fp = u.u_ofile[i + j];
409 				if (fp == NULL) {
410 					u.u_error = EBADF;
411 					break;
412 				}
413 				if ((*fp->f_ops->fo_select)(fp, flag)) {
414 					FD_SET(i + j, &obits[which]);
415 					n++;
416 				}
417 			}
418 		}
419 	}
420 	return (n);
421 }
422 
423 /*ARGSUSED*/
424 seltrue(dev, flag)
425 	dev_t dev;
426 	int flag;
427 {
428 
429 	return (1);
430 }
431 
432 selwakeup(p, coll)
433 	register struct proc *p;
434 	int coll;
435 {
436 
437 	if (coll) {
438 		nselcoll++;
439 		wakeup((caddr_t)&selwait);
440 	}
441 	if (p) {
442 		int s = splhigh();
443 		if (p->p_wchan == (caddr_t)&selwait) {
444 			if (p->p_stat == SSLEEP)
445 				setrun(p);
446 			else
447 				unsleep(p);
448 		} else if (p->p_flag & SSEL)
449 			p->p_flag &= ~SSEL;
450 		splx(s);
451 	}
452 }
453