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