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