1 static char *sccsid ="@(#)dnd.c 4.4 (Berkeley) 01/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 for(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<QSIZE;j++) { 271 runq[i] = runq[j]; 272 i = j; 273 } 274 runq[j].uid = -1; 275 return(x); 276 } 277 return(0); 278 } 279 wchan(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 } 404