Commit | Line | Data |
---|---|---|
4b582bb8 | 1 | static char *sccsid ="@(#)dnd.c 4.4 (Berkeley) %G%"; |
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 | ||
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; | |
4b582bb8 | 27 | } pdevs[] = {{"/dev/cua0",'4','8'}, /*{"/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 | ||
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); | |
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 | ||
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 | } |