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