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