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