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