support new format of /etc/ttys (from rick@seismo)
[unix-history] / usr / src / usr.bin / uucp / uucico / condevs.c
... / ...
CommitLineData
1#ifndef lint
2static char sccsid[] = "@(#)condevs.c 5.11 (Berkeley) %G%";
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.
17 *
18 * Anyway, in conclusion, condevs.c is plagued with register variables
19 * that are used inside
20 * if (setjmp(...)) {
21 * ....
22 * }
23 *
24 * THE FIX: Don't declare variables to be register
25 */
26
27#include "condevs.h"
28
29struct condev condevs[] = {
30 { "DIR", "direct", diropn, nulldev, dircls },
31#ifdef DATAKIT
32 { "DK", "datakit", dkopn, nulldev, nulldev },
33#endif DATAKIT
34#ifdef PNET
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
43#ifdef MICOM
44 { "MICOM", "micom", micopn, nulldev, miccls },
45#endif MICOM
46#ifdef DN11
47 { "ACU", "dn11", Acuopn, dnopn, dncls },
48#endif DN11
49#ifdef HAYES
50 { "ACU", "hayes", Acuopn, hyspopn, hyscls },
51 { "ACU", "hayespulse", Acuopn, hyspopn, hyscls },
52 { "ACU", "hayestone", Acuopn, hystopn, hyscls },
53#endif HAYES
54#ifdef HAYESQ /* a version of hayes that doesn't use result codes */
55 { "ACU", "hayesq", Acuopn, hysqpopn, hysqcls },
56 { "ACU", "hayesqpulse", Acuopn, hysqpopn, hysqcls },
57 { "ACU", "hayesqtone", Acuopn, hysqtopn, hysqcls },
58#endif HAYESQ
59#ifdef NOVATION
60 { "ACU", "novation", Acuopn, novopn, novcls},
61#endif NOVATION
62#ifdef DF02
63 { "ACU", "DF02", Acuopn, df2opn, df2cls },
64#endif DF02
65#ifdef DF112
66 { "ACU", "DF112P", Acuopn, df12popn, df12cls },
67 { "ACU", "DF112T", Acuopn, df12topn, df12cls },
68#endif DF112
69#ifdef VENTEL
70 { "ACU", "ventel", Acuopn, ventopn, ventcls },
71#endif VENTEL
72#ifdef PENRIL
73 { "ACU", "penril", Acuopn, penopn, pencls },
74#endif PENRIL
75#ifdef VADIC
76 { "ACU", "vadic", Acuopn, vadopn, vadcls },
77#endif VADIC
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
89#ifdef RVMACS
90 { "ACU", "rvmacs", Acuopn, rvmacsopn, rvmacscls },
91#endif RVMACS
92#ifdef VMACS
93 { "ACU", "vmacs", Acuopn, vmacsopn, vmacscls },
94#endif VMACS
95#ifdef SYTEK
96 { "SYTEK", "sytek", sykopn, nulldev, sykcls },
97#endif SYTEK
98
99 /* Insert new entries before this line */
100 { NULL, NULL, NULL, NULL, NULL }
101};
102
103/*
104 * nulldev a null device (returns CF_DIAL)
105 */
106nulldev()
107{
108 return CF_DIAL;
109}
110
111/*
112 * nodev a null device (returns CF_NODEV)
113 */
114nodev()
115{
116 return CF_NODEV;
117}
118
119/*
120 * Generic devices look through L-devices and call the CU_open routines for
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
123 * right routine to call.
124 */
125
126/*
127 * diropn(flds) connect to hardware line
128 *
129 * return codes:
130 * > 0 - file number - ok
131 * FAIL - failed
132 */
133diropn(flds)
134register char *flds[];
135{
136 register int dcr, status;
137 struct Devices dev;
138 char dcname[20];
139 FILE *dfp;
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
148 dfp = fopen(DEVFILE, "r");
149 ASSERT(dfp != NULL, "CAN'T OPEN", DEVFILE, 0);
150 while ((status = rddev(dfp, &dev)) != FAIL) {
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
166 if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
167 continue;
168 if (strcmp(flds[F_PHONE], dev.D_line) != SAME)
169#endif !VMSDTR
170 continue;
171 if (mlock(dev.D_line) != FAIL)
172 break;
173 }
174 fclose(dfp);
175 if (status == FAIL) {
176 logent("DEVICE", "NO");
177 return CF_NODEV;
178 }
179
180 sprintf(dcname, "/dev/%s", dev.D_line);
181 if (setjmp(Sjbuf)) {
182 delock(dev.D_line);
183 return CF_DIAL;
184 }
185 signal(SIGALRM, alarmtr);
186 alarm(10);
187 getnextfd();
188 errno = 0;
189 DEBUG(4,"Opening %s",dcname);
190 dcr = open(dcname, 2); /* read/write */
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
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);
218 return CF_DIAL;
219 }
220 fflush(stdout);
221 if (fixline(dcr, dev.D_speed) == FAIL)
222 return CF_DIAL;
223 strcpy(devSel, dev.D_line); /* for latter unlock */
224 CU_end = dircls;
225 return dcr;
226}
227
228dircls(fd)
229register int fd;
230{
231 if (fd > 0) {
232 close(fd);
233 delock(devSel);
234 }
235}
236
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.
240 *
241 * return codes: >0 - file number - o.k.
242 * FAIL - failed
243 */
244char devSel[20]; /* used for later unlock() */
245
246Acuopn(flds)
247register char *flds[];
248{
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 char nobrand[MAXPH];
256
257 exphone(flds[F_PHONE], phone);
258 devSel[0] = '\0';
259 nobrand[0] = '\0';
260 DEBUG(4, "Dialing %s\n", phone);
261 dfp = fopen(DEVFILE, "r");
262 ASSERT(dfp != NULL, "Can't open", DEVFILE, 0);
263
264 acustatus = 0; /* none found, none locked */
265 for(cd = condevs; cd->CU_meth != NULL; cd++) {
266 if (snccmp(flds[F_LINE], cd->CU_meth) == SAME) {
267 rewind(dfp);
268 while(rddev(dfp, &dev) != FAIL) {
269 /*
270 * for each ACU L.sys line, try at most twice
271 * (TRYCALLS) to establish carrier. The old way tried every
272 * available dialer, which on big sites takes forever!
273 * Sites with a single auto-dialer get one try.
274 * Sites with multiple dialers get a try on each of two
275 * different dialers.
276 * To try 'harder' to connect to a remote site,
277 * use multiple L.sys entries.
278 */
279 if (acustatus > TRYCALLS)
280 continue;
281 if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
282 continue;
283 if (snccmp(flds[F_LINE], dev.D_type) != SAME)
284 continue;
285 if (dev.D_brand[0] == '\0') {
286 logent("Acuopn","No 'brand' name on ACU");
287 continue;
288 }
289 if (snccmp(dev.D_brand, cd->CU_brand) != SAME) {
290 strncpy(nobrand, dev.D_brand, sizeof nobrand);
291 continue;
292 }
293
294 if (mlock(dev.D_line) == FAIL) {
295 acustatus++;
296 continue;
297 }
298 if (acustatus < 1)
299 acustatus = 1; /* has been found */
300#ifdef DIALINOUT
301#ifdef ALLACUINOUT
302 if (1) {
303#else !ALLACUINOUT
304 if (snccmp("inout", dev.D_calldev) == SAME) {
305#endif !ALLACUINOUT
306 if (disable(dev.D_line) == FAIL) {
307 delock(dev.D_line);
308 continue;
309 }
310 } else
311 reenable();
312#endif DIALINOUT
313
314 DEBUG(4, "Using %s\n", cd->CU_brand);
315 acustatus++;
316 fd = (*(cd->CU_open))(phone, flds, &dev);
317 if (fd > 0) {
318 CU_end = cd->CU_clos; /* point CU_end at close func */
319 fclose(dfp);
320 strcpy(devSel, dev.D_line); /* save for later unlock() */
321 return fd;
322 } else
323 delock(dev.D_line);
324 retval = CF_DIAL;
325 }
326 }
327 }
328 fclose(dfp);
329 if (acustatus == 0) {
330 if (nobrand[0])
331 logent(nobrand, "unsupported ACU type");
332 else
333 logent("L-devices", "No appropriate ACU");
334 }
335 if (acustatus == 1)
336 logent("DEVICE", "NO");
337 return retval;
338}
339
340#if defined(VENTEL) || defined(NOVATION) || defined(DF112)
341/*
342 * intervaldelay: delay execution for numerator/denominator seconds.
343 */
344
345#ifdef INTERVALTIMER
346#include <sys/time.h>
347#define uucpdelay(num,denom) intervaldelay(num,denom)
348intervaldelay(num,denom)
349int num, denom;
350{
351 struct timeval tv;
352 tv.tv_sec = num / denom;
353 tv.tv_usec = (num * 1000000L / denom ) % 1000000L;
354 (void) select (0, (int *)0, (int *)0, (int *)0, &tv);
355}
356#endif INTERVALTIMER
357
358#ifdef FASTTIMER
359#define uucpdelay(num,denom) nap(60*num/denom)
360/* Sleep in increments of 60ths of second. */
361nap (time)
362register int time;
363{
364 static int fd;
365
366 if (fd == 0)
367 fd = open (FASTTIMER, 0);
368
369 read (fd, 0, time);
370}
371#endif FASTTIMER
372
373#ifdef FTIME
374#define uucpdelay(num,denom) ftimedelay(1000*num/denom)
375ftimedelay(n)
376{
377 static struct timeb loctime;
378 register i = loctime.millitm;
379
380 ftime(&loctime);
381 while (abs((int)(loctime.millitm - i))<n) ftime(&loctime)
382 ;
383}
384#endif FTIME
385
386#ifdef BUSYLOOP
387#define uucpdelay(num,denom) busyloop(CPUSPEED*num/denom)
388#define CPUSPEED 1000000 /* VAX 780 is 1MIPS */
389#define DELAY(n) { register long N = (n); while (--N > 0); }
390busyloop(n)
391{
392 DELAY(n);
393}
394#endif BUSYLOOP
395
396slowrite(fd, str)
397register char *str;
398{
399 DEBUG(6, "slowrite ", CNULL);
400 while (*str) {
401 DEBUG(6, "%c", *str);
402 uucpdelay(1,10); /* delay 1/10 second */
403 write(fd, str, 1);
404 str++;
405 }
406 DEBUG(6, "\n", CNULL);
407}
408#endif VENTEL || NOVATION || DF112
409
410#ifdef DIALINOUT
411/* DIALIN/OUT CODE (WLS) */
412/*
413 * disable and reenable: allow a single line to be use for dialin/dialout
414 *
415 */
416
417char enbdev[16];
418
419disable(dev)
420register char *dev;
421{
422 register char *rdev;
423
424 /* strip off directory prefixes */
425 rdev = dev;
426 while (*rdev)
427 rdev++;
428 while (--rdev >= dev && *rdev != '/')
429 ;
430 rdev++;
431
432 if (enbdev[0]) {
433 if (strcmp(enbdev, rdev) == SAME)
434 return SUCCESS; /* already disabled */
435 delock(enbdev);
436 reenable(); /* else, reenable the old one */
437 }
438 DEBUG(4, "Disable %s\n", rdev);
439 if (enbcall("disable", rdev) == FAIL)
440 return FAIL;
441 logent(rdev, "DISABLED LOGIN");
442 strcpy(enbdev, rdev);
443 return SUCCESS;
444}
445
446reenable()
447{
448 if (enbdev[0] == '\0')
449 return;
450 DEBUG(4, "Reenable %s\n", enbdev);
451 (void) enbcall("enable", enbdev);
452 logent(enbdev, "REENABLED LOGIN");
453 enbdev[0] = '\0';
454}
455
456enbcall(type, dev)
457char *type, *dev;
458{
459 int pid;
460 register char *p;
461 int fildes[2];
462 int status;
463 FILE *fil;
464 char buf[80];
465
466 fflush(stderr);
467 fflush(stdout);
468 pipe(fildes);
469 if ((pid = fork()) == 0) {
470 DEBUG(4, DIALINOUT, CNULL);
471 DEBUG(4, " %s", type);
472 DEBUG(4, " %s\n", dev);
473 close(fildes[0]);
474 close(0); close(1); close(2);
475 open("/dev/null",0);
476 dup(fildes[1]); dup(fildes[1]);
477 setuid(geteuid()); /* for chown(uid()) in acu program */
478 execl(DIALINOUT, "acu", type, dev, 0);
479 exit(-1);
480 }
481 if (pid<0)
482 return FAIL;
483
484 close(fildes[1]);
485 fil = fdopen(fildes[0],"r");
486 if (fil!=NULL) {
487#ifdef BSD4_2
488 setlinebuf(fil);
489#endif BSD4_2
490 while (fgets(buf, sizeof buf, fil) != NULL) {
491 p = buf + strlen(buf) - 1;
492 if (*p == '\n')
493 *p = '\0';
494 logent(buf,"ACUCNTRL:");
495 }
496 }
497 while(wait(&status) != pid)
498 ;
499 fclose(fil);
500 return status ? FAIL : SUCCESS;
501}
502#endif DIALINOUT