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