callers.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "uucp.h"
#include <rpc/trace.h>
#ifdef BSD4_2
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#ifdef UNET
#include "UNET/unetio.h"
#include "UNET/tcp.h"
#endif
EXTERN void alarmtr();
EXTERN jmp_buf Sjbuf;
EXTERN char *fdig(), *strecpy();
EXTERN int interface();
EXTERN int fd_mklock(), fd_cklock(), chat(), getdialline();
EXTERN void fixline(), fd_rmlock();
static void translate();
static int gdial();
EXTERN int Modemctrl;
EXTERN unsigned connecttime;
EXTERN int (*Setup)();
extern int _fcntl(int, int, ...);
/*
* to add a new caller:
* declare the function that knows how to call on the device,
* add a line to the callers table giving the name of the device
* (from Devices file) and the name of the function
* add the function to the end of this file
*/
#ifdef DIAL801
EXTERN int dial801();
EXTERN int open801();
#endif
#ifdef DATAKIT
EXTERN int dkcall();
#endif /* DATAKIT */
#ifdef V8
int Dialout();
#endif
#ifdef TCP
GLOBAL int unetcall();
GLOBAL int tcpcall();
#endif /* TCP */
#ifdef SYTEK
int sytcall();
#endif /* SYTEK */
#ifdef TLI
EXTERN int tlicall();
#endif /* TLI */
static struct caller Caller[] = {
#ifdef DIAL801
{"801", dial801},
{"212", dial801},
#endif /* DIAL801 */
#ifdef V8
{"Dialout", Dialout}, /* ditto but using dialout(III) */
#endif
#ifdef TCP
#ifdef BSD4_2
{"TCP", tcpcall}, /* 4.2BSD sockets */
#else /* !BSD4_2 */
#ifdef UNET
{"TCP", unetcall}, /* 3com implementation of tcp */
{"Unetserver", unetcall},
#endif /* UNET */
#endif /* BSD4_2 */
#endif /* TCP */
#ifdef DATAKIT
{"DK", dkcall}, /* standard AT&T DATAKIT VCS caller */
#endif /* DATAKIT */
#ifdef SYTEK
{"Sytek", sytcall}, /* untested but should work */
#endif /* SYTEK */
#ifdef TLI
{"TLI", tlicall}, /* AT&T Transport Layer Interface */
#ifdef TLIS
{"TLIS", tlicall}, /* AT&T Transport Layer Interface */
#endif /* TLIS */
#endif /* TLI */
{NULL, NULL} /* this line must be last */
};
/*
* exphone - expand phone number for given prefix and number
*
* return code - none
*/
static void
exphone(in, out)
char *in, *out;
{
FILE *fn;
char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
char buf[BUFSIZ];
char *s1;
trace1(TR_exphone, 0);
if (!isalpha(*in)) {
(void) strcpy(out, in);
trace1(TR_exphone, 1);
return;
}
s1=pre;
while (isalpha(*in))
*s1++ = *in++;
*s1 = NULLCHAR;
s1 = npart;
while (*in != NULLCHAR)
*s1++ = *in++;
*s1 = NULLCHAR;
tpre[0] = NULLCHAR;
fn = fopen(DIALCODES, "r");
if (fn != NULL) {
while (fgets(buf, BUFSIZ, fn)) {
if (sscanf(buf, "%s%s", p, tpre) < 1)
continue;
if (EQUALS(p, pre))
break;
tpre[0] = NULLCHAR;
}
fclose(fn);
}
(void) strcpy(out, tpre);
(void) strcat(out, npart);
trace1(TR_exphone, 1);
return;
}
/*
* repphone - Replace \D and \T sequences in arg with phone
* expanding and translating as appropriate.
*/
static char *
repphone(arg, phone, trstr)
register char *arg, *phone, *trstr;
{
static char *pbuf; /* dynamically allocated below */
register char *fp, *tp;
trace1(TR_repphone, 0);
if (pbuf == NULL) {
pbuf = (char *)malloc(2*(MAXPH+2));
if (pbuf == NULL)
return (arg);
}
for (tp=pbuf; *arg; arg++) {
if (*arg != '\\') {
*tp++ = *arg;
continue;
} else {
switch (*(arg+1)) {
case 'T':
exphone(phone, tp);
translate(trstr, tp);
for (; *tp; tp++)
;
arg++;
break;
case 'D':
for (fp=phone; *tp = *fp++; tp++)
;
arg++;
break;
default:
*tp++ = *arg;
break;
}
}
}
*tp = '\0';
trace1(TR_repphone, 1);
return (pbuf);
}
static u_int saved_mode;
static char saved_dcname[20];
/*
* processdev - Process a line from the Devices file
*
* return codes:
* file descriptor - succeeded
* FAIL - failed
*/
GLOBAL int
processdev(flds, dev)
register char *flds[], *dev[];
{
int dcf = -1;
register struct caller *ca;
char *args[D_MAX+1], dcname[20];
register char **sdev;
EXTERN int pop_push();
EXTERN void setdevcfg();
int nullfd;
char *phonecl; /* clear phone string */
char phoneex[2*(MAXPH+2)]; /* expanded phone string */
EXTERN void ttygenbrk();
struct termio tty_orig;
int ret_orig = -1;
trace1(TR_processdev, 0);
sdev = dev;
/* set up default "break" routine */
genbrk = ttygenbrk;
/* initialize Devconfig info */
DEBUG(5, "processdev: calling setdevcfg(%s, ", Progname);
DEBUG(5, "%s)\n", flds[F_TYPE]);
setdevcfg(Progname, flds[F_TYPE]);
for (ca = Caller; ca->CA_type != NULL; ca++) {
/* This will find built-in caller functions */
if (EQUALS(ca->CA_type, dev[D_CALLER])) {
DEBUG(5, "Internal caller type %s\n", dev[D_CALLER]);
if (dev[D_ARG] == NULL) {
/* if NULL - assume translate */
dev[D_ARG+1] = NULL; /* needed for for loop later to mark the end */
dev[D_ARG] = "\\T";
}
dev[D_ARG] = repphone(dev[D_ARG], flds[F_PHONE], "");
if ((dcf = (*(ca->CA_caller))(flds, dev)) < 0) {
trace1(TR_processdev, 1);
return (dcf) ;
}
if (interface(ca->CA_type)) {
DEBUG(5, "interface(%s) failed", ca->CA_type);
Uerror = SS_DEVICE_FAILED;
/* restore vanilla unix interface */
(void)interface("UNIX");
trace1(TR_processdev, 1);
return (FAIL);
}
dev += 2; /* Skip to next CALLER and ARG */
break;
}
}
if (dcf == -1) {
/* Here if not a built-in caller function */
/* We do locking (file and advisory) after open */
/*
* Open the line
*/
if (*dev[D_LINE] != '/') {
(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
} else {
(void) strcpy(dcname, dev[D_LINE]);
}
/* take care of the possible partial open fd */
(void) close(nullfd = open("/", O_RDONLY));
if (setjmp(Sjbuf)) {
(void) close(nullfd);
DEBUG(1, "generic open timeout\n%s", "");
logent("generic open", "TIMEOUT");
Uerror = SS_CANT_ACCESS_DEVICE;
goto bad;
}
(void) signal(SIGALRM, alarmtr);
(void) alarm(10);
if (Modemctrl) {
DEBUG(7, "opening with O_NDELAY set\n%s", "");
dcf = open(dcname, (O_RDWR | O_NDELAY) );
saved_mode = O_RDWR | O_NDELAY;
} else {
dcf = open(dcname, O_RDWR );
saved_mode = O_RDWR;
}
strcpy(saved_dcname, dcname);
(void) alarm(0);
if (dcf < 0) {
DEBUG(1, "generic open failed, errno = %d\n", errno);
(void) close(nullfd);
logent("generic open", "FAILED");
Uerror = SS_CANT_ACCESS_DEVICE;
goto bad;
}
/* check locks BEFORE modifying the stream */
if (fd_mklock(dcf) != SUCCESS) {
DEBUG(1, "failed to lock device %s\n", dcname);
Uerror = SS_LOCKED_DEVICE;
goto bad;
}
if (Modemctrl) {
DEBUG(7, "clear O_NDELAY\n%s", "");
if (_fcntl(dcf, F_SETFL,
(_fcntl(dcf, F_GETFL, 0) & ~O_NDELAY)) < 0) {
DEBUG(7, "clear O_NDELAY failed, errno %d\n", errno);
Uerror = SS_DEVICE_FAILED;
goto bad;
}
}
}
if ((*Setup)(MASTER, &dcf, &dcf)) {
/* any device|system lock files we should remove? */
DEBUG(5, "MASTER Setup failed%s", "");
Uerror = SS_DEVICE_FAILED;
goto bad;
}
/* configure any requested streams modules */
if (!pop_push(dcf)) {
DEBUG(5, "STREAMS module configuration failed%s\n","");
Uerror = SS_DEVICE_FAILED;
goto bad;
}
/* save initial state of line in case script fails */
ret_orig = ioctl(dcf, TCGETA, &tty_orig);
/* use sdev[] since dev[] is incremented for internal callers */
fixline(dcf, atoi(fdig(sdev[D_CLASS])), D_DIRECT);
/*
* Now loop through the remaining callers and chat
* according to scripts in dialers file.
*/
for (; dev[D_CALLER] != NULL; dev += 2) {
register int w;
/*
* Scan Dialers file to find an entry
*/
if ((w = gdial(dev[D_CALLER], args, D_MAX)) < 1) {
logent("generic call to gdial", "FAILED");
Uerror = SS_CANT_ACCESS_DEVICE;
goto bad;
}
if (w <= 2) /* do nothing - no chat */
break;
/*
* Translate the phone number
*/
if (dev[D_ARG] == NULL) {
/* if NULL - assume no translation */
dev[D_ARG+1] = NULL; /* needed for for loop to mark the end */
dev[D_ARG] = "\\D";
}
phonecl = repphone(dev[D_ARG], flds[F_PHONE], args[1]);
exphone(phonecl, phoneex);
translate(args[1], phoneex);
/*
* Chat
*/
if (chat(w-2, &args[2], dcf, phonecl, phoneex) != SUCCESS) {
CDEBUG(5, "\nCHAT gdial(%s) FAILED\n", dev[D_CALLER]);
Uerror = SS_CHAT_FAILED;
goto bad;
}
}
/*
* Success at last!
*/
strcpy(Dc, sdev[D_LINE]);
trace1(TR_processdev, 1);
return (dcf);
bad:
if (dcf >= 0) {
/* reset line settings if we got them in the beginning */
if (ret_orig == 0)
(void) ioctl(dcf, TCSETAW, &tty_orig);
fd_rmlock(dcf);
(void)close(dcf);
}
/* restore vanilla unix interface */
(void)interface("UNIX");
trace1(TR_processdev, 1);
return (FAIL);
}
/*
* clear_hup() clear the hangup state of the given device
*/
GLOBAL int
clear_hup(dcf)
int dcf;
{
int ndcf;
if ((ndcf = open(saved_dcname, saved_mode)) < 0) {
return (FAIL);
}
if (ndcf != dcf) {
close(ndcf);
}
return (SUCCESS);
}
/*
* translate the pairs of characters present in the first
* string whenever the first of the pair appears in the second
* string.
*/
static void
translate(ttab, str)
register char *ttab, *str;
{
register char *s;
trace1(TR_translate, 0);
for (;*ttab && *(ttab+1); ttab += 2)
for (s=str;*s;s++)
if (*ttab == *s)
*s = *(ttab+1);
trace1(TR_translate, 1);
return;
}
#define MAXLINE 512
/*
* Get the information about the dialer.
* gdial(type, arps, narps)
* type -> type of dialer (e.g., penril)
* arps -> array of pointers returned by gdial
* narps -> number of elements in array returned by gdial
* Return value:
* -1 -> Can't open DIALERFILE
* 0 -> requested type not found
* >0 -> success - number of fields filled in
*/
static int
gdial(type, arps, narps)
register char *type, *arps[];
register int narps;
{
static char *info; /* dynamically allocated MAXLINE */
int na;
EXTERN void dialreset();
EXTERN char * currdial();
trace2(TR_gdial, 0, narps);
DEBUG(2, "gdial(%s) called\n", type);
if (info == NULL) {
info = (char *)malloc(MAXLINE);
if (info == NULL) {
DEBUG(1, "malloc failed for info in gdial\n", 0);
return (0);
}
}
while (getdialline(info, MAXLINE)) {
if ((info[0] == '#') || (info[0] == ' ') ||
(info[0] == '\t') || (info[0] == '\n'))
continue;
if ((na = getargs(info, arps, narps)) == 0)
continue;
if (EQUALS(arps[0], type)) {
DEBUG(5, "Trying caller script '%s'", type);
DEBUG(5, " from '%s'.\n", currdial());
dialreset();
bsfix(arps);
trace2(TR_gdial, 1, narps);
return (na);
}
}
DEBUG(1, "%s not found in Dialers file\n", type);
dialreset();
trace2(TR_gdial, 1, narps);
return (0);
}
#ifdef DATAKIT
/*
* dkcall(flds, dev) make a DATAKIT VCS connection
* DATAKIT VCS is a trademark of AT&T
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
#include "dk.h"
EXTERN int dkdial();
/*ARGSUSED*/
GLOBAL int
dkcall(flds, dev)
char *flds[], *dev[];
{
register fd;
#ifdef V8
extern int cdkp_ld;
#endif
char dialstring[64];
EXTERN void dkbreak();
trace1(TR_dkcall, 0);
strcpy(dialstring, dev[D_ARG]);
DEBUG(4, "dkcall(%s)\n", dialstring);
#ifdef V8
if (setjmp(Sjbuf)) {
Uerror = SS_DIAL_FAILED;
trace1(TR_dkcall, 1);
return (FAIL);
}
(void) signal(SIGALRM, alarmtr);
(void) alarm(connecttime);
DEBUG(4, "tdkdial(%s", flds[F_PHONE]);
DEBUG(4, ", %d)\n", atoi(dev[D_CLASS]));
if ((fd = tdkdial(flds[F_PHONE], atoi(dev[D_CLASS]))) >= 0)
if (dkproto(fd, cdkp_ld) < 0)
{
close(fd);
fd = -1;
}
(void) alarm(0);
#else
fd = dkdial(dialstring);
#endif
(void) strcpy(Dc, "DK");
if (fd < 0) {
Uerror = SS_DIAL_FAILED;
trace1(TR_dkcall, 1);
return (FAIL);
}
else {
genbrk = dkbreak;
trace1(TR_dkcall, 1);
return (fd);
}
}
#endif /* DATAKIT */
#ifdef TCP
/*
* tcpcall(flds, dev) make ethernet/socket connection
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
#ifndef BSD4_2
/*ARGSUSED*/
GLOBAL int
tcpcall(flds, dev)
char *flds[], *dev[];
{
trace1(TR_tcpcall, 0);
Uerror = SS_NO_DEVICE;
trace1(TR_tcpcall, 1);
return (FAIL);
}
#else /* BSD4_2 */
GLOBAL int
tcpcall(flds, dev)
char *flds[], *dev[];
{
int ret;
short port;
struct servent *sp;
struct hostent *hp;
struct sockaddr_in sin;
trace1(TR_tcpcall, 0);
port = atoi(dev[D_ARG]);
if (port == 0) {
sp = getservbyname("uucp", "tcp");
ASSERT(sp != NULL, "No uucp server", 0, 0);
port = sp->s_port;
}
else port = htons(port);
hp = gethostbyname(flds[F_NAME]);
if (hp == NULL) {
logent("tcpopen", "no such host");
Uerror = SS_NO_DEVICE;
trace1(TR_tcpcall, 1);
return (FAIL);
}
DEBUG(4, "tcpdial host %s, ", flds[F_NAME]);
DEBUG(4, "port %d\n", ntohs(port));
ret = socket(AF_INET, SOCK_STREAM, 0);
if (ret < 0) {
char *errstr;
if ((errstr = strerror(errno)) != (char *) NULL) {
DEBUG(5, "no socket: %s\n", errstr);
logent("no socket", errstr);
}
else {
DEBUG(5, "no socket, errno %d\n", errno);
logent("tcpopen", "NO SOCKET");
}
Uerror = SS_NO_DEVICE;
trace1(TR_tcpcall, 1);
return (FAIL);
}
sin.sin_family = hp->h_addrtype;
bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
sin.sin_port = port;
if (setjmp(Sjbuf)) {
DEBUG(4, "timeout tcpopen\n%s", "");
logent("tcpopen", "TIMEOUT");
Uerror = SS_NO_DEVICE;
trace1(TR_tcpcall, 1);
return (FAIL);
}
(void) signal(SIGALRM, alarmtr);
(void) alarm(connecttime);
DEBUG(7, "family: %d\n", sin.sin_family);
DEBUG(7, "port: %d\n", sin.sin_port);
DEBUG(7, "addr: %08x\n",*((int *) &sin.sin_addr));
if (connect(ret, (caddr_t)&sin, sizeof (sin)) < 0) {
char *errstr;
(void) alarm(0);
(void) close(ret);
if ((errstr = strerror(errno)) != (char *) NULL) {
DEBUG(5, "connect failed: %s\n", errstr);
logent("connect failed", errstr);
}
else {
DEBUG(5, "connect failed, errno %d\n", errno);
logent("tcpopen", "CONNECT FAILED");
}
Uerror = SS_NO_DEVICE;
trace1(TR_tcpcall, 1);
return (FAIL);
}
(void) signal(SIGPIPE, SIG_IGN); /* watch out for broken ipc link...*/
(void) alarm(0);
(void) strcpy(Dc, "IPC");
trace1(TR_tcpcall, 1);
return (ret);
}
#endif /* BSD4_2 */
/*
* unetcall(flds, dev) make ethernet connection
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
#ifndef UNET
GLOBAL int
unetcall(flds, dev)
char *flds[], *dev[];
{
trace1(TR_unetcall, 0);
Uerror = SS_NO_DEVICE;
trace1(TR_unetcall, 1);
return (FAIL);
}
#else /* UNET */
GLOBAL int
unetcall(flds, dev)
char *flds[], *dev[];
{
int ret;
int port;
trace1(TR_unetcall, 0);
port = atoi(dev[D_ARG]);
DEBUG(4, "unetdial host %s, ", flds[F_NAME]);
DEBUG(4, "port %d\n", port);
(void) alarm(connecttime);
ret = tcpopen(flds[F_NAME], port, 0, TO_ACTIVE, "rw");
(void) alarm(0);
endhnent();
if (ret < 0) {
DEBUG(5, "tcpopen failed: errno %d\n", errno);
Uerror = SS_DIAL_FAILED;
trace1(TR_unetcall, 1);
return (FAIL);
}
(void) strcpy(Dc, "UNET");
trace1(TR_unetcall, 1);
return (ret);
}
#endif /* UNET */
#endif /* TCP */
#ifdef SYTEK
/*
* sytcall(flds, dev) make a sytek connection
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
/*ARGSUSED*/
GLOBAL int
sytcall(flds, dev)
char *flds[], *dev[];
{
int dcr, dcr2, nullfd, ret;
char dcname[20], command[BUFSIZ];
trace1(TR_sytcall, 0);
(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
DEBUG(4, "dc - %s, ", dcname);
dcr = open(dcname, O_WRONLY|O_NDELAY);
if (dcr < 0) {
Uerror = SS_DIAL_FAILED;
DEBUG(4, "OPEN FAILED %s\n", dcname);
trace1(TR_sytcall, 1);
return (FAIL);
}
if (fd_mklock(dcr) != SUCCESS) {
(void)close(dcr);
DEBUG(1, "failed to lock device %s\n", dcname);
Uerror = SS_LOCKED_DEVICE;
trace1(TR_sytcall, 1);
return (FAIL);
}
sytfixline(dcr, atoi(fdig(dev[D_CLASS])), D_DIRECT);
(void) sleep(2);
DEBUG(4, "Calling Sytek unit %s\n", dev[D_ARG]);
(void) sprintf(command,"\r\rcall %s\r", dev[D_ARG]);
ret = (*Write)(dcr, command, strlen(command));
(void) sleep(1);
DEBUG(4, "COM1 return = %d\n", ret);
sytfix2line(dcr);
(void) close(nullfd = open("/", O_RDONLY));
(void) signal(SIGALRM, alarmtr);
if (setjmp(Sjbuf)) {
DEBUG(4, "timeout sytek open\n%s", "");
(void) close(nullfd);
(void) close(dcr2);
fd_rmlock(dcr);
(void) close(dcr);
Uerror = SS_DIAL_FAILED;
trace1(TR_sytcall, 1);
return (FAIL);
}
(void) alarm(10);
dcr2 = open(dcname,O_RDWR);
(void) alarm(0);
fd_rmlock(dcr);
(void) close(dcr);
if (dcr2 < 0) {
DEBUG(4, "OPEN 2 FAILED %s\n", dcname);
Uerror = SS_DIAL_FAILED;
(void) close(nullfd); /* kernel might think dc2 is open */
trace1(TR_sytcall, 1);
return (FAIL);
}
if (fd_mklock(dcr2) != SUCCESS) {
(void)close(dcr2);
DEBUG(1, "failed to lock device %s\n", dcname);
Uerror = SS_LOCKED_DEVICE;
trace1(TR_sytcall, 1);
return (FAIL);
}
trace1(TR_sytcall, 1);
return (dcr2);
}
#endif /* SYTEK */
#ifdef DIAL801
/*
* dial801(flds, dev) dial remote machine on 801/801
* char *flds[], *dev[];
*
* return codes:
* file descriptor - succeeded
* FAIL - failed
*
* unfortunately, open801() is different for usg and non-usg
*/
/*ARGSUSED*/
GLOBAL int
dial801(flds, dev)
char *flds[], *dev[];
{
char dcname[20], dnname[20], phone[MAXPH+2];
int dcf = -1, speed;
trace1(TR_dial801, 0);
(void) sprintf(dnname, "/dev/%s", dev[D_CALLDEV]);
(void) sprintf(phone, "%s%s", dev[D_ARG] , ACULAST);
(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
CDEBUG(1, "Use Port %s, ", dcname);
DEBUG(4, "acu - %s, ", dnname);
VERBOSE("Trying modem - %s, ", dcname); /* for cu */
VERBOSE("acu - %s, ", dnname); /* for cu */
if (getuid()==0 || GRPCHK(getgid())) {
CDEBUG(1, "Phone Number %s\n", phone);
/* In cu, only give out the phone number to trusted people. */
VERBOSE("calling %s: ", phone); /* for cu */
}
speed = atoi(fdig(dev[D_CLASS]));
dcf = open801(dcname, dnname, phone, speed);
if (dcf >= 0) {
if (fd_mklock(dcf) != SUCCESS) {
(void) close(dcf);
DEBUG(5, "fd_mklock line %s failed\n", dev[D_LINE]);
Uerror = SS_LOCKED_DEVICE;
trace1(TR_dial801, 1);
return (FAIL);
}
fixline(dcf, speed, D_ACU);
(void) strcpy(Dc, dev[D_LINE]); /* for later unlock() */
VERBOSE("SUCCEEDED\n%s", "");
} else {
VERBOSE("FAILED\n%s", "");
}
trace1(TR_dial801, 1);
return (dcf);
}
#ifndef ATTSV
/*ARGSUSED*/
GLOBAL int
open801(dcname, dnname, phone, speed)
char *dcname, *dnname, *phone;
{
int nw, lt, dcf = -1, nullfd, dnf = -1;
pid_t w_ret, pid = -1;
unsigned timelim;
trace1(TR_open801, 0);
if ((dnf = open(dnname, O_WRONLY)) < 0) {
DEBUG(5, "can't open %s\n", dnname);
Uerror = SS_CANT_ACCESS_DEVICE;
trace1(TR_open801, 1);
return (FAIL);
}
DEBUG(5, "%s is open\n", dnname);
(void) close(nullfd = open("/dev/null", O_RDONLY));/* partial open hack */
if (setjmp(Sjbuf)) {
DEBUG(4, "timeout modem open\n%s", "");
(void) close(nullfd);
(void) close(dcf);
(void) close(dnf);
logent("801 open", "TIMEOUT");
if (pid > 0) {
kill(pid, 9);
wait((int *) 0);
}
Uerror = SS_DIAL_FAILED;
trace1(TR_open801, 1);
return (FAIL);
}
(void) signal(SIGALRM, alarmtr);
timelim = 5 * strlen(phone);
(void) alarm(timelim < connecttime ? connecttime : timelim);
if ((pid = fork()) == 0) {
sleep(2);
nw = (*Write)(dnf, phone, lt = strlen(phone));
if (nw != lt) {
DEBUG(4, "ACU write error %d\n", errno);
logent("ACU write", "FAILED");
trace1(TR_open801, 1);
exit(1);
}
DEBUG(4, "ACU write ok\n%s", "");
trace1(TR_open801, 1);
exit(0);
}
/* open line - will return on carrier */
dcf = open(dcname, O_RDWR);
DEBUG(4, "dcf is %d\n", dcf);
if (dcf < 0) { /* handle like a timeout */
(void) alarm(0);
longjmp(Sjbuf, 1);
}
/* modem is open */
while ((w_ret = wait(&lt)) != pid)
if (w_ret == -1 && errno != EINTR) {
DEBUG(4, "Wait failed errno=%d\n", errno);
(void) close(dcf);
(void) close(dnf);
Uerror = SS_DIAL_FAILED;
trace1(TR_open801, 1);
return (FAIL);
}
(void) alarm(0);
(void) close(dnf); /* no reason to keep the 801 open */
if (lt != 0) {
DEBUG(4, "Fork Stat %o\n", lt);
(void) close(dcf);
Uerror = SS_DIAL_FAILED;
trace1(TR_open801, 1);
return (FAIL);
}
trace1(TR_open801, 1);
return (dcf);
}
#else /* ATTSV */
GLOBAL int
open801(dcname, dnname, phone, speed)
char *dcname, *dnname, *phone;
{
int nw, lt, dcf = -1, nullfd, dnf = -1, ret;
unsigned timelim;
trace1(TR_open801, 0);
(void) close(nullfd = open("/", O_RDONLY)); /* partial open hack */
if (setjmp(Sjbuf)) {
DEBUG(4, "DN write %s\n", "timeout");
(void) close(dnf);
(void) close(dcf);
(void) close(nullfd);
Uerror = SS_DIAL_FAILED;
trace1(TR_open801, 1);
return (FAIL);
}
(void) signal(SIGALRM, alarmtr);
timelim = 5 * strlen(phone);
(void) alarm(timelim < connecttime ? connecttime : timelim);
if ((dnf = open(dnname, O_WRONLY)) < 0) {
DEBUG(5, "can't open %s\n", dnname);
Uerror = SS_CANT_ACCESS_DEVICE;
trace1(TR_open801, 1);
return (FAIL);
}
DEBUG(5, "%s is open\n", dnname);
if (fd_mklock(dnf) != SUCCESS) {
(void)close(dnf);
DEBUG(1, "failed to lock device %s\n", dnname);
Uerror = SS_LOCKED_DEVICE;
}
if ((dcf = open(dcname, O_RDWR | O_NDELAY)) < 0) {
DEBUG(5, "can't open %s\n", dcname);
Uerror = SS_CANT_ACCESS_DEVICE;
trace1(TR_open801, 1);
return (FAIL);
}
if (fd_mklock(dcf) != SUCCESS) {
(void)close(dcf);
DEBUG(1, "failed to lock device %s\n", dcname);
Uerror = SS_LOCKED_DEVICE;
trace1(TR_open801, 1);
return (FAIL);
}
DEBUG(4, "dcf is %d\n", dcf);
fixline(dcf, speed, D_ACU);
nw = (*Write)(dnf, phone, lt = strlen(phone));
if (nw != lt) {
(void) alarm(0);
DEBUG(4, "ACU write error %d\n", errno);
(void) close(dnf);
(void) close(dcf);
Uerror = SS_DIAL_FAILED;
trace1(TR_open801, 1);
return (FAIL);
} else
DEBUG(4, "ACU write ok\n%s", "");
(void) close(dnf);
(void) close(nullfd = open("/", O_RDONLY)); /* partial open hack */
ret = open(dcname, O_RDWR); /* wait for carrier */
(void) alarm(0);
(void) close(ret); /* close 2nd modem open() */
if (ret < 0) { /* open() interrupted by alarm */
DEBUG(4, "Line open %s\n", "failed");
Uerror = SS_DIAL_FAILED;
(void) close(nullfd); /* close partially opened modem */
trace1(TR_open801, 1);
return (FAIL);
}
(void) _fcntl(dcf,F_SETFL, _fcntl(dcf, F_GETFL, 0) & ~O_NDELAY);
trace1(TR_open801, 1);
return (dcf);
}
#endif /* ATTSV */
#endif /* DIAL801 */
#ifdef V8
GLOBAL int
Dialout(flds)
char *flds[];
{
int fd;
char phone[MAXPH+2];
trace1(TR_Dialout, 0);
exphone(flds[F_PHONE], phone);
DEBUG(4, "call dialout(%s", phone);
DEBUG(4, ", %s)\n", dev[D_CLASS]);
fd = dialout(phone, dev[D_CLASS]);
if (fd == -1)
Uerror = SS_NO_DEVICE;
if (fd == -3)
Uerror = SS_DIAL_FAILED;
if (fd == -9)
Uerror = SS_DEVICE_FAILED;
(void) strcpy(Dc, "Dialout");
trace1(TR_Dialout, 1);
return (fd);
}
#endif /* V8 */
#ifdef TLI
/*
*
* AT&T Transport Layer Interface
*
* expected in Devices
* TLI line1 - - TLI
* or
* TLIS line1 - - TLIS
*
*/
#include <tiuser.h>
#if defined(__STDC__)
EXTERN void tfaillog(int fd, const char *s);
#else
EXTERN void tfaillog();
#endif
char *t_alloc();
int t_bind(), t_close(), t_connect(), t_free(), t_look(), t_open(), t_rcvdis();
#define CONNECT_ATTEMPTS 3
#define TFREE(p, type) if ((p)) t_free((char *)(p), (type))
/*
* returns fd to remote uucp daemon
*/
/*ARGSUSED*/
GLOBAL int
tlicall(flds, dev)
char *flds[];
char *dev[];
{
char addrbuf[ BUFSIZ ];
char devname[MAXNAMESIZE];
int fd;
register int i, j;
struct t_bind *bind_ret = 0;
struct t_info tinfo;
struct t_call *sndcall = 0, *rcvcall = 0;
EXTERN struct netbuf *stoa();
trace1(TR_tlicall, 0);
if (dev[D_LINE][0] != '/') {
/* dev holds device name relative to /dev */
sprintf(devname, "/dev/%s", dev[D_LINE]);
} else {
/* dev holds full path name of device */
strcpy(devname, dev[D_LINE]);
}
/* gimme local transport endpoint */
errno = t_errno = 0;
if (setjmp(Sjbuf)) {
DEBUG(1, "t_open timeout\n%s", "");
logent("t_open", "TIMEOUT");
Uerror = SS_NO_DEVICE;
trace1(TR_tlicall, 1);
return (FAIL);
}
(void) signal(SIGALRM, alarmtr);
(void) alarm(5);
fd = t_open(devname, O_RDWR, &tinfo);
(void) alarm(0);
if (fd < 0) {
tfaillog(fd, "t_open");
Uerror = SS_NO_DEVICE;
trace1(TR_tlicall, 1);
return (FAIL);
}
if (fd_mklock(fd) != SUCCESS) {
(void)t_close(fd);
DEBUG(1, "tlicall: failed to lock device %s\n", devname);
Uerror = SS_LOCKED_DEVICE;
trace1(TR_tlicall, 1);
return (FAIL);
}
/* allocate tli structures */
errno = t_errno = 0;
if ((bind_ret = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL)) ==
(struct t_bind *)NULL
|| (sndcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
(struct t_call *)NULL
|| (rcvcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
(struct t_call *)NULL) {
tfaillog(fd, "t_alloc");
TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
TFREE(rcvcall, T_CALL);
Uerror = SS_NO_DEVICE;
trace1(TR_tlicall, 1);
return (FAIL);
}
/* bind */
errno = t_errno = 0;
if (t_bind(fd, (struct t_bind *) 0, bind_ret) < 0) {
tfaillog(fd, "t_bind");
TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
TFREE(rcvcall, T_CALL);
Uerror = SS_NO_DEVICE;
fd_rmlock(fd);
(void) t_close(fd);
trace1(TR_tlicall, 1);
return (FAIL);
}
DEBUG(5, "tlicall: bound to %s\n", bind_ret->addr.buf);
/*
* Prepare to connect.
*
* If address begins with "\x", "\X", "\o", or "\O",
* assume is hexadecimal or octal address and use stoa()
* to convert it.
*
* Else is usual uucico address -- only \N's left to process.
* Walk thru connection address, changing \N's to NULLCHARs.
* Note: If a NULLCHAR must be part of the connection address,
* it must be overtly included in the address. One recommended
* way is to do it in the Devices file, thusly:
* Netname /dev/netport - - TLI \D\000
* bsfix() turns \000 into \N and then the loop below makes it a
* real, included-in-the-length null-byte.
*
* The DEBUG must print the strecpy'd address (so that
* non-printables will have been replaced with C escapes).
*/
DEBUG(5, "t_connect to addr \"%s\"\n",
strecpy(addrbuf, dev[D_ARG], "\\"));
if (dev[D_ARG][0] == '\\' &&
(dev[D_ARG][1] == 'x' || dev[D_ARG][1] == 'X'
|| dev[D_ARG][1] == 'o' || dev[D_ARG][1] == 'O')) {
if (stoa(dev[D_ARG], &(sndcall->addr)) == (struct netbuf *)NULL) {
DEBUG(5, "tlicall: stoa failed\n%s", "");
logent("tlicall", "string-to-address failed");
TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
TFREE(rcvcall, T_CALL);
Uerror = SS_NO_DEVICE;
fd_rmlock(fd);
(void) t_close(fd);
trace1(TR_tlicall, 1);
return (FAIL);
}
} else {
for (i = j = 0; i < BUFSIZ && dev[D_ARG][i] != NULLCHAR;
++i, ++j) {
if (dev[D_ARG][i] == '\\' && dev[D_ARG][i+1] == 'N') {
addrbuf[j] = NULLCHAR;
++i;
}
else {
addrbuf[j] = dev[D_ARG][i];
}
}
sndcall->addr.buf = addrbuf;
sndcall->addr.len = j;
}
if (setjmp(Sjbuf)) {
DEBUG(4, "timeout tlicall\n%s", "");
logent("tlicall", "TIMEOUT");
TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
TFREE(rcvcall, T_CALL);
Uerror = SS_NO_DEVICE;
fd_rmlock(fd);
(void) t_close(fd);
trace1(TR_tlicall, 1);
return (FAIL);
}
(void) signal(SIGALRM, alarmtr);
(void) alarm(connecttime);
/* connect to the service -- some listeners can't handle */
/* multiple connect requests, so try it a few times */
errno = t_errno = 0;
for (i = 0; i < CONNECT_ATTEMPTS; ++i) {
if (t_connect(fd, sndcall, rcvcall) == 0)
break;
if ((t_errno == TLOOK) && (t_look(fd) == T_DISCONNECT)) {
t_rcvdis(fd,NULL);
(void) alarm(0);
} else {
(void) alarm(0);
tfaillog(fd, "t_connect");
TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
TFREE(rcvcall, T_CALL);
Uerror = SS_DIAL_FAILED;
fd_rmlock(fd);
(void) t_close(fd);
trace1(TR_tlicall, 1);
return (FAIL);
}
}
(void) alarm(0);
TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
TFREE(rcvcall, T_CALL);
if (i == CONNECT_ATTEMPTS) {
tfaillog(fd, "t_connect");
Uerror = SS_DIAL_FAILED;
fd_rmlock(fd);
(void) t_close(fd);
trace1(TR_tlicall, 1);
return (FAIL);
}
errno = t_errno = 0;
(void) strcpy(Dc, dev[D_CALLER]);
trace1(TR_tlicall, 1);
return (fd);
}
#endif /* TLI */