xref: /illumos-gate/usr/src/cmd/bnu/callers.c (revision 7f698155b6fd0ee137eb4a2e7c85f0915a94bfee)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 #include "uucp.h"
30 
31 #if defined(BSD4_2) || defined(ATTSVR4)
32 #include <netdb.h>
33 #include <netinet/in.h>
34 #include <sys/socket.h>
35 #endif
36 #ifdef UNET
37 #include  "UNET/unetio.h"
38 #include  "UNET/tcp.h"
39 #endif
40 
41 #include <libgen.h>
42 
43 EXTERN void alarmtr();
44 EXTERN jmp_buf Sjbuf;
45 EXTERN char *fdig();
46 EXTERN int interface();
47 EXTERN int fd_mklock(), fd_cklock(), chat(), getdialline();
48 EXTERN void fixline(), fd_rmlock();
49 static void translate();
50 static int gdial();
51 EXTERN int	Modemctrl;
52 EXTERN unsigned connecttime;
53 EXTERN int (*Setup)();
54 
55 /*
56  *	to add a new caller:
57  *	declare the function that knows how to call on the device,
58  *	add a line to the callers table giving the name of the device
59  *	(from Devices file) and the name of the function
60  *	add the function to the end of this file
61  */
62 
63 #ifdef DIAL801
64 EXTERN int	dial801();
65 EXTERN int	open801();
66 #endif
67 
68 #ifdef DATAKIT
69 EXTERN int	dkcall();
70 #endif /* DATAKIT */
71 
72 #ifdef V8
73 int	Dialout();
74 #endif
75 
76 #ifdef TCP
77 int	unetcall();
78 int	tcpcall();
79 #endif /* TCP */
80 
81 #ifdef SYTEK
82 int	sytcall();
83 #endif /* SYTEK */
84 
85 #ifdef TLI
86 EXTERN int	tlicall();
87 #endif /* TLI */
88 
89 static struct caller Caller[] = {
90 
91 #ifdef DIAL801
92 	{"801",		dial801},
93 	{"212",		dial801},
94 #endif /* DIAL801 */
95 
96 #ifdef V8
97 	{"Dialout",	Dialout},	/* ditto but using dialout(III) */
98 #endif
99 
100 #ifdef TCP
101 #if defined(BSD4_2) || defined(ATTSVR4)
102 	{"TCP",		tcpcall},	/* 4.2BSD sockets */
103 #else /* !BSD4_2 */
104 #ifdef UNET
105 	{"TCP",		unetcall},	/* 3com implementation of tcp */
106 	{"Unetserver",	unetcall},
107 #endif /* UNET */
108 #endif /* BSD4_2 || ATTSVR4 */
109 #endif /* TCP */
110 
111 #ifdef DATAKIT
112 	{"DK",		dkcall},	/* standard AT&T DATAKIT VCS caller */
113 #endif /* DATAKIT */
114 
115 #ifdef SYTEK
116 	{"Sytek",	sytcall},	/* untested but should work */
117 #endif /* SYTEK */
118 
119 #ifdef TLI
120 	{"TLI",		tlicall},	/* AT&T Transport Layer Interface */
121 #ifdef TLIS
122 	{"TLIS",	tlicall},	/* AT&T Transport Layer Interface */
123 #endif /*  TLIS  */
124 #endif /* TLI */
125 
126 	{NULL, 		NULL}		/* this line must be last */
127 };
128 
129 /*
130  *	exphone - expand phone number for given prefix and number
131  *
132  *	return code - none
133  */
134 
135 static void
136 exphone(in, out)
137 char *in, *out;
138 {
139 	FILE *fn;
140 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
141 	char buf[BUFSIZ];
142 	char *s1;
143 
144 	if (!isalpha(*in)) {
145 		(void) strcpy(out, in);
146 		return;
147 	}
148 
149 	s1=pre;
150 	while (isalpha(*in))
151 		*s1++ = *in++;
152 	*s1 = NULLCHAR;
153 	s1 = npart;
154 	while (*in != NULLCHAR)
155 		*s1++ = *in++;
156 	*s1 = NULLCHAR;
157 
158 	tpre[0] = NULLCHAR;
159 	fn = fopen(DIALCODES, "r");
160 	if (fn != NULL) {
161 		while (fgets(buf, BUFSIZ, fn)) {
162 			if ( sscanf(buf, "%s%s", p, tpre) < 1)
163 				continue;
164 			if (EQUALS(p, pre))
165 				break;
166 			tpre[0] = NULLCHAR;
167 		}
168 		fclose(fn);
169 	}
170 
171 	(void) strcpy(out, tpre);
172 	(void) strcat(out, npart);
173 	return;
174 }
175 
176 /*
177  * repphone - Replace \D and \T sequences in arg with phone
178  * expanding and translating as appropriate.
179  */
180 static char *
181 repphone(arg, phone, trstr)
182 char *arg, *phone, *trstr;
183 {
184 	static char pbuf[2*(MAXPH+2)];
185 	char *fp, *tp;
186 
187 	for (tp=pbuf; *arg; arg++) {
188 		if (*arg != '\\') {
189 			*tp++ = *arg;
190 			continue;
191 		} else {
192 			switch (*(arg+1)) {
193 			case 'T':
194 				exphone(phone, tp);
195 				translate(trstr, tp);
196 				for(; *tp; tp++)
197 				    ;
198 				arg++;
199 				break;
200 			case 'D':
201 				for(fp=phone; *tp = *fp++; tp++)
202 				    ;
203 				arg++;
204 				break;
205 			default:
206 				*tp++ = *arg;
207 				break;
208 			}
209 		}
210 	}
211 	*tp = '\0';
212 	return(pbuf);
213 }
214 
215 static u_int saved_mode;
216 static char saved_dcname[20];
217 
218 /*
219  * processdev - Process a line from the Devices file
220  *
221  * return codes:
222  *	file descriptor  -  succeeded
223  *	FAIL  -  failed
224  */
225 GLOBAL int
226 processdev(flds, dev)
227 char *flds[], *dev[];
228 {
229 	int dcf = -1;
230 	struct caller	*ca;
231 	char *args[D_MAX+1], dcname[20];
232 	char **sdev;
233 	EXTERN int pop_push();
234 	EXTERN void  setdevcfg();
235 	int nullfd;
236 	char *phonecl;			/* clear phone string */
237 	char phoneex[2*(MAXPH+2)];	/* expanded phone string */
238 	EXTERN void ttygenbrk();
239 	struct termio tty_orig;
240 	int ret_orig = -1;
241 
242 	sdev = dev;
243 	/*	set up default "break" routine	*/
244 	genbrk = ttygenbrk;
245 
246 	/*	initialize Devconfig info	*/
247 	DEBUG(5, "processdev: calling setdevcfg(%s, ", Progname);
248 	DEBUG(5, "%s)\n", flds[F_TYPE]);
249 	setdevcfg(Progname, flds[F_TYPE]);
250 
251 	for (ca = Caller; ca->CA_type != NULL; ca++) {
252 		/* This will find built-in caller functions */
253 		if (EQUALS(ca->CA_type, dev[D_CALLER])) {
254 			DEBUG(5, "Internal caller type %s\n", dev[D_CALLER]);
255 			if (dev[D_ARG] == NULL) {
256 				/* if NULL - assume translate */
257 				dev[D_ARG+1] = NULL;	/* needed for for loop later to mark the end */
258 				dev[D_ARG] = "\\T";
259 			}
260 			dev[D_ARG] = repphone(dev[D_ARG], flds[F_PHONE], "");
261 			if ((dcf = (*(ca->CA_caller))(flds, dev)) < 0)
262 				return(dcf) ;
263 			if ( interface( ca->CA_type ) ) {
264 				DEBUG(5, "interface(%s) failed", ca->CA_type);
265 				Uerror = SS_DEVICE_FAILED;
266 				/*	restore vanilla unix interface	*/
267 				(void)interface("UNIX");
268 				return(FAIL);
269 			}
270 			dev += 2; /* Skip to next CALLER and ARG */
271 			break;
272 		}
273 	}
274 	if (dcf == -1) {
275 		/* Here if not a built-in caller function */
276 
277 		/* We do locking (file and advisory) after open	*/
278 
279 		/*
280 		 * Open the line
281 		 */
282 		if ( *dev[D_LINE] != '/' ) {
283 			(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
284 		} else {
285 			(void) strcpy(dcname, dev[D_LINE] );
286 		}
287 		/* take care of the possible partial open fd */
288 		(void) close(nullfd = open("/", O_RDONLY));
289 		if (setjmp(Sjbuf)) {
290 			(void) close(nullfd);
291 			DEBUG(1, "generic open timeout\n%s", "");
292 			logent("generic open", "TIMEOUT");
293 			Uerror = SS_CANT_ACCESS_DEVICE;
294 			goto bad;
295 		}
296 		(void) signal(SIGALRM, alarmtr);
297 		(void) alarm(10);
298 		if ( Modemctrl ) {
299 			DEBUG(7, "opening with O_NDELAY set\n%s", "");
300 			dcf = open(dcname, (O_RDWR | O_NDELAY) );
301 			saved_mode = O_RDWR | O_NDELAY;
302 		} else {
303 			dcf = open(dcname, O_RDWR );
304 			saved_mode = O_RDWR;
305 		}
306 		strcpy(saved_dcname, dcname);
307 		(void) alarm(0);
308 		if (dcf < 0) {
309 			DEBUG(1, "generic open failed, errno = %d\n", errno);
310 			(void) close(nullfd);
311 			logent("generic open", "FAILED");
312 			Uerror = SS_CANT_ACCESS_DEVICE;
313 			goto bad;
314 		}
315 
316 		/* check locks BEFORE modifying the stream */
317 
318 		if ( fd_mklock(dcf) != SUCCESS ) {
319 			DEBUG(1, "failed to lock device %s\n", dcname);
320 			Uerror = SS_LOCKED_DEVICE;
321 			goto bad;
322 		}
323 
324 		if ( Modemctrl ) {
325 			DEBUG(7, "clear O_NDELAY\n%s", "");
326 			if ( fcntl(dcf, F_SETFL,
327 				(fcntl(dcf, F_GETFL, 0) & ~O_NDELAY)) < 0 ) {
328 				DEBUG( 7, "clear O_NDELAY failed, errno %d\n", errno);
329 				Uerror = SS_DEVICE_FAILED;
330 				goto bad;
331 			}
332 		}
333 	}
334 
335 	if ( (*Setup)( MASTER, &dcf, &dcf ) ) {
336 		/*	any device|system lock files we should remove?	*/
337 		DEBUG(5, "MASTER Setup failed%s", "");
338 		Uerror = SS_DEVICE_FAILED;
339 		goto bad;
340 	}
341 
342 	/* configure any requested streams modules */
343 	if ( !pop_push(dcf) ) {
344 		DEBUG(5, "STREAMS module configuration failed%s\n","");
345 		Uerror = SS_DEVICE_FAILED;
346 		goto bad;
347 	}
348 
349 	/* save initial state of line in case script fails */
350 	ret_orig = ioctl(dcf, TCGETA, &tty_orig);
351 
352 	/* use sdev[] since dev[] is incremented for internal callers */
353 	fixline(dcf, atoi(fdig(sdev[D_CLASS])), D_DIRECT);
354 
355 	/*
356 	 * Now loop through the remaining callers and chat
357 	 * according to scripts in dialers file.
358 	 */
359 	for (; dev[D_CALLER] != NULL; dev += 2) {
360 		int w;
361 		/*
362 		 * Scan Dialers file to find an entry
363 		 */
364 		if ((w = gdial(dev[D_CALLER], args, D_MAX)) < 1) {
365 			logent("generic call to gdial", "FAILED");
366 			Uerror = SS_CANT_ACCESS_DEVICE;
367 			goto bad;
368 		}
369 		if (w <= 2)	/* do nothing - no chat */
370 			break;
371 		/*
372 		 * Translate the phone number
373 		 */
374 		if (dev[D_ARG] == NULL) {
375 			/* if NULL - assume no translation */
376 			dev[D_ARG+1] = NULL; /* needed for for loop to mark the end */
377 			dev[D_ARG] = "\\D";
378 		}
379 
380 		phonecl = repphone(dev[D_ARG], flds[F_PHONE], args[1]);
381 		exphone(phonecl, phoneex);
382 		translate(args[1], phoneex);
383 		/*
384 		 * Chat
385 		 */
386 		if (chat(w-2, &args[2], dcf, phonecl, phoneex) != SUCCESS) {
387 			CDEBUG(5, "\nCHAT gdial(%s) FAILED\n", dev[D_CALLER]);
388 			Uerror = SS_CHAT_FAILED;
389 			goto bad;
390 		}
391 	}
392 	/*
393 	 * Success at last!
394 	 */
395 	strcpy(Dc, sdev[D_LINE]);
396 	return(dcf);
397 bad:
398 	if ( dcf >= 0 ) {
399 		/* reset line settings if we got them in the beginning */
400 		if ( ret_orig == 0 )
401 			(void) ioctl(dcf, TCSETAW, &tty_orig);
402 		fd_rmlock(dcf);
403 		(void)close(dcf);
404 	}
405 	/*	restore vanilla unix interface	*/
406 	(void)interface("UNIX");
407 	return(FAIL);
408 }
409 
410 /*
411  * clear_hup()	clear the hangup state of the given device
412  */
413 GLOBAL int
414 clear_hup(dcf)
415 int dcf;
416 {
417 	int ndcf;
418 	if ((ndcf = open(saved_dcname, saved_mode)) < 0) {
419 		return (FAIL);
420 	}
421 	if (ndcf != dcf) {
422 		close(ndcf);
423 	}
424 	return (SUCCESS);
425 }
426 
427 
428 /*
429  * translate the pairs of characters present in the first
430  * string whenever the first of the pair appears in the second
431  * string.
432  */
433 static void
434 translate(ttab, str)
435 char *ttab, *str;
436 {
437 	char *s;
438 
439 	for(;*ttab && *(ttab+1); ttab += 2)
440 		for(s=str;*s;s++)
441 			if(*ttab == *s)
442 				*s = *(ttab+1);
443 	return;
444 }
445 
446 #define MAXLINE	512
447 /*
448  * Get the information about the dialer.
449  * gdial(type, arps, narps)
450  *	type	-> type of dialer (e.g., penril)
451  *	arps	-> array of pointers returned by gdial
452  *	narps	-> number of elements in array returned by gdial
453  * Return value:
454  *	-1	-> Can't open DIALERFILE
455  *	0	-> requested type not found
456  *	>0	-> success - number of fields filled in
457  */
458 static int
459 gdial(type, arps, narps)
460 char *type, *arps[];
461 int narps;
462 {
463 	static char info[MAXLINE];
464 	int na;
465 	EXTERN void dialreset();
466 	EXTERN char * currdial();
467 
468 	DEBUG(2, "gdial(%s) called\n", type);
469 	while (getdialline(info, sizeof(info))) {
470 		if ((info[0] == '#') || (info[0] == ' ') ||
471 		    (info[0] == '\t') || (info[0] == '\n'))
472 			continue;
473 		if ((na = getargs(info, arps, narps)) == 0)
474 			continue;
475 		if (EQUALS(arps[0], type)) {
476 		    DEBUG(5, "Trying caller script '%s'", type);
477 		    DEBUG(5, " from '%s'.\n", currdial());
478 		    dialreset();
479 		    bsfix(arps);
480 		    return(na);
481 		}
482 	}
483 	DEBUG(1, "%s not found in Dialers file\n", type);
484 	dialreset();
485 	return(0);
486 }
487 
488 
489 #ifdef DATAKIT
490 
491 /*
492  *	dkcall(flds, dev)	make a DATAKIT VCS connection
493  *				  DATAKIT VCS is a trademark of AT&T
494  *
495  *	return codes:
496  *		>0 - file number - ok
497  *		FAIL - failed
498  */
499 
500 #include "dk.h"
501 EXTERN int dkdial();
502 
503 /*ARGSUSED*/
504 GLOBAL int
505 dkcall(flds, dev)
506 char *flds[], *dev[];
507 {
508 	int fd;
509 #ifdef V8
510 	extern int cdkp_ld;
511 #endif
512 
513 	char	dialstring[64];
514 	EXTERN	void dkbreak();
515 
516 	strcpy(dialstring, dev[D_ARG]);
517 	DEBUG(4, "dkcall(%s)\n", dialstring);
518 
519 
520 #ifdef V8
521 	if (setjmp(Sjbuf)) {
522 		Uerror = SS_DIAL_FAILED;
523 		return(FAIL);
524 	}
525 
526 	(void) signal(SIGALRM, alarmtr);
527 	(void) alarm(connecttime);
528 	DEBUG(4, "tdkdial(%s", flds[F_PHONE]);
529 	DEBUG(4, ", %d)\n", atoi(dev[D_CLASS]));
530     	if ((fd = tdkdial(flds[F_PHONE], atoi(dev[D_CLASS]))) >= 0)
531 	    if (dkproto(fd, cdkp_ld) < 0)
532 	       {
533 	    	close(fd);
534 	    	fd = -1;
535 	       }
536 	(void) alarm(0);
537 #else
538 	fd = dkdial(dialstring);
539 #endif
540 
541 	(void) strcpy(Dc, "DK");
542 	if (fd < 0) {
543 		Uerror = SS_DIAL_FAILED;
544 		return(FAIL);
545 	}
546 	else {
547 		genbrk = dkbreak;
548 		return(fd);
549 	}
550 }
551 
552 #endif /* DATAKIT */
553 
554 #ifdef TCP
555 
556 /*
557  *	tcpcall(flds, dev)	make ethernet/socket connection
558  *
559  *	return codes:
560  *		>0 - file number - ok
561  *		FAIL - failed
562  */
563 
564 #if !(defined(BSD4_2) || defined(ATTSVR4))
565 /*ARGSUSED*/
566 GLOBAL int
567 tcpcall(flds, dev)
568 char	*flds[], *dev[];
569 {
570 	Uerror = SS_NO_DEVICE;
571 	return(FAIL);
572 }
573 #else /* BSD4_2 */
574 /*ARGSUSED*/
575 GLOBAL int
576 tcpcall(flds, dev)
577 char *flds[], *dev[];
578 {
579 	int ret;
580 	short port;
581 	struct servent *sp;
582 	struct hostent *hp;
583 	struct sockaddr_in sin;
584 
585 	if (EQUALS(flds[F_CLASS], "-")) {
586 		/*
587 		 * Use standard UUCP port number.
588 		 */
589 		sp = getservbyname("uucp", "tcp");
590 		endservent();
591 		ASSERT(sp != NULL, "No uucp service number", 0, 0);
592 		port = sp->s_port;
593 	} else {
594 		/*
595 		 * Systems file specifies a port number.
596 		 */
597 		sp = getservbyname(flds[F_CLASS], "tcp");
598 		endservent();
599 		if (sp == NULL) {
600 			port = htons(atoi(flds[F_CLASS]));
601 			if (port == 0) {
602 				logent("tcpopen", "unknown port number");
603 				Uerror = SS_NO_DEVICE;
604 				return(FAIL);
605 			}
606 		} else
607 			port = sp->s_port;
608 	}
609 	if (EQUALS(flds[F_PHONE], "-")) {
610 		/*
611 		 * Use UUCP name as host name.
612 		 */
613 		hp = gethostbyname(flds[F_NAME]);
614 	} else {
615 		/*
616 		 * Systems file specifies a host name different from the UUCP
617 		 * host name.
618 		 */
619 		hp = gethostbyname(flds[F_PHONE]);
620 	}
621 	endhostent();
622 	if (hp == NULL) {
623 		logent("tcpopen", "no such host");
624 		Uerror = SS_NO_DEVICE;
625 		return(FAIL);
626 	}
627 	DEBUG(4, "tcpdial host %s, ", hp->h_name);
628 	DEBUG(4, "port %d\n", ntohs(port));
629 
630 	ret = socket(AF_INET, SOCK_STREAM, 0);
631 	if (ret < 0) {
632 		DEBUG(5, "no socket: %s\n", strerror(errno));
633 		logent("no socket", strerror(errno));
634 		Uerror = SS_NO_DEVICE;
635 		return(FAIL);
636 	}
637 	sin.sin_family = hp->h_addrtype;
638 #ifdef BSD4_2
639 	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
640 #else
641 	memcpy((caddr_t)&sin.sin_addr, hp->h_addr, hp->h_length);
642 #endif
643 	sin.sin_port = port;
644 	if (setjmp(Sjbuf)) {
645 		DEBUG(4, "timeout tcpopen\n%s", "");
646 		logent("tcpopen", "TIMEOUT");
647 		Uerror = SS_NO_DEVICE;
648 		return(FAIL);
649 	}
650 	(void) signal(SIGALRM, alarmtr);
651 	(void) alarm(connecttime);
652 	DEBUG(7, "family: %d\n", sin.sin_family);
653 	DEBUG(7, "port: %d\n", sin.sin_port);
654 	DEBUG(7, "addr: %08x\n",*((int *) &sin.sin_addr));
655 	if (connect(ret, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
656 		(void) alarm(0);
657 		(void) close(ret);
658 		DEBUG(5, "connect failed: %s\n", strerror(errno));
659 		logent("connect failed", strerror(errno));
660 		Uerror = SS_NO_DEVICE;
661 		return(FAIL);
662 	}
663 	(void) signal(SIGPIPE, SIG_IGN);  /* watch out for broken ipc link...*/
664 	(void) alarm(0);
665 	(void) strcpy(Dc, "IPC");
666 	return(ret);
667 }
668 
669 #endif /* BSD4_2 */
670 
671 /*
672  *	unetcall(flds, dev)	make ethernet connection
673  *
674  *	return codes:
675  *		>0 - file number - ok
676  *		FAIL - failed
677  */
678 
679 #ifndef UNET
680 /*ARGSUSED*/
681 GLOBAL int
682 unetcall(flds, dev)
683 char	*flds[], *dev[];
684 {
685 	Uerror = SS_NO_DEVICE;
686 	return(FAIL);
687 }
688 #else /* UNET */
689 GLOBAL int
690 unetcall(flds, dev)
691 char *flds[], *dev[];
692 {
693 	int ret;
694 	int port;
695 
696 	port = atoi(dev[D_ARG]);
697 	DEBUG(4, "unetdial host %s, ", flds[F_PHONE]);
698 	DEBUG(4, "port %d\n", port);
699 	(void) alarm(connecttime);
700 	ret = tcpopen(flds[F_PHONE], port, 0, TO_ACTIVE, "rw");
701 	(void) alarm(0);
702 	endhnent();
703 	if (ret < 0) {
704 		DEBUG(5, "tcpopen failed: errno %d\n", errno);
705 		Uerror = SS_DIAL_FAILED;
706 		return(FAIL);
707 	}
708 	(void) strcpy(Dc, "UNET");
709 	return(ret);
710 }
711 #endif /* UNET */
712 
713 #endif /* TCP */
714 
715 #ifdef SYTEK
716 
717 /*
718  *	sytcall(flds, dev)	make a sytek connection
719  *
720  *	return codes:
721  *		>0 - file number - ok
722  *		FAIL - failed
723  */
724 
725 /*ARGSUSED*/
726 GLOBAL int
727 sytcall(flds, dev)
728 char *flds[], *dev[];
729 {
730 	int dcr, dcr2, nullfd, ret;
731 	char dcname[20], command[BUFSIZ];
732 
733 	(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
734 	DEBUG(4, "dc - %s, ", dcname);
735 	dcr = open(dcname, O_WRONLY|O_NDELAY);
736 	if (dcr < 0) {
737 		Uerror = SS_DIAL_FAILED;
738 		DEBUG(4, "OPEN FAILED %s\n", dcname);
739 		return(FAIL);
740 	}
741 	if ( fd_mklock(dcr) != SUCCESS ) {
742 		(void)close(dcr);
743 		DEBUG(1, "failed to lock device %s\n", dcname);
744 		Uerror = SS_LOCKED_DEVICE;
745 		return(FAIL);
746 	}
747 
748 	sytfixline(dcr, atoi(fdig(dev[D_CLASS])), D_DIRECT);
749 	(void) sleep(2);
750 	DEBUG(4, "Calling Sytek unit %s\n", dev[D_ARG]);
751 	(void) sprintf(command,"\r\rcall %s\r", dev[D_ARG]);
752 	ret = (*Write)(dcr, command, strlen(command));
753 	(void) sleep(1);
754 	DEBUG(4, "COM1 return = %d\n", ret);
755 	sytfix2line(dcr);
756 	(void) close(nullfd = open("/", O_RDONLY));
757 	(void) signal(SIGALRM, alarmtr);
758 	if (setjmp(Sjbuf)) {
759 		DEBUG(4, "timeout sytek open\n%s", "");
760 		(void) close(nullfd);
761 		(void) close(dcr2);
762 		fd_rmlock(dcr);
763 		(void) close(dcr);
764 		Uerror = SS_DIAL_FAILED;
765 		return(FAIL);
766 	}
767 	(void) alarm(10);
768 	dcr2 = open(dcname,O_RDWR);
769 	(void) alarm(0);
770 	fd_rmlock(dcr);
771 	(void) close(dcr);
772 	if (dcr2 < 0) {
773 		DEBUG(4, "OPEN 2 FAILED %s\n", dcname);
774 		Uerror = SS_DIAL_FAILED;
775 		(void) close(nullfd);	/* kernel might think dc2 is open */
776 		return(FAIL);
777 	}
778 	if ( fd_mklock(dcr2) != SUCCESS ) {
779 		(void)close(dcr2);
780 		DEBUG(1, "failed to lock device %s\n", dcname);
781 		Uerror = SS_LOCKED_DEVICE;
782 		return(FAIL);
783 	return(dcr2);
784 }
785 
786 #endif /* SYTEK */
787 
788 #ifdef DIAL801
789 
790 /*
791  *	dial801(flds, dev)	dial remote machine on 801/801
792  *	char *flds[], *dev[];
793  *
794  *	return codes:
795  *		file descriptor  -  succeeded
796  *		FAIL  -  failed
797  *
798  *	unfortunately, open801() is different for usg and non-usg
799  */
800 
801 /*ARGSUSED*/
802 GLOBAL int
803 dial801(flds, dev)
804 char *flds[], *dev[];
805 {
806 	char dcname[20], dnname[20], phone[MAXPH+2];
807 	int dcf = -1, speed;
808 
809 	(void) sprintf(dnname, "/dev/%s", dev[D_CALLDEV]);
810 	(void) sprintf(phone, "%s%s", dev[D_ARG]   , ACULAST);
811 	(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
812 	CDEBUG(1, "Use Port %s, ", dcname);
813 	DEBUG(4, "acu - %s, ", dnname);
814 	VERBOSE("Trying modem - %s, ", dcname);	/* for cu */
815 	VERBOSE("acu - %s, ", dnname);	/* for cu */
816 	if(getuid()==0 || GRPCHK(getgid())) {
817 		CDEBUG(1, "Phone Number  %s\n", phone);
818 		/* In cu, only give out the phone number to trusted people. */
819 		VERBOSE("calling  %s:  ", phone);	/* for cu */
820 	}
821 	speed = atoi(fdig(dev[D_CLASS]));
822 	dcf = open801(dcname, dnname, phone, speed);
823 	if (dcf >= 0) {
824 	        if ( fd_mklock(dcf) != SUCCESS ) {
825 			(void) close(dcf);
826 			DEBUG(5, "fd_mklock line %s failed\n", dev[D_LINE]);
827 			Uerror = SS_LOCKED_DEVICE;
828 			return(FAIL);
829 		}
830 		fixline(dcf, speed, D_ACU);
831 		(void) strcpy(Dc, dev[D_LINE]);	/* for later unlock() */
832 		VERBOSE("SUCCEEDED\n%s", "");
833 	} else {
834 		VERBOSE("FAILED\n%s", "");
835 	}
836 	return(dcf);
837 }
838 
839 
840 #ifndef ATTSV
841 /*ARGSUSED*/
842 GLOBAL int
843 open801(dcname, dnname, phone, speed)
844 char *dcname, *dnname, *phone;
845 {
846 	int nw, lt, dcf = -1, nullfd, dnf = -1;
847 	pid_t w_ret, pid = -1;
848 	unsigned timelim;
849 
850 	if ((dnf = open(dnname, O_WRONLY)) < 0) {
851 		DEBUG(5, "can't open %s\n", dnname);
852 		Uerror = SS_CANT_ACCESS_DEVICE;
853 		return(FAIL);
854 	}
855 	DEBUG(5, "%s is open\n", dnname);
856 
857 	(void) close(nullfd = open("/dev/null", O_RDONLY));/* partial open hack */
858 	if (setjmp(Sjbuf)) {
859 		DEBUG(4, "timeout modem open\n%s", "");
860 		(void) close(nullfd);
861 		(void) close(dcf);
862 		(void) close(dnf);
863 		logent("801 open", "TIMEOUT");
864 		if (pid > 0) {
865 			kill(pid, 9);
866 			wait((int *) 0);
867 		}
868 		Uerror = SS_DIAL_FAILED;
869 		return(FAIL);
870 	}
871 	(void) signal(SIGALRM, alarmtr);
872 	timelim = 5 * strlen(phone);
873 	(void) alarm(timelim < connecttime ? connecttime : timelim);
874 	if ((pid = fork()) == 0) {
875 		sleep(2);
876 		nw = (*Write)(dnf, phone, lt = strlen(phone));
877 		if (nw != lt) {
878 			DEBUG(4, "ACU write error %d\n", errno);
879 			logent("ACU write", "FAILED");
880 			exit(1);
881 		}
882 		DEBUG(4, "ACU write ok\n%s", "");
883 		exit(0);
884 	}
885 	/*  open line - will return on carrier */
886 	dcf = open(dcname, O_RDWR);
887 
888 	DEBUG(4, "dcf is %d\n", dcf);
889 	if (dcf < 0) {	/* handle like a timeout */
890 		(void) alarm(0);
891 		longjmp(Sjbuf, 1);
892 	}
893 
894 	/* modem is open */
895 	while ((w_ret = wait(&lt)) != pid)
896 		if (w_ret == -1 && errno != EINTR) {
897 			DEBUG(4, "Wait failed errno=%d\n", errno);
898 			(void) close(dcf);
899 			(void) close(dnf);
900 			Uerror = SS_DIAL_FAILED;
901 			return(FAIL);
902 		}
903 	(void) alarm(0);
904 
905 	(void) close(dnf);	/* no reason to keep the 801 open */
906 	if (lt != 0) {
907 		DEBUG(4, "Fork Stat %o\n", lt);
908 		(void) close(dcf);
909 		Uerror = SS_DIAL_FAILED;
910 		return(FAIL);
911 	}
912 	return(dcf);
913 }
914 
915 #else /* ATTSV */
916 
917 GLOBAL int
918 open801(dcname, dnname, phone, speed)
919 char *dcname, *dnname, *phone;
920 {
921 	int nw, lt, dcf = -1, nullfd, dnf = -1, ret;
922 	unsigned timelim;
923 
924 	(void) close(nullfd = open("/", O_RDONLY));	/* partial open hack */
925 	if (setjmp(Sjbuf)) {
926 		DEBUG(4, "DN write %s\n", "timeout");
927 		(void) close(dnf);
928 		(void) close(dcf);
929 		(void) close(nullfd);
930 		Uerror = SS_DIAL_FAILED;
931 		return(FAIL);
932 	}
933 	(void) signal(SIGALRM, alarmtr);
934 	timelim = 5 * strlen(phone);
935 	(void) alarm(timelim < connecttime ? connecttime : timelim);
936 
937 	if ((dnf = open(dnname, O_WRONLY)) < 0 ) {
938 		DEBUG(5, "can't open %s\n", dnname);
939 		Uerror = SS_CANT_ACCESS_DEVICE;
940 		return(FAIL);
941 	}
942 	DEBUG(5, "%s is open\n", dnname);
943 	if ( fd_mklock(dnf) != SUCCESS ) {
944 		(void)close(dnf);
945 		DEBUG(1, "failed to lock device %s\n", dnname);
946 		Uerror = SS_LOCKED_DEVICE;
947 	}
948 	if (  (dcf = open(dcname, O_RDWR | O_NDELAY)) < 0 ) {
949 		DEBUG(5, "can't open %s\n", dcname);
950 		Uerror = SS_CANT_ACCESS_DEVICE;
951 		return(FAIL);
952 	}
953 	if ( fd_mklock(dcf) != SUCCESS ) {
954 		(void)close(dcf);
955 		DEBUG(1, "failed to lock device %s\n", dcname);
956 		Uerror = SS_LOCKED_DEVICE;
957 		return(FAIL);
958 	}
959 
960 	DEBUG(4, "dcf is %d\n", dcf);
961 	fixline(dcf, speed, D_ACU);
962 	nw = (*Write)(dnf, phone, lt = strlen(phone));
963 	if (nw != lt) {
964 		(void) alarm(0);
965 		DEBUG(4, "ACU write error %d\n", errno);
966 		(void) close(dnf);
967 		(void) close(dcf);
968 		Uerror = SS_DIAL_FAILED;
969 		return(FAIL);
970 	} else
971 		DEBUG(4, "ACU write ok\n%s", "");
972 
973 	(void) close(dnf);
974 	(void) close(nullfd = open("/", O_RDONLY));	/* partial open hack */
975 	ret = open(dcname, O_RDWR);  /* wait for carrier  */
976 	(void) alarm(0);
977 	(void) close(ret);	/* close 2nd modem open() */
978 	if (ret < 0) {		/* open() interrupted by alarm */
979 		DEBUG(4, "Line open %s\n", "failed");
980 		Uerror = SS_DIAL_FAILED;
981 		(void) close(nullfd);		/* close partially opened modem */
982 		return(FAIL);
983 	}
984 	(void) fcntl(dcf,F_SETFL, fcntl(dcf, F_GETFL, 0) & ~O_NDELAY);
985 	return(dcf);
986 }
987 #endif /* ATTSV */
988 
989 #endif /* DIAL801 */
990 
991 #ifdef V8
992 GLOBAL int
993 Dialout(flds)
994 char *flds[];
995 {
996     int fd;
997     char phone[MAXPH+2];
998 
999     exphone(flds[F_PHONE], phone);
1000 
1001     DEBUG(4, "call dialout(%s", phone);
1002     DEBUG(4, ", %s)\n", dev[D_CLASS]);
1003     fd = dialout(phone, dev[D_CLASS]);
1004     if (fd == -1)
1005 	Uerror = SS_NO_DEVICE;
1006     if (fd == -3)
1007 	Uerror = SS_DIAL_FAILED;
1008     if (fd == -9)
1009 	Uerror = SS_DEVICE_FAILED;
1010 
1011     (void) strcpy(Dc, "Dialout");
1012 
1013     return(fd);
1014 }
1015 #endif /* V8 */
1016 
1017 #ifdef TLI
1018 /*
1019  *
1020  * AT&T Transport Layer Interface
1021  *
1022  * expected in Devices
1023  *	TLI line1 - - TLI
1024  * or
1025  *	TLIS line1 - - TLIS
1026  *
1027  */
1028 
1029 #include <sys/tiuser.h>
1030 
1031 EXTERN void tfaillog();
1032 
1033 char *t_alloc();
1034 int t_bind(), t_close(), t_connect(), t_free(), t_look(), t_open(), t_rcvdis();
1035 
1036 #define	CONNECT_ATTEMPTS	3
1037 #define	TFREE(p, type)	if ((p)) t_free((char *)(p), (type))
1038 
1039 /*
1040  * returns fd to remote uucp daemon
1041  */
1042 /*ARGSUSED*/
1043 GLOBAL int
1044 tlicall(flds, dev)
1045 char *flds[];
1046 char *dev[];
1047 {
1048 	char		addrbuf[ BUFSIZ ];
1049 	char		devname[MAXNAMESIZE];
1050 	int		fd;
1051 	int	i, j;
1052 	struct t_bind	*bind_ret = 0;
1053 	struct t_info	tinfo;
1054 	struct t_call	*sndcall = 0, *rcvcall = 0;
1055 	extern int	t_errno;
1056 
1057 	EXTERN struct netbuf	*stoa();
1058 
1059 	if ( dev[D_LINE][0] != '/' ) {
1060 		/*	dev holds device name relative to /dev	*/
1061 		sprintf(devname, "/dev/%s", dev[D_LINE]);
1062 	} else {
1063 		/*	dev holds full path name of device	*/
1064 		strcpy(devname, dev[D_LINE]);
1065 	}
1066 	/* gimme local transport endpoint */
1067 	errno = t_errno = 0;
1068 	if (setjmp(Sjbuf)) {
1069 		DEBUG(1, "t_open timeout\n%s", "");
1070 		logent("t_open", "TIMEOUT");
1071 		Uerror = SS_NO_DEVICE;
1072 		return(FAIL);
1073 	}
1074 	(void) signal(SIGALRM, alarmtr);
1075 	(void) alarm(5);
1076 	fd = t_open(devname, O_RDWR, &tinfo);
1077 	(void) alarm(0);
1078 	if (fd < 0) {
1079 		tfaillog(fd, "t_open" );
1080 		Uerror = SS_NO_DEVICE;
1081 		return(FAIL);
1082 	}
1083 	if ( fd_mklock(fd) != SUCCESS ) {
1084 		(void)t_close(fd);
1085 		DEBUG(1, "tlicall: failed to lock device %s\n", devname);
1086 		Uerror = SS_LOCKED_DEVICE;
1087 		return(FAIL);
1088 	}
1089 
1090 	/* allocate tli structures	*/
1091 	errno = t_errno = 0;
1092 	if ( (bind_ret = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL)) ==
1093 	    (struct t_bind *)NULL
1094 	|| (sndcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
1095 	    (struct t_call *)NULL
1096 	|| (rcvcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
1097 	    (struct t_call *)NULL ) {
1098 		tfaillog(fd, "t_alloc" );
1099 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1100 		TFREE(rcvcall, T_CALL);
1101 		Uerror = SS_NO_DEVICE;
1102 		return(FAIL);
1103 	}
1104 
1105 	/* bind */
1106 	errno = t_errno = 0;
1107 	if (t_bind(fd, (struct t_bind *) 0, bind_ret ) < 0) {
1108 		tfaillog(fd, "t_bind" );
1109 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1110 		TFREE(rcvcall, T_CALL);
1111 		Uerror = SS_NO_DEVICE;
1112 		fd_rmlock(fd);
1113 		(void) t_close(fd);
1114 		return(FAIL);
1115 	}
1116 	DEBUG(5, "tlicall: bound to %s\n", bind_ret->addr.buf);
1117 
1118 	/*
1119 	 * Prepare to connect.
1120 	 *
1121 	 * If address begins with "\x", "\X", "\o", or "\O",
1122 	 * assume is hexadecimal or octal address and use stoa()
1123 	 * to convert it.
1124 	 *
1125 	 * Else is usual uucico address -- only \N's left to process.
1126 	 * Walk thru connection address, changing \N's to NULLCHARs.
1127 	 * Note:  If a NULLCHAR must be part of the connection address,
1128 	 * it must be overtly included in the address.  One recommended
1129 	 * way is to do it in the Devices file, thusly:
1130 	 *		Netname /dev/netport - - TLI \D\000
1131 	 * bsfix() turns \000 into \N and then the loop below makes it a
1132 	 * real, included-in-the-length null-byte.
1133 	 *
1134 	 * The DEBUG must print the strecpy'd address (so that
1135 	 * non-printables will have been replaced with C escapes).
1136 	 */
1137 
1138 	DEBUG(5, "t_connect to addr \"%s\"\n",
1139 		strecpy( addrbuf, dev[D_ARG], "\\" ) );
1140 
1141 	if ( dev[D_ARG][0] == '\\' &&
1142 	( dev[D_ARG][1] == 'x' || dev[D_ARG][1] == 'X'
1143 	|| dev[D_ARG][1] == 'o' || dev[D_ARG][1] == 'O' ) ) {
1144 		if ( stoa(dev[D_ARG], &(sndcall->addr)) == (struct netbuf *)NULL ) {
1145 			DEBUG(5, "tlicall: stoa failed\n%s", "");
1146 			logent("tlicall", "string-to-address failed");
1147 			TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1148 			TFREE(rcvcall, T_CALL);
1149 			Uerror = SS_NO_DEVICE;
1150 			fd_rmlock(fd);
1151 			(void) t_close(fd);
1152 			return(FAIL);
1153 		}
1154 	} else {
1155 		for( i = j = 0; i < BUFSIZ && dev[D_ARG][i] != NULLCHAR;
1156 		++i, ++j ) {
1157 			if( dev[D_ARG][i] == '\\'  &&  dev[D_ARG][i+1] == 'N' ) {
1158 				addrbuf[j] = NULLCHAR;
1159 				++i;
1160 			}
1161 			else {
1162 				addrbuf[j] = dev[D_ARG][i];
1163 			}
1164 		}
1165 		sndcall->addr.buf = addrbuf;
1166 		sndcall->addr.len = j;
1167 	}
1168 
1169 	if (setjmp(Sjbuf)) {
1170 		DEBUG(4, "timeout tlicall\n%s", "");
1171 		logent("tlicall", "TIMEOUT");
1172 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1173 		TFREE(rcvcall, T_CALL);
1174 		Uerror = SS_NO_DEVICE;
1175 		fd_rmlock(fd);
1176 		(void) t_close(fd);
1177 		return(FAIL);
1178 	}
1179 	(void) signal(SIGALRM, alarmtr);
1180 	(void) alarm(connecttime);
1181 
1182 	/* connect to the service -- some listeners can't handle */
1183 	/* multiple connect requests, so try it a few times */
1184 	errno = t_errno = 0;
1185 	for ( i = 0; i < CONNECT_ATTEMPTS; ++i ) {
1186 		if (t_connect(fd, sndcall, rcvcall) == 0)
1187 			break;
1188 		if ( (t_errno == TLOOK) && (t_look(fd) == T_DISCONNECT)) {
1189 			t_rcvdis(fd,NULL);
1190 			(void) alarm(0);
1191 		} else {
1192 			(void) alarm(0);
1193 			tfaillog(fd, "t_connect");
1194 			TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1195 			TFREE(rcvcall, T_CALL);
1196 			Uerror = SS_DIAL_FAILED;
1197 			fd_rmlock(fd);
1198 			(void) t_close(fd);
1199 			return(FAIL);
1200 		}
1201 	}
1202 	(void) alarm(0);
1203 	TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1204 	TFREE(rcvcall, T_CALL);
1205 	if ( i == CONNECT_ATTEMPTS ) {
1206 		tfaillog(fd, "t_connect");
1207 		Uerror = SS_DIAL_FAILED;
1208 		fd_rmlock(fd);
1209 		(void) t_close(fd);
1210 		return(FAIL);
1211 	}
1212 	errno = t_errno = 0;
1213 	(void) strcpy(Dc, dev[D_CALLER]);
1214 	return(fd);
1215 }
1216 #endif /* TLI */
1217