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