4.3BSD release version
[unix-history] / usr / src / sys / kern / sys_generic.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
0880b18e 6 * @(#)sys_generic.c 7.1 (Berkeley) %G%
da7c5cc6 7 */
ffe28cfe 8
94368568
JB
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"
ffe28cfe
BJ
19
20/*
21 * Read system call.
22 */
23read()
24{
ffe28cfe
BJ
25 register struct a {
26 int fdes;
27 char *cbuf;
28 unsigned count;
b9429893 29 } *uap = (struct a *)u.u_ap;
32a43ee2
BJ
30 struct uio auio;
31 struct iovec aiov;
ffe28cfe 32
32a43ee2
BJ
33 aiov.iov_base = (caddr_t)uap->cbuf;
34 aiov.iov_len = uap->count;
35 auio.uio_iov = &aiov;
36 auio.uio_iovcnt = 1;
b9429893
BJ
37 rwuio(&auio, UIO_READ);
38}
39
40readv()
41{
42 register struct a {
43 int fdes;
44 struct iovec *iovp;
31286ce2 45 unsigned iovcnt;
b9429893
BJ
46 } *uap = (struct a *)u.u_ap;
47 struct uio auio;
48 struct iovec aiov[16]; /* XXX */
49
31286ce2 50 if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
b9429893
BJ
51 u.u_error = EINVAL;
52 return;
53 }
54 auio.uio_iov = aiov;
55 auio.uio_iovcnt = uap->iovcnt;
127f7d76 56 u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
31286ce2 57 uap->iovcnt * sizeof (struct iovec));
127f7d76 58 if (u.u_error)
b9429893 59 return;
b9429893 60 rwuio(&auio, UIO_READ);
ffe28cfe
BJ
61}
62
63/*
64 * Write system call
65 */
66write()
67{
ffe28cfe
BJ
68 register struct a {
69 int fdes;
70 char *cbuf;
31286ce2 71 unsigned count;
b9429893
BJ
72 } *uap = (struct a *)u.u_ap;
73 struct uio auio;
74 struct iovec aiov;
ffe28cfe 75
b9429893
BJ
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
83writev()
84{
85 register struct a {
86 int fdes;
87 struct iovec *iovp;
31286ce2 88 unsigned iovcnt;
b9429893
BJ
89 } *uap = (struct a *)u.u_ap;
90 struct uio auio;
91 struct iovec aiov[16]; /* XXX */
92
31286ce2 93 if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
ffe28cfe
BJ
94 u.u_error = EINVAL;
95 return;
96 }
b9429893
BJ
97 auio.uio_iov = aiov;
98 auio.uio_iovcnt = uap->iovcnt;
127f7d76 99 u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
31286ce2 100 uap->iovcnt * sizeof (struct iovec));
127f7d76 101 if (u.u_error)
b9429893 102 return;
b9429893
BJ
103 rwuio(&auio, UIO_WRITE);
104}
105
106rwuio(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;
b9429893
BJ
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) {
ffe28cfe
BJ
119 u.u_error = EBADF;
120 return;
121 }
b9429893 122 uio->uio_resid = 0;
c41770c0 123 uio->uio_segflg = UIO_USERSPACE;
b9429893
BJ
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 }
2a0114a8 135 iov++;
b9429893
BJ
136 }
137 count = uio->uio_resid;
88a7a62a 138 uio->uio_offset = fp->f_offset;
fe7f81f4
KM
139 if (setjmp(&u.u_qsave)) {
140 if (uio->uio_resid == count) {
9f49ba41 141 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
fe7f81f4
KM
142 u.u_error = EINTR;
143 else
144 u.u_eosys = RESTARTSYS;
145 }
b9429893 146 } else
88a7a62a
SL
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;
4147b3f6 150}
ffe28cfe
BJ
151
152/*
153 * Ioctl system call
ffe28cfe
BJ
154 */
155ioctl()
156{
157 register struct file *fp;
4b72e2f9 158 struct a {
ffe28cfe
BJ
159 int fdes;
160 int cmd;
161 caddr_t cmarg;
162 } *uap;
b9429893
BJ
163 register int com;
164 register u_int size;
4b72e2f9 165 char data[IOCPARM_MASK+1];
ffe28cfe
BJ
166
167 uap = (struct a *)u.u_ap;
21e0a474 168 GETF(fp, uap->fdes);
ffe28cfe
BJ
169 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
170 u.u_error = EBADF;
171 return;
172 }
4b72e2f9
SL
173 com = uap->cmd;
174
75a02b8d 175#if defined(vax) && defined(COMPAT)
4b72e2f9
SL
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) {
3650c37d 189 u.u_pofile[uap->fdes] |= UF_EXCLOSE;
ffe28cfe
BJ
190 return;
191 }
4b72e2f9 192 if (com == FIONCLEX) {
3650c37d 193 u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
ffe28cfe
BJ
194 return;
195 }
4b72e2f9
SL
196
197 /*
198 * Interpret high order word to find
199 * amount of data to be copied to/from the
200 * user's address space.
4b72e2f9
SL
201 */
202 size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
203 if (size > sizeof (data)) {
204 u.u_error = EFAULT;
ffe28cfe
BJ
205 return;
206 }
471f17ed
SL
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 */
4b72e2f9 220 bzero((caddr_t)data, size);
a76b60f6
SL
221 else if (com&IOC_VOID)
222 *(caddr_t *)data = uap->cmarg;
4b72e2f9 223
88a7a62a
SL
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;
4b72e2f9 237
88a7a62a
SL
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);
4b72e2f9
SL
243 /*
244 * Copy any data to user, size was
245 * already set and checked above.
246 */
127f7d76
SL
247 if (u.u_error == 0 && (com&IOC_OUT) && size)
248 u.u_error = copyout(data, uap->cmarg, (u_int)size);
ffe28cfe
BJ
249}
250
88a7a62a
SL
251int unselect();
252int nselcoll;
d441e5bc 253
ffe28cfe 254/*
88a7a62a 255 * Select system call.
ffe28cfe 256 */
88a7a62a
SL
257select()
258{
259 register struct uap {
260 int nd;
b8e71e77 261 fd_set *in, *ou, *ex;
88a7a62a
SL
262 struct timeval *tv;
263 } *uap = (struct uap *)u.u_ap;
b8e71e77 264 fd_set ibits[3], obits[3];
88a7a62a 265 struct timeval atv;
d441e5bc 266 int s, ncoll, ni;
88a7a62a
SL
267 label_t lqsave;
268
01b0e233
MK
269 bzero((caddr_t)ibits, sizeof(ibits));
270 bzero((caddr_t)obits, sizeof(obits));
88a7a62a
SL
271 if (uap->nd > NOFILE)
272 uap->nd = NOFILE; /* forgiving, if slightly wrong */
b8e71e77 273 ni = howmany(uap->nd, NFDBITS);
88a7a62a
SL
274
275#define getbits(name, x) \
276 if (uap->name) { \
b8e71e77 277 u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
01b0e233 278 (unsigned)(ni * sizeof(fd_mask))); \
88a7a62a
SL
279 if (u.u_error) \
280 goto done; \
d441e5bc 281 }
88a7a62a
SL
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 }
c4e1f1e5 296 s = splhigh(); timevaladd(&atv, &time); splx(s);
88a7a62a
SL
297 }
298retry:
299 ncoll = nselcoll;
300 u.u_procp->p_flag |= SSEL;
d441e5bc 301 u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
88a7a62a
SL
302 if (u.u_error || u.u_r.r_val1)
303 goto done;
c4e1f1e5 304 s = splhigh();
e394e134
SL
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)) {
88a7a62a
SL
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;
334done:
335#define putbits(name, x) \
336 if (uap->name) { \
b8e71e77 337 int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
01b0e233 338 (unsigned)(ni * sizeof(fd_mask))); \
88a7a62a
SL
339 if (error) \
340 u.u_error = error; \
341 }
87a3ba07 342 if (u.u_error == 0) {
79f403fc
MK
343 putbits(in, 0);
344 putbits(ou, 1);
345 putbits(ex, 2);
88a7a62a 346#undef putbits
79f403fc 347 }
88a7a62a
SL
348}
349
350unselect(p)
351 register struct proc *p;
352{
c4e1f1e5 353 register int s = splhigh();
88a7a62a
SL
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
d441e5bc 368selscan(ibits, obits, nfd)
b8e71e77 369 fd_set *ibits, *obits;
88a7a62a 370{
b8e71e77
MK
371 register int which, i, j;
372 register fd_mask bits;
88a7a62a
SL
373 int flag;
374 struct file *fp;
375 int n = 0;
376
377 for (which = 0; which < 3; which++) {
88a7a62a
SL
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 }
b8e71e77
MK
389 for (i = 0; i < nfd; i += NFDBITS) {
390 bits = ibits[which].fds_bits[i/NFDBITS];
d441e5bc
MK
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)) {
b8e71e77 399 FD_SET(i + j, &obits[which]);
d441e5bc
MK
400 n++;
401 }
88a7a62a
SL
402 }
403 }
404 }
405 return (n);
406}
407
ffe28cfe 408/*ARGSUSED*/
88a7a62a
SL
409seltrue(dev, flag)
410 dev_t dev;
411 int flag;
ffe28cfe
BJ
412{
413
88a7a62a 414 return (1);
ffe28cfe 415}
1edb1cf8 416
88a7a62a
SL
417selwakeup(p, coll)
418 register struct proc *p;
419 int coll;
1edb1cf8
BJ
420{
421
88a7a62a
SL
422 if (coll) {
423 nselcoll++;
424 wakeup((caddr_t)&selwait);
425 }
426 if (p) {
c4e1f1e5 427 int s = splhigh();
6bc3aba9
MK
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)
88a7a62a
SL
434 p->p_flag &= ~SSEL;
435 splx(s);
436 }
1edb1cf8 437}