xref: /csrg-svn/sys/kern/sys_generic.c (revision 42922)
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.17 (Berkeley) 06/05/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;
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)IOCPARM_LEN(com), M_IOCTLOPS,
359 		    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 == 0)
467 		error = u.u_error;		/* XXX */
468 	if (error || *retval)
469 		goto done;
470 	s = splhigh();
471 	/* this should be timercmp(&time, &atv, >=) */
472 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
473 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
474 		splx(s);
475 		goto done;
476 	}
477 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
478 		splx(s);
479 		goto retry;
480 	}
481 	p->p_flag &= ~SSEL;
482 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
483 	splx(s);
484 	if (error == 0)
485 		goto retry;
486 done:
487 	p->p_flag &= ~SSEL;
488 	/* select is not restarted after signals... */
489 	if (error == ERESTART)
490 		error = EINTR;
491 	if (error == EWOULDBLOCK)
492 		error = 0;
493 #define	putbits(name, x) \
494 	if (uap->name) { \
495 		int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
496 		    (unsigned)(ni * sizeof(fd_mask))); \
497 		if (error2) \
498 			error = error2; \
499 	}
500 	if (error == 0) {
501 		putbits(in, 0);
502 		putbits(ou, 1);
503 		putbits(ex, 2);
504 #undef putbits
505 	}
506 	RETURN (error);
507 }
508 
509 selscan(ibits, obits, nfd, retval)
510 	fd_set *ibits, *obits;
511 	int nfd, *retval;
512 {
513 	register int which, i, j;
514 	register fd_mask bits;
515 	int flag;
516 	struct file *fp;
517 	int error = 0, n = 0;
518 
519 	for (which = 0; which < 3; which++) {
520 		switch (which) {
521 
522 		case 0:
523 			flag = FREAD; break;
524 
525 		case 1:
526 			flag = FWRITE; break;
527 
528 		case 2:
529 			flag = 0; break;
530 		}
531 		for (i = 0; i < nfd; i += NFDBITS) {
532 			bits = ibits[which].fds_bits[i/NFDBITS];
533 			while ((j = ffs(bits)) && i + --j < nfd) {
534 				bits &= ~(1 << j);
535 				fp = u.u_ofile[i + j];
536 				if (fp == NULL) {
537 					error = EBADF;
538 					break;
539 				}
540 				if ((*fp->f_ops->fo_select)(fp, flag)) {
541 					FD_SET(i + j, &obits[which]);
542 					n++;
543 				}
544 			}
545 		}
546 	}
547 	*retval = n;
548 	return (error);
549 }
550 
551 /*ARGSUSED*/
552 seltrue(dev, flag)
553 	dev_t dev;
554 	int flag;
555 {
556 
557 	return (1);
558 }
559 
560 selwakeup(p, coll)
561 	register struct proc *p;
562 	int coll;
563 {
564 
565 	if (coll) {
566 		nselcoll++;
567 		wakeup((caddr_t)&selwait);
568 	}
569 	if (p) {
570 		int s = splhigh();
571 		if (p->p_wchan == (caddr_t)&selwait) {
572 			if (p->p_stat == SSLEEP)
573 				setrun(p);
574 			else
575 				unsleep(p);
576 		} else if (p->p_flag & SSEL)
577 			p->p_flag &= ~SSEL;
578 		splx(s);
579 	}
580 }
581