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