|
|
1.1 ! root 1: #include "sys/param.h" ! 2: #include "sys/user.h" ! 3: #include "sys/buf.h" ! 4: #include "sys/stream.h" ! 5: #include "sys/inode.h" ! 6: #include "sys/filio.h" ! 7: #include "sys/ttyio.h" ! 8: #include "sys/conf.h" ! 9: #include "sys/proc.h" ! 10: #include "sys/file.h" ! 11: ! 12: extern struct queue queue[]; ! 13: ! 14: #define STIPRI 28 ! 15: #define STOPRI 29 ! 16: ! 17: extern struct stdata streams[]; ! 18: extern int streamcnt; ! 19: ! 20: struct stdata *stenter(); ! 21: int strput(), stwsrv(), nulldev(), nilput(); ! 22: long nilopen(); ! 23: ! 24: struct qinit strdata = { strput, NULL, nilopen, nulldev, 512, 256 }; ! 25: struct qinit stwdata = { nulldev, stwsrv, nilopen, nulldev, 0, 0}; ! 26: struct qinit nilw = { nilput, NULL, nilopen, nulldev, 1, 0 }; ! 27: struct streamtab nilinfo = { &nilw, &nilw }; ! 28: ! 29: /* ! 30: * open a stream device ! 31: * returns the inode, ! 32: * which may be different from ip, ! 33: * in which event ip has been put. ! 34: * return NULL on error, ! 35: * in which event ip has also been put. ! 36: */ ! 37: struct inode * ! 38: stopen(qinfo, dev, flag, ip) ! 39: struct streamtab *qinfo; ! 40: dev_t dev; ! 41: struct inode *ip; ! 42: { ! 43: register struct queue *qp; ! 44: register struct stdata *sp; ! 45: register struct inode *nip; ! 46: register s; ! 47: ! 48: if (sp = ip->i_sptr) { /* already streaming? */ ! 49: if (sp->flag & EXCL && u.u_uid!=0 ! 50: && (sp->pgrp==0 || sp->pgrp != u.u_procp->p_pgrp)) { ! 51: u.u_error = ENXIO; ! 52: iput(ip); ! 53: return(NULL); ! 54: } ! 55: if (stenter(ip)==NULL) { ! 56: iput(ip); ! 57: return(NULL); ! 58: } ! 59: while (sp->flag&STWOPEN) { ! 60: if (tsleep((caddr_t)sp, STOPRI, 0)!=TS_OK) { ! 61: stexit(ip); ! 62: u.u_error = ENXIO; ! 63: iput(ip); ! 64: return(NULL); ! 65: } ! 66: } ! 67: if (sp->flag&HUNGUP) { ! 68: flushq(RD(sp->wrq), 1); ! 69: stexit(ip); ! 70: u.u_error = ENXIO; ! 71: iput(ip); ! 72: return(NULL); ! 73: } ! 74: for (qp = sp->wrq; qp->next && (qp->next->flag&QREADR)==0; qp = qp->next) { ! 75: /* device-cloning; qopen s.b. struct inode * */ ! 76: nip = (struct inode *) ! 77: (*qp->next->qinfo->qopen)(RD(qp->next), dev); ! 78: if (nip == NULL) { /* open failed */ ! 79: stexit(ip); ! 80: u.u_error = ENXIO; ! 81: iput(ip); ! 82: return(NULL); ! 83: } ! 84: if ((long)nip != 1) { /* changed inode, so stop now */ ! 85: stexit(ip); ! 86: iput(ip); ! 87: return(nip); ! 88: } ! 89: } ! 90: stexit(ip); ! 91: return(ip); ! 92: } else { /* new stream */ ! 93: register struct stdata *esp = &streams[streamcnt]; ! 94: register struct queue *nq; ! 95: ! 96: for (sp = streams; sp < esp; sp++) ! 97: if (sp->wrq==NULL) ! 98: break; ! 99: if (sp >= esp) { ! 100: printf("out of streams\n"); ! 101: u.u_error = ENFILE; ! 102: iput(ip); ! 103: return(NULL); ! 104: } ! 105: if ((qp = allocq()) == NULL) { ! 106: printf("Out of queues in stopen\n"); ! 107: u.u_error = ENFILE; ! 108: iput(ip); ! 109: return(NULL); ! 110: } ! 111: sp->wrq = WR(qp); ! 112: sp->pgrp = 0; ! 113: sp->inode = ip; ! 114: sp->flag = 0; ! 115: sp->iocblk = NULL; ! 116: sp->count = 1; ! 117: qp->ptr = (caddr_t)sp; ! 118: WR(qp)->ptr = (caddr_t)sp; ! 119: qp->qinfo = &strdata; ! 120: WR(qp)->qinfo = &stwdata; ! 121: qp->flag |= QBIGB; ! 122: WR(qp)->flag |= QDELIM; ! 123: ip->i_sptr = sp; ! 124: s = spl6(); ! 125: if (qattach(qinfo, qp, dev) == 0) { ! 126: sp->flag |= HUNGUP; ! 127: splx(s); ! 128: stexit(ip); ! 129: u.u_error = ENXIO; ! 130: iput(ip); ! 131: return(NULL); ! 132: } ! 133: nq = RD(WR(qp)->next); ! 134: sp->flag |= STWOPEN; ! 135: nip = (struct inode *)(*nq->qinfo->qopen)(nq, dev); ! 136: sp->flag &= ~STWOPEN; ! 137: splx(s); ! 138: wakeup((caddr_t)sp); ! 139: if (nip == NULL) { ! 140: qdetach(nq, 0); ! 141: sp->flag |= HUNGUP; ! 142: stexit(ip); ! 143: u.u_error = ENXIO; ! 144: iput(ip); ! 145: return(NULL); ! 146: } ! 147: if ((long)nip != 1) { ! 148: stexit(ip); ! 149: iput(ip); ! 150: return(nip); ! 151: } ! 152: stexit(ip); ! 153: return(ip); ! 154: } ! 155: } ! 156: ! 157: /* ! 158: * Shut down a stream ! 159: * -- pop all line disciplines ! 160: * -- shut down the driver ! 161: */ ! 162: stclose(ip, sleepOK) ! 163: struct inode *ip; ! 164: { ! 165: register struct stdata *stp; ! 166: register struct queue *qp; ! 167: register s; ! 168: register struct block *bp; ! 169: ! 170: s = spl6(); ! 171: if ((stp = ip->i_sptr) == NULL) { ! 172: splx(s); ! 173: return; ! 174: } ! 175: forceclose(stp, FREAD|FWRITE); ! 176: if (stp->count != 0) { ! 177: printf("count is %d in stclose, stream %x\n", stp->count, stp); ! 178: splx(s); ! 179: return; ! 180: } ! 181: ip->i_sptr = NULL; ! 182: splx(s); ! 183: qp = stp->wrq; ! 184: while (qp->next) { ! 185: register i; ! 186: /* detect cross-connects, and seal off other end */ ! 187: if (qp->next->flag & QREADR) { ! 188: putctl(qp->next, M_HANGUP); ! 189: if (qattach(&nilinfo, qp->next, (dev_t)-1) == 0) ! 190: panic("close/qattach"); ! 191: WR(qp->next)->next = NULL; ! 192: break; ! 193: } ! 194: if (sleepOK && (stp->flag&HUNGUP)==0) ! 195: for (i=0; qp->next->count!=0 && i<60; i++) ! 196: tsleep((caddr_t)qp, STIPRI, 1); ! 197: qdetach(RD(qp->next), 1); ! 198: } ! 199: flushq(qp, 1); ! 200: while (bp = getq(RD(qp))) { ! 201: if (bp->type == M_PASS) ! 202: closef(((struct kpassfd *)bp->rptr)->f.fp); ! 203: freeb(bp); ! 204: } ! 205: stp->wrq = NULL; ! 206: RD(qp)->flag = 0; ! 207: qp->flag = 0; ! 208: } ! 209: ! 210: /* ! 211: * Read a stream ! 212: */ ! 213: stread(ip) ! 214: struct inode *ip; ! 215: { ! 216: register struct stdata *stq; ! 217: register struct block *bp; ! 218: register n; ! 219: register s, nc = 0; ! 220: ! 221: if ((stq = stenter(ip)) == NULL) { ! 222: u.u_error = 0; /* return EOF not error */ ! 223: return; ! 224: } ! 225: /* ! 226: * Read is complete when: ! 227: * Q is empty and some data has been read and next Q might not generate ! 228: * delimiters, or ! 229: * There is data on Q and count has been satisfied, or ! 230: * A delimiter is taken from the Q, or ! 231: * There was an error. ! 232: */ ! 233: for (;;) { ! 234: s = spl6(); ! 235: if ((bp = getq(RD(stq->wrq))) == NULL) { ! 236: if ((nc && (OTHERQ(stq->wrq->next)->flag&QDELIM)==0) ! 237: || stq->flag&HUNGUP) { ! 238: splx(s); ! 239: stexit(ip); ! 240: return; ! 241: } ! 242: stq->flag |= RSLEEP; ! 243: n = tsleep((caddr_t)RD(stq->wrq), STIPRI, 0); ! 244: splx(s); ! 245: if (n == TS_SIG) { ! 246: stexit(ip); ! 247: longjmp(u.u_qsav); ! 248: } ! 249: continue; ! 250: } ! 251: splx(s); ! 252: switch (bp->type) { ! 253: ! 254: case M_DATA: ! 255: n = min(u.u_count, bp->wptr - bp->rptr); ! 256: if (n) ! 257: iomove(bp->rptr, n, B_READ); ! 258: bp->rptr += n; ! 259: nc += n; ! 260: if (bp->rptr >= bp->wptr) { ! 261: n = bp->class; ! 262: freeb(bp); ! 263: if (n&S_DELIM) ! 264: goto out; ! 265: } else { ! 266: putbq(RD(stq->wrq), bp); ! 267: if (u.u_count == 0) ! 268: goto out; ! 269: } ! 270: if (u.u_error) ! 271: goto out; ! 272: continue; ! 273: ! 274: case M_PASS: ! 275: putbq(RD(stq->wrq), bp); ! 276: goto out; ! 277: ! 278: default: ! 279: printf("stread: msg %d\n", bp->type); ! 280: freeb(bp); ! 281: continue; ! 282: } ! 283: } ! 284: out: ! 285: stexit(ip); ! 286: } ! 287: ! 288: /* ! 289: * Internal version of stread: transfer to given address. ! 290: * Always returns; >= 0 is # bytes transferred, -1 is error. ! 291: * Always reads a whole record; excess discarded. ! 292: */ ! 293: istread(ip, addr, count, flag) /* flag is for timeout debugging */ ! 294: struct inode *ip; ! 295: caddr_t addr; ! 296: { ! 297: register struct stdata *stq; ! 298: register struct block *bp; ! 299: register n; ! 300: register s, nc = 0; ! 301: ! 302: if ((stq = stenter(ip)) == NULL) ! 303: return(-1); ! 304: for (;;) { ! 305: s = spl6(); ! 306: if ((bp = getq(RD(stq->wrq))) == NULL) { ! 307: if ((nc && (OTHERQ(stq->wrq->next)->flag&QDELIM)==0) ! 308: || stq->flag&HUNGUP) { ! 309: splx(s); ! 310: stexit(ip); ! 311: return(nc); ! 312: } ! 313: stq->flag |= RSLEEP; ! 314: n = tsleep((caddr_t)RD(stq->wrq), PRIBIO, 30); ! 315: splx(s); ! 316: if (n == TS_TIME) { ! 317: if(flag) ! 318: printf("nb timeout nc %d count %d addr #%x\n", ! 319: nc, count, addr); ! 320: stexit(ip); ! 321: return(-1); ! 322: } ! 323: continue; ! 324: } ! 325: splx(s); ! 326: switch (bp->type) { ! 327: ! 328: case M_DATA: ! 329: n = min(count, bp->wptr - bp->rptr); ! 330: if (n) ! 331: bcopy(bp->rptr, addr, n); ! 332: addr += n; ! 333: nc += n; ! 334: count -= n; ! 335: n = bp->class; ! 336: freeb(bp); ! 337: if (n&S_DELIM) { ! 338: stexit(ip); ! 339: return(nc); ! 340: } ! 341: continue; ! 342: ! 343: case M_PASS: ! 344: putbq(RD(stq->wrq), bp); ! 345: stexit(ip); ! 346: return(nc); ! 347: ! 348: default: ! 349: printf("istread: msg %d\n", bp->type); ! 350: freeb(bp); ! 351: continue; ! 352: } ! 353: } ! 354: } ! 355: ! 356: /* ! 357: * Stream input put proc ! 358: * -- collect signals and ioctl acks ! 359: -- put data and delims on data queue ! 360: -- see hangups and seal off channel ! 361: */ ! 362: strput(q, bp) ! 363: register struct queue *q; ! 364: register struct block *bp; ! 365: { ! 366: register struct stdata *stp = (struct stdata *)q->ptr; ! 367: ! 368: switch (bp->type) { ! 369: ! 370: case M_DATA: ! 371: default: ! 372: putq(q, bp); ! 373: if (stp->flag & RSLEEP) { ! 374: stp->flag &= ~RSLEEP; ! 375: wakeup((caddr_t)q); ! 376: } ! 377: break; ! 378: ! 379: case M_HANGUP: ! 380: stp->flag |= HUNGUP; ! 381: freeb(bp); ! 382: if (stp->pgrp) ! 383: gsignal(stp->pgrp, SIGHUP); ! 384: forceclose(stp, FWRITE); ! 385: wakeup((caddr_t)q); /* the readers */ ! 386: wakeup((caddr_t)WR(q)); /* the writers */ ! 387: wakeup((caddr_t)stp); /* the ioctllers */ ! 388: break; ! 389: ! 390: case M_SIGNAL: ! 391: gsignal(stp->pgrp, *bp->rptr); ! 392: case M_FLUSH: ! 393: flushq(q, 0); /* flush races with select */ ! 394: case M_BREAK: ! 395: case M_YDEL: ! 396: case M_NDEL: ! 397: case M_CTL: ! 398: freeb(bp); ! 399: return; ! 400: ! 401: case M_IOCACK: ! 402: case M_IOCNAK: ! 403: case M_IOCWAIT: ! 404: if(stp->iocblk && stp->iocblk->type==M_IOCWAIT) { ! 405: freeb(stp->iocblk); ! 406: stp->iocblk = NULL; ! 407: } ! 408: if ((stp->flag&IOCWAIT)==0 || stp->iocblk) { ! 409: freeb(bp); ! 410: return; ! 411: } ! 412: stp->iocblk = bp; ! 413: wakeup((caddr_t)stp); ! 414: return; ! 415: ! 416: case M_IOCTL: ! 417: bp->type = M_IOCNAK; ! 418: bp->wptr = bp->rptr; /* data means error */ ! 419: qreply(q, bp); ! 420: return; ! 421: } ! 422: if (stp->rsel) { ! 423: selwakeup(stp->rsel, stp->flag&RSEL); ! 424: stp->flag &= ~RSEL; ! 425: stp->rsel = NULL; ! 426: } ! 427: } ! 428: ! 429: ! 430: /* ! 431: * Write on a stream ! 432: */ ! 433: stwrite(ip) ! 434: struct inode *ip; ! 435: { ! 436: register struct stdata *stq; ! 437: register struct block *bp; ! 438: register n; ! 439: register s; ! 440: ! 441: if ((stq = stenter(ip)) == NULL) ! 442: return; ! 443: do { ! 444: s = spl6(); ! 445: while ((stq->flag&HUNGUP)==0 && stq->wrq->next->flag&QFULL) { ! 446: stq->flag |= WSLEEP; ! 447: if (tsleep((caddr_t)stq->wrq, STOPRI, 0)==TS_SIG) { ! 448: splx(s); ! 449: stexit(ip); ! 450: longjmp(u.u_qsav); ! 451: } ! 452: } ! 453: splx(s); ! 454: if (stq->flag & HUNGUP) { ! 455: psignal(u.u_procp, SIGPIPE); ! 456: u.u_error = ENXIO; ! 457: break; ! 458: } ! 459: n = QBSIZE; ! 460: if (u.u_count >= 512 && stq->wrq->next->flag&QBIGB) ! 461: n = 1024; ! 462: if ((bp = allocb(n)) == NULL) { ! 463: printf("stwrite can't alloc\n"); ! 464: continue; /* temp */ ! 465: } ! 466: bp->type = M_DATA; ! 467: n = min(bp->lim - bp->wptr, u.u_count); ! 468: iomove(bp->wptr, n, B_WRITE); ! 469: if (u.u_error) { ! 470: freeb(bp); ! 471: break; ! 472: } ! 473: bp->wptr += n; ! 474: if (u.u_count==0) ! 475: bp->class |= S_DELIM; ! 476: (*stq->wrq->next->qinfo->putp)(stq->wrq->next, bp); ! 477: } while (u.u_count); ! 478: stexit(ip); ! 479: } ! 480: ! 481: /* ! 482: * Stream output -- internal version ! 483: * return -1 on error, 0 OK ! 484: */ ! 485: istwrite(ip, addr, count) ! 486: register count; ! 487: struct inode *ip; ! 488: caddr_t addr; ! 489: { ! 490: register struct stdata *stq; ! 491: register struct block *bp; ! 492: register n; ! 493: register s; ! 494: ! 495: if ((stq = stenter(ip)) == NULL) ! 496: return(-1); ! 497: do { ! 498: s = spl6(); ! 499: while (stq->wrq->next->flag&QFULL && (stq->flag&HUNGUP)==0) { ! 500: stq->flag |= WSLEEP; ! 501: if (tsleep((caddr_t)stq->wrq, PRIBIO, 30)==TS_TIME) { ! 502: splx(s); ! 503: stexit(ip); ! 504: return(-1); ! 505: } ! 506: } ! 507: splx(s); ! 508: if (stq->flag & HUNGUP) { ! 509: stexit(ip); ! 510: return(-1); ! 511: } ! 512: n = QBSIZE; ! 513: if (count >= 512 && stq->wrq->next->flag&QBIGB) ! 514: n = 1024; ! 515: if ((bp = allocb(n)) == NULL) { ! 516: printf("istwrite can't alloc\n"); ! 517: continue; /* temp */ ! 518: } ! 519: bp->type = M_DATA; ! 520: n = min(bp->lim - bp->wptr, count); ! 521: bcopy(addr, bp->wptr, n); ! 522: bp->wptr += n; ! 523: addr += n; ! 524: count -= n; ! 525: if (count==0) ! 526: bp->class |= S_DELIM; ! 527: (*stq->wrq->next->qinfo->putp)(stq->wrq->next, bp); ! 528: } while (count); ! 529: stexit(ip); ! 530: return(0); ! 531: } ! 532: ! 533: /* ! 534: * Stream output server (when full queue empties) ! 535: */ ! 536: stwsrv(q) ! 537: register struct queue *q; ! 538: { ! 539: register struct stdata *stq = (struct stdata *)q->ptr; ! 540: ! 541: if (stq->flag & WSLEEP) { ! 542: stq->flag &= ~WSLEEP; ! 543: wakeup((caddr_t)q); ! 544: } ! 545: if (stq->wsel) { ! 546: selwakeup(stq->wsel, stq->flag&WSEL); ! 547: stq->flag &= ~WSEL; ! 548: stq->wsel = NULL; ! 549: } ! 550: } ! 551: ! 552: /* ! 553: * ioctl for streams ! 554: */ ! 555: stioctl(ip, cmd, arg) ! 556: struct inode *ip; ! 557: caddr_t arg; ! 558: { ! 559: register struct stdata *stq; ! 560: register struct block *bp; ! 561: register struct queue *q; ! 562: register s; ! 563: int fmt, nld, ioctime; ! 564: struct insld ld; ! 565: extern nstreamtab; ! 566: ! 567: if ((stq = stenter(ip)) == NULL) ! 568: return; ! 569: switch(cmd) { ! 570: ! 571: case FIONREAD: ! 572: nld = 0; ! 573: bp = RD(stq->wrq)->first; ! 574: if (bp && bp->type==M_DATA) ! 575: nld = bp->wptr - bp->rptr; ! 576: if (copyout((caddr_t)&nld, arg, sizeof(nld))) ! 577: u.u_error = EFAULT; ! 578: goto out; ! 579: ! 580: case TIOCGPGRP: ! 581: if (copyout ((caddr_t) &stq->pgrp, arg, sizeof (stq->pgrp))) ! 582: u.u_error = EFAULT; ! 583: goto out; ! 584: ! 585: case TIOCSPGRP: ! 586: if (arg==0) { ! 587: stq->pgrp = u.u_procp->p_pgrp = u.u_procp->p_pid; ! 588: u.u_ttydev = ip->i_dev; ! 589: u.u_ttyino = ip->i_number; ! 590: } else if (copyin(arg, (caddr_t)&stq->pgrp, sizeof(stq->pgrp))) ! 591: u.u_error = EFAULT; ! 592: goto out; ! 593: ! 594: case TIOCEXCL: ! 595: stq->flag |= EXCL; ! 596: goto out; ! 597: ! 598: case TIOCNXCL: ! 599: stq->flag &= ~EXCL; ! 600: goto out; ! 601: ! 602: case TIOCFLUSH: ! 603: if (stq->flag & HUNGUP) { ! 604: u.u_error = ENXIO; ! 605: goto out; ! 606: } ! 607: flushq(RD(stq->wrq), 0); ! 608: putctl(stq->wrq->next, M_FLUSH); ! 609: goto out; ! 610: ! 611: case TIOCSBRK: ! 612: if (stq->flag & HUNGUP) { ! 613: u.u_error = ENXIO; ! 614: goto out; ! 615: } ! 616: putctl(stq->wrq->next, M_BREAK); ! 617: goto out; ! 618: ! 619: case FIOSNDFD: ! 620: if (stq->flag & HUNGUP) { ! 621: u.u_error = ENXIO; ! 622: goto out; ! 623: } ! 624: usndfile(stq, arg); ! 625: goto out; ! 626: ! 627: case FIORCVFD: ! 628: urcvfile(stq, arg); ! 629: goto out; ! 630: ! 631: case FIOPUSHLD: /* add a line discipline */ ! 632: case FIOINSLD: ! 633: if (stq->flag & HUNGUP) { ! 634: u.u_error = ENXIO; ! 635: goto out; ! 636: } ! 637: if (copyin(arg, (caddr_t)&ld, sizeof(ld))) { ! 638: u.u_error = EFAULT; ! 639: goto out; ! 640: } ! 641: if(ld.ld<0 || ld.ld>=nstreamtab || streamtab[ld.ld]==NULL){ ! 642: u.u_error = EINVAL; ! 643: goto out; ! 644: } ! 645: if (cmd==FIOPUSHLD) ! 646: ld.level = 0; ! 647: q = stq->wrq; ! 648: while (ld.level > 0) { ! 649: if (q->next == NULL) { ! 650: u.u_error = EINVAL; ! 651: goto out; ! 652: } ! 653: q = q->next; ! 654: ld.level--; ! 655: } ! 656: s = spl6(); ! 657: if (qattach(streamtab[ld.ld], RD(q), ip->i_un.i_rdev)) { ! 658: long nip = ! 659: (*q->next->qinfo->qopen)(RD(q->next), ip->i_un.i_rdev); ! 660: if (nip==0) { ! 661: qdetach(RD(q->next), 0); ! 662: u.u_error = ENXIO; ! 663: } else if (nip!=1) ! 664: panic("pushld qopen returns inode"); ! 665: splx(s); ! 666: goto out; ! 667: } ! 668: splx(s); ! 669: u.u_error = ENOMEM; ! 670: goto out; ! 671: ! 672: case FIOPOPLD: ! 673: if (stq->flag & HUNGUP) { ! 674: u.u_error = ENXIO; ! 675: goto out; ! 676: } ! 677: nld = 0; ! 678: if (arg) { ! 679: if (copyin(arg, (caddr_t)&nld, sizeof(nld))) { ! 680: u.u_error = EFAULT; ! 681: goto out; ! 682: } ! 683: } ! 684: q = stq->wrq; ! 685: while (nld > 0) { ! 686: if (q == NULL || q->next==NULL ! 687: || q->next->flag&QREADR) { ! 688: u.u_error = EINVAL; ! 689: goto out; ! 690: } ! 691: q = q->next; ! 692: nld--; ! 693: } ! 694: if (q->next->next && (q->next->flag&QREADR) == 0) { /* LD exists? */ ! 695: qdetach(RD(q->next), 1); ! 696: goto out; ! 697: } ! 698: u.u_error = EINVAL; ! 699: goto out; ! 700: ! 701: case FIOLOOKLD: ! 702: nld = 0; ! 703: if (arg) { ! 704: if (copyin(arg, (caddr_t)&nld, sizeof(nld))) { ! 705: u.u_error = EFAULT; ! 706: goto out; ! 707: } ! 708: } ! 709: q = stq->wrq; ! 710: for (;;) { ! 711: if (q == NULL || q->next==NULL || q->next->next == NULL ! 712: || q->next->flag&QREADR) { ! 713: u.u_error = EINVAL; ! 714: goto out; ! 715: } ! 716: if (--nld < 0) ! 717: break; ! 718: q = q->next; ! 719: } ! 720: for (fmt=0; fmt<nstreamtab; fmt++) ! 721: if(streamtab[fmt] && streamtab[fmt]->wrinit==q->next->qinfo) ! 722: break; ! 723: if (fmt >= nstreamtab) { ! 724: u.u_error = ENXIO; ! 725: goto out; ! 726: } ! 727: if (arg) { ! 728: if (copyout((caddr_t)&fmt, arg, sizeof(arg))) { ! 729: u.u_error = EINVAL; ! 730: goto out; ! 731: } ! 732: } ! 733: u.u_r.r_val1 = fmt; ! 734: goto out; ! 735: ! 736: } ! 737: if (stq->flag & HUNGUP) { ! 738: u.u_error = ENXIO; ! 739: goto out; ! 740: } ! 741: if ((bp = allocb(STIOCHDR+(arg?STIOCSIZE:0))) == NULL) { ! 742: u.u_error = ENOSPC; ! 743: goto out; ! 744: } ! 745: ((struct stioctl *)bp->wptr)->com[0] = cmd; ! 746: ((struct stioctl *)bp->wptr)->com[1] = cmd>>8; ! 747: ((struct stioctl *)bp->wptr)->com[2] = cmd>>16; ! 748: ((struct stioctl *)bp->wptr)->com[3] = cmd>>24; ! 749: bp->wptr += STIOCHDR; ! 750: if (arg) { ! 751: if (copyin(arg, (caddr_t)stiodata(bp), STIOCSIZE)) { ! 752: u.u_error = EFAULT; ! 753: freeb(bp); ! 754: goto out; ! 755: } ! 756: bp->wptr += STIOCSIZE; ! 757: } ! 758: bp->type = M_IOCTL; ! 759: s = spl6(); ! 760: while (stq->flag & IOCWAIT) { ! 761: if (tsleep((caddr_t)stq,STIPRI,0)!=TS_OK || stq->flag&HUNGUP) { ! 762: splx(s); ! 763: u.u_error = EIO; ! 764: freeb(bp); ! 765: goto out; ! 766: } ! 767: } ! 768: stq->flag |= IOCWAIT; ! 769: splx(s); ! 770: (*stq->wrq->next->qinfo->putp)(stq->wrq->next, bp); ! 771: /* wait for acknowledgment */ ! 772: s = spl6(); ! 773: ioctime = 15; ! 774: while ((bp = stq->iocblk) == NULL || bp->type == M_IOCWAIT) { ! 775: if (bp) ! 776: ioctime = 0; ! 777: if (tsleep((caddr_t)stq, STIPRI, ioctime) != TS_OK ! 778: || stq->flag & HUNGUP) { ! 779: if (stq->iocblk) ! 780: freeb(stq->iocblk); ! 781: stq->iocblk = NULL; ! 782: u.u_error = EIO; ! 783: stq->flag &= ~IOCWAIT; ! 784: splx(s); ! 785: goto out; ! 786: } ! 787: } ! 788: stq->iocblk = NULL; ! 789: stq->flag &= ~IOCWAIT; ! 790: splx(s); ! 791: switch (bp->type) { ! 792: case M_IOCACK: ! 793: if (bp->wptr > bp->rptr) { ! 794: bp->rptr = (u_char *)((struct stioctl *)(bp->rptr))->data; ! 795: if (copyout((caddr_t)bp->rptr, arg, bp->wptr-bp->rptr)) ! 796: u.u_error = EFAULT; ! 797: } ! 798: freeb(bp); ! 799: break; ! 800: ! 801: case M_IOCNAK: ! 802: if (bp->rptr < bp->wptr) ! 803: u.u_error = *bp->rptr; ! 804: freeb(bp); ! 805: if (u.u_error==0) ! 806: u.u_error = ENOTTY; ! 807: break; ! 808: ! 809: default: ! 810: printf("strange stuff on ioctl ack cell %x\n", stq); ! 811: break; ! 812: } ! 813: wakeup((caddr_t)stq); ! 814: out: ! 815: stexit(ip); ! 816: } ! 817: ! 818: /* ! 819: * attach a stream device or line discipline ! 820: * qp is a read queue; the new queue goes in so its next ! 821: * read ptr is the argument, and the write queue corresponding ! 822: * to the argument points to this queue. ! 823: */ ! 824: qattach(qinfo, qp, dev) ! 825: register struct streamtab *qinfo; ! 826: register struct queue *qp; ! 827: dev_t dev; ! 828: { ! 829: register struct queue *nq; ! 830: register s; ! 831: extern putq(); ! 832: ! 833: if ((nq = allocq()) == NULL) { ! 834: printf("allocq NULL\n"); ! 835: return(0); ! 836: } ! 837: s = spl6(); ! 838: nq->next = qp; ! 839: WR(nq)->next = WR(qp)->next; ! 840: if (WR(qp)->next) ! 841: OTHERQ(WR(qp)->next)->next = nq; ! 842: WR(qp)->next = WR(nq); ! 843: nq->qinfo = qinfo->rdinit; ! 844: WR(nq)->qinfo = qinfo->wrinit; ! 845: nq->flag |= QREADR|QWANTR; ! 846: WR(nq)->flag |= QWANTR; ! 847: nq->ptr = NULL; ! 848: WR(nq)->ptr = NULL; ! 849: splx(s); ! 850: return(1); ! 851: } ! 852: ! 853: /* ! 854: * Detach a stream device or line discipline. ! 855: * Call its close routine, then evict it. ! 856: * The close routine is required to return. ! 857: * The flag (if 1) indicates that the close routine ! 858: * should be called (real shutdown) otherwise this ! 859: * is merely a failed open. ! 860: */ ! 861: qdetach(qp, flag) ! 862: register struct queue *qp; ! 863: { ! 864: register s = spl6(); ! 865: register i; ! 866: ! 867: if (flag) { ! 868: queuerun(); ! 869: (*qp->qinfo->qclose)(qp); ! 870: for (i=0; (qp->flag|WR(qp)->flag)&QENAB; i++) { ! 871: queuerun(); ! 872: if (i>10) ! 873: panic("queue won't give up"); ! 874: } ! 875: flushq(qp, 1); ! 876: flushq(WR(qp), 1); ! 877: } ! 878: if (WR(qp)->next) ! 879: backq(qp)->next = qp->next; ! 880: if (qp->next) ! 881: backq(WR(qp))->next = WR(qp)->next; ! 882: qp->flag = 0; ! 883: WR(qp)->flag = 0; ! 884: splx(s); ! 885: } ! 886: ! 887: /* ! 888: * Count entries/exits to the routines that process streams. ! 889: * If a stream receives a HANGUP, it should be shut down ! 890: * forcibly, and this makes sure that it does not happen while ! 891: * pointers are still floating about. ! 892: */ ! 893: struct stdata * ! 894: stenter(ip) ! 895: register struct inode *ip; ! 896: { ! 897: register struct stdata *stp; ! 898: register s = spl6(); ! 899: ! 900: if ((stp = ip->i_sptr) == NULL) { ! 901: u.u_error = ENXIO; ! 902: splx(s); ! 903: return(NULL); ! 904: } ! 905: stp->count++; ! 906: splx(s); ! 907: return(stp); ! 908: } ! 909: ! 910: stexit(ip) ! 911: register struct inode *ip; ! 912: { ! 913: register struct stdata *stp = ip->i_sptr; ! 914: ! 915: if(stp == 0) { ! 916: printf("null stp in stexit\n"); ! 917: return; ! 918: } /* can't happen, of course */ ! 919: if (--stp->count==0 && stp->flag&HUNGUP && RD(stp->wrq)->count==0) ! 920: stclose(ip, 1); ! 921: } ! 922: ! 923: /* ! 924: * create a message transferring a file to process on the other end of a stream ! 925: */ ! 926: usndfile(stq, arg) ! 927: register struct stdata *stq; ! 928: caddr_t arg; ! 929: { ! 930: int f; ! 931: register struct file *fp; ! 932: ! 933: if (copyin(arg, (caddr_t)&f, sizeof(f))) { ! 934: u.u_error = EFAULT; ! 935: return; ! 936: } ! 937: if ((fp = getf(f)) == NULL) { ! 938: u.u_error = EBADF; ! 939: return; ! 940: } ! 941: sndfile(stq->wrq, fp); ! 942: } ! 943: ! 944: sndfile(q, fp) ! 945: register struct queue *q; ! 946: register struct file *fp; ! 947: { ! 948: register struct block *bp; ! 949: ! 950: for (;;) { ! 951: if (q==NULL) { ! 952: u.u_error = ENXIO; ! 953: return(0); ! 954: } ! 955: if (q->qinfo == &strdata) ! 956: break; ! 957: /* follow pt's here */ ! 958: q = q->next; ! 959: } ! 960: if (q->flag&QFULL) { ! 961: u.u_error = ENOMEM; ! 962: return(0); ! 963: } ! 964: if ((bp = allocb(sizeof(struct kpassfd))) == NULL) { ! 965: u.u_error = ENOMEM; ! 966: return(0); ! 967: } ! 968: bp->type = M_PASS; ! 969: ((struct kpassfd *)bp->rptr)->uid = u.u_uid; ! 970: ((struct kpassfd *)bp->rptr)->gid = u.u_gid; ! 971: ((struct kpassfd *)bp->rptr)->nice = u.u_procp->p_nice-NZERO; ! 972: bcopy(u.u_logname,((struct kpassfd *)bp->rptr)->logname, ! 973: sizeof(u.u_logname)); ! 974: ((struct kpassfd *)bp->rptr)->f.fp = fp; ! 975: bp->wptr += sizeof(struct kpassfd); ! 976: fp->f_count++; ! 977: strput(q, bp); ! 978: return(1); ! 979: } ! 980: ! 981: urcvfile(stq, arg) ! 982: register struct stdata *stq; ! 983: caddr_t arg; ! 984: { ! 985: register struct block *bp; ! 986: register i; ! 987: register struct file *fp; ! 988: register struct kpassfd *kp; ! 989: struct passfd pfd; ! 990: ! 991: while ((bp = getq(RD(stq->wrq))) == NULL) { ! 992: if (stq->flag&HUNGUP) { ! 993: u.u_error = ENXIO; ! 994: return; ! 995: } ! 996: stq->flag |= RSLEEP; ! 997: if (tsleep((caddr_t)RD(stq->wrq), STIPRI, 0)==TS_SIG) { ! 998: stexit(stq->inode); ! 999: longjmp(u.u_qsav); ! 1000: } ! 1001: } ! 1002: if (bp->type != M_PASS) { ! 1003: putbq(RD(stq->wrq), bp); ! 1004: u.u_error = EIO; ! 1005: return; ! 1006: } ! 1007: kp = (struct kpassfd *)bp->rptr; ! 1008: fp = kp->f.fp; ! 1009: i = ufalloc(); ! 1010: if (i < 0) { ! 1011: closef(fp); ! 1012: freeb(bp); ! 1013: return; ! 1014: } ! 1015: u.u_ofile[i] = fp; ! 1016: pfd.fd = i; ! 1017: pfd.uid = kp->uid; ! 1018: pfd.gid = kp->gid; ! 1019: bcopy(kp->logname, pfd.logname, sizeof(kp->logname)); ! 1020: if (copyout((caddr_t)&pfd, arg, sizeof(struct passfd))) ! 1021: u.u_error = EFAULT; ! 1022: freeb(bp); ! 1023: } ! 1024: ! 1025: stselect(stp, rw, anyyet) ! 1026: register struct stdata *stp; ! 1027: { ! 1028: register ret = 0; ! 1029: register s = spl6(); ! 1030: extern int selwait; ! 1031: ! 1032: if (rw==FWRITE) { ! 1033: if ((stp->wrq->next->flag&QFULL) == 0) ! 1034: ret = 1; ! 1035: else if (!anyyet) { ! 1036: if (stp->wsel && stp->wsel->p_wchan==(caddr_t)&selwait) ! 1037: stp->flag |= WSEL; ! 1038: else ! 1039: stp->wsel = u.u_procp; ! 1040: } ! 1041: } else { ! 1042: if (streadable(RD(stp->wrq)) || stp->flag&HUNGUP) ! 1043: ret = 1; ! 1044: else if (!anyyet) { ! 1045: if (stp->rsel && stp->rsel->p_wchan==(caddr_t)&selwait) ! 1046: stp->flag |= RSEL; ! 1047: else ! 1048: stp->rsel = u.u_procp; ! 1049: } ! 1050: } ! 1051: splx(s); ! 1052: return(ret); ! 1053: } ! 1054: ! 1055: /* ! 1056: * poison the flags in the file table leading to this stream ! 1057: */ ! 1058: forceclose(sptr, whichflags) ! 1059: register struct stdata *sptr; ! 1060: { ! 1061: register struct file *fp; ! 1062: ! 1063: for (fp = &file[0]; fp < fileNFILE; fp++) { ! 1064: if (fp->f_count==0) ! 1065: continue; ! 1066: if (fp->f_inode==NULL || fp->f_inode->i_sptr != sptr) ! 1067: continue; ! 1068: fp->f_flag &= ~whichflags; ! 1069: fp->f_flag |= FHUNGUP; ! 1070: } ! 1071: } ! 1072: ! 1073: /* ! 1074: * check if a queue is likely to be readable ! 1075: */ ! 1076: streadable(q) ! 1077: register struct queue *q; ! 1078: { ! 1079: register struct block *bp; ! 1080: ! 1081: if (q->first == 0) ! 1082: return(0); ! 1083: if ((backq(q)->flag&QDELIM) == 0 || q->count >= q->qinfo->lolimit) ! 1084: return(1); ! 1085: for (bp = q->first; bp; bp = bp->next) ! 1086: if (bp->class&S_DELIM || bp->type==M_PASS) ! 1087: return(1); ! 1088: return(0); ! 1089: } ! 1090: ! 1091: ! 1092: /* ! 1093: * Black hole to seal off closed pipes, and serve as a stub device. ! 1094: */ ! 1095: long ! 1096: nilopen(q, dev) ! 1097: struct queue *q; ! 1098: dev_t dev; ! 1099: { ! 1100: return(1); ! 1101: } ! 1102: ! 1103: nilput(q, bp) ! 1104: struct queue *q; ! 1105: struct block *bp; ! 1106: { ! 1107: if (bp->type == M_IOCTL) { ! 1108: bp->type = M_IOCNAK; ! 1109: bp->wptr = bp->rptr; ! 1110: qreply(q, bp); ! 1111: return; ! 1112: } ! 1113: freeb(bp); ! 1114: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.