xref: /original-bsd/sys/kern/sys_generic.c (revision faf3fd95)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)sys_generic.c	7.20 (Berkeley) 06/22/90
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "syscontext.h"
23 #include "ioctl.h"
24 #include "file.h"
25 #include "proc.h"
26 #include "uio.h"
27 #include "kernel.h"
28 #include "stat.h"
29 #include "malloc.h"
30 #ifdef KTRACE
31 #include "ktrace.h"
32 #endif
33 
34 /*
35  * Read system call.
36  */
37 read(p, uap, retval)
38 	struct proc *p;
39 	register struct args {
40 		int	fdes;
41 		char	*cbuf;
42 		unsigned count;
43 	} *uap;
44 	int *retval;
45 {
46 	register struct file *fp;
47 	struct uio auio;
48 	struct iovec aiov;
49 	long cnt, error = 0;
50 #ifdef KTRACE
51 	struct iovec ktriov;
52 #endif
53 
54 	if (((unsigned)uap->fdes) >= NOFILE ||
55 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
56 	    (fp->f_flag & FREAD) == 0)
57 		RETURN (EBADF);
58 	aiov.iov_base = (caddr_t)uap->cbuf;
59 	aiov.iov_len = uap->count;
60 	auio.uio_iov = &aiov;
61 	auio.uio_iovcnt = 1;
62 	auio.uio_resid = uap->count;
63 	auio.uio_rw = UIO_READ;
64 	auio.uio_segflg = UIO_USERSPACE;
65 #ifdef KTRACE
66 	/*
67 	 * if tracing, save a copy of iovec
68 	 */
69 	if (KTRPOINT(p, KTR_GENIO))
70 		ktriov = aiov;
71 #endif
72 	cnt = uap->count;
73 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
74 		if (auio.uio_resid != cnt && (error == ERESTART ||
75 		    error == EINTR || error == EWOULDBLOCK))
76 			error = 0;
77 	cnt -= auio.uio_resid;
78 #ifdef KTRACE
79 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
80 		ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
81 #endif
82 	*retval = cnt;
83 	RETURN (error);
84 }
85 
86 /*
87  * Scatter read system call.
88  */
89 readv(p, uap, retval)
90 	struct proc *p;
91 	register struct args {
92 		int	fdes;
93 		struct	iovec *iovp;
94 		unsigned iovcnt;
95 	} *uap;
96 	int *retval;
97 {
98 	register struct file *fp;
99 	struct uio auio;
100 	register struct iovec *iov;
101 	struct iovec aiov[UIO_SMALLIOV];
102 	long i, cnt, error = 0;
103 #ifdef KTRACE
104 	struct iovec *ktriov = NULL;
105 #endif
106 
107 	if (((unsigned)uap->fdes) >= NOFILE ||
108 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
109 	    (fp->f_flag & FREAD) == 0)
110 		RETURN (EBADF);
111 	if (uap->iovcnt > UIO_SMALLIOV) {
112 		if (uap->iovcnt > UIO_MAXIOV)
113 			RETURN (EINVAL);
114 		MALLOC(iov, struct iovec *,
115 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
116 	} else
117 		iov = aiov;
118 	auio.uio_iov = iov;
119 	auio.uio_iovcnt = uap->iovcnt;
120 	auio.uio_rw = UIO_READ;
121 	auio.uio_segflg = UIO_USERSPACE;
122 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
123 	    uap->iovcnt * sizeof (struct iovec)))
124 		goto done;
125 	auio.uio_resid = 0;
126 	for (i = 0; i < uap->iovcnt; i++) {
127 		if (iov->iov_len < 0) {
128 			error = EINVAL;
129 			goto done;
130 		}
131 		auio.uio_resid += iov->iov_len;
132 		if (auio.uio_resid < 0) {
133 			error = EINVAL;
134 			goto done;
135 		}
136 		iov++;
137 	}
138 #ifdef KTRACE
139 	/*
140 	 * if tracing, save a copy of iovec
141 	 */
142 	if (KTRPOINT(p, KTR_GENIO))  {
143 		unsigned iovlen = auio.uio_iovcnt * sizeof (struct iovec);
144 
145 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
146 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
147 	}
148 #endif
149 	cnt = auio.uio_resid;
150 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
151 		if (auio.uio_resid != cnt && (error == ERESTART ||
152 		    error == EINTR || error == EWOULDBLOCK))
153 			error = 0;
154 	cnt -= auio.uio_resid;
155 #ifdef KTRACE
156 	if (ktriov != NULL) {
157 		if (error == 0)
158 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
159 			    cnt, error);
160 		FREE(ktriov, M_TEMP);
161 	}
162 #endif
163 	*retval = cnt;
164 done:
165 	if (uap->iovcnt > UIO_SMALLIOV)
166 		FREE(iov, M_IOV);
167 	RETURN (error);
168 }
169 
170 /*
171  * Write system call
172  */
173 write(p, uap, retval)
174 	struct proc *p;
175 	register struct args {
176 		int	fdes;
177 		char	*cbuf;
178 		unsigned count;
179 	} *uap;
180 	int *retval;
181 {
182 	register struct file *fp;
183 	struct uio auio;
184 	struct iovec aiov;
185 	long cnt, error = 0;
186 #ifdef KTRACE
187 	struct iovec ktriov;
188 #endif
189 
190 	if (((unsigned)uap->fdes) >= NOFILE ||
191 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
192 	    (fp->f_flag & FWRITE) == 0)
193 		RETURN (EBADF);
194 	aiov.iov_base = (caddr_t)uap->cbuf;
195 	aiov.iov_len = uap->count;
196 	auio.uio_iov = &aiov;
197 	auio.uio_iovcnt = 1;
198 	auio.uio_resid = uap->count;
199 	auio.uio_rw = UIO_WRITE;
200 	auio.uio_segflg = UIO_USERSPACE;
201 #ifdef KTRACE
202 	/*
203 	 * if tracing, save a copy of iovec
204 	 */
205 	if (KTRPOINT(p, KTR_GENIO))
206 		ktriov = aiov;
207 #endif
208 	cnt = uap->count;
209 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
210 		if (auio.uio_resid != cnt && (error == ERESTART ||
211 		    error == EINTR || error == EWOULDBLOCK))
212 			error = 0;
213 		if (error == EPIPE)
214 			psignal(p, SIGPIPE);
215 	}
216 	cnt -= auio.uio_resid;
217 #ifdef KTRACE
218 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
219 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
220 		    &ktriov, cnt, error);
221 #endif
222 	*retval = cnt;
223 	RETURN (error);
224 }
225 
226 /*
227  * Gather write system call
228  */
229 writev(p, uap, retval)
230 	struct proc *p;
231 	register struct args {
232 		int	fdes;
233 		struct	iovec *iovp;
234 		unsigned iovcnt;
235 	} *uap;
236 	int *retval;
237 {
238 	register struct file *fp;
239 	struct uio auio;
240 	register struct iovec *iov;
241 	struct iovec aiov[UIO_SMALLIOV];
242 	long i, cnt, error = 0;
243 #ifdef KTRACE
244 	struct iovec *ktriov = NULL;
245 #endif
246 
247 	if (((unsigned)uap->fdes) >= NOFILE ||
248 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
249 	    (fp->f_flag & FWRITE) == 0)
250 		RETURN (EBADF);
251 	if (uap->iovcnt > UIO_SMALLIOV) {
252 		if (uap->iovcnt > UIO_MAXIOV)
253 			RETURN (EINVAL);
254 		MALLOC(iov, struct iovec *,
255 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
256 	} else
257 		iov = aiov;
258 	auio.uio_iov = iov;
259 	auio.uio_iovcnt = uap->iovcnt;
260 	auio.uio_rw = UIO_WRITE;
261 	auio.uio_segflg = UIO_USERSPACE;
262 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
263 	    uap->iovcnt * sizeof (struct iovec)))
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 		unsigned iovlen = auio.uio_iovcnt * sizeof (struct iovec);
284 
285 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
286 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
287 	}
288 #endif
289 	cnt = auio.uio_resid;
290 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
291 		if (auio.uio_resid != cnt && (error == ERESTART ||
292 		    error == EINTR || error == EWOULDBLOCK))
293 			error = 0;
294 		if (error == EPIPE)
295 			psignal(p, SIGPIPE);
296 	}
297 	cnt -= auio.uio_resid;
298 #ifdef KTRACE
299 	if (ktriov != NULL) {
300 		if (error == 0)
301 			ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
302 				ktriov, cnt, error);
303 		FREE(ktriov, M_TEMP);
304 	}
305 #endif
306 	*retval = cnt;
307 done:
308 	if (uap->iovcnt > UIO_SMALLIOV)
309 		FREE(iov, M_IOV);
310 	RETURN (error);
311 }
312 
313 /*
314  * Ioctl system call
315  */
316 /* ARGSUSED */
317 ioctl(p, uap, retval)
318 	struct proc *p;
319 	register struct args {
320 		int	fdes;
321 		int	cmd;
322 		caddr_t	cmarg;
323 	} *uap;
324 	int *retval;
325 {
326 	register struct file *fp;
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 >= NOFILE ||
335 	    (fp = u.u_ofile[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 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
343 		RETURN (0);
344 	}
345 	if (com == FIONCLEX) {
346 		u.u_pofile[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 > NOFILE)
434 		uap->nd = NOFILE;	/* forgiving, if 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(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(ibits, obits, nfd, retval)
508 	fd_set *ibits, *obits;
509 	int nfd, *retval;
510 {
511 	register int which, i, j;
512 	register fd_mask bits;
513 	int flag;
514 	struct file *fp;
515 	int error = 0, n = 0;
516 
517 	for (which = 0; which < 3; which++) {
518 		switch (which) {
519 
520 		case 0:
521 			flag = FREAD; break;
522 
523 		case 1:
524 			flag = FWRITE; break;
525 
526 		case 2:
527 			flag = 0; break;
528 		}
529 		for (i = 0; i < nfd; i += NFDBITS) {
530 			bits = ibits[which].fds_bits[i/NFDBITS];
531 			while ((j = ffs(bits)) && i + --j < nfd) {
532 				bits &= ~(1 << j);
533 				fp = u.u_ofile[i + j];
534 				if (fp == NULL) {
535 					error = EBADF;
536 					break;
537 				}
538 				if ((*fp->f_ops->fo_select)(fp, flag)) {
539 					FD_SET(i + j, &obits[which]);
540 					n++;
541 				}
542 			}
543 		}
544 	}
545 	*retval = n;
546 	return (error);
547 }
548 
549 /*ARGSUSED*/
550 seltrue(dev, flag)
551 	dev_t dev;
552 	int flag;
553 {
554 
555 	return (1);
556 }
557 
558 selwakeup(p, coll)
559 	register struct proc *p;
560 	int coll;
561 {
562 
563 	if (coll) {
564 		nselcoll++;
565 		wakeup((caddr_t)&selwait);
566 	}
567 	if (p) {
568 		int s = splhigh();
569 		if (p->p_wchan == (caddr_t)&selwait) {
570 			if (p->p_stat == SSLEEP)
571 				setrun(p);
572 			else
573 				unsleep(p);
574 		} else if (p->p_flag & SSEL)
575 			p->p_flag &= ~SSEL;
576 		splx(s);
577 	}
578 }
579