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
57GLOBAL unsigned int	dk_timewait = DK_DEFWAIT; /* Caller to dkdial might modify */
58
59static char	Conn_Msg[] = "Can't connect to %s: %s\n";
60static char	Resp_Msg[] = "No response from Datakit";
61
62static SIGRTN	timout();	/* Alarm signal handler */
63static void	setalarm(), usralarm();
64EXTERN int	dkndial();
65static int	Elapsed;	/* Alarm time elapsed during dial */
66static int	Timer;		/* Current alarm setting */
67static short	TimeErr;	/* Alarm clock rang */
68
69extern char	*getenv();
70EXTERN int	dk_verbose, dk_errno;
71
72GLOBAL int
73dkdial(dest)
74	char *dest;
75{
76	return(dkndial(dest, atoi(getenv("DKINTF"))));
77}
78
79GLOBAL int
80dkndial(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 */
172static SIGRTN
173timout(arg)
174int 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
184static void
185setalarm(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
197static void
198usralarm(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