xref: /csrg-svn/sys/kern/sys_generic.c (revision 23384)
1 /*
2  * Copyright (c) 1982 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	6.11 (Berkeley) 06/08/85
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 
20 /*
21  * Read system call.
22  */
23 read()
24 {
25 	register struct a {
26 		int	fdes;
27 		char	*cbuf;
28 		unsigned count;
29 	} *uap = (struct a *)u.u_ap;
30 	struct uio auio;
31 	struct iovec aiov;
32 
33 	aiov.iov_base = (caddr_t)uap->cbuf;
34 	aiov.iov_len = uap->count;
35 	auio.uio_iov = &aiov;
36 	auio.uio_iovcnt = 1;
37 	rwuio(&auio, UIO_READ);
38 }
39 
40 readv()
41 {
42 	register struct a {
43 		int	fdes;
44 		struct	iovec *iovp;
45 		int	iovcnt;
46 	} *uap = (struct a *)u.u_ap;
47 	struct uio auio;
48 	struct iovec aiov[16];		/* XXX */
49 
50 	if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
51 		u.u_error = EINVAL;
52 		return;
53 	}
54 	auio.uio_iov = aiov;
55 	auio.uio_iovcnt = uap->iovcnt;
56 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
57 	    (unsigned)(uap->iovcnt * sizeof (struct iovec)));
58 	if (u.u_error)
59 		return;
60 	rwuio(&auio, UIO_READ);
61 }
62 
63 /*
64  * Write system call
65  */
66 write()
67 {
68 	register struct a {
69 		int	fdes;
70 		char	*cbuf;
71 		int	count;
72 	} *uap = (struct a *)u.u_ap;
73 	struct uio auio;
74 	struct iovec aiov;
75 
76 	auio.uio_iov = &aiov;
77 	auio.uio_iovcnt = 1;
78 	aiov.iov_base = uap->cbuf;
79 	aiov.iov_len = uap->count;
80 	rwuio(&auio, UIO_WRITE);
81 }
82 
83 writev()
84 {
85 	register struct a {
86 		int	fdes;
87 		struct	iovec *iovp;
88 		int	iovcnt;
89 	} *uap = (struct a *)u.u_ap;
90 	struct uio auio;
91 	struct iovec aiov[16];		/* XXX */
92 
93 	if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
94 		u.u_error = EINVAL;
95 		return;
96 	}
97 	auio.uio_iov = aiov;
98 	auio.uio_iovcnt = uap->iovcnt;
99 	u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
100 	    (unsigned)(uap->iovcnt * sizeof (struct iovec)));
101 	if (u.u_error)
102 		return;
103 	rwuio(&auio, UIO_WRITE);
104 }
105 
106 rwuio(uio, rw)
107 	register struct uio *uio;
108 	enum uio_rw rw;
109 {
110 	struct a {
111 		int	fdes;
112 	};
113 	register struct file *fp;
114 	register struct iovec *iov;
115 	int i, count;
116 
117 	GETF(fp, ((struct a *)u.u_ap)->fdes);
118 	if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
119 		u.u_error = EBADF;
120 		return;
121 	}
122 	uio->uio_resid = 0;
123 	uio->uio_segflg = UIO_USERSPACE;
124 	iov = uio->uio_iov;
125 	for (i = 0; i < uio->uio_iovcnt; i++) {
126 		if (iov->iov_len < 0) {
127 			u.u_error = EINVAL;
128 			return;
129 		}
130 		uio->uio_resid += iov->iov_len;
131 		if (uio->uio_resid < 0) {
132 			u.u_error = EINVAL;
133 			return;
134 		}
135 		iov++;
136 	}
137 	count = uio->uio_resid;
138 	uio->uio_offset = fp->f_offset;
139 	if (setjmp(&u.u_qsave)) {
140 		if (uio->uio_resid == count) {
141 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
142 				u.u_error = EINTR;
143 			else
144 				u.u_eosys = RESTARTSYS;
145 		}
146 	} else
147 		u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio);
148 	u.u_r.r_val1 = count - uio->uio_resid;
149 	fp->f_offset += u.u_r.r_val1;
150 }
151 
152 /*
153  * Ioctl system call
154  */
155 ioctl()
156 {
157 	register struct file *fp;
158 	struct a {
159 		int	fdes;
160 		int	cmd;
161 		caddr_t	cmarg;
162 	} *uap;
163 	register int com;
164 	register u_int size;
165 	char data[IOCPARM_MASK+1];
166 
167 	uap = (struct a *)u.u_ap;
168 	GETF(fp, uap->fdes);
169 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
170 		u.u_error = EBADF;
171 		return;
172 	}
173 	com = uap->cmd;
174 
175 #if defined(vax) && defined(COMPAT)
176 	/*
177 	 * Map old style ioctl's into new for the
178 	 * sake of backwards compatibility (sigh).
179 	 */
180 	if ((com&~0xffff) == 0) {
181 		com = mapioctl(com);
182 		if (com == 0) {
183 			u.u_error = EINVAL;
184 			return;
185 		}
186 	}
187 #endif
188 	if (com == FIOCLEX) {
189 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
190 		return;
191 	}
192 	if (com == FIONCLEX) {
193 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
194 		return;
195 	}
196 
197 	/*
198 	 * Interpret high order word to find
199 	 * amount of data to be copied to/from the
200 	 * user's address space.
201 	 */
202 	size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
203 	if (size > sizeof (data)) {
204 		u.u_error = EFAULT;
205 		return;
206 	}
207 	if (com&IOC_IN) {
208 		if (size) {
209 			u.u_error =
210 			    copyin(uap->cmarg, (caddr_t)data, (u_int)size);
211 			if (u.u_error)
212 				return;
213 		} else
214 			*(caddr_t *)data = uap->cmarg;
215 	} else if ((com&IOC_OUT) && size)
216 		/*
217 		 * Zero the buffer on the stack so the user
218 		 * always gets back something deterministic.
219 		 */
220 		bzero((caddr_t)data, size);
221 	else if (com&IOC_VOID)
222 		*(caddr_t *)data = uap->cmarg;
223 
224 	switch (com) {
225 
226 	case FIONBIO:
227 		u.u_error = fset(fp, FNDELAY, *(int *)data);
228 		return;
229 
230 	case FIOASYNC:
231 		u.u_error = fset(fp, FASYNC, *(int *)data);
232 		return;
233 
234 	case FIOSETOWN:
235 		u.u_error = fsetown(fp, *(int *)data);
236 		return;
237 
238 	case FIOGETOWN:
239 		u.u_error = fgetown(fp, (int *)data);
240 		return;
241 	}
242 	u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
243 	/*
244 	 * Copy any data to user, size was
245 	 * already set and checked above.
246 	 */
247 	if (u.u_error == 0 && (com&IOC_OUT) && size)
248 		u.u_error = copyout(data, uap->cmarg, (u_int)size);
249 }
250 
251 int	unselect();
252 int	nselcoll;
253 
254 /*
255  * Select uses bit masks of file descriptors in ints.
256  * These macros manipulate such bit fields (the filesystem macros use chars).
257  */
258 #define NBI		(sizeof(int) * NBBY)		/* bits per int */
259 #define	NI		howmany(NOFILE, NBI)
260 #define	tbit(p, n)	((p)[(n)/NBI] & (1 << ((n) % NBI)))
261 #define	sbit(p, n)	((p)[(n)/NBI] |= (1 << ((n) % NBI)))
262 #define	cbit(p, n)	((p)[(n)/NBI] &= ~(1 << ((n) % NBI)))
263 
264 /*
265  * Select system call.
266  */
267 select()
268 {
269 	register struct uap  {
270 		int	nd;
271 		int	*in, *ou, *ex;
272 		struct	timeval *tv;
273 	} *uap = (struct uap *)u.u_ap;
274 	int ibits[3][NI], obits[3][NI];
275 	struct timeval atv;
276 	int s, ncoll, ni;
277 	label_t lqsave;
278 
279 	bzero(ibits, sizeof(ibits));
280 	bzero(obits, sizeof(obits));
281 	if (uap->nd > NOFILE)
282 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
283 	ni = howmany(uap->nd, NBI);
284 
285 #define	getbits(name, x) \
286 	if (uap->name) { \
287 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)ibits[x], \
288 		    ni * sizeof(int)); \
289 		if (u.u_error) \
290 			goto done; \
291 	}
292 	getbits(in, 0);
293 	getbits(ou, 1);
294 	getbits(ex, 2);
295 #undef	getbits
296 
297 	if (uap->tv) {
298 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
299 			sizeof (atv));
300 		if (u.u_error)
301 			goto done;
302 		if (itimerfix(&atv)) {
303 			u.u_error = EINVAL;
304 			goto done;
305 		}
306 		s = splhigh(); timevaladd(&atv, &time); splx(s);
307 	}
308 retry:
309 	ncoll = nselcoll;
310 	u.u_procp->p_flag |= SSEL;
311 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
312 	if (u.u_error || u.u_r.r_val1)
313 		goto done;
314 	s = splhigh();
315 	/* this should be timercmp(&time, &atv, >=) */
316 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
317 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
318 		splx(s);
319 		goto done;
320 	}
321 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
322 		u.u_procp->p_flag &= ~SSEL;
323 		splx(s);
324 		goto retry;
325 	}
326 	u.u_procp->p_flag &= ~SSEL;
327 	if (uap->tv) {
328 		lqsave = u.u_qsave;
329 		if (setjmp(&u.u_qsave)) {
330 			untimeout(unselect, (caddr_t)u.u_procp);
331 			u.u_error = EINTR;
332 			splx(s);
333 			goto done;
334 		}
335 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
336 	}
337 	sleep((caddr_t)&selwait, PZERO+1);
338 	if (uap->tv) {
339 		u.u_qsave = lqsave;
340 		untimeout(unselect, (caddr_t)u.u_procp);
341 	}
342 	splx(s);
343 	goto retry;
344 done:
345 #define	putbits(name, x) \
346 	if (uap->name) { \
347 		int error = copyout((caddr_t)obits[x], (caddr_t)uap->name, \
348 		    ni * sizeof(int)); \
349 		if (error) \
350 			u.u_error = error; \
351 	}
352 	if (u.u_error != EINTR) {
353 		putbits(in, 0);
354 		putbits(ou, 1);
355 		putbits(ex, 2);
356 #undef putbits
357 	}
358 }
359 
360 unselect(p)
361 	register struct proc *p;
362 {
363 	register int s = splhigh();
364 
365 	switch (p->p_stat) {
366 
367 	case SSLEEP:
368 		setrun(p);
369 		break;
370 
371 	case SSTOP:
372 		unsleep(p);
373 		break;
374 	}
375 	splx(s);
376 }
377 
378 selscan(ibits, obits, nfd)
379 	int (*ibits)[NI], (*obits)[NI];
380 {
381 	register int which, bits, i, j;
382 	int flag;
383 	struct file *fp;
384 	int n = 0;
385 
386 	for (which = 0; which < 3; which++) {
387 		switch (which) {
388 
389 		case 0:
390 			flag = FREAD; break;
391 
392 		case 1:
393 			flag = FWRITE; break;
394 
395 		case 2:
396 			flag = 0; break;
397 		}
398 		for (i = 0; i < nfd; i += NBI) {
399 			bits = ibits[which][i/NBI];
400 			while ((j = ffs(bits)) && i + --j < nfd) {
401 				bits &= ~(1 << j);
402 				fp = u.u_ofile[i + j];
403 				if (fp == NULL) {
404 					u.u_error = EBADF;
405 					break;
406 				}
407 				if ((*fp->f_ops->fo_select)(fp, flag)) {
408 					sbit(obits[which], i + j);
409 					n++;
410 				}
411 			}
412 		}
413 	}
414 	return (n);
415 }
416 
417 /*ARGSUSED*/
418 seltrue(dev, flag)
419 	dev_t dev;
420 	int flag;
421 {
422 
423 	return (1);
424 }
425 
426 selwakeup(p, coll)
427 	register struct proc *p;
428 	int coll;
429 {
430 
431 	if (coll) {
432 		nselcoll++;
433 		wakeup((caddr_t)&selwait);
434 	}
435 	if (p) {
436 		int s = splhigh();
437 		if (p->p_wchan == (caddr_t)&selwait) {
438 			if (p->p_stat == SSLEEP)
439 				setrun(p);
440 			else
441 				unsleep(p);
442 		} else if (p->p_flag & SSEL)
443 			p->p_flag &= ~SSEL;
444 		splx(s);
445 	}
446 }
447