xref: /original-bsd/sys/kern/sys_generic.c (revision 05dfbb6f)
1 /*
2  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)sys_generic.c	7.9 (Berkeley) 03/10/89
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "dir.h"
12 #include "user.h"
13 #include "ioctl.h"
14 #include "file.h"
15 #include "proc.h"
16 #include "uio.h"
17 #include "kernel.h"
18 #include "stat.h"
19 #include "malloc.h"
20 #ifdef KTRACE
21 #include "ktrace.h"
22 #endif
23 
24 /*
25  * Read system call.
26  */
27 read()
28 {
29 	register struct a {
30 		int	fdes;
31 		char	*cbuf;
32 		unsigned count;
33 	} *uap = (struct a *)u.u_ap;
34 	struct uio auio;
35 	struct iovec aiov;
36 
37 	aiov.iov_base = (caddr_t)uap->cbuf;
38 	aiov.iov_len = uap->count;
39 	auio.uio_iov = &aiov;
40 	auio.uio_iovcnt = 1;
41 	rwuio(&auio, UIO_READ);
42 }
43 
44 readv()
45 {
46 	register struct a {
47 		int	fdes;
48 		struct	iovec *iovp;
49 		unsigned iovcnt;
50 	} *uap = (struct a *)u.u_ap;
51 	struct uio auio;
52 	struct iovec aiov[UIO_SMALLIOV], *iov;
53 
54 	if (uap->iovcnt > UIO_SMALLIOV) {
55 		if (uap->iovcnt > UIO_MAXIOV) {
56 			u.u_error = EINVAL;
57 			return;
58 		}
59 		MALLOC(iov, struct iovec *,
60 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
61 		if (iov == NULL) {
62 			u.u_error = ENOMEM;
63 			return;
64 		}
65 	} else
66 		iov = aiov;
67 	auio.uio_iov = iov;
68 	auio.uio_iovcnt = uap->iovcnt;
69 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)auio.uio_iov,
70 	    uap->iovcnt * sizeof (struct iovec));
71 	if (u.u_error)
72 		goto done;
73 	rwuio(&auio, UIO_READ);
74 done:
75 	if (iov != aiov)
76 		FREE(iov, M_IOV);
77 }
78 
79 /*
80  * Write system call
81  */
82 write()
83 {
84 	register struct a {
85 		int	fdes;
86 		char	*cbuf;
87 		unsigned count;
88 	} *uap = (struct a *)u.u_ap;
89 	struct uio auio;
90 	struct iovec aiov;
91 
92 	auio.uio_iov = &aiov;
93 	auio.uio_iovcnt = 1;
94 	aiov.iov_base = uap->cbuf;
95 	aiov.iov_len = uap->count;
96 	rwuio(&auio, UIO_WRITE);
97 }
98 
99 writev()
100 {
101 	register struct a {
102 		int	fdes;
103 		struct	iovec *iovp;
104 		unsigned iovcnt;
105 	} *uap = (struct a *)u.u_ap;
106 	struct uio auio;
107 	struct iovec aiov[UIO_SMALLIOV], *iov;
108 
109 	if (uap->iovcnt > UIO_SMALLIOV) {
110 		if (uap->iovcnt > UIO_MAXIOV) {
111 			u.u_error = EINVAL;
112 			return;
113 		}
114 		MALLOC(iov, struct iovec *,
115 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
116 		if (iov == NULL) {
117 			u.u_error = ENOMEM;
118 			return;
119 		}
120 	} else
121 		iov = aiov;
122 	auio.uio_iov = iov;
123 	auio.uio_iovcnt = uap->iovcnt;
124 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)auio.uio_iov,
125 	    uap->iovcnt * sizeof (struct iovec));
126 	if (u.u_error)
127 		goto done;
128 	rwuio(&auio, UIO_WRITE);
129 done:
130 	if (iov != aiov)
131 		FREE(iov, M_IOV);
132 }
133 
134 rwuio(uio, rw)
135 	register struct uio *uio;
136 	enum uio_rw rw;
137 {
138 	struct a {
139 		int	fdes;
140 	};
141 	register struct file *fp;
142 	register struct iovec *iov;
143 	int i, count;
144 #ifdef KTRACE
145 	struct iovec *ktriov = NULL;
146 #endif
147 
148 
149 	GETF(fp, ((struct a *)u.u_ap)->fdes);
150 	if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
151 		u.u_error = EBADF;
152 		return;
153 	}
154 	uio->uio_resid = 0;
155 	uio->uio_segflg = UIO_USERSPACE;
156 	iov = uio->uio_iov;
157 	for (i = 0; i < uio->uio_iovcnt; i++) {
158 		if (iov->iov_len < 0) {
159 			u.u_error = EINVAL;
160 			return;
161 		}
162 		uio->uio_resid += iov->iov_len;
163 		if (uio->uio_resid < 0) {
164 			u.u_error = EINVAL;
165 			return;
166 		}
167 		iov++;
168 	}
169 	count = uio->uio_resid;
170 #ifdef KTRACE
171 	/* if tracing, save a copy of iovec */
172 	if (KTRPOINT(u.u_procp, KTR_GENIO))  {
173 		int iovlen = uio->uio_iovcnt * sizeof (struct iovec);
174 
175 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
176 		if (ktriov != NULL)
177 			bcopy((caddr_t)uio->uio_iov, (caddr_t)ktriov, iovlen);
178 	}
179 #endif
180 	if (setjmp(&u.u_qsave)) {
181 		if (uio->uio_resid == count) {
182 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
183 				u.u_error = EINTR;
184 			else
185 				u.u_eosys = RESTARTSYS;
186 		}
187 	} else
188 		u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio);
189 	u.u_r.r_val1 = count - uio->uio_resid;
190 #ifdef KTRACE
191 	if (ktriov != NULL) {
192 		ktrgenio(u.u_procp->p_tracep, ((struct a *)u.u_ap)->fdes,
193 			rw, ktriov, u.u_r.r_val1);
194 		FREE(ktriov, M_TEMP);
195 	}
196 #endif
197 }
198 
199 /*
200  * Ioctl system call
201  */
202 ioctl()
203 {
204 	register struct file *fp;
205 	struct a {
206 		int	fdes;
207 		int	cmd;
208 		caddr_t	cmarg;
209 	} *uap;
210 	register int com;
211 	register u_int size;
212 	caddr_t memp = 0;
213 #define STK_PARAMS	128
214 	char stkbuf[STK_PARAMS];
215 	caddr_t data = stkbuf;
216 
217 	uap = (struct a *)u.u_ap;
218 	GETF(fp, uap->fdes);
219 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
220 		u.u_error = EBADF;
221 		return;
222 	}
223 	com = uap->cmd;
224 
225 	if (com == FIOCLEX) {
226 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
227 		return;
228 	}
229 	if (com == FIONCLEX) {
230 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
231 		return;
232 	}
233 
234 	/*
235 	 * Interpret high order word to find
236 	 * amount of data to be copied to/from the
237 	 * user's address space.
238 	 */
239 	size = IOCPARM_LEN(com);
240 	if (size > IOCPARM_MAX) {
241 		u.u_error = ENOTTY;
242 		return;
243 	}
244 	if (size > sizeof (stkbuf)) {
245 		memp = (caddr_t)malloc((u_long)IOCPARM_LEN(com), M_IOCTLOPS,
246 		    M_WAITOK);
247 		data = memp;
248 	}
249 	if (com&IOC_IN) {
250 		if (size) {
251 			u.u_error = copyin(uap->cmarg, data, (u_int)size);
252 			if (u.u_error) {
253 				if (memp)
254 					free(memp, M_IOCTLOPS);
255 				return;
256 			}
257 		} else
258 			*(caddr_t *)data = uap->cmarg;
259 	} else if ((com&IOC_OUT) && size)
260 		/*
261 		 * Zero the buffer so the user always
262 		 * gets back something deterministic.
263 		 */
264 		bzero(data, size);
265 	else if (com&IOC_VOID)
266 		*(caddr_t *)data = uap->cmarg;
267 
268 	switch (com) {
269 
270 	case FIONBIO:
271 		u.u_error = fset(fp, FNDELAY, *(int *)data);
272 		break;
273 
274 	case FIOASYNC:
275 		u.u_error = fset(fp, FASYNC, *(int *)data);
276 		break;
277 
278 	case FIOSETOWN:
279 		u.u_error = fsetown(fp, *(int *)data);
280 		break;
281 
282 	case FIOGETOWN:
283 		u.u_error = fgetown(fp, (int *)data);
284 		break;
285 	default:
286 		if (setjmp(&u.u_qsave))
287 			u.u_error = EINTR;
288 		else
289 			u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
290 		/*
291 		 * Copy any data to user, size was
292 		 * already set and checked above.
293 		 */
294 		if (u.u_error == 0 && (com&IOC_OUT) && size)
295 			u.u_error = copyout(data, uap->cmarg, (u_int)size);
296 		break;
297 	}
298 	if (memp)
299 		free(memp, M_IOCTLOPS);
300 }
301 
302 int	unselect();
303 int	nselcoll;
304 
305 /*
306  * Select system call.
307  */
308 select()
309 {
310 	register struct uap  {
311 		int	nd;
312 		fd_set	*in, *ou, *ex;
313 		struct	timeval *tv;
314 	} *uap = (struct uap *)u.u_ap;
315 	fd_set ibits[3], obits[3];
316 	struct timeval atv;
317 	int s, ncoll, ni;
318 	label_t lqsave;
319 
320 	bzero((caddr_t)ibits, sizeof(ibits));
321 	bzero((caddr_t)obits, sizeof(obits));
322 	if (uap->nd > NOFILE)
323 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
324 	ni = howmany(uap->nd, NFDBITS);
325 
326 #define	getbits(name, x) \
327 	if (uap->name) { \
328 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
329 		    (unsigned)(ni * sizeof(fd_mask))); \
330 		if (u.u_error) \
331 			goto done; \
332 	}
333 	getbits(in, 0);
334 	getbits(ou, 1);
335 	getbits(ex, 2);
336 #undef	getbits
337 
338 	if (uap->tv) {
339 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
340 			sizeof (atv));
341 		if (u.u_error)
342 			goto done;
343 		if (itimerfix(&atv)) {
344 			u.u_error = EINVAL;
345 			goto done;
346 		}
347 		s = splhigh(); timevaladd(&atv, &time); splx(s);
348 	}
349 retry:
350 	ncoll = nselcoll;
351 	u.u_procp->p_flag |= SSEL;
352 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
353 	if (u.u_error || u.u_r.r_val1)
354 		goto done;
355 	s = splhigh();
356 	/* this should be timercmp(&time, &atv, >=) */
357 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
358 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
359 		splx(s);
360 		goto done;
361 	}
362 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
363 		splx(s);
364 		goto retry;
365 	}
366 	u.u_procp->p_flag &= ~SSEL;
367 	if (uap->tv) {
368 		lqsave = u.u_qsave;
369 		if (setjmp(&u.u_qsave)) {
370 			untimeout(unselect, (caddr_t)u.u_procp);
371 			u.u_error = EINTR;
372 			splx(s);
373 			goto done;
374 		}
375 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
376 	}
377 	sleep((caddr_t)&selwait, PZERO+1);
378 	if (uap->tv) {
379 		u.u_qsave = lqsave;
380 		untimeout(unselect, (caddr_t)u.u_procp);
381 	}
382 	splx(s);
383 	goto retry;
384 done:
385 	u.u_procp->p_flag &= ~SSEL;
386 #define	putbits(name, x) \
387 	if (uap->name) { \
388 		int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
389 		    (unsigned)(ni * sizeof(fd_mask))); \
390 		if (error) \
391 			u.u_error = error; \
392 	}
393 	if (u.u_error == 0) {
394 		putbits(in, 0);
395 		putbits(ou, 1);
396 		putbits(ex, 2);
397 #undef putbits
398 	}
399 }
400 
401 unselect(p)
402 	register struct proc *p;
403 {
404 	register int s = splhigh();
405 
406 	switch (p->p_stat) {
407 
408 	case SSLEEP:
409 		setrun(p);
410 		break;
411 
412 	case SSTOP:
413 		unsleep(p);
414 		break;
415 	}
416 	splx(s);
417 }
418 
419 selscan(ibits, obits, nfd)
420 	fd_set *ibits, *obits;
421 {
422 	register int which, i, j;
423 	register fd_mask bits;
424 	int flag;
425 	struct file *fp;
426 	int n = 0;
427 
428 	for (which = 0; which < 3; which++) {
429 		switch (which) {
430 
431 		case 0:
432 			flag = FREAD; break;
433 
434 		case 1:
435 			flag = FWRITE; break;
436 
437 		case 2:
438 			flag = 0; break;
439 		}
440 		for (i = 0; i < nfd; i += NFDBITS) {
441 			bits = ibits[which].fds_bits[i/NFDBITS];
442 			while ((j = ffs(bits)) && i + --j < nfd) {
443 				bits &= ~(1 << j);
444 				fp = u.u_ofile[i + j];
445 				if (fp == NULL) {
446 					u.u_error = EBADF;
447 					break;
448 				}
449 				if ((*fp->f_ops->fo_select)(fp, flag)) {
450 					FD_SET(i + j, &obits[which]);
451 					n++;
452 				}
453 			}
454 		}
455 	}
456 	return (n);
457 }
458 
459 /*ARGSUSED*/
460 seltrue(dev, flag)
461 	dev_t dev;
462 	int flag;
463 {
464 
465 	return (1);
466 }
467 
468 selwakeup(p, coll)
469 	register struct proc *p;
470 	int coll;
471 {
472 
473 	if (coll) {
474 		nselcoll++;
475 		wakeup((caddr_t)&selwait);
476 	}
477 	if (p) {
478 		int s = splhigh();
479 		if (p->p_wchan == (caddr_t)&selwait) {
480 			if (p->p_stat == SSLEEP)
481 				setrun(p);
482 			else
483 				unsleep(p);
484 		} else if (p->p_flag & SSEL)
485 			p->p_flag &= ~SSEL;
486 		splx(s);
487 	}
488 }
489