BSD 4 release
[unix-history] / usr / src / cmd / dnd.c
CommitLineData
31cef89c 1static char *sccsid ="@(#)dnd.c 4.3 (Berkeley) 11/4/80";
5e890ce8
BJ
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
14int xd;
15int dndebug = 1; /* we actually run debug = 1 */
16int nactive; /* number running */
17int max; /* max allowable */
18int jobnum;
19char dialbuf[DSIZE];
20char *dp = dialbuf;
21FILE *actfile;
22struct mx_leaves {
23 char *name;
24 char rack,modem;
25 short chan;
26 int file;
0a341f33 27} pdevs[] = {{"/dev/cua0",'4','0'}, {"/dev/cua1",'4','1'}, {0}};
5e890ce8
BJ
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
33struct actinfo {
34 short index;
35 short uid;
36} runq[QSIZE], xx;
37
38#define INDEX(x) ((x&0xff00)>>4)
39
40main(argc, argv)
41char **argv;
42{
43register cc;
44char 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);
19490c09
BJ
54 while(fork()) {
55 sleep(10);
5e890ce8 56 wait(0);
19490c09 57 }
5e890ce8
BJ
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 }
19490c09 67 _exit(0);
5e890ce8
BJ
68}
69
70short noioctl = M_IOANS;
71control(x, cb, cc)
72register char *cb;
73{
74register char *end;
75register struct chan *cp;
76int cmd, stat, ch;
77int 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
103startjob()
104{
105register 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
121stopjob(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 */
137init()
138{
139register struct mx_leaves *lp;
140register int t;
141int 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 */
173unpack(bp, cc)
174register char *bp;
175{
176register char *end;
177register 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 */
196perform(rp,data)
197register struct rh *rp;
198register char *data;
199{
200register char *lim;
201long clock; char c;
202char *mdata, *tmpt, *ctime();
203struct 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}
225quit(msg)
226char *msg;
227{
228 printf("%s\n", msg);
229 exit(1);
230}
231
232putq(x,uid)
233{
234register 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
244getq()
245{
246register 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
260delq(x)
261register x;
262{
263register 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}
279wchan(chan,obuf,count)
280register char *obuf;
281{
282struct 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}
290wctl(chan,obuf,count)
291register char *obuf;
292{
293struct 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
303char *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)
310static struct sgttyb cntrl;
311dialit(string)
312register 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}
355char *
356sanitize(string)
357register 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
376dialer while line in use */
377char *DZ = "/dev/cul0";
378#include <setjmp.h>
379#include <signal.h>
380jmp_buf handy;
381linebusy() {
382void 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}
400void
401catchit(){
402 longjmp(handy,1);
403}