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.19 (Berkeley) 06/21/90 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(p, uap, retval) 38 struct proc *p; 39 register struct args { 40 int fdes; 41 char *cbuf; 42 unsigned count; 43 } *uap; 44 int *retval; 45 { 46 register struct file *fp; 47 struct uio auio; 48 struct iovec aiov; 49 long cnt, error = 0; 50 #ifdef KTRACE 51 struct iovec ktriov; 52 #endif 53 54 if (((unsigned)uap->fdes) >= NOFILE || 55 (fp = u.u_ofile[uap->fdes]) == NULL || 56 (fp->f_flag & FREAD) == 0) 57 RETURN (EBADF); 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(p, KTR_GENIO)) 70 ktriov = aiov; 71 #endif 72 cnt = uap->count; 73 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) 74 if (auio.uio_resid != cnt && (error == ERESTART || 75 error == EINTR || error == EWOULDBLOCK)) 76 error = 0; 77 cnt -= auio.uio_resid; 78 #ifdef KTRACE 79 if (KTRPOINT(p, KTR_GENIO) && error == 0) 80 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt); 81 #endif 82 *retval = cnt; 83 RETURN (error); 84 } 85 86 /* 87 * Scatter read system call. 88 */ 89 readv(p, uap, retval) 90 struct proc *p; 91 register struct args { 92 int fdes; 93 struct iovec *iovp; 94 unsigned iovcnt; 95 } *uap; 96 int *retval; 97 { 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(p, KTR_GENIO)) { 143 unsigned 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 (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) 151 if (auio.uio_resid != cnt && (error == ERESTART || 152 error == EINTR || error == EWOULDBLOCK)) 153 error = 0; 154 cnt -= auio.uio_resid; 155 #ifdef KTRACE 156 if (ktriov != NULL) { 157 if (error == 0) 158 ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov, cnt); 159 FREE(ktriov, M_TEMP); 160 } 161 #endif 162 *retval = cnt; 163 done: 164 if (uap->iovcnt > UIO_SMALLIOV) 165 FREE(iov, M_IOV); 166 RETURN (error); 167 } 168 169 /* 170 * Write system call 171 */ 172 write(p, uap, retval) 173 struct proc *p; 174 register struct args { 175 int fdes; 176 char *cbuf; 177 unsigned count; 178 } *uap; 179 int *retval; 180 { 181 register struct file *fp; 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) >= NOFILE || 190 (fp = u.u_ofile[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 #ifdef KTRACE 201 /* 202 * if tracing, save a copy of iovec 203 */ 204 if (KTRPOINT(p, KTR_GENIO)) 205 ktriov = aiov; 206 #endif 207 cnt = uap->count; 208 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { 209 if (auio.uio_resid != cnt && (error == ERESTART || 210 error == EINTR || error == EWOULDBLOCK)) 211 error = 0; 212 if (error == EPIPE) 213 psignal(p, SIGPIPE); 214 } 215 cnt -= auio.uio_resid; 216 #ifdef KTRACE 217 if (KTRPOINT(p, KTR_GENIO) && error == 0) 218 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE, 219 &ktriov, cnt); 220 #endif 221 *retval = cnt; 222 RETURN (error); 223 } 224 225 /* 226 * Gather write system call 227 */ 228 writev(p, uap, retval) 229 struct proc *p; 230 register struct args { 231 int fdes; 232 struct iovec *iovp; 233 unsigned iovcnt; 234 } *uap; 235 int *retval; 236 { 237 register struct file *fp; 238 struct uio auio; 239 register struct iovec *iov; 240 struct iovec aiov[UIO_SMALLIOV]; 241 long i, cnt, error = 0; 242 #ifdef KTRACE 243 struct iovec *ktriov = NULL; 244 #endif 245 246 if (((unsigned)uap->fdes) >= NOFILE || 247 (fp = u.u_ofile[uap->fdes]) == NULL || 248 (fp->f_flag & FWRITE) == 0) 249 RETURN (EBADF); 250 if (uap->iovcnt > UIO_SMALLIOV) { 251 if (uap->iovcnt > UIO_MAXIOV) 252 RETURN (EINVAL); 253 MALLOC(iov, struct iovec *, 254 sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK); 255 } else 256 iov = aiov; 257 auio.uio_iov = iov; 258 auio.uio_iovcnt = uap->iovcnt; 259 auio.uio_rw = UIO_WRITE; 260 auio.uio_segflg = UIO_USERSPACE; 261 if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, 262 uap->iovcnt * sizeof (struct iovec))) 263 goto done; 264 auio.uio_resid = 0; 265 for (i = 0; i < uap->iovcnt; i++) { 266 if (iov->iov_len < 0) { 267 error = EINVAL; 268 goto done; 269 } 270 auio.uio_resid += iov->iov_len; 271 if (auio.uio_resid < 0) { 272 error = EINVAL; 273 goto done; 274 } 275 iov++; 276 } 277 #ifdef KTRACE 278 /* 279 * if tracing, save a copy of iovec 280 */ 281 if (KTRPOINT(p, KTR_GENIO)) { 282 unsigned iovlen = auio.uio_iovcnt * sizeof (struct iovec); 283 284 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 285 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); 286 } 287 #endif 288 cnt = auio.uio_resid; 289 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { 290 if (auio.uio_resid != cnt && (error == ERESTART || 291 error == EINTR || error == EWOULDBLOCK)) 292 error = 0; 293 if (error == EPIPE) 294 psignal(p, SIGPIPE); 295 } 296 cnt -= auio.uio_resid; 297 #ifdef KTRACE 298 if (ktriov != NULL) { 299 if (error == 0) 300 ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE, 301 ktriov, cnt); 302 FREE(ktriov, M_TEMP); 303 } 304 #endif 305 *retval = cnt; 306 done: 307 if (uap->iovcnt > UIO_SMALLIOV) 308 FREE(iov, M_IOV); 309 RETURN (error); 310 } 311 312 /* 313 * Ioctl system call 314 */ 315 /* ARGSUSED */ 316 ioctl(p, uap, retval) 317 struct proc *p; 318 register struct args { 319 int fdes; 320 int cmd; 321 caddr_t cmarg; 322 } *uap; 323 int *retval; 324 { 325 register struct file *fp; 326 register int com, error; 327 register u_int size; 328 caddr_t memp = 0; 329 #define STK_PARAMS 128 330 char stkbuf[STK_PARAMS]; 331 caddr_t data = stkbuf; 332 333 if ((unsigned)uap->fdes >= NOFILE || 334 (fp = u.u_ofile[uap->fdes]) == NULL) 335 RETURN (EBADF); 336 if ((fp->f_flag & (FREAD|FWRITE)) == 0) 337 RETURN (EBADF); 338 com = uap->cmd; 339 340 if (com == FIOCLEX) { 341 u.u_pofile[uap->fdes] |= UF_EXCLOSE; 342 RETURN (0); 343 } 344 if (com == FIONCLEX) { 345 u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; 346 RETURN (0); 347 } 348 349 /* 350 * Interpret high order word to find 351 * amount of data to be copied to/from the 352 * user's address space. 353 */ 354 size = IOCPARM_LEN(com); 355 if (size > IOCPARM_MAX) 356 RETURN (ENOTTY); 357 if (size > sizeof (stkbuf)) { 358 memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); 359 data = memp; 360 } 361 if (com&IOC_IN) { 362 if (size) { 363 error = copyin(uap->cmarg, data, (u_int)size); 364 if (error) { 365 if (memp) 366 free(memp, M_IOCTLOPS); 367 RETURN (error); 368 } 369 } else 370 *(caddr_t *)data = uap->cmarg; 371 } else if ((com&IOC_OUT) && size) 372 /* 373 * Zero the buffer so the user always 374 * gets back something deterministic. 375 */ 376 bzero(data, size); 377 else if (com&IOC_VOID) 378 *(caddr_t *)data = uap->cmarg; 379 380 switch (com) { 381 382 case FIONBIO: 383 error = fset(fp, FNDELAY, *(int *)data); 384 break; 385 386 case FIOASYNC: 387 error = fset(fp, FASYNC, *(int *)data); 388 break; 389 390 case FIOSETOWN: 391 error = fsetown(fp, *(int *)data); 392 break; 393 394 case FIOGETOWN: 395 error = fgetown(fp, (int *)data); 396 break; 397 default: 398 error = (*fp->f_ops->fo_ioctl)(fp, com, data); 399 /* 400 * Copy any data to user, size was 401 * already set and checked above. 402 */ 403 if (error == 0 && (com&IOC_OUT) && size) 404 error = copyout(data, uap->cmarg, (u_int)size); 405 break; 406 } 407 if (memp) 408 free(memp, M_IOCTLOPS); 409 RETURN (error); 410 } 411 412 int nselcoll; 413 414 /* 415 * Select system call. 416 */ 417 select(p, uap, retval) 418 register struct proc *p; 419 register struct args { 420 int nd; 421 fd_set *in, *ou, *ex; 422 struct timeval *tv; 423 } *uap; 424 int *retval; 425 { 426 fd_set ibits[3], obits[3]; 427 struct timeval atv; 428 int s, ncoll, ni, error = 0, timo; 429 430 bzero((caddr_t)ibits, sizeof(ibits)); 431 bzero((caddr_t)obits, sizeof(obits)); 432 if (uap->nd > NOFILE) 433 uap->nd = NOFILE; /* forgiving, if slightly wrong */ 434 ni = howmany(uap->nd, NFDBITS); 435 436 #define getbits(name, x) \ 437 if (uap->name) { \ 438 error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ 439 (unsigned)(ni * sizeof(fd_mask))); \ 440 if (error) \ 441 goto done; \ 442 } 443 getbits(in, 0); 444 getbits(ou, 1); 445 getbits(ex, 2); 446 #undef getbits 447 448 if (uap->tv) { 449 error = copyin((caddr_t)uap->tv, (caddr_t)&atv, 450 sizeof (atv)); 451 if (error) 452 goto done; 453 if (itimerfix(&atv)) { 454 error = EINVAL; 455 goto done; 456 } 457 s = splhigh(); timevaladd(&atv, &time); splx(s); 458 timo = hzto(&atv); 459 } else 460 timo = 0; 461 retry: 462 ncoll = nselcoll; 463 p->p_flag |= SSEL; 464 error = selscan(ibits, obits, uap->nd, retval); 465 if (error || *retval) 466 goto done; 467 s = splhigh(); 468 /* this should be timercmp(&time, &atv, >=) */ 469 if (uap->tv && (time.tv_sec > atv.tv_sec || 470 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { 471 splx(s); 472 goto done; 473 } 474 if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) { 475 splx(s); 476 goto retry; 477 } 478 p->p_flag &= ~SSEL; 479 error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); 480 splx(s); 481 if (error == 0) 482 goto retry; 483 done: 484 p->p_flag &= ~SSEL; 485 /* select is not restarted after signals... */ 486 if (error == ERESTART) 487 error = EINTR; 488 if (error == EWOULDBLOCK) 489 error = 0; 490 #define putbits(name, x) \ 491 if (uap->name) { \ 492 int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \ 493 (unsigned)(ni * sizeof(fd_mask))); \ 494 if (error2) \ 495 error = error2; \ 496 } 497 if (error == 0) { 498 putbits(in, 0); 499 putbits(ou, 1); 500 putbits(ex, 2); 501 #undef putbits 502 } 503 RETURN (error); 504 } 505 506 selscan(ibits, obits, nfd, retval) 507 fd_set *ibits, *obits; 508 int nfd, *retval; 509 { 510 register int which, i, j; 511 register fd_mask bits; 512 int flag; 513 struct file *fp; 514 int error = 0, n = 0; 515 516 for (which = 0; which < 3; which++) { 517 switch (which) { 518 519 case 0: 520 flag = FREAD; break; 521 522 case 1: 523 flag = FWRITE; break; 524 525 case 2: 526 flag = 0; break; 527 } 528 for (i = 0; i < nfd; i += NFDBITS) { 529 bits = ibits[which].fds_bits[i/NFDBITS]; 530 while ((j = ffs(bits)) && i + --j < nfd) { 531 bits &= ~(1 << j); 532 fp = u.u_ofile[i + j]; 533 if (fp == NULL) { 534 error = EBADF; 535 break; 536 } 537 if ((*fp->f_ops->fo_select)(fp, flag)) { 538 FD_SET(i + j, &obits[which]); 539 n++; 540 } 541 } 542 } 543 } 544 *retval = n; 545 return (error); 546 } 547 548 /*ARGSUSED*/ 549 seltrue(dev, flag) 550 dev_t dev; 551 int flag; 552 { 553 554 return (1); 555 } 556 557 selwakeup(p, coll) 558 register struct proc *p; 559 int coll; 560 { 561 562 if (coll) { 563 nselcoll++; 564 wakeup((caddr_t)&selwait); 565 } 566 if (p) { 567 int s = splhigh(); 568 if (p->p_wchan == (caddr_t)&selwait) { 569 if (p->p_stat == SSLEEP) 570 setrun(p); 571 else 572 unsleep(p); 573 } else if (p->p_flag & SSEL) 574 p->p_flag &= ~SSEL; 575 splx(s); 576 } 577 } 578