xref: /csrg-svn/sys/kern/sys_generic.c (revision 26277)
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.14 (Berkeley) 02/20/86
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 system call.
256  */
257 select()
258 {
259 	register struct uap  {
260 		int	nd;
261 		fd_set	*in, *ou, *ex;
262 		struct	timeval *tv;
263 	} *uap = (struct uap *)u.u_ap;
264 	fd_set ibits[3], obits[3];
265 	struct timeval atv;
266 	int s, ncoll, ni;
267 	label_t lqsave;
268 
269 	bzero((caddr_t)ibits, sizeof(ibits));
270 	bzero((caddr_t)obits, sizeof(obits));
271 	if (uap->nd > NOFILE)
272 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
273 	ni = howmany(uap->nd, NFDBITS);
274 
275 #define	getbits(name, x) \
276 	if (uap->name) { \
277 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
278 		    (unsigned)(ni * sizeof(fd_mask))); \
279 		if (u.u_error) \
280 			goto done; \
281 	}
282 	getbits(in, 0);
283 	getbits(ou, 1);
284 	getbits(ex, 2);
285 #undef	getbits
286 
287 	if (uap->tv) {
288 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
289 			sizeof (atv));
290 		if (u.u_error)
291 			goto done;
292 		if (itimerfix(&atv)) {
293 			u.u_error = EINVAL;
294 			goto done;
295 		}
296 		s = splhigh(); timevaladd(&atv, &time); splx(s);
297 	}
298 retry:
299 	ncoll = nselcoll;
300 	u.u_procp->p_flag |= SSEL;
301 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
302 	if (u.u_error || u.u_r.r_val1)
303 		goto done;
304 	s = splhigh();
305 	/* this should be timercmp(&time, &atv, >=) */
306 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
307 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
308 		splx(s);
309 		goto done;
310 	}
311 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
312 		u.u_procp->p_flag &= ~SSEL;
313 		splx(s);
314 		goto retry;
315 	}
316 	u.u_procp->p_flag &= ~SSEL;
317 	if (uap->tv) {
318 		lqsave = u.u_qsave;
319 		if (setjmp(&u.u_qsave)) {
320 			untimeout(unselect, (caddr_t)u.u_procp);
321 			u.u_error = EINTR;
322 			splx(s);
323 			goto done;
324 		}
325 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
326 	}
327 	sleep((caddr_t)&selwait, PZERO+1);
328 	if (uap->tv) {
329 		u.u_qsave = lqsave;
330 		untimeout(unselect, (caddr_t)u.u_procp);
331 	}
332 	splx(s);
333 	goto retry;
334 done:
335 #define	putbits(name, x) \
336 	if (uap->name) { \
337 		int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
338 		    (unsigned)(ni * sizeof(fd_mask))); \
339 		if (error) \
340 			u.u_error = error; \
341 	}
342 	if (u.u_error == 0) {
343 		putbits(in, 0);
344 		putbits(ou, 1);
345 		putbits(ex, 2);
346 #undef putbits
347 	}
348 }
349 
350 unselect(p)
351 	register struct proc *p;
352 {
353 	register int s = splhigh();
354 
355 	switch (p->p_stat) {
356 
357 	case SSLEEP:
358 		setrun(p);
359 		break;
360 
361 	case SSTOP:
362 		unsleep(p);
363 		break;
364 	}
365 	splx(s);
366 }
367 
368 selscan(ibits, obits, nfd)
369 	fd_set *ibits, *obits;
370 {
371 	register int which, i, j;
372 	register fd_mask bits;
373 	int flag;
374 	struct file *fp;
375 	int n = 0;
376 
377 	for (which = 0; which < 3; which++) {
378 		switch (which) {
379 
380 		case 0:
381 			flag = FREAD; break;
382 
383 		case 1:
384 			flag = FWRITE; break;
385 
386 		case 2:
387 			flag = 0; break;
388 		}
389 		for (i = 0; i < nfd; i += NFDBITS) {
390 			bits = ibits[which].fds_bits[i/NFDBITS];
391 			while ((j = ffs(bits)) && i + --j < nfd) {
392 				bits &= ~(1 << j);
393 				fp = u.u_ofile[i + j];
394 				if (fp == NULL) {
395 					u.u_error = EBADF;
396 					break;
397 				}
398 				if ((*fp->f_ops->fo_select)(fp, flag)) {
399 					FD_SET(i + j, &obits[which]);
400 					n++;
401 				}
402 			}
403 		}
404 	}
405 	return (n);
406 }
407 
408 /*ARGSUSED*/
409 seltrue(dev, flag)
410 	dev_t dev;
411 	int flag;
412 {
413 
414 	return (1);
415 }
416 
417 selwakeup(p, coll)
418 	register struct proc *p;
419 	int coll;
420 {
421 
422 	if (coll) {
423 		nselcoll++;
424 		wakeup((caddr_t)&selwait);
425 	}
426 	if (p) {
427 		int s = splhigh();
428 		if (p->p_wchan == (caddr_t)&selwait) {
429 			if (p->p_stat == SSLEEP)
430 				setrun(p);
431 			else
432 				unsleep(p);
433 		} else if (p->p_flag & SSEL)
434 			p->p_flag &= ~SSEL;
435 		splx(s);
436 	}
437 }
438