v_count => v_usecount; v_lastr is being used; v_mounton is gone;
[unix-history] / usr / src / sys / kern / sys_generic.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * @(#)sys_generic.c 7.12 (Berkeley) %G%
18 */
19
20#include "param.h"
21#include "systm.h"
22#include "syscontext.h"
23#include "ioctl.h"
24#include "file.h"
25#include "proc.h"
26#include "uio.h"
27#include "kernel.h"
28#include "stat.h"
29#include "malloc.h"
30#ifdef KTRACE
31#include "ktrace.h"
32#endif
33
34/*
35 * Read system call.
36 */
37read()
38{
39 register struct a {
40 int fdes;
41 char *cbuf;
42 unsigned count;
43 } *uap = (struct a *)u.u_ap;
44 register struct file *fp;
45 struct uio auio;
46 struct iovec aiov;
47 long cnt, error = 0;
48#ifdef KTRACE
49 struct iovec ktriov;
50#endif
51
52 if (((unsigned)uap->fdes) >= NOFILE ||
53 (fp = u.u_ofile[uap->fdes]) == NULL ||
54 (fp->f_flag & FREAD) == 0)
55 RETURN (EBADF);
56 if (uap->count < 0)
57 RETURN (EINVAL);
58 aiov.iov_base = (caddr_t)uap->cbuf;
59 aiov.iov_len = uap->count;
60 auio.uio_iov = &aiov;
61 auio.uio_iovcnt = 1;
62 auio.uio_resid = uap->count;
63 auio.uio_rw = UIO_READ;
64 auio.uio_segflg = UIO_USERSPACE;
65#ifdef KTRACE
66 /*
67 * if tracing, save a copy of iovec
68 */
69 if (KTRPOINT(u.u_procp, KTR_GENIO))
70 ktriov = aiov;
71#endif
72 cnt = uap->count;
73 if (setjmp(&u.u_qsave)) {
74 if (auio.uio_resid == cnt) {
75 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
76 error = EINTR;
77 else
78 u.u_eosys = RESTARTSYS;
79 }
80 } else
81 error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred);
82 cnt -= auio.uio_resid;
83#ifdef KTRACE
84 if (KTRPOINT(u.u_procp, KTR_GENIO))
85 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt);
86#endif
87 u.u_r.r_val1 = cnt;
88 RETURN (error);
89}
90
91readv()
92{
93 register struct a {
94 int fdes;
95 struct iovec *iovp;
96 unsigned iovcnt;
97 } *uap = (struct a *)u.u_ap;
98 register struct file *fp;
99 struct uio auio;
100 register struct iovec *iov;
101 struct iovec aiov[UIO_SMALLIOV];
102 long i, cnt, error = 0;
103#ifdef KTRACE
104 struct iovec *ktriov = NULL;
105#endif
106
107 if (((unsigned)uap->fdes) >= NOFILE ||
108 (fp = u.u_ofile[uap->fdes]) == NULL ||
109 (fp->f_flag & FREAD) == 0)
110 RETURN (EBADF);
111 if (uap->iovcnt > UIO_SMALLIOV) {
112 if (uap->iovcnt > UIO_MAXIOV)
113 RETURN (EINVAL);
114 MALLOC(iov, struct iovec *,
115 sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
116 } else
117 iov = aiov;
118 auio.uio_iov = iov;
119 auio.uio_iovcnt = uap->iovcnt;
120 auio.uio_rw = UIO_READ;
121 auio.uio_segflg = UIO_USERSPACE;
122 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
123 uap->iovcnt * sizeof (struct iovec)))
124 goto done;
125 auio.uio_resid = 0;
126 for (i = 0; i < uap->iovcnt; i++) {
127 if (iov->iov_len < 0) {
128 error = EINVAL;
129 goto done;
130 }
131 auio.uio_resid += iov->iov_len;
132 if (auio.uio_resid < 0) {
133 error = EINVAL;
134 goto done;
135 }
136 iov++;
137 }
138#ifdef KTRACE
139 /*
140 * if tracing, save a copy of iovec
141 */
142 if (KTRPOINT(u.u_procp, KTR_GENIO)) {
143 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
144
145 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
146 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
147 }
148#endif
149 cnt = auio.uio_resid;
150 if (setjmp(&u.u_qsave)) {
151 if (auio.uio_resid == cnt) {
152 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
153 error = EINTR;
154 else
155 u.u_eosys = RESTARTSYS;
156 }
157 } else
158 error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred);
159 cnt -= auio.uio_resid;
160#ifdef KTRACE
161 if (ktriov != NULL) {
162 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_READ, ktriov, cnt);
163 FREE(ktriov, M_TEMP);
164 }
165#endif
166 u.u_r.r_val1 = cnt;
167done:
168 if (uap->iovcnt > UIO_SMALLIOV)
169 FREE(iov, M_IOV);
170 RETURN (error);
171}
172
173/*
174 * Write system call
175 */
176write()
177{
178 register struct a {
179 int fdes;
180 char *cbuf;
181 unsigned count;
182 } *uap = (struct a *)u.u_ap;
183 register struct file *fp;
184 struct uio auio;
185 struct iovec aiov;
186 long cnt, error = 0;
187#ifdef KTRACE
188 struct iovec ktriov;
189#endif
190
191 if (((unsigned)uap->fdes) >= NOFILE ||
192 (fp = u.u_ofile[uap->fdes]) == NULL ||
193 (fp->f_flag & FWRITE) == 0)
194 RETURN (EBADF);
195 if (uap->count < 0)
196 RETURN (EINVAL);
197 aiov.iov_base = (caddr_t)uap->cbuf;
198 aiov.iov_len = uap->count;
199 auio.uio_iov = &aiov;
200 auio.uio_iovcnt = 1;
201 auio.uio_resid = uap->count;
202 auio.uio_rw = UIO_WRITE;
203 auio.uio_segflg = UIO_USERSPACE;
204#ifdef KTRACE
205 /*
206 * if tracing, save a copy of iovec
207 */
208 if (KTRPOINT(u.u_procp, KTR_GENIO))
209 ktriov = aiov;
210#endif
211 cnt = uap->count;
212 if (setjmp(&u.u_qsave)) {
213 if (auio.uio_resid == cnt) {
214 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
215 error = EINTR;
216 else
217 u.u_eosys = RESTARTSYS;
218 }
219 } else
220 error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred);
221 cnt -= auio.uio_resid;
222#ifdef KTRACE
223 if (KTRPOINT(u.u_procp, KTR_GENIO))
224 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_WRITE,
225 &ktriov, cnt);
226#endif
227 u.u_r.r_val1 = cnt;
228 RETURN (error);
229}
230
231writev()
232{
233 register struct a {
234 int fdes;
235 struct iovec *iovp;
236 unsigned iovcnt;
237 } *uap = (struct a *)u.u_ap;
238 register struct file *fp;
239 struct uio auio;
240 register struct iovec *iov;
241 struct iovec aiov[UIO_SMALLIOV];
242 long i, cnt, error = 0;
243#ifdef KTRACE
244 struct iovec *ktriov = NULL;
245#endif
246
247 if (((unsigned)uap->fdes) >= NOFILE ||
248 (fp = u.u_ofile[uap->fdes]) == NULL ||
249 (fp->f_flag & FWRITE) == 0)
250 RETURN (EBADF);
251 if (uap->iovcnt > UIO_SMALLIOV) {
252 if (uap->iovcnt > UIO_MAXIOV)
253 RETURN (EINVAL);
254 MALLOC(iov, struct iovec *,
255 sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
256 } else
257 iov = aiov;
258 auio.uio_iov = iov;
259 auio.uio_iovcnt = uap->iovcnt;
260 auio.uio_rw = UIO_WRITE;
261 auio.uio_segflg = UIO_USERSPACE;
262 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
263 uap->iovcnt * sizeof (struct iovec)))
264 goto done;
265 auio.uio_resid = 0;
266 for (i = 0; i < uap->iovcnt; i++) {
267 if (iov->iov_len < 0) {
268 error = EINVAL;
269 goto done;
270 }
271 auio.uio_resid += iov->iov_len;
272 if (auio.uio_resid < 0) {
273 error = EINVAL;
274 goto done;
275 }
276 iov++;
277 }
278#ifdef KTRACE
279 /*
280 * if tracing, save a copy of iovec
281 */
282 if (KTRPOINT(u.u_procp, KTR_GENIO)) {
283 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
284
285 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
286 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
287 }
288#endif
289 cnt = auio.uio_resid;
290 if (setjmp(&u.u_qsave)) {
291 if (auio.uio_resid == cnt) {
292 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
293 error = EINTR;
294 else
295 u.u_eosys = RESTARTSYS;
296 }
297 } else
298 error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred);
299 cnt -= auio.uio_resid;
300#ifdef KTRACE
301 if (ktriov != NULL) {
302 ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_WRITE,
303 ktriov, cnt);
304 FREE(ktriov, M_TEMP);
305 }
306#endif
307 u.u_r.r_val1 = cnt;
308done:
309 if (uap->iovcnt > UIO_SMALLIOV)
310 FREE(iov, M_IOV);
311 RETURN (error);
312}
313
314/*
315 * Ioctl system call
316 */
317ioctl()
318{
319 register struct file *fp;
320 struct a {
321 int fdes;
322 int cmd;
323 caddr_t cmarg;
324 } *uap = (struct a *)u.u_ap;
325 register int com;
326 register u_int size;
327 caddr_t memp = 0;
328#define STK_PARAMS 128
329 char stkbuf[STK_PARAMS];
330 caddr_t data = stkbuf;
331
332 if ((unsigned)uap->fdes >= NOFILE ||
333 (fp = u.u_ofile[uap->fdes]) == NULL)
334 RETURN (EBADF);
335 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
336 u.u_error = EBADF;
337 return;
338 }
339 com = uap->cmd;
340
341 if (com == FIOCLEX) {
342 u.u_pofile[uap->fdes] |= UF_EXCLOSE;
343 return;
344 }
345 if (com == FIONCLEX) {
346 u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
347 return;
348 }
349
350 /*
351 * Interpret high order word to find
352 * amount of data to be copied to/from the
353 * user's address space.
354 */
355 size = IOCPARM_LEN(com);
356 if (size > IOCPARM_MAX) {
357 u.u_error = ENOTTY;
358 return;
359 }
360 if (size > sizeof (stkbuf)) {
361 memp = (caddr_t)malloc((u_long)IOCPARM_LEN(com), M_IOCTLOPS,
362 M_WAITOK);
363 data = memp;
364 }
365 if (com&IOC_IN) {
366 if (size) {
367 u.u_error = copyin(uap->cmarg, data, (u_int)size);
368 if (u.u_error) {
369 if (memp)
370 free(memp, M_IOCTLOPS);
371 return;
372 }
373 } else
374 *(caddr_t *)data = uap->cmarg;
375 } else if ((com&IOC_OUT) && size)
376 /*
377 * Zero the buffer so the user always
378 * gets back something deterministic.
379 */
380 bzero(data, size);
381 else if (com&IOC_VOID)
382 *(caddr_t *)data = uap->cmarg;
383
384 switch (com) {
385
386 case FIONBIO:
387 u.u_error = fset(fp, FNDELAY, *(int *)data);
388 break;
389
390 case FIOASYNC:
391 u.u_error = fset(fp, FASYNC, *(int *)data);
392 break;
393
394 case FIOSETOWN:
395 u.u_error = fsetown(fp, *(int *)data);
396 break;
397
398 case FIOGETOWN:
399 u.u_error = fgetown(fp, (int *)data);
400 break;
401 default:
402 if (setjmp(&u.u_qsave))
403 u.u_error = EINTR;
404 else
405 u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
406 /*
407 * Copy any data to user, size was
408 * already set and checked above.
409 */
410 if (u.u_error == 0 && (com&IOC_OUT) && size)
411 u.u_error = copyout(data, uap->cmarg, (u_int)size);
412 break;
413 }
414 if (memp)
415 free(memp, M_IOCTLOPS);
416}
417
418int unselect();
419int nselcoll;
420
421/*
422 * Select system call.
423 */
424select()
425{
426 register struct uap {
427 int nd;
428 fd_set *in, *ou, *ex;
429 struct timeval *tv;
430 } *uap = (struct uap *)u.u_ap;
431 fd_set ibits[3], obits[3];
432 struct timeval atv;
433 int s, ncoll, ni;
434 label_t lqsave;
435
436 bzero((caddr_t)ibits, sizeof(ibits));
437 bzero((caddr_t)obits, sizeof(obits));
438 if (uap->nd > NOFILE)
439 uap->nd = NOFILE; /* forgiving, if slightly wrong */
440 ni = howmany(uap->nd, NFDBITS);
441
442#define getbits(name, x) \
443 if (uap->name) { \
444 u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
445 (unsigned)(ni * sizeof(fd_mask))); \
446 if (u.u_error) \
447 goto done; \
448 }
449 getbits(in, 0);
450 getbits(ou, 1);
451 getbits(ex, 2);
452#undef getbits
453
454 if (uap->tv) {
455 u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
456 sizeof (atv));
457 if (u.u_error)
458 goto done;
459 if (itimerfix(&atv)) {
460 u.u_error = EINVAL;
461 goto done;
462 }
463 s = splhigh(); timevaladd(&atv, &time); splx(s);
464 }
465retry:
466 ncoll = nselcoll;
467 u.u_procp->p_flag |= SSEL;
468 u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
469 if (u.u_error || u.u_r.r_val1)
470 goto done;
471 s = splhigh();
472 /* this should be timercmp(&time, &atv, >=) */
473 if (uap->tv && (time.tv_sec > atv.tv_sec ||
474 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
475 splx(s);
476 goto done;
477 }
478 if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
479 splx(s);
480 goto retry;
481 }
482 u.u_procp->p_flag &= ~SSEL;
483 if (uap->tv) {
484 lqsave = u.u_qsave;
485 if (setjmp(&u.u_qsave)) {
486 untimeout(unselect, (caddr_t)u.u_procp);
487 u.u_error = EINTR;
488 splx(s);
489 goto done;
490 }
491 timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
492 }
493 sleep((caddr_t)&selwait, PZERO+1);
494 if (uap->tv) {
495 u.u_qsave = lqsave;
496 untimeout(unselect, (caddr_t)u.u_procp);
497 }
498 splx(s);
499 goto retry;
500done:
501 u.u_procp->p_flag &= ~SSEL;
502#define putbits(name, x) \
503 if (uap->name) { \
504 int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
505 (unsigned)(ni * sizeof(fd_mask))); \
506 if (error) \
507 u.u_error = error; \
508 }
509 if (u.u_error == 0) {
510 putbits(in, 0);
511 putbits(ou, 1);
512 putbits(ex, 2);
513#undef putbits
514 }
515}
516
517unselect(p)
518 register struct proc *p;
519{
520 register int s = splhigh();
521
522 switch (p->p_stat) {
523
524 case SSLEEP:
525 setrun(p);
526 break;
527
528 case SSTOP:
529 unsleep(p);
530 break;
531 }
532 splx(s);
533}
534
535selscan(ibits, obits, nfd)
536 fd_set *ibits, *obits;
537{
538 register int which, i, j;
539 register fd_mask bits;
540 int flag;
541 struct file *fp;
542 int n = 0;
543
544 for (which = 0; which < 3; which++) {
545 switch (which) {
546
547 case 0:
548 flag = FREAD; break;
549
550 case 1:
551 flag = FWRITE; break;
552
553 case 2:
554 flag = 0; break;
555 }
556 for (i = 0; i < nfd; i += NFDBITS) {
557 bits = ibits[which].fds_bits[i/NFDBITS];
558 while ((j = ffs(bits)) && i + --j < nfd) {
559 bits &= ~(1 << j);
560 fp = u.u_ofile[i + j];
561 if (fp == NULL) {
562 u.u_error = EBADF;
563 break;
564 }
565 if ((*fp->f_ops->fo_select)(fp, flag)) {
566 FD_SET(i + j, &obits[which]);
567 n++;
568 }
569 }
570 }
571 }
572 return (n);
573}
574
575/*ARGSUSED*/
576seltrue(dev, flag)
577 dev_t dev;
578 int flag;
579{
580
581 return (1);
582}
583
584selwakeup(p, coll)
585 register struct proc *p;
586 int coll;
587{
588
589 if (coll) {
590 nselcoll++;
591 wakeup((caddr_t)&selwait);
592 }
593 if (p) {
594 int s = splhigh();
595 if (p->p_wchan == (caddr_t)&selwait) {
596 if (p->p_stat == SSLEEP)
597 setrun(p);
598 else
599 unsleep(p);
600 } else if (p->p_flag & SSEL)
601 p->p_flag &= ~SSEL;
602 splx(s);
603 }
604}