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