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