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.10 (Berkeley) 05/09/89 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 */ 37 read() 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, u.u_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 91 readv() 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, u.u_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; 167 done: 168 if (uap->iovcnt > UIO_SMALLIOV) 169 FREE(iov, M_IOV); 170 RETURN (error); 171 } 172 173 /* 174 * Write system call 175 */ 176 write() 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, u.u_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 231 writev() 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, u.u_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; 308 done: 309 if (uap->iovcnt > UIO_SMALLIOV) 310 FREE(iov, M_IOV); 311 RETURN (error); 312 } 313 314 /* 315 * Ioctl system call 316 */ 317 ioctl() 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 418 int unselect(); 419 int nselcoll; 420 421 /* 422 * Select system call. 423 */ 424 select() 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 } 465 retry: 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; 500 done: 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 517 unselect(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 535 selscan(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*/ 576 seltrue(dev, flag) 577 dev_t dev; 578 int flag; 579 { 580 581 return (1); 582 } 583 584 selwakeup(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 } 605