xref: /illumos-gate/usr/src/cmd/bnu/dkdial.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1994 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /*
34  *	create a Datakit connection to a remote destination
35  */
36 #ifndef DIAL
37 	static char	SCCSID[] = "@(#)dkdial.c	2.7+BNU DKHOST 87/03/09";
38 #endif
39 /*
40  *	COMMKIT(TM) Software - Datakit(R) VCS Interface Release 2.0 V1
41  */
42 
43 #include <fcntl.h>
44 #include "dk.h"
45 #include <stdio.h>
46 #include <signal.h>
47 #define	SIGRTN	void
48 #include <setjmp.h>
49 #include <sysexits.h>
50 #include <errno.h>
51 
52 
53 #define DK_DEFWAIT	89	/* default time to wait for dial return */
54 #define	DK_MAXWAIT	600	/* maximum wait to allow the caller - 10 min */
55 
56 
57 GLOBAL unsigned int	dk_timewait = DK_DEFWAIT; /* Caller to dkdial might modify */
58 
59 static char	Conn_Msg[] = "Can't connect to %s: %s\n";
60 static char	Resp_Msg[] = "No response from Datakit";
61 
62 static SIGRTN	timout();	/* Alarm signal handler */
63 static void	setalarm(), usralarm();
64 EXTERN int	dkndial();
65 static int	Elapsed;	/* Alarm time elapsed during dial */
66 static int	Timer;		/* Current alarm setting */
67 static short	TimeErr;	/* Alarm clock rang */
68 
69 extern char	*getenv();
70 EXTERN int	dk_verbose, dk_errno;
71 
72 GLOBAL int
73 dkdial(dest)
74 	char *dest;
75 {
76 	return(dkndial(dest, atoi(getenv("DKINTF"))));
77 }
78 
79 GLOBAL int
80 dkndial(dest, intf)
81 	char *dest;
82 {
83 	short		fd;		/* Channel Descriptor	*/
84 	SIGRTN		(*SigWas)();	/* Caller's alarm handler */
85 	unsigned int	TimWas;		/* Caller's alarm clock */
86 	char		*key;
87 	struct diocdial {
88 			struct	diocreq iocb;
89 			char	dialstring[128];
90 		}	ioreq;
91 	char		dial_dev[32];
92 
93 
94 	sprintf(dial_dev, "/dev/dk/dial%d", intf);
95 
96 	/*
97 	** Clear our elapsed time and save caller's alarm stuff.
98 	*/
99 
100 	Timer = Elapsed = 0;
101 	SigWas = signal(SIGALRM, timout);
102 	TimWas = alarm(0);
103 
104 	/*
105 	** If requested timeout interval is unreasonable, use the default.
106 	*/
107 
108 	if ((dk_timewait == 0)  || (dk_timewait > DK_MAXWAIT))
109 		dk_timewait = DK_DEFWAIT;
110 
111 	/*
112 	** Do an alarm protected open of the dial device
113 	*/
114 
115 	setalarm(dk_timewait);
116 
117 	if ((fd = open(dial_dev, O_RDWR)) < 0) {
118 		setalarm(0);
119 		if (dk_verbose)
120 			fprintf(stderr, "dkdial: Can't open %s\n", dial_dev);
121 		usralarm(TimWas, SigWas);
122 		if (errno == EBUSY)
123 			return(dk_errno = -EX_TEMPFAIL);
124 		else
125 			return(dk_errno = -EX_OSFILE);
126 	}
127 
128 	/*
129 	** If the caller has a DKKEY, use it.
130 	*/
131 
132 	if((key = getenv("DKKEY")) != NULL && getuid() == geteuid())
133 		sprintf(ioreq.dialstring, "%s\n%s", dest, key);
134 	else
135 		strcpy(ioreq.dialstring, dest);
136 
137 	ioreq.iocb.req_traffic = 0;
138 	ioreq.iocb.req_1param = 0;
139 	ioreq.iocb.req_2param = 0;
140 
141 	/*
142 	** Try to dial the call.  If the alarm expires during the ioctl,
143 	** the ioctl will return in error.
144 	*/
145 
146 	if (ioctl(fd, DKIODIAL, &ioreq) < 0) {
147 		setalarm(0);
148 		if (dk_verbose)
149 		if (TimeErr)
150 			fprintf(stderr, Conn_Msg, Resp_Msg, ioreq.dialstring);
151 		else
152 			fprintf(stderr, Conn_Msg, ioreq.dialstring, dkerr(ioreq.iocb.req_error));
153 
154 		setalarm(2);		/* Don't wait forever on close */
155 		close(fd);
156 		usralarm(TimWas, SigWas);
157 		if (errno == EBUSY)
158 			return(-dkerrmap(dk_errno = -EX_TEMPFAIL));
159 		else
160 			return(-dkerrmap(dk_errno = ioreq.iocb.req_error));
161 	}
162 	usralarm(TimWas, SigWas);
163 	return (fd);
164 }
165 
166 /*
167 ** timout() is the alarm clock signal handling routine.  It is called
168 ** whenever the alarm clock expires during dial processing.
169 */
170 
171 /* ARGSUSED */
172 static SIGRTN
173 timout(arg)
174 int arg;
175 {
176 	TimeErr++;
177 }
178 
179 /*
180 ** setalarm() is called to request an alarm at a future time.  The residual
181 ** from the previous alarm (if any) is added to the elapsed time counter.
182 */
183 
184 static void
185 setalarm(Seconds)
186 {
187 	TimeErr = 0;
188 	(void) signal(SIGALRM, timout);
189 	Elapsed += Timer - alarm(Seconds);
190 	Timer = Seconds;
191 }
192 
193 /*
194 ** usralarm() is used to restore the alarm service for the caller.
195 */
196 
197 static void
198 usralarm(TimWas, SigWas)
199 	int		TimWas;		/* Caller's alarm clock */
200 	SIGRTN		(*SigWas)();	/* Caller's alarm handler */
201 {
202 	Elapsed += Timer - alarm(0);
203 	(void) signal(SIGALRM, SigWas);
204 	if (TimWas > 0) {
205 		TimWas -= Elapsed;
206 		if (TimWas < 2)
207 			TimWas = 2;
208 	}
209 	alarm(TimWas);
210 }
211