xref: /csrg-svn/sys/kern/sys_generic.c (revision 43403)
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.19 (Berkeley) 06/21/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);
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, cnt);
159 		FREE(ktriov, M_TEMP);
160 	}
161 #endif
162 	*retval = cnt;
163 done:
164 	if (uap->iovcnt > UIO_SMALLIOV)
165 		FREE(iov, M_IOV);
166 	RETURN (error);
167 }
168 
169 /*
170  * Write system call
171  */
172 write(p, uap, retval)
173 	struct proc *p;
174 	register struct args {
175 		int	fdes;
176 		char	*cbuf;
177 		unsigned count;
178 	} *uap;
179 	int *retval;
180 {
181 	register struct file *fp;
182 	struct uio auio;
183 	struct iovec aiov;
184 	long cnt, error = 0;
185 #ifdef KTRACE
186 	struct iovec ktriov;
187 #endif
188 
189 	if (((unsigned)uap->fdes) >= NOFILE ||
190 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
191 	    (fp->f_flag & FWRITE) == 0)
192 		RETURN (EBADF);
193 	aiov.iov_base = (caddr_t)uap->cbuf;
194 	aiov.iov_len = uap->count;
195 	auio.uio_iov = &aiov;
196 	auio.uio_iovcnt = 1;
197 	auio.uio_resid = uap->count;
198 	auio.uio_rw = UIO_WRITE;
199 	auio.uio_segflg = UIO_USERSPACE;
200 #ifdef KTRACE
201 	/*
202 	 * if tracing, save a copy of iovec
203 	 */
204 	if (KTRPOINT(p, KTR_GENIO))
205 		ktriov = aiov;
206 #endif
207 	cnt = uap->count;
208 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
209 		if (auio.uio_resid != cnt && (error == ERESTART ||
210 		    error == EINTR || error == EWOULDBLOCK))
211 			error = 0;
212 		if (error == EPIPE)
213 			psignal(p, SIGPIPE);
214 	}
215 	cnt -= auio.uio_resid;
216 #ifdef KTRACE
217 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
218 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
219 		    &ktriov, cnt);
220 #endif
221 	*retval = cnt;
222 	RETURN (error);
223 }
224 
225 /*
226  * Gather write system call
227  */
228 writev(p, uap, retval)
229 	struct proc *p;
230 	register struct args {
231 		int	fdes;
232 		struct	iovec *iovp;
233 		unsigned iovcnt;
234 	} *uap;
235 	int *retval;
236 {
237 	register struct file *fp;
238 	struct uio auio;
239 	register struct iovec *iov;
240 	struct iovec aiov[UIO_SMALLIOV];
241 	long i, cnt, error = 0;
242 #ifdef KTRACE
243 	struct iovec *ktriov = NULL;
244 #endif
245 
246 	if (((unsigned)uap->fdes) >= NOFILE ||
247 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
248 	    (fp->f_flag & FWRITE) == 0)
249 		RETURN (EBADF);
250 	if (uap->iovcnt > UIO_SMALLIOV) {
251 		if (uap->iovcnt > UIO_MAXIOV)
252 			RETURN (EINVAL);
253 		MALLOC(iov, struct iovec *,
254 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
255 	} else
256 		iov = aiov;
257 	auio.uio_iov = iov;
258 	auio.uio_iovcnt = uap->iovcnt;
259 	auio.uio_rw = UIO_WRITE;
260 	auio.uio_segflg = UIO_USERSPACE;
261 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
262 	    uap->iovcnt * sizeof (struct iovec)))
263 		goto done;
264 	auio.uio_resid = 0;
265 	for (i = 0; i < uap->iovcnt; i++) {
266 		if (iov->iov_len < 0) {
267 			error = EINVAL;
268 			goto done;
269 		}
270 		auio.uio_resid += iov->iov_len;
271 		if (auio.uio_resid < 0) {
272 			error = EINVAL;
273 			goto done;
274 		}
275 		iov++;
276 	}
277 #ifdef KTRACE
278 	/*
279 	 * if tracing, save a copy of iovec
280 	 */
281 	if (KTRPOINT(p, KTR_GENIO))  {
282 		unsigned iovlen = auio.uio_iovcnt * sizeof (struct iovec);
283 
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);
302 		FREE(ktriov, M_TEMP);
303 	}
304 #endif
305 	*retval = cnt;
306 done:
307 	if (uap->iovcnt > UIO_SMALLIOV)
308 		FREE(iov, 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 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 >= NOFILE ||
334 	    (fp = u.u_ofile[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 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
342 		RETURN (0);
343 	}
344 	if (com == FIONCLEX) {
345 		u.u_pofile[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);
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 > NOFILE)
433 		uap->nd = NOFILE;	/* forgiving, if 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(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(ibits, obits, nfd, retval)
507 	fd_set *ibits, *obits;
508 	int nfd, *retval;
509 {
510 	register int which, i, j;
511 	register fd_mask bits;
512 	int flag;
513 	struct file *fp;
514 	int error = 0, n = 0;
515 
516 	for (which = 0; which < 3; which++) {
517 		switch (which) {
518 
519 		case 0:
520 			flag = FREAD; break;
521 
522 		case 1:
523 			flag = FWRITE; break;
524 
525 		case 2:
526 			flag = 0; break;
527 		}
528 		for (i = 0; i < nfd; i += NFDBITS) {
529 			bits = ibits[which].fds_bits[i/NFDBITS];
530 			while ((j = ffs(bits)) && i + --j < nfd) {
531 				bits &= ~(1 << j);
532 				fp = u.u_ofile[i + j];
533 				if (fp == NULL) {
534 					error = EBADF;
535 					break;
536 				}
537 				if ((*fp->f_ops->fo_select)(fp, flag)) {
538 					FD_SET(i + j, &obits[which]);
539 					n++;
540 				}
541 			}
542 		}
543 	}
544 	*retval = n;
545 	return (error);
546 }
547 
548 /*ARGSUSED*/
549 seltrue(dev, flag)
550 	dev_t dev;
551 	int flag;
552 {
553 
554 	return (1);
555 }
556 
557 selwakeup(p, coll)
558 	register struct proc *p;
559 	int coll;
560 {
561 
562 	if (coll) {
563 		nselcoll++;
564 		wakeup((caddr_t)&selwait);
565 	}
566 	if (p) {
567 		int s = splhigh();
568 		if (p->p_wchan == (caddr_t)&selwait) {
569 			if (p->p_stat == SSLEEP)
570 				setrun(p);
571 			else
572 				unsleep(p);
573 		} else if (p->p_flag & SSEL)
574 			p->p_flag &= ~SSEL;
575 		splx(s);
576 	}
577 }
578