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