|
|
1.1 root 1: /* mx2.c 4.2 11/9/80 */
2:
3: #include "../h/param.h"
4: #include "../h/systm.h"
5: #include "../h/dir.h"
6: #include "../h/user.h"
7: #include "../h/proc.h"
8: #include "../h/tty.h"
9: #include "../h/inode.h"
10: #include "../h/mx.h"
11: #include "../h/file.h"
12: #include "../h/conf.h"
13: #include "../h/buf.h"
14: /*
15: * multiplexor driver
16: */
17: struct chan chans[NCHANS];
18: struct group *groups[NGROUPS];
19: int mpxline;
20:
21: short cmask[16] ={
22: 01, 02, 04,
23: 010, 020, 040,
24: 0100, 0200, 0400,
25: 01000, 02000, 04000,
26: 010000, 020000, 040000, 0100000
27: };
28:
29: #define IOMOVE iomove
30: #define FPEND &file[NFILE]
31: struct chan *xcp(),*addch(),*nextcp();
32:
33: #define HIQ 100
34: #define LOQ 20
35: #define FP ((struct file *)cp)
36:
37: char mcdebugs[NDEBUGS];
38:
39: struct group *
40: getmpx(dev)
41: dev_t dev;
42: {
43: register d;
44:
45: d = minor(dev);
46: if (d >= NGROUPS) {
47: u.u_error = ENXIO;
48: return(NULL);
49: }
50: return(groups[d]);
51: }
52:
53:
54: /*ARGSUSED*/
55: mxopen(dev, flag)
56: {
57: register struct group *gp;
58: register struct file *fp;
59: register struct chan *cp;
60: int msg;
61:
62: if ((gp=getmpx(dev)) == NULL) {
63: return;
64: }
65: if (!(gp->g_state&INUSE)) {
66: u.u_error = ENXIO;
67: return;
68: }
69: fp = u.u_ofile[u.u_r.r_val1];
70: if (fp->f_inode != gp->g_inode) {
71: u.u_error = ENXIO;
72: return;
73: }
74: if ((cp=addch(gp->g_inode,0)) == NULL) {
75: u.u_error = ENXIO;
76: return;
77: }
78:
79: cp->c_flags = XGRP;
80: cp->c_ottyp = cp->c_ttyp = (struct tty *)cp;
81: cp->c_line = cp->c_oline = mpxline;
82:
83: fp->f_flag |= FMPY;
84: fp->f_flag |= FREAD+FWRITE;
85: fp->f_un.f_chan = cp;
86:
87: if (gp->g_inode == mpxip) {
88: plock(mpxip);
89: mpxname(cp);
90: msg = M_OPEN;
91: } else
92: msg = M_WATCH;
93:
94: scontrol(cp, msg+(cp->c_index<<8), u.u_uid);
95: sleep((caddr_t)cp,TTIPRI);
96: if (cp->c_flags&NMBUF)
97: prele(mpxip);
98: if (cp->c_flags & WCLOSE) {
99: chdrain(cp);
100: chfree(cp);
101: u.u_error = ENXIO;
102: return;
103: }
104: cp->c_fy = fp;
105: cp->c_pgrp = u.u_procp->p_pgrp;
106: }
107:
108:
109: char mxnmbuf[NMSIZE];
110: int nmsize;
111:
112: mpxname(cp)
113: register struct chan *cp;
114: {
115: register char *np;
116: register c;
117:
118: np = mxnmbuf;
119: u.u_dirp = (caddr_t)u.u_arg[0];
120:
121: while (np < &mxnmbuf[NMSIZE]) {
122: c = uchar();
123: if (c <= 0)
124: break;
125: *np++ = c;
126: }
127: *np++ = '\0';
128: nmsize = np - mxnmbuf;
129:
130: cp->c_flags |= NMBUF;
131: }
132:
133:
134: mxclose(dev, flag, cp)
135: dev_t dev;
136: register struct chan *cp;
137: {
138: register struct group *gp;
139: register struct inode *ip;
140: register struct file *fp;
141: int i, fmp;
142:
143: fmp = flag&FMP;
144: if ((gp=getmpx(dev)) == NULL)
145: return;
146:
147: ip = gp->g_inode;
148: if (ip==NULL || (ip->i_mode&IFMT)!=IFMPC) {
149: return;
150: }
151:
152: /*
153: * close a channel
154: */
155: if (cp!=NULL && fmp && fmp!=FMP) {
156: for(fp=file; fp< FPEND; fp++)
157: if(fp->f_count && fp->f_flag&FMP && fp->f_un.f_chan==cp){
158: return;
159: }
160: chdrain(cp);
161: if ((cp->c_flags&WCLOSE)==0) {
162: scontrol(cp, M_CLOSE, 0);
163: cp->c_flags |= WCLOSE;
164: } else {
165: chfree(cp);
166: }
167: goto out;
168: }
169:
170:
171: for(fp=file; fp < FPEND; fp++) {
172: if (fp->f_count && (fp->f_flag&FMP)==FMP && fp->f_inode==ip)
173: return;
174: }
175:
176: if (ip == mpxip) {
177: mpxip = NULL;
178: prele(ip);
179: }
180:
181: for(i=0;i<NINDEX;i++)
182: (void) detach(gp->g_chans[i]);
183:
184: out:
185: if (ip->i_count == 1) {
186: groups[minor(dev)] = NULL;
187: plock(ip);
188: zero((caddr_t)gp, sizeof (struct group));
189: ip->i_mode = IFREG + 0666;
190: ip->i_un.i_rdev = 0;
191: ip->i_flag |= IUPD|ICHG;
192: iput(ip);
193: }
194: }
195:
196: zero(s, cc)
197: register char *s;
198: register cc;
199: {
200: while (cc--)
201: *s++ = 0;
202: }
203:
204: char m_eot[] ={ M_EOT, 0, 0, 0};
205:
206: /*
207: * Mxread + mxwrite are entered from cdevsw
208: * for all read/write calls. Operations on
209: * an mpx file are handled here.
210: * Calls are made through linesw to handle actual
211: * data movement.
212: */
213: mxread(dev)
214: {
215: register struct group *gp;
216: register struct chan *cp;
217: register esc;
218: struct rh h;
219: caddr_t base;
220: unsigned count;
221: int s, xfr, more, fmp;
222:
223: if ((gp=getmpx(dev))==NULL || (FP=getf(u.u_arg[0]))==NULL) {
224: u.u_error = ENXIO;
225: return;
226: }
227:
228: fmp = FP->f_flag & FMP;
229: if (fmp != FMP) {
230: if (u.u_count == 0)
231: return;
232: msread(fmp, FP->f_un.f_chan);
233: return;
234: }
235:
236: if ((int)u.u_base & 1) {
237: u.u_error = ENXIO;
238: return;
239: }
240:
241: s = spl6();
242: if (u.u_count == 0)
243: {
244: if (gp->g_datq == 0)
245: u.u_error = ENXIO;
246: splx(s);
247: return;
248: }
249: while (gp->g_datq == 0) {
250: sleep((caddr_t)&gp->g_datq, TTIPRI);
251: }
252: splx(s);
253:
254: while (gp->g_datq && u.u_count >= CNTLSIZ + 2) {
255: esc = 0;
256: cp = nextcp(gp);
257: if (cp==NULL) {
258: continue;
259: }
260: h.index = cpx(cp);
261: if (count = cp->c_ctlx.c_cc) {
262: count += CNTLSIZ;
263: if (cp->c_flags&NMBUF)
264: count += nmsize;
265: if (count > u.u_count) {
266: (void) sdata(cp);
267: return;
268: }
269: esc++;
270: }
271: base = u.u_base;
272: count = u.u_count;
273: u.u_base += sizeof h;
274: u.u_count -= sizeof h;
275: xfr = u.u_count;
276: if (esc) {
277: more = mcread(cp);
278: } else {
279: more = (*linesw[cp->c_line].l_read)(cp->c_ttyp);
280: }
281: if (more > 0)
282: (void) sdata(cp);
283: if (more < 0)
284: scontrol(cp, M_CLOSE, 0);
285: (void) spl0();
286: if (xfr == u.u_count) {
287: esc++;
288: IOMOVE((caddr_t)m_eot, sizeof m_eot, B_READ);
289: }
290: xfr -= u.u_count;
291: if (esc) {
292: h.count = 0;
293: h.ccount = xfr;
294: } else {
295: h.count = xfr;
296: h.ccount = 0;
297: mxrstrt(cp, &cp->cx.datq, BLOCK|ALT);
298: }
299: if (u.u_count && (xfr&1)) {
300: u.u_base++;
301: u.u_count--;
302: }
303: (void) copyout((caddr_t)&h, base, sizeof h);
304:
305: }
306: }
307:
308:
309: mxwrite(dev)
310: {
311: register struct chan *cp;
312: struct wh h;
313: struct group *gp;
314: int ucount, esc, fmp, burpcount;
315: caddr_t ubase, hbase;
316:
317: if ((gp=getmpx(dev))==NULL || (FP=getf(u.u_arg[0]))==NULL) {
318: return;
319: }
320: fmp = FP->f_flag & FMP;
321: if (fmp != FMP) {
322: mswrite(fmp, FP->f_un.f_chan);
323: return;
324: }
325:
326: burpcount = 0;
327: while (u.u_count >= sizeof h) {
328: hbase = u.u_base;
329: IOMOVE((caddr_t)&h, sizeof h, B_WRITE);
330: if (u.u_error)
331: return;
332: esc = 0;
333: if (h.count==0) {
334: esc++;
335: h.count = h.ccount;
336: }
337: cp = xcp(gp, h.index);
338: if (cp==NULL || cp->c_flags&ISGRP) {
339: u.u_error = ENXIO;
340: return;
341: }
342: ucount = u.u_count;
343: ubase = u.u_base;
344: u.u_count = h.count;
345: u.u_base = h.data;
346:
347: if (esc==0) {
348: struct tty *tp;
349: caddr_t waddr;
350: int line;
351:
352: if (cp->c_flags&PORT) {
353: line = cp->c_line;
354: tp = cp->c_ttyp;
355: } else {
356: line = cp->c_oline;
357: tp = cp->c_ottyp;
358: }
359: loop:
360: waddr = (caddr_t)(*linesw[line].l_write)(tp);
361: if (u.u_count) {
362: if (gp->g_state&ENAMSG) {
363: burpcount++;
364: cp->c_flags |= BLKMSG;
365: /*
366: scontrol(cp, M_BLK, u.u_count);
367: */
368: h.ccount = -1;
369: h.count = u.u_count;
370: h.data = u.u_base;
371: (void) copyout((caddr_t)&h, hbase, sizeof h);
372: } else {
373: if(waddr == 0) {
374: u.u_error = ENXIO;
375: return;
376: }
377: sleep(waddr, TTOPRI);
378: goto loop;
379: }
380: }
381: } else {
382: mxwcontrol(cp);
383: }
384: u.u_count = ucount;
385: u.u_base = ubase;
386: }
387: u.u_count = burpcount;
388: }
389:
390:
391:
392: /*
393: * Mcread and mcwrite move data on an mpx file.
394: * Transfer addr and length is controlled by mxread/mxwrite.
395: * Kernel-to-Kernel and other special transfers are not
396: * yet in.
397: */
398: mcread(cp)
399: register struct chan *cp;
400: {
401: register struct clist *q;
402: register char *np;
403:
404:
405: q = (cp->c_ctlx.c_cc) ? &cp->c_ctlx : &cp->cx.datq;
406: (void) mxmove(q, B_READ);
407:
408: if (cp->c_flags&NMBUF && q == &cp->c_ctlx) {
409: np = mxnmbuf;
410: while (nmsize--)
411: (void) passc(*np++);
412: cp->c_flags &= ~NMBUF;
413: prele(mpxip);
414: }
415: if (cp->c_flags&PORT)
416: return(cp->c_ctlx.c_cc + cp->c_ttyp->t_rawq.c_cc); else
417: return(cp->c_ctlx.c_cc + cp->cx.datq.c_cc);
418:
419: }
420:
421:
422: caddr_t
423: mcwrite(cp)
424: register struct chan *cp;
425: {
426: register struct clist *q;
427: int s;
428:
429: q = &cp->cy.datq;
430: while (u.u_count) {
431: s = spl6();
432: if (q->c_cc > HIQ || (cp->c_flags&EOTMARK)) {
433: cp->c_flags |= SIGBLK;
434: splx(s);
435: break;
436: }
437: splx(s);
438: (void) mxmove(q, B_WRITE);
439: }
440: wakeup((caddr_t)q);
441: return((caddr_t)q);
442: }
443:
444:
445: /*
446: * Msread and mswrite move bytes
447: * between user and non-multiplexed channel.
448: */
449: msread(fmp, cp)
450: register struct chan *cp;
451: {
452: register struct clist *q;
453: int s;
454:
455: q = (fmp&FMPX) ? &cp->cx.datq : &cp->cy.datq;
456: s = spl6();
457: while (q->c_cc == 0) {
458: if (cp->c_flags&WCLOSE) {
459: u.u_error = ENXIO;
460: goto out;
461: }
462: if (cp->c_flags & EOTMARK) {
463: cp->c_flags &= ~EOTMARK;
464: if(msgenab(cp))
465: scontrol(cp, M_UBLK, 0);
466: else {
467: wakeup((caddr_t)cp);
468: wakeup((caddr_t)q);
469: }
470: goto out;
471: }
472: sleep((caddr_t)q,TTIPRI);
473: }
474: if (cp->c_flags&WCLOSE) {
475: u.u_error = ENXIO;
476: goto out;
477: }
478: splx(s);
479: while (mxmove(q, B_READ) > 0)
480: ;
481: mxrstrt(cp, q, SIGBLK);
482: return;
483: out:
484: splx(s);
485: }
486:
487:
488: mswrite(fmp, cp)
489: register struct chan *cp;
490: {
491: register struct clist *q;
492: register int cc;
493:
494: q = (fmp&FMPX) ? &cp->cy.datq : &cp->cx.datq;
495: while (u.u_count) {
496: (void) spl6();
497: if (cp->c_flags&WCLOSE) {
498: gsignal(cp->c_pgrp, SIGPIPE);
499: (void) spl0();
500: return;
501: }
502: if (q->c_cc>= HIQ || cp->c_flags&FBLOCK) {
503: if (cp->c_flags&WCLOSE) {
504: gsignal(cp->c_pgrp, SIGPIPE);
505: (void) spl0();
506: return;
507: }
508: (void) sdata(cp);
509: cp->c_flags |= BLOCK;
510: sleep((caddr_t)q+1,TTOPRI);
511: (void) spl0();
512: continue;
513: }
514: (void) spl0();
515: cc = mxmove(q, B_WRITE);
516: if (cc < 0)
517: break;
518: }
519: if (fmp&FMPX) {
520: if (cp->c_flags&YGRP) (void) sdata(cp);
521: else wakeup((caddr_t)q);
522: } else {
523: if (cp->c_flags&XGRP) (void) sdata(cp);
524: else wakeup((caddr_t)q);
525: }
526: }
527:
528:
529: /*
530: * move chars between clist and user space.
531: */
532:
533: mxmove(q, dir)
534: register struct clist *q;
535: register dir;
536: {
537: register cc;
538: char cbuf[HIQ];
539:
540: cc = MIN(u.u_count, sizeof cbuf);
541: if (dir == B_READ)
542: cc = q_to_b(q, cbuf, cc);
543: if (cc <= 0)
544: return(cc);
545: IOMOVE((caddr_t)cbuf, (unsigned)cc, dir);
546: if (dir == B_WRITE)
547: cc = b_to_q(cbuf, cc, q);
548: return(cc);
549: }
550:
551:
552:
553: mxrstrt(cp, q, b)
554: register struct chan *cp;
555: register struct clist *q;
556: register b;
557: {
558: int s;
559:
560: s = spl6();
561: if (cp->c_flags&b && q->c_cc<LOQ) {
562: cp->c_flags &= ~b;
563: if (b&ALT)
564: wakeup((caddr_t)q+1); else
565: mcstart(cp, (caddr_t)q);
566: }
567: if (cp->c_flags&WFLUSH)
568: wakeup((caddr_t)q+2);
569: splx(s);
570: }
571:
572:
573:
574: /*
575: * called from driver start or xint routines
576: * to wakeup output sleeper.
577: */
578: mcstart(cp, q)
579: register struct chan *cp;
580: register caddr_t q;
581: {
582:
583: if (cp->c_flags&(BLKMSG)) {
584: cp->c_flags &= ~BLKMSG;
585: scontrol(cp, M_UBLK, 0);
586: } else
587: wakeup((caddr_t)q);
588: }
589:
590:
591: mxwcontrol(cp)
592: register struct chan *cp;
593: {
594: short cmd;
595: struct sgttyb vec;
596: int s;
597:
598: IOMOVE((caddr_t)&cmd, sizeof cmd, B_WRITE);
599: if (u.u_error)
600: return;
601: switch(cmd) {
602: /*
603: * not ready to queue this up yet.
604: */
605: case M_EOT:
606: s = spl6();
607: while (cp->c_flags & EOTMARK)
608: if(msgenab(cp)){
609: scontrol(cp, M_BLK, 0);
610: goto out;
611: } else
612: sleep((caddr_t)cp, TTOPRI);
613: cp->c_flags |= EOTMARK;
614: out:
615: wakeup((caddr_t)&cp->cy.datq);
616: splx(s);
617: break;
618: case M_IOCTL:
619: break;
620: case M_IOANS:
621: if (cp->c_flags&SIOCTL) {
622: IOMOVE((caddr_t)&vec, sizeof vec, B_WRITE);
623: (void) b_to_q((caddr_t)&vec, sizeof vec, &cp->c_ctly);
624: cp->c_flags &= ~SIOCTL;
625: wakeup((caddr_t)cp);
626: }
627: break;
628: case M_BLK:
629: cp->c_flags |= FBLOCK;
630: break;
631: case M_UBLK:
632: cp->c_flags &= ~FBLOCK;
633: chwake(cp);
634: break;
635: default:
636: u.u_error = ENXIO;
637: }
638: }
639:
640:
641:
642: /*ARGSUSED*/
643: mxioctl(dev, cmd, addr, flag)
644: caddr_t addr;
645: {
646: struct group *gp;
647: int fmp;
648: struct file *fp;
649: struct {
650: short c_ctl;
651: short c_cmd;
652: struct sgttyb c_vec;
653: } ctlbuf;
654:
655: if ((gp=getmpx(dev))==NULL || (fp=getf(u.u_arg[0]))==NULL) {
656: return;
657: }
658:
659: fmp = fp->f_flag & FMP;
660: if (fmp == FMP) {
661: switch(cmd) {
662:
663: case MXLSTN:
664: if (mpxip == NULL) {
665: mpxip = gp->g_inode;
666: } else {
667: u.u_error = ENXIO;
668: return;
669: }
670: break;
671:
672: case MXNBLK:
673: gp->g_state |= ENAMSG;
674: break;
675:
676: default:
677: u.u_error = ENXIO;
678: return;
679: }
680: } else {
681: ctlbuf.c_ctl = M_IOCTL;
682: ctlbuf.c_cmd = cmd;
683: (void) copyin(addr, (caddr_t)&ctlbuf.c_vec, sizeof (struct sgttyb));
684: sioctl(fp->f_un.f_chan, (char *)&ctlbuf, sizeof ctlbuf);
685: (void) copyout((caddr_t)&ctlbuf, addr, sizeof (struct sgttyb));
686: }
687: }
688:
689:
690: chdrain(cp)
691: register struct chan *cp;
692: {
693: register struct tty *tp;
694: int wflag;
695:
696: chwake(cp);
697:
698: wflag = (cp->c_flags&WCLOSE)==0;
699: tp = cp->c_ttyp;
700: if (tp == NULL) /* prob not required */
701: return;
702: if (cp->c_flags&PORT && tp->t_chan == cp) {
703: cp->c_ttyp = NULL;
704: tp->t_chan = NULL;
705: return;
706: }
707: if (wflag)
708: wflush(cp,&cp->cx.datq); else
709: flush(&cp->cx.datq);
710: if (!(cp->c_flags&YGRP)) {
711: flush(&cp->cy.datq);
712: }
713: }
714:
715: chwake(cp)
716: register struct chan *cp;
717: {
718: register char *p;
719:
720: wakeup((caddr_t)cp);
721: flush(&cp->c_ctlx);
722: p = (char *)&cp->cx.datq;
723: wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p);
724: p = (char *)&cp->cy.datq;
725: wakeup((caddr_t)p); wakeup((caddr_t)++p); wakeup((caddr_t)++p);
726: }
727:
728:
729: chfree(cp)
730: register struct chan *cp;
731: {
732: register struct group *gp;
733: register i;
734:
735: gp = cp->c_group;
736: if (gp==NULL)
737: return;
738: i = cp->c_index;
739: if (cp == gp->g_chans[i]) {
740: gp->g_chans[i] = NULL;
741: }
742: cp->c_group = NULL;
743: wakeup((caddr_t)gp);
744: }
745:
746:
747: flush(q)
748: register struct clist *q;
749: {
750:
751: while(q->c_cc)
752: (void) getc(q);
753: }
754:
755:
756: wflush(cp,q)
757: register struct chan *cp;
758: register struct clist *q;
759: {
760: register s;
761:
762: s = spl6();
763: if(q->c_cc && (cp->c_flags&WCLOSE) == 0) {
764: cp->c_flags |= WFLUSH;
765: (void) sdata(cp);
766: (void) tsleep((caddr_t)q+2, TTOPRI, 30);
767: }
768: flush(q);
769: cp->c_flags &= ~WFLUSH;
770: splx(s);
771: }
772:
773:
774: scontrol(cp,event,value)
775: register struct chan *cp;
776: short event,value;
777: {
778: register struct clist *q;
779: int s;
780:
781: q = &cp->c_ctlx;
782: s = spl6();
783: if (sdata(cp) == NULL)
784: return;
785: (void) putw(event,q);
786: (void) putw(value,q);
787: splx(s);
788: }
789:
790:
791:
792: sioctl(cp, vec, cc)
793: register struct chan *cp;
794: char *vec;
795: {
796: register s;
797: register struct clist *q;
798:
799: s = spl6();
800: q = &cp->cx.datq;
801: while (q->c_cc) {
802: cp->c_flags |= BLOCK;
803: if (sdata(cp)==NULL) {
804: u.u_error = ENXIO;
805: return;
806: }
807: sleep((caddr_t)q+1, TTOPRI);
808: }
809: (void) b_to_q(vec, cc, &cp->c_ctlx);
810: cp->c_flags |= SIOCTL;
811: while (cp->c_flags&SIOCTL) {
812: if (cp->c_ctlx.c_cc)
813: if (sdata(cp)==NULL) {
814: u.u_error = ENXIO;
815: return;
816: }
817: sleep((caddr_t)cp, TTOPRI);
818: }
819: (void) q_to_b(&cp->c_ctly, vec, cp->c_ctly.c_cc);
820: splx(s);
821: }
822:
823: sdata(cp)
824: struct chan *cp;
825: {
826: register struct group *gp = (struct group *)cp;
827: register struct group *ngp;
828: register int s;
829:
830: ngp = gp->g_group;
831: if (ngp==NULL || (ngp->g_state&ISGRP)==0)
832: return(NULL);
833:
834: s = spl6();
835: do {
836: ngp->g_datq |= cmask[gp->g_index];
837: wakeup((caddr_t)&ngp->g_datq);
838: gp = ngp;
839: } while(ngp=ngp->g_group);
840: splx(s);
841: return((int)gp);
842: }
843:
844:
845:
846: struct chan *
847: xcp(gp, x)
848: register struct group *gp;
849: register short x;
850: {
851: register int i;
852:
853: while (gp->g_group) gp=gp->g_group;
854: for (i=0;i<NLEVELS;i++) {
855: if ((x&017) >= NINDEX)
856: break;
857: if (gp==NULL || (gp->g_state&ISGRP)==0)
858: return((struct chan *)NULL);
859: gp = (struct group *)gp->g_chans[x&017];
860: x >>= 4;
861: }
862: return((struct chan *)gp);
863: }
864:
865: cpx(cp)
866: register struct chan *cp;
867: {
868: register x;
869: register struct group *gp;
870:
871: x = (-1<<4) + cp->c_index;
872: gp = cp->c_group;
873: while (gp->g_group) {
874: x <<= 4;
875: x |= gp->g_index;
876: gp = gp->g_group;
877: }
878: return(x);
879: }
880:
881:
882: struct chan *
883: nextcp(gp)
884: register struct group *gp;
885: {
886: register struct group *lgp, *ngp;
887:
888: do {
889: while ((gp->g_datq & cmask[gp->g_rot]) == 0) {
890: gp->g_rot = (gp->g_rot+1)%NINDEX;
891: }
892: lgp = gp;
893: gp = (struct group *)gp->g_chans[gp->g_rot];
894: } while (gp!=NULL && gp->g_state&ISGRP);
895:
896: lgp->g_datq &= ~cmask[lgp->g_rot];
897: lgp->g_rot = (lgp->g_rot+1)%NINDEX;
898:
899: while (ngp=lgp->g_group) {
900: ngp->g_datq &= ~cmask[lgp->g_index];
901: if (ngp->g_datq)
902: break;
903: lgp = ngp;
904: }
905: return((struct chan *)gp);
906: }
907:
908:
909:
910: msgenab(cp)
911: register struct chan *cp;
912: {
913: register struct group *gp;
914:
915: for(gp=cp->c_group;gp;gp=gp->g_group)
916: if(gp->g_state & ENAMSG)return(1);
917: return(0);
918: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.