xref: /original-bsd/old/dnd/dnd.c (revision a95f03a8)
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