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