1: #include "param.h" 2: #include <sys/systm.h> 3: #include <sys/dir.h> 4: #include <sys/user.h> 5: #include <sys/reg.h> 6: #include <sys/proc.h> 7: #include <sys/tty.h> 8: #include <sys/inode.h> 9: #include <sys/mx.h> 10: #include <sys/file.h> 11: #include <sys/conf.h> 12: 13: /* 14: * SCCS id @(#)mx1.c 2.1 (Berkeley) 8/5/83 15: */ 16: 17: /* 18: * Multiplexor: clist version 19: * 20: * installation: 21: * requires a line in cdevsw - 22: * mxopen, mxclose, mxread, mxwrite, mxioctl, 0, 23: * 24: * also requires a line in linesw - 25: * mxopen, mxclose, mcread, mcwrite, mxioctl, nulldev, nulldev, 26: * 27: * The linesw entry for mpx should be the last one in the table. 28: * 'nldisp' (number of line disciplines) should not include the 29: * mpx line. This is to prevent mpx from being enabled by an ioctl. 30: 31: * mxtty.c must be loaded instead of tty.c so that certain 32: * sleeps will not be done if a typewriter is connected to 33: * a channel and so that sdata will be called from ttyinput. 34: * 35: */ 36: struct chan chans[NCHANS]; 37: struct schan schans[NPORTS]; 38: struct group *groups[NGROUPS]; 39: int mpxline; 40: struct chan *xcp(); 41: dev_t mpxdev = -1; 42: 43: 44: char mcdebugs[NDEBUGS]; 45: 46: 47: /* 48: * Allocate a channel, set c_index to index. 49: */ 50: struct chan * 51: challoc(index, isport) 52: { 53: register s,i; 54: register struct chan *cp; 55: 56: s = spl6(); 57: for(i=0;i<((isport)?NPORTS:NCHANS);i++) { 58: cp = (isport)? (struct chan *)(schans+i): chans+i; 59: if(cp->c_group == NULL) { 60: cp->c_index = index; 61: cp->c_pgrp = 0; 62: cp->c_flags = 0; 63: splx(s); 64: return(cp); 65: } 66: } 67: splx(s); 68: return(NULL); 69: } 70: 71: 72: 73: /* 74: * Allocate a group table cell. 75: */ 76: gpalloc() 77: { 78: register i; 79: 80: for (i=NGROUPS-1; i>=0; i--) 81: if (groups[i]==NULL) { 82: groups[i]++; 83: return(i); 84: } 85: u.u_error = ENXIO; 86: return(i); 87: } 88: 89: 90: /* 91: * Add a channel to the group in 92: * inode ip. 93: */ 94: struct chan * 95: addch(ip, isport) 96: struct inode *ip; 97: { 98: register struct chan *cp; 99: register struct group *gp; 100: register i; 101: 102: plock(ip); 103: gp = &ip->i_un.i_group; 104: for(i=0;i<NINDEX;i++) { 105: cp = (struct chan *)gp->g_chans[i]; 106: if (cp == NULL) { 107: if ((cp=challoc(i, isport)) != NULL) { 108: gp->g_chans[i] = cp; 109: cp->c_group = gp; 110: } 111: break; 112: } 113: cp = NULL; 114: } 115: prele(ip); 116: return(cp); 117: } 118: 119: /* 120: * Mpxchan system call. 121: */ 122: 123: mpxchan() 124: { 125: extern mxopen(), mcread(), sdata(), scontrol(); 126: struct inode *ip, *gip; 127: struct tty *tp; 128: struct file *fp, *chfp, *gfp; 129: struct chan *cp; 130: struct group *gp, *ngp; 131: struct mx_args vec; 132: struct a { 133: int cmd; 134: int *argvec; 135: } *uap; 136: dev_t dev; 137: register int i; 138: 139: /* 140: * Common setup code. 141: */ 142: 143: uap = (struct a *)u.u_ap; 144: (void) copyin((caddr_t)uap->argvec, (caddr_t)&vec, sizeof vec); 145: gp = NULL; gfp = NULL; cp = NULL; 146: 147: switch(uap->cmd) { 148: 149: case NPGRP: 150: if (vec.m_arg[1] < 0) 151: break; 152: case CHAN: 153: case JOIN: 154: case EXTR: 155: case ATTACH: 156: case DETACH: 157: case CSIG: 158: gfp = getf(vec.m_arg[1]); 159: if (gfp==NULL) 160: return; 161: gip = gfp->f_inode; 162: gp = &gip->i_un.i_group; 163: if (gp->g_inode != gip) { 164: u.u_error = ENXIO; 165: return; 166: } 167: } 168: 169: switch(uap->cmd) { 170: 171: /* 172: * Create an MPX file. 173: */ 174: 175: case MPX: 176: case MPXN: 177: if (mpxdev < 0) { 178: for (i=0; linesw[i].l_open; i++) { 179: if (linesw[i].l_read==mcread) { 180: mpxline = i; 181: for (i=0; cdevsw[i].d_open; i++) { 182: if (cdevsw[i].d_open==mxopen) { 183: mpxdev = (dev_t)(i<<8); 184: } 185: } 186: } 187: } 188: if (mpxdev < 0) { 189: u.u_error = ENXIO; 190: return; 191: } 192: } 193: if (uap->cmd==MPXN) { 194: if ((ip=ialloc(pipedev))==NULL) 195: return; 196: ip->i_mode = ((vec.m_arg[1]&0777)+IFMPC) & ~u.u_cmask; 197: ip->i_flag = IACC|IUPD|ICHG; 198: } else { 199: u.u_dirp = vec.m_name; 200: ip = namei(uchar,1); 201: if (ip != NULL) { 202: i = ip->i_mode&IFMT; 203: u.u_error = EEXIST; 204: if (i==IFMPC || i==IFMPB) { 205: i = minor(ip->i_un.i_rdev); 206: gp = groups[i]; 207: if (gp && gp->g_inode==ip) 208: u.u_error = EBUSY; 209: } 210: iput(ip); 211: return; 212: } 213: if (u.u_error) 214: return; 215: ip = maknode((vec.m_arg[1]&0777)+IFMPC); 216: if (ip == NULL) 217: return; 218: } 219: if ((i=gpalloc()) < 0) { 220: iput(ip); 221: return; 222: } 223: if ((fp=falloc()) == NULL) { 224: iput(ip); 225: groups[i] = NULL; 226: return; 227: } 228: ip->i_un.i_rdev = (daddr_t)(mpxdev+i); 229: ip->i_count++; 230: prele(ip); 231: 232: gp = &ip->i_un.i_group; 233: groups[i] = gp; 234: gp->g_inode = ip; 235: gp->g_state = INUSE|ISGRP; 236: gp->g_group = NULL; 237: gp->g_file = fp; 238: gp->g_index = 0; 239: gp->g_rotmask = 1; 240: gp->g_rot = 0; 241: gp->g_datq = 0; 242: for(i=0;i<NINDEX;) 243: gp->g_chans[i++] = NULL; 244: 245: fp->f_flag = FREAD|FWRITE|FMP; 246: fp->f_inode = ip; 247: fp->f_un.f_chan = NULL; 248: return; 249: 250: /* 251: * join file descriptor (arg 0) to group (arg 1) 252: * return channel number 253: */ 254: 255: case JOIN: 256: if ((fp=getf(vec.m_arg[0]))==NULL) 257: return; 258: ip = fp->f_inode; 259: switch (ip->i_mode & IFMT) { 260: 261: case IFMPC: 262: if ((fp->f_flag&FMP) != FMP) { 263: u.u_error = ENXIO; 264: return; 265: } 266: ngp = &ip->i_un.i_group; 267: if (mtree(ngp, gp) == NULL) 268: return; 269: fp->f_count++; 270: u.u_r.r_val1 = cpx((struct chan *)ngp); 271: return; 272: 273: case IFCHR: 274: dev = (dev_t)ip->i_un.i_rdev; 275: tp = cdevsw[major(dev)].d_ttys; 276: if (tp==NULL) { 277: u.u_error = ENXIO; 278: return; 279: } 280: tp = &tp[minor(dev)]; 281: if (tp->t_chan) { 282: u.u_error = ENXIO; 283: return; 284: } 285: if ((cp=addch(gip, 1))==NULL) { 286: u.u_error = ENXIO; 287: return; 288: } 289: tp->t_chan = cp; 290: cp->c_fy = fp; 291: fp->f_count++; 292: cp->c_ttyp = tp; 293: cp->c_line = tp->t_line; 294: cp->c_flags = XGRP+PORT; 295: u.u_r.r_val1 = cpx(cp); 296: return; 297: 298: default: 299: u.u_error = ENXIO; 300: return; 301: 302: } 303: 304: /* 305: * Attach channel (arg 0) to group (arg 1). 306: */ 307: 308: case ATTACH: 309: cp = xcp(gp, vec.m_arg[0]); 310: if (cp==NULL || cp->c_flags&ISGRP) { 311: u.u_error = ENXIO; 312: return; 313: } 314: u.u_r.r_val1 = cpx(cp); 315: wakeup((caddr_t)cp); 316: return; 317: 318: case DETACH: 319: cp = xcp(gp, vec.m_arg[0]); 320: if (cp==NULL) { 321: u.u_error = ENXIO; 322: return; 323: } 324: (void) detach(cp); 325: return; 326: 327: /* 328: * Extract channel (arg 0) from group (arg 1). 329: */ 330: 331: case EXTR: 332: cp = xcp(gp, vec.m_arg[0]); 333: if (cp==NULL) { 334: u.u_error = ENXIO; 335: return; 336: } 337: if (cp->c_flags & ISGRP) { 338: (void) mxfalloc(((struct group *)cp)->g_file); 339: return; 340: } 341: if ((fp=cp->c_fy) != NULL) { 342: (void) mxfalloc(fp); 343: return; 344: } 345: if ((fp=falloc()) == NULL) 346: return; 347: fp->f_inode = gip; 348: gip->i_count++; 349: fp->f_un.f_chan = cp; 350: fp->f_flag = (vec.m_arg[2]) ? 351: (FREAD|FWRITE|FMPY) : (FREAD|FWRITE|FMPX); 352: cp->c_fy = fp; 353: return; 354: 355: /* 356: * Make new chan on group (arg 1). 357: */ 358: 359: case CHAN: 360: if((gfp->f_flag&FMP)==FMP)cp = addch(gip, 0); 361: if(cp == NULL){ 362: u.u_error = ENXIO; 363: return; 364: } 365: cp->c_flags = XGRP; 366: cp->c_fy = NULL; 367: cp->c_ttyp = cp->c_ottyp = (struct tty *)cp; 368: cp->c_line = cp->c_oline = mpxline; 369: u.u_r.r_val1 = cpx(cp); 370: return; 371: 372: /* 373: * Connect fd (arg 0) to channel fd (arg 1). 374: * (arg 2 < 0) => fd to chan only 375: * (arg 2 > 0) => chan to fd only 376: * (arg 2 == 0) => both directions 377: */ 378: 379: case CONNECT: 380: if ((fp=getf(vec.m_arg[0]))==NULL) 381: return; 382: if ((chfp=getf(vec.m_arg[1]))==NULL) 383: return; 384: ip = fp->f_inode; 385: i = ip->i_mode&IFMT; 386: if (i!=IFCHR) { 387: u.u_error = ENXIO; 388: return; 389: } 390: dev = (dev_t)ip->i_un.i_rdev; 391: tp = cdevsw[major(dev)].d_ttys; 392: if (tp==NULL) { 393: u.u_error = ENXIO; 394: return; 395: } 396: tp = &tp[minor(dev)]; 397: if (!(chfp->f_flag&FMPY)) { 398: u.u_error = ENXIO; 399: return; 400: } 401: cp = chfp->f_un.f_chan; 402: if (cp==NULL || cp->c_flags&PORT) { 403: u.u_error = ENXIO; 404: return; 405: } 406: i = vec.m_arg[2]; 407: if (i>=0) { 408: cp->c_ottyp = tp; 409: cp->c_oline = tp->t_line; 410: } 411: if (i<=0) { 412: tp->t_chan = cp; 413: cp->c_ttyp = tp; 414: cp->c_line = tp->t_line; 415: } 416: u.u_r.r_val1 = 0; 417: return; 418: 419: case NPGRP: { 420: register struct proc *pp; 421: 422: if (gp != NULL) { 423: cp = xcp(gp, vec.m_arg[0]); 424: if (cp==NULL) { 425: u.u_error = ENXIO; 426: return; 427: } 428: } 429: pp = u.u_procp; 430: pp->p_pgrp = pp->p_pid; 431: if (vec.m_arg[2]) 432: pp->p_pgrp = vec.m_arg[2]; 433: if (gp != NULL) 434: cp->c_pgrp = pp->p_pgrp; 435: u.u_r.r_val1 = pp->p_pgrp; 436: return; 437: } 438: 439: case CSIG: 440: cp = xcp(gp, vec.m_arg[0]); 441: if (cp==NULL) { 442: u.u_error = ENXIO; 443: return; 444: } 445: gsignal(cp->c_pgrp, vec.m_arg[2]); 446: u.u_r.r_val1 = vec.m_arg[2]; 447: return; 448: 449: case DEBUG: 450: i = vec.m_arg[0]; 451: if (i<0 || i>NDEBUGS) 452: return; 453: mcdebugs[i] = vec.m_arg[1]; 454: if (i==ALL) 455: for(i=0;i<NDEBUGS;i++) 456: mcdebugs[i] = vec.m_arg[1]; 457: return; 458: 459: default: 460: u.u_error = ENXIO; 461: return; 462: } 463: 464: } 465: 466: detach(cp) 467: register struct chan *cp; 468: { 469: register struct group *master,*sub; 470: register index; 471: 472: if (cp==NULL) 473: return(0); 474: if (cp->c_flags&ISGRP) { 475: sub = (struct group *)cp; 476: master = sub->g_group; index = sub->g_index; 477: closef(sub->g_file); 478: if (master != NULL) 479: master->g_chans[index] = NULL; 480: else 481: printf("detach: master null\n"); 482: return(0); 483: } else if (cp->c_flags&PORT && cp->c_ttyp != NULL) { 484: closef(cp->c_fy); 485: chdrain(cp); 486: chfree(cp); 487: return(0); 488: } 489: if (cp->c_flags & WCLOSE) { 490: if (cp->c_fy) { 491: if (cp->c_fy->f_count) 492: return(1); 493: chdrain(cp); 494: chfree(cp); 495: return(0); 496: } 497: } 498: cp->c_flags |= WCLOSE; 499: chwake(cp); 500: return(1); 501: } 502: 503: mxfalloc(fp) 504: register struct file *fp; 505: { 506: register i; 507: 508: if (fp==NULL) { 509: u.u_error = ENXIO; 510: return(-1); 511: } 512: i = ufalloc(); 513: if (i < 0) 514: return(i); 515: u.u_ofile[i] = fp; 516: fp->f_count++; 517: u.u_r.r_val1 = i; 518: return(i); 519: } 520: 521: /* 522: * Grow a branch on a tree. 523: */ 524: 525: mtree(sub,master) 526: register struct group *sub, *master; 527: { 528: register i; 529: int mtresiz, stresiz; 530: 531: if ((mtresiz=mup(master,sub)) == NULL) { 532: u.u_error = ENXIO; 533: return(NULL); 534: } 535: if ((stresiz=mdown(sub,master)) <= 0) { 536: u.u_error = ENXIO; 537: return(NULL); 538: } 539: if (sub->g_group != NULL) { 540: u.u_error = ENXIO; 541: return(NULL); 542: } 543: if (stresiz+mtresiz > NLEVELS) { 544: u.u_error = ENXIO; 545: return(NULL); 546: } 547: for (i=0;i<NINDEX;i++) { 548: if (master->g_chans[i] != NULL) 549: continue; 550: master->g_chans[i] = (struct chan *)sub; 551: sub->g_group = master; 552: sub->g_index = i; 553: return(1); 554: } 555: u.u_error = ENXIO; 556: return(NULL); 557: } 558: 559: mup(master,sub) 560: struct group *master, *sub; 561: { 562: register struct group *top; 563: register int depth; 564: 565: depth = 1; top = master; 566: while (top->g_group) { 567: depth++; 568: top = top->g_group; 569: } 570: if(top == sub) 571: return(NULL); 572: return(depth); 573: } 574: 575: 576: mdown(sub,master) 577: struct group *sub, *master; 578: { 579: register int maxdepth, i, depth; 580: 581: if(sub == (struct group *)NULL || (sub->g_state&ISGRP) == 0) 582: return(0); 583: if(sub == master) 584: return(-1); 585: maxdepth = 0; 586: for(i=0; i<NINDEX; i++) { 587: if((depth=mdown((struct group *)sub->g_chans[i],master)) == -1) 588: return(-1); 589: maxdepth = (depth>maxdepth) ? depth: maxdepth; 590: } 591: return(maxdepth+1); 592: }