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