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