xref: /csrg-svn/sys/kern/sys_generic.c (revision 47974)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)sys_generic.c	7.27 (Berkeley) 04/12/91
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "filedesc.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 "malloc.h"
20 #ifdef KTRACE
21 #include "ktrace.h"
22 #endif
23 
24 /*
25  * Read system call.
26  */
27 /* ARGSUSED */
28 read(p, uap, retval)
29 	struct proc *p;
30 	register struct args {
31 		int	fdes;
32 		char	*cbuf;
33 		unsigned count;
34 	} *uap;
35 	int *retval;
36 {
37 	register struct file *fp;
38 	register struct filedesc *fdp = p->p_fd;
39 	struct uio auio;
40 	struct iovec aiov;
41 	long cnt, error = 0;
42 #ifdef KTRACE
43 	struct iovec ktriov;
44 #endif
45 
46 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
47 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
48 	    (fp->f_flag & FREAD) == 0)
49 		return (EBADF);
50 	aiov.iov_base = (caddr_t)uap->cbuf;
51 	aiov.iov_len = uap->count;
52 	auio.uio_iov = &aiov;
53 	auio.uio_iovcnt = 1;
54 	auio.uio_resid = uap->count;
55 	auio.uio_rw = UIO_READ;
56 	auio.uio_segflg = UIO_USERSPACE;
57 #ifdef KTRACE
58 	/*
59 	 * if tracing, save a copy of iovec
60 	 */
61 	if (KTRPOINT(p, KTR_GENIO))
62 		ktriov = aiov;
63 #endif
64 	cnt = uap->count;
65 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
66 		if (auio.uio_resid != cnt && (error == ERESTART ||
67 		    error == EINTR || error == EWOULDBLOCK))
68 			error = 0;
69 	cnt -= auio.uio_resid;
70 #ifdef KTRACE
71 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
72 		ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
73 #endif
74 	*retval = cnt;
75 	return (error);
76 }
77 
78 /*
79  * Scatter read system call.
80  */
81 /* ARGSUSED */
82 readv(p, uap, retval)
83 	struct proc *p;
84 	register struct args {
85 		int	fdes;
86 		struct	iovec *iovp;
87 		unsigned iovcnt;
88 	} *uap;
89 	int *retval;
90 {
91 	register struct file *fp;
92 	register struct filedesc *fdp = p->p_fd;
93 	struct uio auio;
94 	register struct iovec *iov;
95 	struct iovec *saveiov;
96 	struct iovec aiov[UIO_SMALLIOV];
97 	long i, cnt, error = 0;
98 	unsigned iovlen;
99 #ifdef KTRACE
100 	struct iovec *ktriov = NULL;
101 #endif
102 
103 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
104 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
105 	    (fp->f_flag & FREAD) == 0)
106 		return (EBADF);
107 	/* note: can't use iovlen until iovcnt is validated */
108 	iovlen = uap->iovcnt * sizeof (struct iovec);
109 	if (uap->iovcnt > UIO_SMALLIOV) {
110 		if (uap->iovcnt > UIO_MAXIOV)
111 			return (EINVAL);
112 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
113 		saveiov = iov;
114 	} else
115 		iov = aiov;
116 	auio.uio_iov = iov;
117 	auio.uio_iovcnt = uap->iovcnt;
118 	auio.uio_rw = UIO_READ;
119 	auio.uio_segflg = UIO_USERSPACE;
120 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
121 		goto done;
122 	auio.uio_resid = 0;
123 	for (i = 0; i < uap->iovcnt; i++) {
124 		if (iov->iov_len < 0) {
125 			error = EINVAL;
126 			goto done;
127 		}
128 		auio.uio_resid += iov->iov_len;
129 		if (auio.uio_resid < 0) {
130 			error = EINVAL;
131 			goto done;
132 		}
133 		iov++;
134 	}
135 #ifdef KTRACE
136 	/*
137 	 * if tracing, save a copy of iovec
138 	 */
139 	if (KTRPOINT(p, KTR_GENIO))  {
140 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
141 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
142 	}
143 #endif
144 	cnt = auio.uio_resid;
145 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
146 		if (auio.uio_resid != cnt && (error == ERESTART ||
147 		    error == EINTR || error == EWOULDBLOCK))
148 			error = 0;
149 	cnt -= auio.uio_resid;
150 #ifdef KTRACE
151 	if (ktriov != NULL) {
152 		if (error == 0)
153 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
154 			    cnt, error);
155 		FREE(ktriov, M_TEMP);
156 	}
157 #endif
158 	*retval = cnt;
159 done:
160 	if (uap->iovcnt > UIO_SMALLIOV)
161 		FREE(saveiov, M_IOV);
162 	return (error);
163 }
164 
165 /*
166  * Write system call
167  */
168 write(p, uap, retval)
169 	struct proc *p;
170 	register struct args {
171 		int	fdes;
172 		char	*cbuf;
173 		unsigned count;
174 	} *uap;
175 	int *retval;
176 {
177 	register struct file *fp;
178 	register struct filedesc *fdp = p->p_fd;
179 	struct uio auio;
180 	struct iovec aiov;
181 	long cnt, error = 0;
182 #ifdef KTRACE
183 	struct iovec ktriov;
184 #endif
185 
186 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
187 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
188 	    (fp->f_flag & FWRITE) == 0)
189 		return (EBADF);
190 	aiov.iov_base = (caddr_t)uap->cbuf;
191 	aiov.iov_len = uap->count;
192 	auio.uio_iov = &aiov;
193 	auio.uio_iovcnt = 1;
194 	auio.uio_resid = uap->count;
195 	auio.uio_rw = UIO_WRITE;
196 	auio.uio_segflg = UIO_USERSPACE;
197 #ifdef KTRACE
198 	/*
199 	 * if tracing, save a copy of iovec
200 	 */
201 	if (KTRPOINT(p, KTR_GENIO))
202 		ktriov = aiov;
203 #endif
204 	cnt = uap->count;
205 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
206 		if (auio.uio_resid != cnt && (error == ERESTART ||
207 		    error == EINTR || error == EWOULDBLOCK))
208 			error = 0;
209 		if (error == EPIPE)
210 			psignal(p, SIGPIPE);
211 	}
212 	cnt -= auio.uio_resid;
213 #ifdef KTRACE
214 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
215 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
216 		    &ktriov, cnt, error);
217 #endif
218 	*retval = cnt;
219 	return (error);
220 }
221 
222 /*
223  * Gather write system call
224  */
225 writev(p, uap, retval)
226 	struct proc *p;
227 	register struct args {
228 		int	fdes;
229 		struct	iovec *iovp;
230 		unsigned iovcnt;
231 	} *uap;
232 	int *retval;
233 {
234 	register struct file *fp;
235 	register struct filedesc *fdp = p->p_fd;
236 	struct uio auio;
237 	register struct iovec *iov;
238 	struct iovec *saveiov;
239 	struct iovec aiov[UIO_SMALLIOV];
240 	long i, cnt, error = 0;
241 	unsigned iovlen;
242 #ifdef KTRACE
243 	struct iovec *ktriov = NULL;
244 #endif
245 
246 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
247 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
248 	    (fp->f_flag & FWRITE) == 0)
249 		return (EBADF);
250 	/* note: can't use iovlen until iovcnt is validated */
251 	iovlen = uap->iovcnt * sizeof (struct iovec);
252 	if (uap->iovcnt > UIO_SMALLIOV) {
253 		if (uap->iovcnt > UIO_MAXIOV)
254 			return (EINVAL);
255 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
256 		saveiov = iov;
257 	} else
258 		iov = aiov;
259 	auio.uio_iov = iov;
260 	auio.uio_iovcnt = uap->iovcnt;
261 	auio.uio_rw = UIO_WRITE;
262 	auio.uio_segflg = UIO_USERSPACE;
263 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
264 		goto done;
265 	auio.uio_resid = 0;
266 	for (i = 0; i < uap->iovcnt; i++) {
267 		if (iov->iov_len < 0) {
268 			error = EINVAL;
269 			goto done;
270 		}
271 		auio.uio_resid += iov->iov_len;
272 		if (auio.uio_resid < 0) {
273 			error = EINVAL;
274 			goto done;
275 		}
276 		iov++;
277 	}
278 #ifdef KTRACE
279 	/*
280 	 * if tracing, save a copy of iovec
281 	 */
282 	if (KTRPOINT(p, KTR_GENIO))  {
283 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
284 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
285 	}
286 #endif
287 	cnt = auio.uio_resid;
288 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
289 		if (auio.uio_resid != cnt && (error == ERESTART ||
290 		    error == EINTR || error == EWOULDBLOCK))
291 			error = 0;
292 		if (error == EPIPE)
293 			psignal(p, SIGPIPE);
294 	}
295 	cnt -= auio.uio_resid;
296 #ifdef KTRACE
297 	if (ktriov != NULL) {
298 		if (error == 0)
299 			ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
300 				ktriov, cnt, error);
301 		FREE(ktriov, M_TEMP);
302 	}
303 #endif
304 	*retval = cnt;
305 done:
306 	if (uap->iovcnt > UIO_SMALLIOV)
307 		FREE(saveiov, M_IOV);
308 	return (error);
309 }
310 
311 /*
312  * Ioctl system call
313  */
314 /* ARGSUSED */
315 ioctl(p, uap, retval)
316 	struct proc *p;
317 	register struct args {
318 		int	fdes;
319 		int	cmd;
320 		caddr_t	cmarg;
321 	} *uap;
322 	int *retval;
323 {
324 	register struct file *fp;
325 	register struct filedesc *fdp = p->p_fd;
326 	register int com, error;
327 	register u_int size;
328 	caddr_t memp = 0;
329 #define STK_PARAMS	128
330 	char stkbuf[STK_PARAMS];
331 	caddr_t data = stkbuf;
332 
333 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
334 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
335 		return (EBADF);
336 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
337 		return (EBADF);
338 	com = uap->cmd;
339 
340 	if (com == FIOCLEX) {
341 		fdp->fd_ofileflags[uap->fdes] |= UF_EXCLOSE;
342 		return (0);
343 	}
344 	if (com == FIONCLEX) {
345 		fdp->fd_ofileflags[uap->fdes] &= ~UF_EXCLOSE;
346 		return (0);
347 	}
348 
349 	/*
350 	 * Interpret high order word to find
351 	 * amount of data to be copied to/from the
352 	 * user's address space.
353 	 */
354 	size = IOCPARM_LEN(com);
355 	if (size > IOCPARM_MAX)
356 		return (ENOTTY);
357 	if (size > sizeof (stkbuf)) {
358 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
359 		data = memp;
360 	}
361 	if (com&IOC_IN) {
362 		if (size) {
363 			error = copyin(uap->cmarg, data, (u_int)size);
364 			if (error) {
365 				if (memp)
366 					free(memp, M_IOCTLOPS);
367 				return (error);
368 			}
369 		} else
370 			*(caddr_t *)data = uap->cmarg;
371 	} else if ((com&IOC_OUT) && size)
372 		/*
373 		 * Zero the buffer so the user always
374 		 * gets back something deterministic.
375 		 */
376 		bzero(data, size);
377 	else if (com&IOC_VOID)
378 		*(caddr_t *)data = uap->cmarg;
379 
380 	switch (com) {
381 
382 	case FIONBIO:
383 		error = fset(fp, FNDELAY, *(int *)data);
384 		break;
385 
386 	case FIOASYNC:
387 		error = fset(fp, FASYNC, *(int *)data);
388 		break;
389 
390 	case FIOSETOWN:
391 		error = fsetown(fp, *(int *)data);
392 		break;
393 
394 	case FIOGETOWN:
395 		error = fgetown(fp, (int *)data);
396 		break;
397 	default:
398 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
399 		/*
400 		 * Copy any data to user, size was
401 		 * already set and checked above.
402 		 */
403 		if (error == 0 && (com&IOC_OUT) && size)
404 			error = copyout(data, uap->cmarg, (u_int)size);
405 		break;
406 	}
407 	if (memp)
408 		free(memp, M_IOCTLOPS);
409 	return (error);
410 }
411 
412 int	nselcoll;
413 
414 /*
415  * Select system call.
416  */
417 select(p, uap, retval)
418 	register struct proc *p;
419 	register struct args {
420 		int	nd;
421 		fd_set	*in, *ou, *ex;
422 		struct	timeval *tv;
423 	} *uap;
424 	int *retval;
425 {
426 	fd_set ibits[3], obits[3];
427 	struct timeval atv;
428 	int s, ncoll, ni, error = 0, timo;
429 
430 	bzero((caddr_t)ibits, sizeof(ibits));
431 	bzero((caddr_t)obits, sizeof(obits));
432 	if (uap->nd > p->p_fd->fd_nfiles)
433 		uap->nd = p->p_fd->fd_nfiles;	/* forgiving; slightly wrong */
434 	ni = howmany(uap->nd, NFDBITS);
435 
436 #define	getbits(name, x) \
437 	if (uap->name) { \
438 		error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
439 		    (unsigned)(ni * sizeof(fd_mask))); \
440 		if (error) \
441 			goto done; \
442 	}
443 	getbits(in, 0);
444 	getbits(ou, 1);
445 	getbits(ex, 2);
446 #undef	getbits
447 
448 	if (uap->tv) {
449 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
450 			sizeof (atv));
451 		if (error)
452 			goto done;
453 		if (itimerfix(&atv)) {
454 			error = EINVAL;
455 			goto done;
456 		}
457 		s = splhigh(); timevaladd(&atv, &time); splx(s);
458 		timo = hzto(&atv);
459 	} else
460 		timo = 0;
461 retry:
462 	ncoll = nselcoll;
463 	p->p_flag |= SSEL;
464 	error = selscan(p, ibits, obits, uap->nd, retval);
465 	if (error || *retval)
466 		goto done;
467 	s = splhigh();
468 	/* this should be timercmp(&time, &atv, >=) */
469 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
470 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
471 		splx(s);
472 		goto done;
473 	}
474 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
475 		splx(s);
476 		goto retry;
477 	}
478 	p->p_flag &= ~SSEL;
479 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
480 	splx(s);
481 	if (error == 0)
482 		goto retry;
483 done:
484 	p->p_flag &= ~SSEL;
485 	/* select is not restarted after signals... */
486 	if (error == ERESTART)
487 		error = EINTR;
488 	if (error == EWOULDBLOCK)
489 		error = 0;
490 #define	putbits(name, x) \
491 	if (uap->name) { \
492 		int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
493 		    (unsigned)(ni * sizeof(fd_mask))); \
494 		if (error2) \
495 			error = error2; \
496 	}
497 	if (error == 0) {
498 		putbits(in, 0);
499 		putbits(ou, 1);
500 		putbits(ex, 2);
501 #undef putbits
502 	}
503 	return (error);
504 }
505 
506 selscan(p, ibits, obits, nfd, retval)
507 	struct proc *p;
508 	fd_set *ibits, *obits;
509 	int nfd, *retval;
510 {
511 	register struct filedesc *fdp = p->p_fd;
512 	register int which, i, j;
513 	register fd_mask bits;
514 	int flag;
515 	struct file *fp;
516 	int error = 0, n = 0;
517 
518 	for (which = 0; which < 3; which++) {
519 		switch (which) {
520 
521 		case 0:
522 			flag = FREAD; break;
523 
524 		case 1:
525 			flag = FWRITE; break;
526 
527 		case 2:
528 			flag = 0; break;
529 		}
530 		for (i = 0; i < nfd; i += NFDBITS) {
531 			bits = ibits[which].fds_bits[i/NFDBITS];
532 			while ((j = ffs(bits)) && i + --j < nfd) {
533 				bits &= ~(1 << j);
534 				fp = fdp->fd_ofiles[i + j];
535 				if (fp == NULL) {
536 					error = EBADF;
537 					break;
538 				}
539 				if ((*fp->f_ops->fo_select)(fp, flag, p)) {
540 					FD_SET(i + j, &obits[which]);
541 					n++;
542 				}
543 			}
544 		}
545 	}
546 	*retval = n;
547 	return (error);
548 }
549 
550 /*ARGSUSED*/
551 #ifdef __STDC__
552 seltrue(dev_t dev, int which, struct proc *p)
553 #else
554 seltrue(dev, flag, p)
555 	dev_t dev;
556 	int flag;
557 	struct proc *p;
558 #endif
559 {
560 
561 	return (1);
562 }
563 
564 selwakeup(p, coll)
565 	register struct proc *p;
566 	int coll;
567 {
568 
569 	if (coll) {
570 		nselcoll++;
571 		wakeup((caddr_t)&selwait);
572 	}
573 	if (p) {
574 		int s = splhigh();
575 		if (p->p_wchan == (caddr_t)&selwait) {
576 			if (p->p_stat == SSLEEP)
577 				setrun(p);
578 			else
579 				unsleep(p);
580 		} else if (p->p_flag & SSEL)
581 			p->p_flag &= ~SSEL;
582 		splx(s);
583 	}
584 }
585