still more fixes from rick adams
[unix-history] / usr / src / usr.bin / uucp / uucico / condevs.c
CommitLineData
572555ee 1#ifndef lint
c8a90aca 2static char sccsid[] = "@(#)condevs.c 5.10 (Berkeley) %G%";
572555ee
SL
3#endif
4
5/*
6 * Here are various dialers to establish the machine-machine connection.
7 * conn.c/condevs.c was glued together by Mike Mitchell.
8 * The dialers were supplied by many people, to whom we are grateful.
9 *
10 * ---------------------------------------------------------------------
11 * NOTE:
12 * There is a bug that occurs at least on PDP11s due to a limitation of
13 * setjmp/longjmp. If the routine that does a setjmp is interrupted
14 * and longjmp-ed to, it loses its register variables (on a pdp11).
15 * What works is if the routine that does the setjmp
16 * calls a routine and it is the *subroutine* that is interrupted.
46b15d8a 17 *
572555ee
SL
18 * Anyway, in conclusion, condevs.c is plagued with register variables
19 * that are used inside
20 * if (setjmp(...)) {
21 * ....
22 * }
46b15d8a
RC
23 *
24 * THE FIX: Don't declare variables to be register
572555ee 25 */
572555ee 26
46b15d8a 27#include "condevs.h"
572555ee
SL
28
29struct condev condevs[] = {
46b15d8a 30 { "DIR", "direct", diropn, nulldev, dircls },
572555ee 31#ifdef DATAKIT
46b15d8a
RC
32 { "DK", "datakit", dkopn, nulldev, nulldev },
33#endif DATAKIT
572555ee 34#ifdef PNET
46b15d8a
RC
35 { "PNET", "pnet", pnetopn, nulldev, nulldev },
36#endif PNET
37#ifdef UNETTCP
38 { "TCP", "TCP", unetopn, nulldev, unetcls },
39#endif UNETTCP
40#ifdef BSDTCP
41 { "TCP", "TCP", bsdtcpopn, nulldev, bsdtcpcls },
42#endif BSDTCP
572555ee 43#ifdef MICOM
46b15d8a 44 { "MICOM", "micom", micopn, nulldev, miccls },
572555ee
SL
45#endif MICOM
46#ifdef DN11
46b15d8a
RC
47 { "ACU", "dn11", Acuopn, dnopn, dncls },
48#endif DN11
572555ee 49#ifdef HAYES
c8a90aca
JB
50 { "ACU", "hayes", Acuopn, hyspopn, hyscls },
51 { "ACU", "hayespulse", Acuopn, hyspopn, hyscls },
52 { "ACU", "hayestone", Acuopn, hystopn, hyscls },
572555ee
SL
53#endif HAYES
54#ifdef HAYESQ /* a version of hayes that doesn't use result codes */
c8a90aca
JB
55 { "ACU", "hayesq", Acuopn, hysqpopn, hysqcls },
56 { "ACU", "hayesqpulse", Acuopn, hysqpopn, hysqcls },
57 { "ACU", "hayesqtone", Acuopn, hysqtopn, hysqcls },
58#endif HAYESQ
46b15d8a
RC
59#ifdef NOVATION
60 { "ACU", "novation", Acuopn, novopn, novcls},
61#endif NOVATION
572555ee 62#ifdef DF02
46b15d8a
RC
63 { "ACU", "DF02", Acuopn, df2opn, df2cls },
64#endif DF02
1a85e9d2
RC
65#ifdef DF112
66 { "ACU", "DF112P", Acuopn, df12popn, df12cls },
67 { "ACU", "DF112T", Acuopn, df12topn, df12cls },
68#endif DF112
572555ee 69#ifdef VENTEL
46b15d8a 70 { "ACU", "ventel", Acuopn, ventopn, ventcls },
572555ee 71#endif VENTEL
1a85e9d2
RC
72#ifdef PENRIL
73 { "ACU", "penril", Acuopn, penopn, pencls },
74#endif PENRIL
572555ee 75#ifdef VADIC
46b15d8a 76 { "ACU", "vadic", Acuopn, vadopn, vadcls },
572555ee 77#endif VADIC
46b15d8a
RC
78#ifdef VA212
79 { "ACU", "va212", Acuopn, va212opn, va212cls },
80#endif VA212
81#ifdef VA811S
82 { "ACU", "va811s", Acuopn, va811opn, va811cls },
83#endif VA811S
84#ifdef VA820
85 { "ACU", "va820", Acuopn, va820opn, va820cls },
86 { "WATS", "va820", Acuopn, va820opn, va820cls },
87 { "LOCAL", "va820", Acuopn, va820opn, va820cls },
88#endif VA820
572555ee 89#ifdef RVMACS
46b15d8a 90 { "ACU", "rvmacs", Acuopn, rvmacsopn, rvmacscls },
572555ee 91#endif RVMACS
46b15d8a
RC
92#ifdef VMACS
93 { "ACU", "vmacs", Acuopn, vmacsopn, vmacscls },
94#endif VMACS
95#ifdef SYTEK
96 { "SYTEK", "sytek", sykopn, nulldev, sykcls },
97#endif SYTEK
572555ee 98
46b15d8a
RC
99 /* Insert new entries before this line */
100 { NULL, NULL, NULL, NULL, NULL }
101};
572555ee 102
46b15d8a 103/*
572555ee
SL
104 * nulldev a null device (returns CF_DIAL)
105 */
46b15d8a 106nulldev()
572555ee 107{
46b15d8a 108 return CF_DIAL;
572555ee
SL
109}
110
46b15d8a 111/*
572555ee
SL
112 * nodev a null device (returns CF_NODEV)
113 */
46b15d8a 114nodev()
572555ee 115{
46b15d8a 116 return CF_NODEV;
572555ee
SL
117}
118
572555ee 119/*
572555ee 120 * Generic devices look through L-devices and call the CU_open routines for
46b15d8a
RC
121 * appropriate devices. Some things, like the tcp/ip interface, or direct
122 * connect, do not use the CU_open entry. ACUs must search to find the
572555ee
SL
123 * right routine to call.
124 */
125
46b15d8a 126/*
572555ee 127 * diropn(flds) connect to hardware line
572555ee
SL
128 *
129 * return codes:
46b15d8a 130 * > 0 - file number - ok
572555ee
SL
131 * FAIL - failed
132 */
572555ee
SL
133diropn(flds)
134register char *flds[];
135{
136 register int dcr, status;
137 struct Devices dev;
138 char dcname[20];
139 FILE *dfp;
46b15d8a
RC
140#ifdef VMSDTR /* Modem control on vms(works dtr) */
141 int modem_control;
142 short iosb[4];
143 int sys$qiow(); /* use this for long reads on vms */
144 int ret;
145 long mode[2];
146 modem_control = 0;
147#endif
572555ee
SL
148 dfp = fopen(DEVFILE, "r");
149 ASSERT(dfp != NULL, "CAN'T OPEN", DEVFILE, 0);
150 while ((status = rddev(dfp, &dev)) != FAIL) {
46b15d8a
RC
151#ifdef VMSDTR /* Modem control on vms(works dtr) */
152 /* If we find MOD in the device type field we go into action */
153 if (strcmp(dev.D_type, "MOD") == SAME) {
154 modem_control = 1;
155 DEBUG(7, "Setting Modem control to %d",modem_control);
156 }
157 if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
158 continue;
159 /*
160 * Modem control on vms(works dtr) Take anything in MOD class.
161 * It probably should work differently anyway so we can have
162 * multiple hardwired lines.
163 */
164 if (!modem_control&&strcmp(flds[F_PHONE], dev.D_line) != SAME)
165#else !VMSDTR
572555ee
SL
166 if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
167 continue;
168 if (strcmp(flds[F_PHONE], dev.D_line) != SAME)
46b15d8a 169#endif !VMSDTR
572555ee
SL
170 continue;
171 if (mlock(dev.D_line) != FAIL)
172 break;
173 }
174 fclose(dfp);
175 if (status == FAIL) {
176 logent("DEVICE", "NO");
46b15d8a 177 return CF_NODEV;
572555ee
SL
178 }
179
180 sprintf(dcname, "/dev/%s", dev.D_line);
181 if (setjmp(Sjbuf)) {
182 delock(dev.D_line);
46b15d8a 183 return CF_DIAL;
572555ee
SL
184 }
185 signal(SIGALRM, alarmtr);
186 alarm(10);
187 getnextfd();
188 errno = 0;
46b15d8a 189 DEBUG(4,"Opening %s",dcname);
572555ee 190 dcr = open(dcname, 2); /* read/write */
46b15d8a
RC
191#ifdef VMSDTR /* Modem control on vms(works dtr) */
192 fflush(stdout);
193 if (modem_control) { /* Did we have MOD in the device type field ? */
194 /* Sense the current terminal setup and save it */
195 if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv,
196 IO$_SENSEMODE,iosb,0,0,mode,8,0,0,0,0))
197 != SS$_NORMAL) {
198 DEBUG(7, "ret status on sense failed on Modem sense=%x<", ret);
199 return CF_DIAL;
200 }
201 mode[1] |= TT$M_MODEM; /* Or in modem control(DTR) */
202 /* Now set the new terminal characteristics */
203 /* This is temporary and will go away when we let go of it */
204 if ((ret = sys$qiow(_$EFN,(fd_fab_pointer[dcr]->fab).fab$l_stv,
205 IO$_SETMODE,iosb,0,0,mode,8,0,0,0,0))
206 != SS$_NORMAL) {
207 DEBUG(7, "ret status on sense failed on Modem setup=%x<", ret);
208 return CF_DIAL;
209 }
210 }
211#endif VMSDTR
572555ee
SL
212 next_fd = -1;
213 if (dcr < 0 && errno == EACCES)
214 logent(dcname, "CAN'T OPEN");
215 alarm(0);
216 if (dcr < 0) {
217 delock(dev.D_line);
46b15d8a 218 return CF_DIAL;
572555ee
SL
219 }
220 fflush(stdout);
c8a90aca
JB
221 if (fixline(dcr, dev.D_speed) == FAIL)
222 return CF_DIAL;
572555ee
SL
223 strcpy(devSel, dev.D_line); /* for latter unlock */
224 CU_end = dircls;
46b15d8a 225 return dcr;
572555ee
SL
226}
227
228dircls(fd)
229register int fd;
230{
231 if (fd > 0) {
232 close(fd);
233 delock(devSel);
572555ee 234 }
572555ee
SL
235}
236
1a85e9d2
RC
237/*
238 * open an ACU and dial the number. The condevs table
239 * will be searched until a dialing unit is found that is free.
572555ee
SL
240 *
241 * return codes: >0 - file number - o.k.
242 * FAIL - failed
243 */
572555ee
SL
244char devSel[20]; /* used for later unlock() */
245
246Acuopn(flds)
247register char *flds[];
248{
1a85e9d2
RC
249 char phone[MAXPH+1];
250 register struct condev *cd;
251 register int fd, acustatus;
252 register FILE *dfp;
253 struct Devices dev;
254 int retval = CF_NODEV;
255
256 exphone(flds[F_PHONE], phone);
257 devSel[0] = '\0';
258 DEBUG(4, "Dialing %s\n", phone);
259 dfp = fopen(DEVFILE, "r");
260 ASSERT(dfp != NULL, "Can't open", DEVFILE, 0);
261
262 acustatus = 0; /* none found, none locked */
263 for(cd = condevs; cd->CU_meth != NULL; cd++) {
264 if (snccmp(flds[F_LINE], cd->CU_meth) == SAME) {
265 rewind(dfp);
266 while(rddev(dfp, &dev) != FAIL) {
267 /*
268 * for each ACU L.sys line, try at most twice
269 * (TRYCALLS) to establish carrier. The old way tried every
270 * available dialer, which on big sites takes forever!
271 * Sites with a single auto-dialer get one try.
272 * Sites with multiple dialers get a try on each of two
273 * different dialers.
274 * To try 'harder' to connect to a remote site,
275 * use multiple L.sys entries.
276 */
277 if (acustatus > TRYCALLS)
278 continue;
279 if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
280 continue;
281 if (snccmp(flds[F_LINE], dev.D_type) != SAME)
282 continue;
283 if (dev.D_brand[0] == '\0') {
284 logent("Acuopn","No 'brand' name on ACU");
285 continue;
286 }
287 for(cd = condevs; cd->CU_meth != NULL; cd++) {
288 if (snccmp(flds[F_LINE], cd->CU_meth) == SAME
289 && snccmp(dev.D_brand, cd->CU_brand) == SAME)
290 break;
291 }
292 if (cd->CU_meth == NULL) {
293 logent(dev.D_brand,"unsupported ACU type");
294 continue;
295 }
296
297 if (acustatus < 1)
298 acustatus = 1; /* has been found */
c8a90aca
JB
299 if (mlock(dev.D_line) == FAIL) {
300 acustatus++;
1a85e9d2 301 continue;
c8a90aca 302 }
1a85e9d2 303#ifdef DIALINOUT
c8a90aca
JB
304#ifdef ALLACUINOUT
305 if (
306#else !ALLACUINOUT
307 if (snccmp("inout", dev.D_calldev) == SAME &&
308#endif !ALLACUINOUT
309 disable(dev.D_line) == FAIL) {
1a85e9d2
RC
310 delock(dev.D_line);
311 continue;
312 }
313#endif DIALINOUT
314
315 DEBUG(4, "Using %s\n", cd->CU_brand);
316 acustatus++;
317 fd = (*(cd->CU_open))(phone, flds, &dev);
318 if (fd > 0) {
319 CU_end = cd->CU_clos; /* point CU_end at close func */
320 fclose(dfp);
321 strcpy(devSel, dev.D_line); /* save for later unlock() */
322 return fd;
323 } else
324 delock(dev.D_line);
325 retval = CF_DIAL;
326 }
572555ee 327 }
572555ee 328 }
1a85e9d2
RC
329 fclose(dfp);
330 if (acustatus == 0)
331 logent("L-devices", "No appropriate ACU");
332 if (acustatus == 1)
333 logent("DEVICE", "NO");
334 return retval;
572555ee
SL
335}
336
1a85e9d2 337#if defined(VENTEL) || defined(NOVATION) || defined(DF112)
572555ee 338/*
c8a90aca 339 * intervaldelay: delay execution for numerator/denominator seconds.
572555ee
SL
340 */
341
342#ifdef INTERVALTIMER
62ba4a08 343#include <sys/time.h>
c8a90aca
JB
344#define uucpdelay(num,denom) intervaldelay(num,denom)
345intervaldelay(num,denom)
346int num, denom;
347{
348 struct timeval tv;
349 tv.tv_sec = num / denom;
350 tv.tv_usec = (num * 1000000L / denom ) % 1000000L;
351 (void) select (0, (int *)0, (int *)0, (int *)0, &tv);
352}
572555ee
SL
353#endif INTERVALTIMER
354
355#ifdef FASTTIMER
356#define uucpdelay(num,denom) nap(60*num/denom)
357/* Sleep in increments of 60ths of second. */
358nap (time)
1a85e9d2 359register int time;
572555ee
SL
360{
361 static int fd;
362
363 if (fd == 0)
364 fd = open (FASTTIMER, 0);
365
366 read (fd, 0, time);
367}
368#endif FASTTIMER
369
370#ifdef FTIME
371#define uucpdelay(num,denom) ftimedelay(1000*num/denom)
572555ee
SL
372ftimedelay(n)
373{
374 static struct timeb loctime;
46b15d8a
RC
375 register i = loctime.millitm;
376
572555ee 377 ftime(&loctime);
46b15d8a
RC
378 while (abs((int)(loctime.millitm - i))<n) ftime(&loctime)
379 ;
572555ee
SL
380}
381#endif FTIME
382
383#ifdef BUSYLOOP
384#define uucpdelay(num,denom) busyloop(CPUSPEED*num/denom)
385#define CPUSPEED 1000000 /* VAX 780 is 1MIPS */
386#define DELAY(n) { register long N = (n); while (--N > 0); }
387busyloop(n)
46b15d8a 388{
572555ee 389 DELAY(n);
46b15d8a 390}
572555ee
SL
391#endif BUSYLOOP
392
393slowrite(fd, str)
394register char *str;
395{
46b15d8a 396 DEBUG(6, "slowrite ", CNULL);
572555ee
SL
397 while (*str) {
398 DEBUG(6, "%c", *str);
399 uucpdelay(1,10); /* delay 1/10 second */
400 write(fd, str, 1);
401 str++;
572555ee 402 }
46b15d8a 403 DEBUG(6, "\n", CNULL);
572555ee 404}
1a85e9d2
RC
405#endif VENTEL || NOVATION || DF112
406
407#ifdef DIALINOUT
408/* DIALIN/OUT CODE (WLS) */
409/*
410 * disable and reenable: allow a single line to be use for dialin/dialout
411 *
412 */
413
414char enbdev[16];
415
416disable(dev)
417register char *dev;
418{
419 register char *rdev;
420
421 /* strip off directory prefixes */
422 rdev = dev;
423 while (*rdev)
424 rdev++;
425 while (--rdev >= dev && *rdev != '/')
426 ;
427 rdev++;
428
429 if (enbdev[0]) {
430 if (strcmp(enbdev, rdev) == SAME)
431 return SUCCESS; /* already disabled */
432 delock(enbdev);
433 reenable(); /* else, reenable the old one */
434 }
435 DEBUG(4, "Disable %s\n", rdev);
436 if (enbcall("disable", rdev) == FAIL)
437 return FAIL;
438 logent(rdev, "DISABLED LOGIN");
439 strcpy(enbdev, rdev);
440 return SUCCESS;
441}
442
443reenable()
444{
445 if (enbdev[0] == NULL)
446 return;
447 DEBUG(4, "Reenable %s\n", enbdev);
448 (void) enbcall("enable", enbdev);
449 logent(enbdev, "REENABLED LOGIN");
450 enbdev[0] = '\0';
451}
452
453enbcall(type, dev)
454char *type, *dev;
455{
456 int pid;
457 register char *p;
458 int fildes[2];
459 int status;
460 FILE *fil;
461 char buf[80];
462
463 fflush(stderr);
464 fflush(stdout);
465 pipe(fildes);
466 if ((pid = fork()) == 0) {
467 DEBUG(4, DIALINOUT, CNULL);
468 DEBUG(4, " %s", type);
469 DEBUG(4, " %s\n", dev);
470 close(fildes[0]);
471 close(0); close(1); close(2);
472 open("/dev/null",0);
473 dup(fildes[1]); dup(fildes[1]);
474 setuid(geteuid()); /* for chown(uid()) in acu program */
475 execl(DIALINOUT, "acu", type, dev, 0);
476 exit(-1);
477 }
478 if (pid<0)
479 return FAIL;
480
481 close(fildes[1]);
482 fil = fdopen(fildes[0],"r");
483 if (fil!=NULL) {
c8a90aca 484#ifdef BSD4_2
1a85e9d2 485 setlinebuf(fil);
c8a90aca 486#endif BSD4_2
1a85e9d2
RC
487 while (fgets(buf, sizeof buf, fil) != NULL) {
488 p = buf + strlen(buf) - 1;
489 if (*p == '\n')
490 *p = '\0';
491 logent(buf,"ACUCNTRL:");
492 }
493 }
494 while(wait(&status) != pid)
495 ;
496 fclose(fil);
497 return status ? FAIL : SUCCESS;
498}
499#endif DIALINOUT