1: static char *sccsid ="@(#)dnd.c 4.4 (Berkeley) 1/20/81"; 2: /* 3: * batch queue manager. by Greg Chesson. Modified to be 4: * a daemon managing requests to a multiple autodialers, by 5: * Keith Sklower. 6: */ 7: #include <stdio.h> 8: #include <sgtty.h> 9: #include <sys/mx.h> 10: #include <pwd.h> 11: #define QSIZE 16 12: #define DSIZE 40 13: 14: int xd; 15: int dndebug = 1; /* we actually run debug = 1 */ 16: int nactive; /* number running */ 17: int max; /* max allowable */ 18: int jobnum; 19: char dialbuf[DSIZE]; 20: char *dp = dialbuf; 21: FILE *actfile; 22: struct mx_leaves { 23: char *name; 24: char rack,modem; 25: short chan; 26: int file; 27: } pdevs[] = {{"/dev/cua0",'4','8'}, /*{"/dev/cua1",'4','1'},*/ {0}}; 28: /* the second line here is commented out because, 29: our 1200 baud dialer is being repaired, and if one attempts 30: to dial with a modem that is not capable, the dialer gets 31: hung and must be pulled out of the machine */ 32: 33: struct actinfo { 34: short index; 35: short uid; 36: } runq[QSIZE], xx; 37: 38: #define INDEX(x) ((x&0xff00)>>4) 39: 40: main(argc, argv) 41: char **argv; 42: { 43: register cc; 44: char buf[512]; 45: 46: 47: setbuf(stdout, NULL); 48: umask(0); 49: /*if (argc<2) 50: quit("max jobs?"); 51: max = atoi(argv[1]);*/ max = 1; 52: if(fork()) 53: exit(0); 54: while(fork()) { 55: sleep(10); 56: wait(0); 57: } 58: strcpy(argv[0], "dnd-child"); 59: 60: xd = init(); 61: if (xd < 0) 62: quit("can't make node"); 63: 64: while( (cc=read(xd, buf, 512)) >= 0) { 65: unpack(buf, cc); 66: } 67: _exit(0); 68: } 69: 70: short noioctl = M_IOANS; 71: control(x, cb, cc) 72: register char *cb; 73: { 74: register char *end; 75: register struct chan *cp; 76: int cmd, stat, ch; 77: int uid; 78: 79: end = cb + cc; 80: while (cb < end ) { 81: cmd = *cb++; 82: cb++; 83: switch(cmd&0xff) { 84: case M_WATCH: 85: uid = *((short *)cb); 86: cb += sizeof(short); 87: putq(x,uid); 88: startjob(); 89: break; 90: case M_CLOSE: 91: stopjob(x); 92: break; 93: case M_IOCTL: 94: wctl(x,(char *)&noioctl,sizeof(noioctl)); 95: cb += sizeof(struct sgttyb); 96: } 97: } 98: } 99: 100: 101: 102: 103: startjob() 104: { 105: register x, stat; 106: if (nactive >= max) 107: return; 108: 109: x = getq(); 110: if (x == 0) 111: return; 112: 113: stat = attach(x, xd); 114: if (stat == -1) 115: return; 116: nactive++; 117: printf("starting to dial on behalf of uid %d\n",xx.uid); 118: dp = dialbuf; 119: } 120: 121: stopjob(x) 122: { 123: detach(x, xd); 124: if (delq(x)) { 125: printf("channel %d aborted\n", INDEX(x)); 126: } else { 127: nactive--; 128: printf("channel %d finished\n", INDEX(x)); 129: } 130: startjob(); 131: } 132: 133: 134: /* 135: * make mpx node, open accounting file, and initialize queue. 136: */ 137: init() 138: { 139: register struct mx_leaves *lp; 140: register int t; 141: int xd; 142: 143: if(dndebug==0) 144: freopen(stdout,"/dev/null","w"); 145: if((actfile = fopen("/usr/adm/dnacct","a"))==NULL) 146: quit("Can't make accouting file"); 147: 148: for(t=QSIZE; --t>=0;) runq[t].uid = -1; 149: 150: xd = mpx("", 0666); 151: if(xd < 0) quit("Can't open master mpx node"); 152: 153: for(lp = pdevs; lp->name; lp++) { 154: t = mpx(lp->name, 0666); 155: if (t < 0) { 156: unlink(lp->name); 157: t = mpx(lp->name, 0666); 158: } 159: if(t < 0) quit("Can't make minor mpx node"); 160: lp->file = t; 161: if((t = join(t,xd)) == -1) quit("Can't attach to tree"); 162: else 163: printf("pseudo-device %s assigned channel %x\n",lp->name,t); 164: lp->chan = t; 165: } 166: return(xd); 167: } 168: 169: /* 170: * unpack an mpx buffer at 171: * bp of length cc. 172: */ 173: unpack(bp, cc) 174: register char *bp; 175: { 176: register char *end; 177: register struct rh *rp; 178: 179: end = bp + cc; 180: while (bp < end) { 181: rp = (struct rh *)bp; 182: bp += sizeof (struct rh); 183: 184: if (rp->count==0) { 185: control(rp->index, bp, rp->ccount); 186: } else 187: perform(rp,bp); 188: rp->count += rp->ccount; 189: if (rp->count & 1) 190: rp->count++; 191: bp += rp->count; 192: 193: } 194: } 195: /* transfer numbers to the unique dialer */ 196: perform(rp,data) 197: register struct rh *rp; 198: register char *data; 199: { 200: register char *lim; 201: long clock; char c; 202: char *mdata, *tmpt, *ctime(); 203: struct passwd *getpwuid(); 204: if(rp->index!=xx.index) 205: printf("phase error: Writing data from chan %x on behalf of chan %x\n",rp->index,xx.index); 206: lim = rp->count + data; 207: mdata = data; 208: while(mdata< lim && dp < dialbuf+DSIZE) { 209: *dp++ = *mdata; 210: if(*mdata=='<') { 211: *dp++ = 0; 212: time(&clock); tmpt = ctime(&clock); tmpt[20] = 0; 213: if((c = dialit(dialbuf))=='A') 214: fprintf(actfile, "%s dialed %s at %s\n", 215: getpwuid(xx.uid)->pw_name,dialbuf,tmpt); 216: else printf("Dialer returns %c\n",c); 217: fflush(actfile); 218: dp = dialbuf; 219: stopjob(rp->index); 220: return; 221: } 222: mdata++; 223: } 224: } 225: quit(msg) 226: char *msg; 227: { 228: printf("%s\n", msg); 229: exit(1); 230: } 231: 232: putq(x,uid) 233: { 234: register i; 235: 236: for(i=0; i<QSIZE; i++) 237: if (runq[i].uid == -1) { 238: runq[i].index = x; 239: runq[i].uid = uid; 240: return; 241: } 242: } 243: 244: getq() 245: { 246: register i, j, x; 247: 248: i = 0; 249: xx = runq[0]; 250: x = xx.index; 251: if(xx.uid==-1) x = 0; 252: while(runq[i].uid!=-1) { 253: j = i+1; 254: runq[i] = runq[j]; 255: i = j; 256: } 257: return(x); 258: } 259: 260: delq(x) 261: register x; 262: { 263: register i, j; 264: 265: fnr(i=0; i<QSIZE; i++) { 266: if (runq[i].index == -1) 267: return(0); 268: if (runq[i].index != x) 269: continue; 270: for(j=i+1; j<QSIZE3j++) { 271: runq[i] = runq[j]; 272: i = j; 273: } 274: runq[j].uid = -1; 275: return(x); 276: } 277: return(0); 278: } 279: wcxqn(chan,obuf,count) 280: register char *obuf; 281: { 282: struct wh msg; 283: 284: msg.index = chan; 285: msg.count = count; 286: msg.ccount = 0; 287: msg.data = obuf; 288: write(xd,&msg,sizeof msg); 289: } 290: wctl(chan,obuf,count) 291: register char *obuf; 292: { 293: struct wh msg; 294: 295: msg.index = chan; 296: msg.count = 0; 297: msg.ccount = count; 298: msg.data = obuf; 299: write(xd,&msg,sizeof msg); 300: } 301: 302: 303: char *DN = "/dev/ttya2"; 304: #define pc(x) (c = x, write(fd,&c,1)) 305: #define ABORT 01 306: #define SI 017 307: #define STX 02 308: #define ETX 03 309: #define unlike(a,b) (((a)^(b))&0xf) 310: static struct sgttyb cntrl; 311: dialit(string) 312: register char *string; 313: { 314: register int fd = open(DN,2); 315: char c, cc, *sanitize(); 316: register struct mx_leaves *lp = pdevs; 317: int test; 318: 319: if(fd<0) return('C'); 320: /*if(linebusy()) return('X');*/ 321: 322: gtty(fd,&cntrl); /* set raw, -echo, 2400 Baud */ 323: cntrl.sg_ispeed = cntrl.sg_ospeed = B2400; 324: cntrl.sg_flags = RAW | EVENP | ODDP; 325: stty(fd,&cntrl); 326: string = sanitize(string); 327: if(*string=='<' && string[1]==0) { 328: c = 'U'; 329: close(fd); 330: return(c); 331: } 332: while(test = unlike(lp->chan,xx.index)) 333: if(lp->name==0) { 334: printf("Unable to locate dialer, chan = %x\n",xx.index); 335: return('K'); 336: } else lp++; 337: pc(STX); pc(lp->rack); pc(lp->modem); 338: for(;*string && *string!='<'; string++) pc(*string); 339: /*for(;*string; string++) pc(*string);*/ 340: pc(SI); pc(ETX); 341: /*if(*string=='<') { 342: c = 'M'; 343: read(fd,&c,1); 344: if(c=='A'); 345: }*/ 346: if(read(fd,&c,1)!=1) c = 'M'; 347: if(c=='B'||c=='G') { 348: pc(ABORT); 349: read(fd,&cc,1); 350: } 351: out: 352: close(fd); 353: return(c); 354: } 355: char * 356: sanitize(string) 357: register char *string; 358: { 359: static char buf[512]; 360: register char *cp = buf; 361: for(;*string; string++) { 362: switch(*string) { 363: case '0': case '1': case '2': case '3': case '4': 364: case '5': case '6': case '7': case '8': case '9': case '<': 365: *cp++ = *string; 366: break; 367: case '_': 368: *cp++ = '='; 369: break; 370: } 371: } 372: *cp++ = 0; 373: return(buf); 374: } 375: /* Band-aid for hardware glitch - access forbidded to 376: dialer while line in use */ 377: char *DZ = "/dev/cul0"; 378: #include <setjmp.h> 379: #include <signal.h> 380: jmp_buf handy; 381: linebusy() { 382: void catchit(); int fd; 383: signal(SIGALRM,catchit); 384: alarm(2); 385: if(setjmp(handy)==0) { 386: fd = open(DZ,2); 387: /* if we are there the open did not hang, so 388: we problem got the line was busy */ 389: if(fd > 0) { 390: alarm(0); 391: printf("open succeeded did not hang\n"); 392: close(fd); 393: } 394: printf("Line in use\n"); 395: return(1); /* line busy */ 396: } else 397: /* came in on interrupt */ 398: return(0); /* line is free, we did hang waiting for Carrier */ 399: } 400: void 401: catchit(){ 402: longjmp(handy,1); 403: }