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