summaryrefslogtreecommitdiff
path: root/usr/src/cmd/tip
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/tip
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/tip')
-rw-r--r--usr/src/cmd/tip/Makefile117
-rw-r--r--usr/src/cmd/tip/acu.c159
-rw-r--r--usr/src/cmd/tip/aculib/Makefile41
-rw-r--r--usr/src/cmd/tip/aculib/biz22.c161
-rw-r--r--usr/src/cmd/tip/aculib/biz31.c223
-rw-r--r--usr/src/cmd/tip/aculib/df.c111
-rw-r--r--usr/src/cmd/tip/aculib/dn11.c122
-rw-r--r--usr/src/cmd/tip/aculib/hayes.c144
-rw-r--r--usr/src/cmd/tip/aculib/v3451.c190
-rw-r--r--usr/src/cmd/tip/aculib/v831.c244
-rw-r--r--usr/src/cmd/tip/aculib/ventel.c214
-rw-r--r--usr/src/cmd/tip/acutab.c59
-rw-r--r--usr/src/cmd/tip/cmds.c927
-rw-r--r--usr/src/cmd/tip/cmdtab.c37
-rw-r--r--usr/src/cmd/tip/cu.c119
-rw-r--r--usr/src/cmd/tip/etc.remote42
-rw-r--r--usr/src/cmd/tip/hunt.c82
-rw-r--r--usr/src/cmd/tip/log.c65
-rw-r--r--usr/src/cmd/tip/partab.c55
-rw-r--r--usr/src/cmd/tip/remcap.c438
-rw-r--r--usr/src/cmd/tip/remote.c181
-rw-r--r--usr/src/cmd/tip/tip.c614
-rw-r--r--usr/src/cmd/tip/tip.h262
-rw-r--r--usr/src/cmd/tip/tipout.c159
-rw-r--r--usr/src/cmd/tip/uucplock.c303
-rw-r--r--usr/src/cmd/tip/value.c336
-rw-r--r--usr/src/cmd/tip/vars.c87
27 files changed, 5492 insertions, 0 deletions
diff --git a/usr/src/cmd/tip/Makefile b/usr/src/cmd/tip/Makefile
new file mode 100644
index 0000000000..af3e06e7e6
--- /dev/null
+++ b/usr/src/cmd/tip/Makefile
@@ -0,0 +1,117 @@
+#
+# Copyright 1998-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Makefile for intermachine communications package.
+#
+# Files are:
+# /etc/remote remote host description file
+# /etc/phones phone number file, owned by $(OWNER) and
+# mode 6??
+# /var/adm/aculog ACU accounting file, owned by $(OWNER) and
+# mode 6?? (if ACULOG defined)
+# Presently supports:
+# BIZCOMP
+# DEC DF02-AC, DF03-AC
+# DEC DN-11/Able Quadracall
+# VENTEL 212+
+# VADIC 831 RS232 adaptor
+# VADIC 3451
+# HAYES SmartModem
+# (drivers are located in aculib.a)
+#
+# Configuration defines:
+# DF02, DF03, DN11 ACU's supported
+# BIZ1031, BIZ1022, VENTEL, V831, V3451, HAYES
+# ACULOG turn on tip logging of ACU use
+# PRISTINE no phone #'s put in ACU log file
+# DEFBR default baud rate to make connection at
+# DEFFS default frame size for FTP buffering of
+# writes on local side
+# BUFSIZ buffer sizing from stdio, must be fed
+# explicitly to remcap.c if not 1024
+#
+# cmd/tip/Makefile
+
+PROG= tip
+
+OBJS= acu.o cmds.o cmdtab.o cu.o hunt.o \
+ log.o partab.o remote.o tip.o tipout.o value.o vars.o \
+ acutab.o remcap.o uucplock.o
+
+# sigh, NSE can't handle wildcards
+#DRIVERS= aculib/*.c
+
+SRCS= $(OBJS:.o=.c)
+
+SOURCES=$(SRCS) $(DRIVERS)
+
+include ../Makefile.cmd
+
+REMOTE= etc.remote
+ACULOG= aculog
+ROOTETCREMOTE= $(ROOTETC)/remote
+ROOTACULOGD= $(ROOT)/var/adm
+ROOTACULOG= $(ROOTACULOGD)/aculog
+
+$(ROOTPROG) := FILEMODE = 4511
+$(ROOTPROG) := OWNER = uucp
+$(ROOTETCREMOTE) := FILEMODE = 644
+$(ROOTACULOG) := FILEMODE = 600
+$(ROOTACULOG) := OWNER = uucp
+
+CPPFLAGS += -DDEFBR=300 -DDEFFS=BUFSIZ -DACULOG -DUSG
+CONFIG= -DV831 -DVENTEL -DV3451 -DDF02 -DDF03 -DBIZ1031 -DBIZ1022 -DHAYES
+ACULIB= aculib/aculib.a
+LDLIBS= $(ACULIB) $(LDLIBS.cmd)
+
+# install rules
+$(ROOTACULOGD)/% : %
+ $(INS.file)
+
+$(ROOTETC)/% : etc.%
+ $(INS.rename)
+
+.KEEP_STATE:
+
+.PARALLEL: $(OBJS)
+
+all: $(PROG) $(REMOTE) $(ACULOG)
+
+$(PROG): $(OBJS) $(ACULIB)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+# special build rules
+remcap.o := CPPFLAGS += -DBUFSIZ=1024
+acutab.o := CPPFLAGS += $(CONFIG)
+
+# acutab is configuration dependent, and so depends on the makefile
+acutab.o: Makefile
+
+# remote.o depends on the makefile because of DEFBR and DEFFS
+remote.o: Makefile
+
+# log.o depends on the makefile because of ACULOG
+log.o: Makefile
+
+$(ACULIB): FRC
+ cd aculib; $(MAKE)
+
+install: all $(ROOTPROG) $(ROOTETCREMOTE) $(ROOTACULOG)
+
+$(ACULOG):
+ cp /dev/null $(ACULOG)
+
+clean: FRC
+ cd aculib; $(MAKE) clean
+ $(RM) $(OBJS)
+
+lint:
+ -lint -hbacvx $(CFLAGS) $(SOURCES)
+
+include ../Makefile.targ
+
+FRC:
diff --git a/usr/src/cmd/tip/acu.c b/usr/src/cmd/tip/acu.c
new file mode 100644
index 0000000000..76de8d1f58
--- /dev/null
+++ b/usr/src/cmd/tip/acu.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 5.3 4/3/86 */
+
+#include "tip.h"
+
+static acu_t *acu = NOACU;
+static int conflag;
+static void acuabort();
+static acu_t *acutype();
+static sigjmp_buf jmpbuf;
+/*
+ * Establish connection for tip
+ *
+ * If DU is true, we should dial an ACU whose type is AT.
+ * The phone numbers are in PN, and the call unit is in CU.
+ *
+ * If the PN is an '@', then we consult the PHONES file for
+ * the phone numbers. This file is /etc/phones, unless overriden
+ * by an exported shell variable.
+ *
+ * The data base files must be in the format:
+ * host-name[ \t]*phone-number
+ * with the possibility of multiple phone numbers
+ * for a single host acting as a rotary (in the order
+ * found in the file).
+ */
+char *
+connect()
+{
+ register char *cp = PN;
+ char *phnum, string[256];
+ int tried = 0;
+
+ if (!DU)
+ return (NOSTR);
+ /*
+ * @ =>'s use data base in PHONES environment variable
+ * otherwise, use /etc/phones
+ */
+ if (sigsetjmp(jmpbuf, 1)) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ printf("\ncall aborted\n");
+ logent(value(HOST), "", "", "call aborted");
+ if (acu != NOACU) {
+ boolean(value(VERBOSE)) = FALSE;
+ if (conflag)
+ disconnect(NOSTR);
+ else
+ (*acu->acu_abort)();
+ }
+ myperm();
+ delock(uucplock);
+ exit(1);
+ }
+ signal(SIGINT, acuabort);
+ signal(SIGQUIT, acuabort);
+ if ((acu = acutype(AT)) == NOACU)
+ return ("unknown ACU type");
+ if (*cp != '@') {
+ while (*cp) {
+ for (phnum = cp; *cp && *cp != '|'; cp++)
+ ;
+ if (*cp)
+ *cp++ = '\0';
+
+ if (conflag = (*acu->acu_dialer)(phnum, CU)) {
+ logent(value(HOST), phnum, acu->acu_name,
+ "call completed");
+ return (NOSTR);
+ } else
+ logent(value(HOST), phnum, acu->acu_name,
+ "call failed");
+ tried++;
+ }
+ } else {
+ if (phfd == NOFILE) {
+ printf("%s: ", PH);
+ return ("can't open phone number file");
+ }
+ rewind(phfd);
+ while (fgets(string, sizeof (string), phfd) != NOSTR) {
+ if (string[0] == '#')
+ continue;
+ for (cp = string; !any(*cp, " \t\n"); cp++)
+ ;
+ if (*cp == '\n')
+ return ("unrecognizable host name");
+ *cp++ = '\0';
+ if (!equal(string, value(HOST)))
+ continue;
+ while (any(*cp, " \t"))
+ cp++;
+ if (*cp == '\n')
+ return ("missing phone number");
+ for (phnum = cp; *cp && *cp != '|' && *cp != '\n'; cp++)
+ ;
+ *cp = '\0';
+
+ if (conflag = (*acu->acu_dialer)(phnum, CU)) {
+ logent(value(HOST), phnum, acu->acu_name,
+ "call completed");
+ return (NOSTR);
+ } else
+ logent(value(HOST), phnum, acu->acu_name,
+ "call failed");
+ tried++;
+ }
+ }
+ if (!tried)
+ logent(value(HOST), "", acu->acu_name, "missing phone number");
+ else
+ (*acu->acu_abort)();
+ return (tried ? "call failed" : "missing phone number");
+}
+
+disconnect(reason)
+ char *reason;
+{
+ if (!conflag)
+ return;
+ if (reason == NOSTR) {
+ logent(value(HOST), "", acu->acu_name, "call terminated");
+ if (boolean(value(VERBOSE)))
+ printf("\r\ndisconnecting...");
+ } else
+ logent(value(HOST), "", acu->acu_name, reason);
+ (*acu->acu_disconnect)();
+}
+
+static void
+acuabort(s)
+{
+ signal(s, SIG_IGN);
+ siglongjmp(jmpbuf, 1);
+}
+
+static acu_t *
+acutype(s)
+ register char *s;
+{
+ register acu_t *p;
+ extern acu_t acutable[];
+
+ if (s != NOSTR)
+ for (p = acutable; p->acu_name != '\0'; p++)
+ if (equal(s, p->acu_name))
+ return (p);
+ return (NOACU);
+}
diff --git a/usr/src/cmd/tip/aculib/Makefile b/usr/src/cmd/tip/aculib/Makefile
new file mode 100644
index 0000000000..4df6c48095
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/Makefile
@@ -0,0 +1,41 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright (c) 1983 Regents of the University of California.
+# All rights reserved. The Berkeley software License Agreement
+# specifies the terms and conditions for redistribution.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# make file for tip device drivers
+#
+# Current drivers:
+# BIZCOMP
+# DEC DF02-AC, DF03-AC
+# DEC DN-11/Able Quadracall
+# VENTEL 212+ (w/o echo)
+# VADIC 831 RS232 adaptor
+# VADIC 3451
+# HAYES SmartModem
+#
+# cmd/tip/aculib/Makefile
+
+ACULIB= aculib.a
+OBJS= biz22.o biz31.o df.o dn11.o hayes.o ventel.o v831.o v3451.o
+
+include ../../Makefile.cmd
+
+CPPFLAGS= -I../ -DUSG $(CPPFLAGS.master)
+
+.KEEP_STATE:
+
+.PARALLEL: $(OBJS)
+
+all: $(ACULIB)
+
+$(ACULIB): $(OBJS)
+ $(AR) cr $(ACULIB) $(OBJS)
+
+clean:
+ $(RM) $(ACULIB) $(OBJS) core errs
diff --git a/usr/src/cmd/tip/aculib/biz22.c b/usr/src/cmd/tip/aculib/biz22.c
new file mode 100644
index 0000000000..c570e4a5ac
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/biz22.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* from UCB 4.4 6/25/83 */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "tip.h"
+
+#define DISCONNECT_CMD "\20\04" /* disconnection string */
+
+static void sigALRM();
+static int timeout = 0;
+static sigjmp_buf timeoutbuf;
+
+/*
+ * Dial up on a BIZCOMP Model 1022 with either
+ * tone dialing (mod = "V")
+ * pulse dialing (mod = "W")
+ */
+static int
+biz_dialer(num, mod)
+ char *num, *mod;
+{
+ register int connected = 0;
+ char cbuf[40];
+
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+ /*
+ * Disable auto-answer and configure for tone/pulse
+ * dialing
+ */
+ if (cmd("\02K\r")) {
+ printf("can't initialize bizcomp...");
+ return (0);
+ }
+ strcpy(cbuf, "\02.\r");
+ cbuf[1] = *mod;
+ if (cmd(cbuf)) {
+ printf("can't set dialing mode...");
+ return (0);
+ }
+ strcpy(cbuf, "\02D");
+ strlcat(cbuf, num, sizeof (cbuf));
+ strlcat(cbuf, "\r", sizeof (cbuf));
+ write(FD, cbuf, strlen(cbuf));
+ if (!detect("7\r")) {
+ printf("can't get dial tone...");
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("ringing...");
+ /*
+ * The reply from the BIZCOMP should be:
+ * 2 \r or 7 \r failure
+ * 1 \r success
+ */
+ connected = detect("1\r");
+#ifdef ACULOG
+ if (timeout) {
+ char line[80];
+
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "biz1022", line);
+ }
+#endif
+ if (timeout)
+ biz22_disconnect(); /* insurance */
+ return (connected);
+}
+
+biz22w_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "W"));
+}
+
+biz22f_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "V"));
+}
+
+biz22_disconnect()
+{
+
+ write(FD, DISCONNECT_CMD, 4);
+ sleep(2);
+ ioctl(FD, TCFLSH, TCOFLUSH);
+}
+
+biz22_abort()
+{
+
+ write(FD, "\02", 1);
+}
+
+static void
+sigALRM()
+{
+
+ timeout = 1;
+ siglongjmp(timeoutbuf, 1);
+}
+
+static int
+cmd(s)
+ register char *s;
+{
+ char c;
+ sig_handler_t f;
+
+ write(FD, s, strlen(s));
+ f = signal(SIGALRM, (sig_handler_t)sigALRM);
+ if (sigsetjmp(timeoutbuf, 1)) {
+ biz22_abort();
+ signal(SIGALRM, f);
+ return (1);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ signal(SIGALRM, f);
+ c &= 0177;
+ return (c != '\r');
+}
+
+static int
+detect(s)
+ register char *s;
+{
+ char c;
+ sig_handler_t f;
+
+ f = signal(SIGALRM, (sig_handler_t)sigALRM);
+ timeout = 0;
+ while (*s) {
+ if (sigsetjmp(timeoutbuf, 1)) {
+ biz22_abort();
+ break;
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ c &= 0177;
+ if (c != *s++)
+ return (0);
+ }
+ signal(SIGALRM, f);
+ return (timeout == 0);
+}
diff --git a/usr/src/cmd/tip/aculib/biz31.c b/usr/src/cmd/tip/aculib/biz31.c
new file mode 100644
index 0000000000..fe0fbac5dc
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/biz31.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.7 6/25/83 */
+
+#include "tip.h"
+
+#define MAXRETRY 3 /* sync up retry count */
+#define DISCONNECT_CMD "\21\25\11\24" /* disconnection string */
+
+static void sigALRM();
+static int timeout = 0;
+static sigjmp_buf timeoutbuf;
+
+/*
+ * Dial up on a BIZCOMP Model 1031 with either
+ * tone dialing (mod = "f")
+ * pulse dialing (mod = "w")
+ */
+static int
+biz_dialer(num, mod)
+ char *num, *mod;
+{
+ register int connected = 0;
+
+ if (!bizsync(FD)) {
+ logent(value(HOST), "", "biz", "out of sync");
+ printf("bizcomp out of sync\n");
+ delock(uucplock);
+ exit(0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+ echo("#\rk$\r$\n"); /* disable auto-answer */
+ echo("$>$.$ #\r"); /* tone/pulse dialing */
+ echo(mod);
+ echo("$\r$\n");
+ echo("$>$.$ #\re$ "); /* disconnection sequence */
+ echo(DISCONNECT_CMD);
+ echo("\r$\n$\r$\n");
+ echo("$>$.$ #\rr$ "); /* repeat dial */
+ echo(num);
+ echo("\r$\n");
+ if (boolean(value(VERBOSE)))
+ printf("ringing...");
+ /*
+ * The reply from the BIZCOMP should be:
+ * `^G NO CONNECTION\r\n^G\r\n' failure
+ * ` CONNECTION\r\n^G' success
+ */
+ connected = detect(" ");
+#ifdef ACULOG
+ if (timeout) {
+ char line[80];
+
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "biz", line);
+ }
+#endif
+ if (!connected)
+ flush(" NO CONNECTION\r\n\07\r\n");
+ else
+ flush("CONNECTION\r\n\07");
+ if (timeout)
+ biz31_disconnect(); /* insurance */
+ return (connected);
+}
+
+biz31w_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "w"));
+}
+
+biz31f_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (biz_dialer(num, "f"));
+}
+
+biz31_disconnect()
+{
+
+ write(FD, DISCONNECT_CMD, 4);
+ sleep(2);
+ ioctl(FD, TCFLSH, TCOFLUSH);
+}
+
+biz31_abort()
+{
+
+ write(FD, "\33", 1);
+}
+
+static int
+echo(s)
+ register char *s;
+{
+ char c;
+
+ while (c = *s++) {
+ switch (c) {
+ case '$':
+ read(FD, &c, 1);
+ s++;
+ break;
+
+ case '#':
+ c = *s++;
+ write(FD, &c, 1);
+ break;
+
+ default:
+ write(FD, &c, 1);
+ read(FD, &c, 1);
+ }
+ }
+}
+
+static void
+sigALRM()
+{
+
+ timeout = 1;
+ siglongjmp(timeoutbuf, 1);
+}
+
+static int
+detect(s)
+ register char *s;
+{
+ char c;
+ sig_handler_t f;
+
+ f = signal(SIGALRM, (sig_handler_t)sigALRM);
+ timeout = 0;
+ while (*s) {
+ if (sigsetjmp(timeoutbuf, 1)) {
+ printf("\07timeout waiting for reply\n");
+ biz31_abort();
+ break;
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ if (c != *s++)
+ break;
+ }
+ signal(SIGALRM, f);
+ return (timeout == 0);
+}
+
+static int
+flush(s)
+ register char *s;
+{
+ char c;
+ sig_handler_t f;
+
+ f = signal(SIGALRM, (sig_handler_t)sigALRM);
+ while (*s++) {
+ if (sigsetjmp(timeoutbuf, 1))
+ break;
+ alarm(10);
+ read(FD, &c, 1);
+ alarm(0);
+ }
+ signal(SIGALRM, f);
+ timeout = 0; /* guard against disconnection */
+}
+
+/*
+ * This convoluted piece of code attempts to get
+ * the bizcomp in sync. If you don't have the capacity or nread
+ * call there are gory ways to simulate this.
+ */
+static int
+bizsync(fd)
+{
+#ifdef FIOCAPACITY
+ struct capacity b;
+#define chars(b) ((b).cp_nbytes)
+#define IOCTL FIOCAPACITY
+#endif
+#ifdef FIONREAD
+ long b;
+#define chars(b) (b)
+#define IOCTL FIONREAD
+#endif
+ register int already = 0;
+ char buf[10];
+
+retry:
+ if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0 && chars(b) > 0)
+ ioctl(fd, TCFLSH, TCIOFLUSH);
+ write(fd, "\rp>\r", 4);
+ sleep(1);
+ if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0) {
+ if (chars(b) != 10) {
+ nono:
+ if (already > MAXRETRY)
+ return (0);
+ write(fd, DISCONNECT_CMD, 4);
+ sleep(2);
+ already++;
+ goto retry;
+ } else {
+ read(fd, buf, 10);
+ if (strncmp(buf, "p >\r\n\r\n>", 8))
+ goto nono;
+ }
+ }
+ return (1);
+}
diff --git a/usr/src/cmd/tip/aculib/df.c b/usr/src/cmd/tip/aculib/df.c
new file mode 100644
index 0000000000..22f00d9345
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/df.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.8 6/25/83 */
+
+/*
+ * Dial the DF02-AC or DF03-AC
+ */
+
+#include "tip.h"
+
+static sigjmp_buf Sjbuf;
+static void timeout();
+
+df02_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (df_dialer(num, acu, 0));
+}
+
+df03_dialer(num, acu)
+ char *num, *acu;
+{
+
+ return (df_dialer(num, acu, 1));
+}
+
+df_dialer(num, acu, df03)
+ char *num, *acu;
+ int df03;
+{
+ register int f = FD;
+ struct termios buf;
+ int speed = 0;
+ char c = '\0';
+
+ ioctl(f, TCGETS, &buf);
+ buf.c_cflag |= HUPCL;
+ ioctl(f, TCSETS, &buf);
+ if (sigsetjmp(Sjbuf, 1)) {
+ printf("connection timed out\r\n");
+ df_disconnect();
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ fflush(stdout);
+#ifdef TIOCMSET
+ if (df03) {
+ int st = TIOCM_ST; /* secondary Transmit flag */
+
+ ioctl(f, TCGETS, &buf);
+ if (cfgetospeed(&buf) != B1200) { /* must dial at 1200 baud */
+ speed = cfgetospeed(&buf);
+ cfsetospeed(&buf, B0);
+ cfsetispeed(&buf, B0);
+ cfsetospeed(&buf, B1200);
+ ioctl(f, TCSETSW, &buf);
+ ioctl(f, TIOCMBIC, &st); /* clear ST for 300 baud */
+ } else
+ ioctl(f, TIOCMBIS, &st); /* set ST for 1200 baud */
+ }
+#endif
+ signal(SIGALRM, timeout);
+ alarm(5 * strlen(num) + 10);
+ ioctl(f, TCFLSH, TCOFLUSH);
+ write(f, "\001", 1);
+ sleep(1);
+ write(f, "\002", 1);
+ write(f, num, strlen(num));
+ read(f, &c, 1);
+#ifdef TIOCMSET
+ if (df03 && speed) {
+ cfsetospeed(&buf, B0);
+ cfsetispeed(&buf, B0);
+ cfsetospeed(&buf, speed);
+ ioctl(f, TCSETSW, &buf);
+ }
+#endif
+ return (c == 'A');
+}
+
+df_disconnect()
+{
+
+ write(FD, "\001", 1);
+ sleep(1);
+ ioctl(FD, TCFLSH, TCOFLUSH);
+}
+
+
+df_abort()
+{
+
+ df_disconnect();
+}
+
+
+static void
+timeout()
+{
+
+ siglongjmp(Sjbuf, 1);
+}
diff --git a/usr/src/cmd/tip/aculib/dn11.c b/usr/src/cmd/tip/aculib/dn11.c
new file mode 100644
index 0000000000..24bac51d5f
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/dn11.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.14 6/25/83 */
+
+/*
+ * Routines for dialing up on DN-11
+ */
+#include "tip.h"
+
+int dn_abort();
+void alarmtr();
+static sigjmp_buf jmpbuf;
+static int child = -1, dn;
+
+dn_dialer(num, acu)
+ char *num, *acu;
+{
+ extern errno;
+ char *p, *q, phone[40];
+ int lt, nw, connected = 1;
+ register int timelim;
+ struct termios buf;
+
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+ if ((dn = open(acu, 1)) < 0) {
+ if (errno == EBUSY)
+ printf("line busy...");
+ else
+ printf("acu open error...");
+ return (0);
+ }
+ if (sigsetjmp(jmpbuf, 1)) {
+ kill(child, SIGKILL);
+ close(dn);
+ return (0);
+ }
+ signal(SIGALRM, alarmtr);
+ timelim = 5 * strlen(num);
+ alarm(timelim < 30 ? 30 : timelim);
+ if ((child = fork()) == 0) {
+ /*
+ * ignore this stuff for aborts
+ */
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ sleep(2);
+ nw = write(dn, num, lt = strlen(num));
+ exit(nw != lt);
+ }
+ /*
+ * open line - will return on carrier
+ */
+ if ((FD = open(DV, 2)) < 0) {
+ if (errno == EIO)
+ printf("lost carrier...");
+ else
+ printf("dialup line open failed...");
+ alarm(0);
+ kill(child, SIGKILL);
+ close(dn);
+ return (0);
+ }
+ alarm(0);
+ ioctl(dn, TCGETS, &buf);
+ buf.c_cflag |= HUPCL;
+ ioctl(dn, TCSETSF, &buf);
+ signal(SIGALRM, SIG_DFL);
+ while ((nw = wait(&lt)) != child && nw != -1)
+ ;
+ fflush(stdout);
+ close(dn);
+ if (lt != 0) {
+ close(FD);
+ return (0);
+ }
+ return (1);
+}
+
+void
+alarmtr()
+{
+
+ alarm(0);
+ siglongjmp(jmpbuf, 1);
+}
+
+/*
+ * Insurance, for some reason we don't seem to be
+ * hanging up...
+ */
+dn_disconnect()
+{
+ int dtr = TIOCM_DTR;
+
+ sleep(2);
+ if (FD > 0)
+ ioctl(FD, TIOCMBIC, &dtr);
+ close(FD);
+}
+
+dn_abort()
+{
+ int dtr = TIOCM_DTR;
+
+ sleep(2);
+ if (child > 0)
+ kill(child, SIGKILL);
+ if (dn > 0)
+ close(dn);
+ if (FD > 0)
+ ioctl(FD, TIOCMBIC, &dtr);
+ close(FD);
+}
diff --git a/usr/src/cmd/tip/aculib/hayes.c b/usr/src/cmd/tip/aculib/hayes.c
new file mode 100644
index 0000000000..85a26a8dc1
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/hayes.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI"
+
+#include "tip.h"
+
+static void sigALRM();
+static sigjmp_buf timeoutbuf;
+
+/*
+ * Dial up on a Hayes Smart Modem 1200 or 2400
+ */
+int
+hayes_dialer(num, acu)
+ char *num, *acu;
+{
+ char code = 0, cr = 0;
+ void (*f)();
+ struct termios buf;
+
+ f = signal(SIGALRM, sigALRM);
+
+ if (!hayes_sync(FD)) {
+ printf("can't synchronize with hayes\n");
+#ifdef ACULOG
+ logent(value(HOST), num, "hayes", "can't synch up");
+#endif
+ signal(SIGALRM, f);
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ fflush(stdout);
+ ioctl(FD, TCGETS, &buf);
+ buf.c_cflag |= HUPCL;
+ ioctl(FD, TCSETS, &buf);
+ ioctl(FD, TCFLSH, TCIOFLUSH);
+
+ if (sigsetjmp(timeoutbuf, 1)) {
+#ifdef ACULOG
+ char line[80];
+
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "hayes", line);
+#endif
+ hayes_disconnect();
+ signal(SIGALRM, f);
+ return (0);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ ioctl(FD, TCFLSH, TCIOFLUSH);
+ if (*num == 'S')
+ write(FD, "AT", 2);
+ else
+ write(FD, "ATDT", 4); /* use tone dialing */
+ write(FD, num, strlen(num));
+ write(FD, "\r", 1);
+ read(FD, &code, 1);
+ read(FD, &cr, 1);
+ if (code == '1' && cr == '0')
+ read(FD, &cr, 1);
+ alarm(0);
+ signal(SIGALRM, f);
+ if ((code == '1' || code == '5') && cr == '\r')
+ return (1);
+ return (0);
+}
+
+hayes_disconnect()
+{
+ close(FD);
+}
+
+hayes_abort()
+{
+ int dtr = TIOCM_DTR;
+
+ alarm(0);
+ ioctl(FD, TIOCMBIC, &dtr);
+ sleep(2);
+ ioctl(FD, TCFLSH, TCIOFLUSH);
+ close(FD);
+}
+
+static void
+sigALRM()
+{
+ siglongjmp(timeoutbuf, 1);
+}
+
+/*
+ * This piece of code attempts to get the hayes in sync.
+ */
+static int
+hayes_sync(fd)
+{
+ register int tries;
+ char code = 0, cr = 0;
+ int dtr = TIOCM_DTR;
+
+ /*
+ * Toggle DTR to force anyone off that might have left
+ * the modem connected, and insure a consistent state
+ * to start from.
+ */
+ ioctl(fd, TIOCMBIC, &dtr);
+ sleep(1);
+ ioctl(fd, TIOCMBIS, &dtr);
+ for (tries = 0; tries < 3; tries++) {
+ /*
+ * After reseting the modem, initialize all
+ * parameters to required vaules:
+ *
+ * V0 - result codes are single digits
+ * Q0 - result codes ARE sent
+ * E0 - do not echo
+ * S0=1 - automatically answer phone
+ * S2=255 - disable escape character
+ * S12=255 - longest possible escape guard time
+ */
+ write(fd, "ATV0Q0E0S0=1S2=255S12=255\r", 26);
+ sleep(1);
+ /* flush any echoes or return codes */
+ ioctl(fd, TCFLSH, TCIOFLUSH);
+ /* now see if the modem is talking to us properly */
+ write(fd, "AT\r", 3);
+ if (sigsetjmp(timeoutbuf, 1) == 0) {
+ alarm(2);
+ read(FD, &code, 1);
+ read(FD, &cr, 1);
+ if (code == '0' && cr == '\r')
+ return (1);
+ }
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/tip/aculib/v3451.c b/usr/src/cmd/tip/aculib/v3451.c
new file mode 100644
index 0000000000..221e67c85a
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/v3451.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* from UCB 4.4 6/25/83 */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines for calling up on a Vadic 3451 Modem
+ */
+#include "tip.h"
+
+static sigjmp_buf Sjbuf;
+
+v3451_dialer(num, acu)
+ register char *num;
+ char *acu;
+{
+ int ok;
+ void (*func)();
+ struct termios buf;
+ int slow = number(value(BAUDRATE)) < 1200;
+ char phone[50];
+#ifdef ACULOG
+ char line[80];
+#endif
+
+ /*
+ * Get in synch
+ */
+ vawrite("I\r", 1 + slow);
+ vawrite("I\r", 1 + slow);
+ vawrite("I\r", 1 + slow);
+ vawrite("\005\r", 2 + slow);
+ if (!expect("READY")) {
+ printf("can't synchronize with vadic 3451\n");
+#ifdef ACULOG
+ logent(value(HOST), num, "vadic", "can't synch up");
+#endif
+ return (0);
+ }
+ ioctl(FD, TCGETS, &buf);
+ buf.c_cflag |= HUPCL;
+ ioctl(FD, TCSETSF, &buf);
+ sleep(1);
+ vawrite("D\r", 2 + slow);
+ if (!expect("NUMBER?")) {
+ printf("Vadic will not accept dial command\n");
+#ifdef ACULOG
+ logent(value(HOST), num, "vadic", "will not accept dial");
+#endif
+ return (0);
+ }
+ strlcpy(phone, num, sizeof (phone));
+ strlcat(phone, "\r", sizeof (phone));
+ vawrite(phone, 1 + slow);
+ if (!expect(phone)) {
+ printf("Vadic will not accept phone number\n");
+#ifdef ACULOG
+ logent(value(HOST), num, "vadic", "will not accept number");
+#endif
+ return (0);
+ }
+ func = signal(SIGINT, SIG_IGN);
+ /*
+ * You cannot interrupt the Vadic when its dialing;
+ * even dropping DTR does not work (definitely a
+ * brain damaged design).
+ */
+ vawrite("\r", 1 + slow);
+ vawrite("\r", 1 + slow);
+ if (!expect("DIALING:")) {
+ printf("Vadic failed to dial\n");
+#ifdef ACULOG
+ logent(value(HOST), num, "vadic", "failed to dial");
+#endif
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ ok = expect("ON LINE");
+ signal(SIGINT, func);
+ if (!ok) {
+ printf("call failed\n");
+#ifdef ACULOG
+ logent(value(HOST), num, "vadic", "call failed");
+#endif
+ return (0);
+ }
+ ioctl(FD, TCFLSH, TCOFLUSH);
+ return (1);
+}
+
+v3451_disconnect()
+{
+
+ close(FD);
+}
+
+v3451_abort()
+{
+
+ close(FD);
+}
+
+static
+vawrite(cp, delay)
+ register char *cp;
+ int delay;
+{
+
+ for (; *cp; sleep(delay), cp++)
+ write(FD, cp, 1);
+}
+
+static
+expect(cp)
+ register char *cp;
+{
+ char buf[300];
+ register char *rp = buf;
+ static void alarmtr();
+ int timeout = 30, online = 0;
+
+ if (strcmp(cp, "\"\"") == 0)
+ return (1);
+ *rp = 0;
+ /*
+ * If we are waiting for the Vadic to complete
+ * dialing and get a connection, allow more time
+ * Unfortunately, the Vadic times out 24 seconds after
+ * the last digit is dialed
+ */
+ online = strcmp(cp, "ON LINE") == 0;
+ if (online)
+ timeout = number(value(DIALTIMEOUT));
+ signal(SIGALRM, alarmtr);
+ if (sigsetjmp(Sjbuf, 1))
+ return (0);
+ alarm(timeout);
+ while (notin(cp, buf) && rp < buf + sizeof (buf) - 1) {
+ if (online && notin("FAILED CALL", buf) == 0)
+ return (0);
+ if (read(FD, rp, 1) < 0) {
+ alarm(0);
+ return (0);
+ }
+ if (*rp &= 0177)
+ rp++;
+ *rp = '\0';
+ }
+ alarm(0);
+ return (1);
+}
+
+static void
+alarmtr()
+{
+
+ siglongjmp(Sjbuf, 1);
+}
+
+static
+notin(sh, lg)
+ char *sh, *lg;
+{
+
+ for (; *lg; lg++)
+ if (prefix(sh, lg))
+ return (0);
+ return (1);
+}
+
+static
+prefix(s1, s2)
+ register char *s1, *s2;
+{
+ register char c;
+
+ while ((c = *s1++) == *s2++)
+ if (c == '\0')
+ return (1);
+ return (c == '\0');
+}
diff --git a/usr/src/cmd/tip/aculib/v831.c b/usr/src/cmd/tip/aculib/v831.c
new file mode 100644
index 0000000000..d117bb4bf1
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/v831.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.5 6/25/83 */
+
+/*
+ * Routines for dialing up on Vadic 831
+ */
+#include <sys/time.h>
+
+#include "tip.h"
+
+int v831_abort();
+static void alarmtr();
+extern errno;
+
+static sigjmp_buf jmpbuf;
+static int child = -1;
+
+v831_dialer(num, acu)
+ char *num, *acu;
+{
+ int status, pid, connected = 1;
+ register int timelim;
+
+ if (boolean(value(VERBOSE)))
+ printf("\nstarting call...");
+#ifdef DEBUG
+ printf("(acu=%s)\n", acu);
+#endif
+ if ((AC = open(acu, O_RDWR)) < 0) {
+ if (errno == EBUSY)
+ printf("line busy...");
+ else
+ printf("acu open error...");
+ return (0);
+ }
+ if (sigsetjmp(jmpbuf, 1)) {
+ kill(child, SIGKILL);
+ close(AC);
+ return (0);
+ }
+ signal(SIGALRM, alarmtr);
+ timelim = 5 * strlen(num);
+ alarm(timelim < 30 ? 30 : timelim);
+ if ((child = fork()) == 0) {
+ /*
+ * ignore this stuff for aborts
+ */
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ sleep(2);
+ exit(dialit(num, acu) != 'A');
+ }
+ /*
+ * open line - will return on carrier
+ */
+ if ((FD = open(DV, O_RDWR)) < 0) {
+#ifdef DEBUG
+ printf("(after open, errno=%d)\n", errno);
+#endif
+ if (errno == EIO)
+ printf("lost carrier...");
+ else
+ printf("dialup line open failed...");
+ alarm(0);
+ kill(child, SIGKILL);
+ close(AC);
+ return (0);
+ }
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ while ((pid = wait(&status)) != child && pid != -1)
+ ;
+ if (status) {
+ close(AC);
+ return (0);
+ }
+ return (1);
+}
+
+static void
+alarmtr()
+{
+
+ alarm(0);
+ siglongjmp(jmpbuf, 1);
+}
+
+/*
+ * Insurance, for some reason we don't seem to be
+ * hanging up...
+ */
+v831_disconnect()
+{
+ struct termios cntrl;
+ int dtr = TIOCM_DTR;
+
+ sleep(2);
+#ifdef DEBUG
+ printf("[disconnect: FD=%d]\n", FD);
+#endif
+ if (FD > 0) {
+ ioctl(FD, TIOCMBIC, &dtr);
+ ioctl(FD, TCGETS, &cntrl);
+ cfsetospeed(&cntrl, B0);
+ cntrl.c_cflag &= ~XCLUDE;
+ ioctl(FD, TCSETSF, &cntrl);
+ }
+ close(FD);
+}
+
+v831_abort()
+{
+ int dtr = TIOCM_DTR;
+ struct termios buf;
+
+#ifdef DEBUG
+ printf("[abort: AC=%d]\n", AC);
+#endif
+ sleep(2);
+ if (child > 0)
+ kill(child, SIGKILL);
+ if (AC > 0) {
+ ioctl(FD, TCGETS, &buf);
+ buf.c_cflag &= ~XCLUDE;
+ ioctl(FD, TCSETSF, &buf);
+ close(AC);
+ }
+ if (FD > 0)
+ ioctl(FD, TIOCMBIC, &dtr);
+ close(FD);
+}
+
+/*
+ * Sigh, this probably must be changed at each site.
+ */
+struct vaconfig {
+ char *vc_name;
+ char vc_rack;
+ char vc_modem;
+} vaconfig[] = {
+ { "/dev/cua0", '4', '0' },
+ { "/dev/cua1", '4', '1' },
+ { 0 }
+};
+
+#define pc(x) (c = x, write(AC, &c, 1))
+#define ABORT 01
+#define SI 017
+#define STX 02
+#define ETX 03
+
+static
+dialit(phonenum, acu)
+ register char *phonenum;
+ char *acu;
+{
+ register struct vaconfig *vp;
+ struct termios cntrl;
+ char c, *sanitize();
+ int i;
+
+ phonenum = sanitize(phonenum);
+#ifdef DEBUG
+ printf("(dial phonenum=%s)\n", phonenum);
+#endif
+ if (*phonenum == '<' && phonenum[1] == 0)
+ return ('Z');
+ for (vp = vaconfig; vp->vc_name; vp++)
+ if (strcmp(vp->vc_name, acu) == 0)
+ break;
+ if (vp->vc_name == 0) {
+ printf("Unable to locate dialer (%s)\n", acu);
+ return ('K');
+ }
+ ioctl(AC, TCGETS, &cntrl);
+ cfsetospeed(&cntrl, B0);
+ cfsetispeed(&cntrl, B0);
+ cntrl.c_cflag &= ~(CSIZE|PARENB|PARODD);
+ cfsetospeed(&cntrl, B2400);
+ cntrl.c_cflag |= CS8;
+ cntrl.c_iflag &= IXOFF|IXANY;
+ cntrl.c_lflag &= ~(ICANON|ISIG);
+ cntrl.c_oflag = 0;
+ cntrl.c_cc[VMIN] = cntrl.c_cc[VTIME] = 0;
+ ioctl(AC, TCSETSF, &cntrl);
+ ioctl(AC, TCFLSH, TCOFLUSH);
+ pc(STX);
+ pc(vp->vc_rack);
+ pc(vp->vc_modem);
+ while (*phonenum && *phonenum != '<')
+ pc(*phonenum++);
+ pc(SI);
+ pc(ETX);
+ sleep(1);
+ i = read(AC, &c, 1);
+#ifdef DEBUG
+ printf("read %d chars, char=%c, errno %d\n", i, c, errno);
+#endif
+ if (i != 1)
+ c = 'M';
+ if (c == 'B' || c == 'G') {
+ char cc, oc = c;
+
+ pc(ABORT);
+ read(AC, &cc, 1);
+#ifdef DEBUG
+ printf("abort response=%c\n", cc);
+#endif
+ c = oc;
+ v831_disconnect();
+ }
+ close(AC);
+#ifdef DEBUG
+ printf("dialit: returns %c\n", c);
+#endif
+ return (c);
+}
+
+static char *
+sanitize(s)
+ register char *s;
+{
+ static char buf[128];
+ register char *cp;
+
+ for (cp = buf; *s; s++) {
+ if (!isdigit(*s) && *s == '<' && *s != '_')
+ continue;
+ if (*s == '_')
+ *s = '=';
+ *cp++ = *s;
+ }
+ *cp++ = 0;
+ return (buf);
+}
diff --git a/usr/src/cmd/tip/aculib/ventel.c b/usr/src/cmd/tip/aculib/ventel.c
new file mode 100644
index 0000000000..635a879c5c
--- /dev/null
+++ b/usr/src/cmd/tip/aculib/ventel.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 1.5 6/25/83 */
+
+/*
+ * Routines for calling up on a Ventel Modem
+ * Define VENNOECHO if the Ventel is strapped for "no echo".
+ */
+#include "tip.h"
+
+#define MAXRETRY 5
+
+static void sigALRM();
+static int timeout = 0;
+static sigjmp_buf timeoutbuf;
+
+ven_dialer(num, acu)
+ register char *num;
+ char *acu;
+{
+ register char *cp;
+ register int connected = 0;
+ struct termios buf;
+#ifdef ACULOG
+ char line[80];
+#endif
+ /*
+ * Get in synch with a couple of carriage returns
+ */
+ if (!vensync(FD)) {
+ printf("can't synchronize with ventel\n");
+#ifdef ACULOG
+ logent(value(HOST), num, "ventel", "can't synch up");
+#endif
+ return (0);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\ndialing...");
+ fflush(stdout);
+ ioctl(FD, TCGETS, &buf);
+ buf.c_cflag |= HUPCL;
+ ioctl(FD, TCSETSF, &buf);
+#ifdef VENNOECHO
+ echo("#k$\r$\n$D$I$A$L$:$ ");
+ for (cp = num; *cp; cp++) {
+ sleep(1);
+ write(FD, cp, 1);
+ }
+ echo("\r$\n");
+#else
+ echo("k$\r$\n$D$I$A$L$:$ <");
+ for (cp = num; *cp; cp++) {
+ char c;
+
+ sleep(1);
+ write(FD, cp, 1);
+ read(FD, &c, 1);
+ }
+ echo(">\r$\n");
+#endif
+ if (gobble('\n'))
+ connected = gobble('!');
+ ioctl(FD, TCFLSH, TCIOFLUSH);
+#ifdef ACULOG
+ if (timeout) {
+ sprintf(line, "%d second dial timeout",
+ number(value(DIALTIMEOUT)));
+ logent(value(HOST), num, "ventel", line);
+ }
+#endif
+ if (timeout)
+ ven_disconnect(); /* insurance */
+ return (connected);
+}
+
+ven_disconnect()
+{
+
+ close(FD);
+}
+
+ven_abort()
+{
+
+ write(FD, "\03", 1);
+ close(FD);
+}
+
+static int
+echo(s)
+ register char *s;
+{
+ char c;
+
+ while (c = *s++) {
+ switch (c) {
+ case '$':
+ read(FD, &c, 1);
+ s++;
+ break;
+
+ case '#':
+ c = *s++;
+ write(FD, &c, 1);
+ break;
+
+ default:
+ write(FD, &c, 1);
+ read(FD, &c, 1);
+ }
+ }
+}
+
+static void
+sigALRM()
+{
+
+ printf("\07timeout waiting for reply\n");
+ timeout = 1;
+ siglongjmp(timeoutbuf, 1);
+}
+
+static int
+gobble(match)
+ register char match;
+{
+ char c;
+ sig_handler_t f;
+
+ f = signal(SIGALRM, (sig_handler_t)sigALRM);
+ timeout = 0;
+ do {
+ if (sigsetjmp(timeoutbuf, 1)) {
+ signal(SIGALRM, f);
+ return (0);
+ }
+ alarm(number(value(DIALTIMEOUT)));
+ read(FD, &c, 1);
+ alarm(0);
+ c &= 0177;
+#ifdef notdef
+ if (boolean(value(VERBOSE)))
+ putchar(c);
+#endif
+ } while (c != '\n' && c != match);
+ signal(SIGALRM, SIG_DFL);
+ return (c == match);
+}
+
+#define min(a, b) (((a) > (b)) ? (b) : (a))
+/*
+ * This convoluted piece of code attempts to get
+ * the ventel in sync. If you don't have FIONREAD
+ * there are gory ways to simulate this.
+ */
+static int
+vensync(fd)
+{
+ int already = 0, nread;
+ char buf[60];
+ int dtr = TIOCM_DTR;
+
+ /*
+ * Toggle DTR to force anyone off that might have left
+ * the modem connected, and insure a consistent state
+ * to start from.
+ *
+ * If you don't have the ioctl calls to diddle directly
+ * with DTR, you can always try setting the baud rate to 0.
+ */
+ ioctl(FD, TIOCMBIC, &dtr);
+ sleep(2);
+ ioctl(FD, TIOCMBIS, &dtr);
+ while (already < MAXRETRY) {
+ /*
+ * After reseting the modem, send it two \r's to
+ * autobaud on. Make sure to delay between them
+ * so the modem can frame the incoming characters.
+ */
+ write(fd, "\r", 1);
+#ifdef VMUNIX
+ {
+#include <sys/time.h>
+ struct timeval tv = {0, 500000};
+
+ select(0, 0, 0, 0, &tv);
+ }
+#else
+ sleep(1);
+#endif
+ write(fd, "\r", 1);
+ sleep(3);
+ if (ioctl(fd, FIONREAD, (caddr_t)&nread) < 0) {
+ perror("tip: ioctl");
+ continue;
+ }
+ while (nread > 0) {
+ read(fd, buf, min(nread, 60));
+ if ((buf[nread - 1] & 0177) == '$')
+ return (1);
+ nread -= min(nread, 60);
+ }
+ sleep(1);
+ already++;
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/tip/acutab.c b/usr/src/cmd/tip/acutab.c
new file mode 100644
index 0000000000..b7711869b2
--- /dev/null
+++ b/usr/src/cmd/tip/acutab.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.7 6/25/83 */
+
+#include "tip.h"
+
+extern int df02_dialer(), df03_dialer(), df_disconnect(), df_abort(),
+ biz31f_dialer(), biz31_disconnect(), biz31_abort(),
+ biz31w_dialer(),
+ biz22f_dialer(), biz22_disconnect(), biz22_abort(),
+ biz22w_dialer(),
+ hayes_dialer(), hayes_disconnect(), hayes_abort(),
+ ven_dialer(), ven_disconnect(), ven_abort(),
+ v3451_dialer(), v3451_disconnect(), v3451_abort(),
+ v831_dialer(), v831_disconnect(), v831_abort(),
+ dn_dialer(), dn_disconnect(), dn_abort();
+
+acu_t acutable[] = {
+#if BIZ1031
+ "biz31f", biz31f_dialer, biz31_disconnect, biz31_abort,
+ "biz31w", biz31w_dialer, biz31_disconnect, biz31_abort,
+#endif
+#if BIZ1022
+ "biz22f", biz22f_dialer, biz22_disconnect, biz22_abort,
+ "biz22w", biz22w_dialer, biz22_disconnect, biz22_abort,
+#endif
+#if DF02
+ "df02", df02_dialer, df_disconnect, df_abort,
+#endif
+#if DF03
+ "df03", df03_dialer, df_disconnect, df_abort,
+#endif
+#if DN11
+ "dn11", dn_dialer, dn_disconnect, dn_abort,
+#endif
+#ifdef VENTEL
+ "ventel", ven_dialer, ven_disconnect, ven_abort,
+#endif
+#ifdef V3451
+#ifndef V831
+ "vadic", v3451_dialer, v3451_disconnect, v3451_abort,
+#endif
+ "v3451", v3451_dialer, v3451_disconnect, v3451_abort,
+#endif
+#ifdef V831
+#ifndef V3451
+ "vadic", v831_dialer, v831_disconnect, v831_abort,
+#endif
+ "v831", v831_dialer, v831_disconnect, v831_abort,
+#endif
+#ifdef HAYES
+ "hayes", hayes_dialer, hayes_disconnect, hayes_abort,
+ "at", hayes_dialer, hayes_disconnect, hayes_abort,
+#endif
+ 0, 0, 0, 0
+};
diff --git a/usr/src/cmd/tip/cmds.c b/usr/src/cmd/tip/cmds.c
new file mode 100644
index 0000000000..79fc0d58a3
--- /dev/null
+++ b/usr/src/cmd/tip/cmds.c
@@ -0,0 +1,927 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 5.4 5/5/86 */
+
+#include "tip.h"
+#ifdef USG
+#include <unistd.h>
+#else
+#include <vfork.h>
+#endif
+
+/*
+ * tip
+ *
+ * miscellaneous commands
+ */
+
+int quant[] = { 60, 60, 24 };
+
+char null = '\0';
+char *sep[] = { "second", "minute", "hour" };
+static char *argv[10]; /* argument vector for take and put */
+
+sigjmp_buf intbuf; /* for interrupts and timeouts */
+
+void timeout(); /* timeout function called on alarm */
+void intcopy(); /* interrupt routine for file transfers */
+
+/*
+ * FTP - remote ==> local
+ * get a file from the remote host
+ */
+getfl(c)
+ char c;
+{
+ char buf[256], *cp, *expand();
+
+ putchar(c);
+ /*
+ * get the UNIX receiving file's name
+ */
+ if (prompt("Local file name? ", copyname, sizeof (copyname)))
+ return;
+ cp = expand(copyname);
+ if (cp == NOSTR)
+ return;
+ if ((sfd = creat(cp, 0666)) < 0) {
+ printf("\r\n%s: cannot creat\r\n", copyname);
+ return;
+ }
+
+ /*
+ * collect parameters
+ */
+ if (prompt("List command for remote system? ", buf, sizeof (buf))) {
+ unlink(copyname);
+ return;
+ }
+ transfer(buf, sfd, value(EOFREAD));
+}
+
+/*
+ * Cu-like take command
+ */
+cu_take(cc)
+ char cc;
+{
+ int fd, argc;
+ char line[BUFSIZ], *expand(), *cp;
+
+ if (prompt("[take] ", copyname, sizeof (copyname)))
+ return;
+ argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
+ if (argc < 1 || argc > 2) {
+ printf("usage: <take> from [to]\r\n");
+ return;
+ }
+ if (argc == 1)
+ argv[1] = argv[0];
+ cp = expand(argv[1]);
+ if (cp == NOSTR)
+ return;
+ if ((fd = creat(cp, 0666)) < 0) {
+ printf("\r\n%s: cannot create\r\n", argv[1]);
+ return;
+ }
+ sprintf(line, "cat %s; echo \01", argv[0]);
+ transfer(line, fd, "\01");
+}
+
+/*
+ * Bulk transfer routine --
+ * used by getfl(), cu_take(), and pipefile()
+ */
+transfer(buf, fd, eofchars)
+ char *buf, *eofchars;
+{
+ register int ct;
+ char c, buffer[BUFSIZ];
+ char *p = buffer; /* can't be register because of longjmp */
+ register int cnt, eof, bol;
+ time_t start;
+ void (*f)();
+
+ parwrite(FD, buf, strlen(buf));
+ kill(pid, SIGIOT);
+ read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
+
+ /*
+ * finish command
+ */
+ parwrite(FD, "\r", 1);
+ do
+ read(FD, &c, 1);
+ while ((c&0177) != '\n');
+
+ if (sigsetjmp(intbuf, 1))
+ goto out;
+ f = signal(SIGINT, intcopy);
+ intr("on");
+
+ start = time(0);
+ bol = 1;
+ ct = 0;
+ for (;;) {
+ eof = read(FD, &c, 1) <= 0;
+ if (noparity)
+ c &= 0377;
+ else
+ c &= 0177;
+ if (eof || (bol && any(c, eofchars)))
+ break;
+ if (c == 0)
+ continue; /* ignore nulls */
+ if (c == '\r')
+ continue;
+ *p++ = c;
+
+ if (c == '\n') {
+ bol = 1;
+ if (boolean(value(VERBOSE)))
+ printf("\r%d", ++ct);
+ } else
+ bol = 0;
+ if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
+ if (write(fd, buffer, cnt) != cnt) {
+ printf("\r\nwrite error\r\n");
+ goto out;
+ }
+ p = buffer;
+ }
+ }
+out:
+ if (cnt = (p-buffer))
+ if (write(fd, buffer, cnt) != cnt)
+ printf("\r\nwrite error\r\n");
+
+ if (boolean(value(VERBOSE)))
+ prtime(" lines transferred in ", time(0)-start);
+ intr("off");
+ write(fildes[1], (char *)&ccc, 1);
+ signal(SIGINT, f);
+ close(fd);
+}
+
+/*
+ * FTP - remote ==> local process
+ * send remote input to local process via pipe
+ */
+pipefile()
+{
+ int cpid, pdes[2];
+ char buf[256];
+ int status, p;
+ extern int errno;
+
+ if (prompt("Local command? ", buf, sizeof (buf)))
+ return;
+
+ if (pipe(pdes)) {
+ printf("can't establish pipe\r\n");
+ return;
+ }
+
+ if ((cpid = fork()) < 0) {
+ printf("can't fork!\r\n");
+ return;
+ } else if (cpid) {
+ if (prompt("List command for remote system? ", buf,
+ sizeof (buf))) {
+ close(pdes[0]), close(pdes[1]);
+ kill(cpid, SIGKILL);
+ } else {
+ close(pdes[0]);
+ signal(SIGPIPE, intcopy);
+ transfer(buf, pdes[1], value(EOFREAD));
+ signal(SIGPIPE, SIG_DFL);
+ while ((p = wait(&status)) > 0 && p != cpid)
+ ;
+ }
+ } else {
+ register int f;
+
+ userperm();
+ dup2(pdes[0], 0);
+ close(pdes[0]);
+ for (f = 3; f < 20; f++)
+ close(f);
+ execute(buf);
+ printf("can't execl!\r\n");
+ exit(0);
+ }
+}
+
+/*
+ * FTP - local ==> remote
+ * send local file to remote host
+ * terminate transmission with pseudo EOF sequence
+ */
+sendfile(cc)
+ char cc;
+{
+ FILE *fd;
+ char *fnamex;
+ char *expand();
+
+ putchar(cc);
+ /*
+ * get file name
+ */
+ if (prompt("Local file name? ", fname, sizeof (fname)))
+ return;
+
+ /*
+ * look up file
+ */
+ fnamex = expand(fname);
+ if (fnamex == NOSTR)
+ return;
+ if ((fd = fopen(fnamex, "r")) == NULL) {
+ printf("%s: cannot open\r\n", fname);
+ return;
+ }
+ transmit(fd, value(EOFWRITE), NULL);
+ if (!boolean(value(ECHOCHECK))) {
+ struct termios buf;
+
+ ioctl(FD, TCGETS, (char *)&buf); /* this does a */
+ ioctl(FD, TCSETSF, (char *)&buf); /* wflushtty */
+ }
+}
+
+/*
+ * Bulk transfer routine to remote host --
+ * used by sendfile() and cu_put()
+ */
+transmit(fd, eofchars, command)
+ FILE *fd;
+ char *eofchars, *command;
+{
+ void (*ointr)();
+ char *pc, lastc, rc;
+ int c, ccount, lcount;
+ time_t start_t, stop_t;
+
+ kill(pid, SIGIOT); /* put TIPOUT into a wait state */
+ timedout = 0;
+ if (sigsetjmp(intbuf, 1)) {
+ if (timedout)
+ printf("\r\ntimed out at eol\r\n");
+ alarm(0);
+ goto out;
+ }
+ ointr = signal(SIGINT, intcopy);
+ intr("on");
+ read(repdes[0], (char *)&ccc, 1);
+ if (command != NULL) {
+ for (pc = command; *pc; pc++)
+ send(*pc);
+ if (boolean(value(ECHOCHECK)))
+ read(FD, (char *)&c, 1); /* trailing \n */
+ else {
+ struct termios buf;
+
+ sleep(5); /* wait for remote stty to take effect */
+ ioctl(FD, TCGETS, (char *)&buf); /* this does a */
+ ioctl(FD, TCSETSF, (char *)&buf); /* wflushtty */
+ }
+ }
+ lcount = 0;
+ lastc = '\0';
+ start_t = time(0);
+ if (boolean(value(RAWFTP))) {
+ while ((c = getc(fd)) != EOF) {
+ lcount++;
+ send(c);
+ if (boolean(value(VERBOSE)) && lcount%100 == 0)
+ printf("\r%d", lcount);
+ }
+ if (boolean(value(VERBOSE)))
+ printf("\r%d", lcount);
+ goto out;
+ }
+ for (;;) {
+ ccount = 0;
+ do {
+ c = getc(fd);
+ if (c == EOF)
+ goto out;
+ if (c == 0177)
+ continue;
+ lastc = c;
+ if (c < 040) {
+ if (c == '\n') {
+ c = '\r';
+ } else if (c == '\t') {
+ if (boolean(value(TABEXPAND))) {
+ send(' ');
+ while ((++ccount % 8) != 0)
+ send(' ');
+ continue;
+ }
+ } else
+ continue;
+ }
+ send(c);
+ } while (c != '\r');
+ if (boolean(value(VERBOSE)))
+ printf("\r%d", ++lcount);
+ if (boolean(value(ECHOCHECK))) {
+ alarm(number(value(ETIMEOUT)));
+ do { /* wait for prompt */
+ read(FD, &rc, 1);
+ } while ((rc&0177) != character(value(PROMPT)));
+ alarm(0);
+ }
+ }
+out:
+ if (lastc != '\n' && !boolean(value(RAWFTP)))
+ send('\r');
+ if (eofchars)
+ for (pc = eofchars; *pc; pc++)
+ send(*pc);
+ stop_t = time(0);
+ fclose(fd);
+ if (boolean(value(VERBOSE)))
+ if (boolean(value(RAWFTP)))
+ prtime(" chars transferred in ", stop_t-start_t);
+ else
+ prtime(" lines transferred in ", stop_t-start_t);
+ write(fildes[1], (char *)&ccc, 1);
+ intr("off");
+ signal(SIGINT, ointr);
+}
+
+/*
+ * Cu-like put command
+ */
+cu_put(cc)
+ char cc;
+{
+ FILE *fd;
+ char line[BUFSIZ];
+ int argc;
+ char *expand();
+ char *copynamex;
+
+ if (prompt("[put] ", copyname, sizeof (copyname)))
+ return;
+ argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
+ if (argc < 1 || argc > 2) {
+ printf("usage: <put> from [to]\r\n");
+ return;
+ }
+ if (argc == 1)
+ argv[1] = argv[0];
+ copynamex = expand(argv[0]);
+ if (copynamex == NOSTR)
+ return;
+ if ((fd = fopen(copynamex, "r")) == NULL) {
+ printf("%s: cannot open\r\n", copynamex);
+ return;
+ }
+ if (boolean(value(ECHOCHECK)))
+ sprintf(line, "cat>%s\r", argv[1]);
+ else
+ sprintf(line, "stty -echo; cat>%s; stty echo\r", argv[1]);
+ transmit(fd, "\04", line);
+}
+
+/*
+ * FTP - send single character
+ * wait for echo & handle timeout
+ */
+send(c)
+ char c;
+{
+ char cc;
+ int retry = 0;
+
+ cc = c;
+ parwrite(FD, &cc, 1);
+#ifdef notdef
+ if (number(value(CDELAY)) > 0 && c != '\r')
+ nap(number(value(CDELAY)));
+#endif
+ if (!boolean(value(ECHOCHECK))) {
+#ifdef notdef
+ if (number(value(LDELAY)) > 0 && c == '\r')
+ nap(number(value(LDELAY)));
+#endif
+ return;
+ }
+tryagain:
+ timedout = 0;
+ if (sigsetjmp(intbuf, 1) && timedout) {
+ printf("\r\ntimeout error (%s)\r\n", ctrl(c));
+ if (retry++ > 3)
+ return;
+ parwrite(FD, &null, 1); /* poke it */
+ goto tryagain;
+ }
+ alarm(number(value(ETIMEOUT)));
+ read(FD, &cc, 1);
+ alarm(0);
+}
+
+void
+timeout()
+{
+ signal(SIGALRM, (sig_handler_t)timeout);
+ timedout = 1;
+ siglongjmp(intbuf, 1);
+}
+
+/*
+ * Stolen from consh() -- puts a remote file on the output of a local command.
+ * Identical to consh() except for where stdout goes.
+ */
+pipeout(c)
+{
+ char buf[256];
+ int cpid, status, p;
+ time_t start;
+
+ putchar(c);
+ if (prompt("Local command? ", buf, sizeof (buf)))
+ return;
+ kill(pid, SIGIOT); /* put TIPOUT into a wait state */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ intr("on");
+ read(repdes[0], (char *)&ccc, 1);
+ /*
+ * Set up file descriptors in the child and
+ * let it go...
+ */
+ if ((cpid = fork()) < 0)
+ printf("can't fork!\r\n");
+ else if (cpid) {
+ start = time(0);
+ while ((p = wait(&status)) > 0 && p != cpid)
+ ;
+ } else {
+ register int i;
+
+ userperm();
+ dup2(FD, 1);
+ for (i = 3; i < 20; i++)
+ close(i);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ execute(buf);
+ printf("can't find `%s'\r\n", buf);
+ exit(0);
+ }
+ if (boolean(value(VERBOSE)))
+ prtime("away for ", time(0)-start);
+ write(fildes[1], (char *)&ccc, 1);
+ intr("off");
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+}
+
+/*
+ * Fork a program with:
+ * 0 <-> remote tty in
+ * 1 <-> remote tty out
+ * 2 <-> local tty stderr out
+ */
+consh(c)
+{
+ char buf[256];
+ int cpid, status, p;
+ void (*ointr)(), (*oquit)();
+ time_t start;
+
+ putchar(c);
+ if (prompt("Local command? ", buf, sizeof (buf)))
+ return;
+ kill(pid, SIGIOT); /* put TIPOUT into a wait state */
+ read(repdes[0], (char *)&ccc, 1);
+ ointr = signal(SIGINT, SIG_IGN);
+ oquit = signal(SIGQUIT, SIG_IGN);
+ unraw();
+ /*
+ * Set up file descriptors in the child and
+ * let it go...
+ */
+ if ((cpid = fork()) < 0)
+ printf("can't fork!\r\n");
+ else if (cpid) {
+ start = time(0);
+ while ((p = wait(&status)) > 0 && p != cpid)
+ ;
+ raw();
+ signal(SIGINT, ointr);
+ signal(SIGQUIT, oquit);
+ } else {
+ register int i;
+
+ userperm();
+ dup2(FD, 0);
+ dup2(0, 1);
+ for (i = 3; i < 20; i++)
+ close(i);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ execute(buf);
+ printf("can't find `%s'\r\n", buf);
+ exit(0);
+ }
+ if (boolean(value(VERBOSE)))
+ prtime("\r\naway for ", time(0)-start);
+ write(fildes[1], (char *)&ccc, 1);
+}
+
+/*
+ * Escape to local shell
+ */
+shell()
+{
+ int shpid, status;
+ void (*ointr)(), (*oquit)();
+ char *cp;
+
+ printf("[sh]\r\n");
+ ointr = signal(SIGINT, SIG_IGN);
+ oquit = signal(SIGQUIT, SIG_IGN);
+ unraw();
+ if (shpid = fork()) {
+ while (shpid != wait(&status))
+ ;
+ raw();
+ printf("\r\n!\r\n");
+ signal(SIGINT, ointr);
+ signal(SIGQUIT, oquit);
+ } else {
+ userperm();
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+ if ((cp = strrchr(value(SHELL), '/')) == NULL)
+ cp = value(SHELL);
+ else
+ cp++;
+ execl(value(SHELL), cp, 0);
+ printf("\r\ncan't execl!\r\n");
+ exit(1);
+ }
+}
+
+/*
+ * TIPIN portion of scripting
+ * initiate the conversation with TIPOUT
+ */
+setscript()
+{
+ char c;
+ /*
+ * enable TIPOUT side for dialogue
+ */
+ kill(pid, SIGEMT);
+ if (boolean(value(SCRIPT)))
+ write(fildes[1], value(RECORD), strlen(value(RECORD)));
+ write(fildes[1], "\n", 1);
+ /*
+ * wait for TIPOUT to finish
+ */
+ read(repdes[0], &c, 1);
+ if (c == 'n')
+ fprintf(stderr, "tip: can't create record file %s\r\n",
+ value(RECORD));
+}
+
+/*
+ * Change current working directory of
+ * local portion of tip
+ */
+chdirectory()
+{
+ char dirname[80];
+ register char *cp = dirname;
+
+ if (prompt("[cd] ", dirname, sizeof (dirname))) {
+ if (stoprompt)
+ return;
+ cp = value(HOME);
+ }
+ if (chdir(cp) < 0)
+ printf("%s: bad directory\r\n", cp);
+ printf("!\r\n");
+}
+
+/* XXX - really should rename this routine to avoid conflict with libc */
+abort(msg)
+ char *msg;
+{
+
+ signal(SIGCHLD, SIG_DFL); /* don't want to hear about our child */
+ kill(pid, SIGTERM);
+ myperm();
+ disconnect(msg);
+ if (msg != NOSTR)
+ printf("\r\n%s", msg);
+ printf("\r\n[EOT]\r\n");
+ delock(uucplock);
+ unraw();
+ exit(0);
+}
+
+finish()
+{
+ char *dismsg;
+
+ if ((dismsg = value(DISCONNECT)) != NOSTR) {
+ write(FD, dismsg, strlen(dismsg));
+ sleep(5);
+ }
+ abort(NOSTR);
+}
+
+void
+intcopy()
+{
+
+ signal(SIGINT, SIG_IGN);
+ siglongjmp(intbuf, 1);
+}
+
+execute(s)
+ char *s;
+{
+ register char *cp;
+
+ if ((cp = strrchr(value(SHELL), '/')) == NULL)
+ cp = value(SHELL);
+ else
+ cp++;
+ execl(value(SHELL), cp, "-c", s, 0);
+}
+
+args(buf, a, na)
+ char *buf, *a[];
+ size_t na;
+{
+ register char *p = buf, *start;
+ register char **parg = a;
+ register int n = 0;
+
+ do {
+ while (*p && (*p == ' ' || *p == '\t'))
+ p++;
+ start = p;
+ if (*p)
+ *parg = p;
+ while (*p && (*p != ' ' && *p != '\t'))
+ p++;
+ if (p != start)
+ parg++, n++;
+ if (*p)
+ *p++ = '\0';
+ } while (*p && n < na);
+
+ return (n);
+}
+
+prtime(s, a)
+ char *s;
+ time_t a;
+{
+ register i;
+ int nums[3];
+
+ for (i = 0; i < 3; i++) {
+ nums[i] = (int)(a % quant[i]);
+ a /= quant[i];
+ }
+ printf("%s", s);
+ while (--i >= 0)
+ if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
+ printf("%d %s%c ", nums[i], sep[i],
+ nums[i] == 1 ? '\0' : 's');
+ printf("\r\n!\r\n");
+}
+
+variable()
+{
+ char buf[256];
+
+ if (prompt("[set] ", buf, sizeof (buf)))
+ return;
+ vlex(buf);
+ if (vtable[BEAUTIFY].v_access&CHANGED) {
+ vtable[BEAUTIFY].v_access &= ~CHANGED;
+ kill(pid, SIGSYS);
+ }
+ if (vtable[SCRIPT].v_access&CHANGED) {
+ vtable[SCRIPT].v_access &= ~CHANGED;
+ setscript();
+ /*
+ * So that "set record=blah script" doesn't
+ * cause two transactions to occur.
+ */
+ if (vtable[RECORD].v_access&CHANGED)
+ vtable[RECORD].v_access &= ~CHANGED;
+ }
+ if (vtable[RECORD].v_access&CHANGED) {
+ vtable[RECORD].v_access &= ~CHANGED;
+ if (boolean(value(SCRIPT)))
+ setscript();
+ }
+ if (vtable[TAND].v_access&CHANGED) {
+ vtable[TAND].v_access &= ~CHANGED;
+ if (boolean(value(TAND)))
+ tandem("on");
+ else
+ tandem("off");
+ }
+ if (vtable[LECHO].v_access&CHANGED) {
+ vtable[LECHO].v_access &= ~CHANGED;
+ boolean(value(HALFDUPLEX)) = boolean(value(LECHO));
+ }
+ if (vtable[PARITY].v_access&CHANGED) {
+ vtable[PARITY].v_access &= ~CHANGED;
+ setparity(NULL);
+ }
+ if (vtable[BAUDRATE].v_access&CHANGED) {
+ vtable[BAUDRATE].v_access &= ~CHANGED;
+ ttysetup(speed(number(value(BAUDRATE))));
+ }
+ if (vtable[HARDWAREFLOW].v_access & CHANGED) {
+ vtable[HARDWAREFLOW].v_access &= ~CHANGED;
+ if (boolean(value(HARDWAREFLOW)))
+ hardwareflow("on");
+ else
+ hardwareflow("off");
+ }
+}
+
+/*
+ * Turn tandem mode on or off for remote tty.
+ */
+tandem(option)
+ char *option;
+{
+ struct termios rmtty;
+
+ ioctl(FD, TCGETS, (char *)&rmtty);
+ if (equal(option, "on")) {
+ rmtty.c_iflag |= IXOFF|IXON;
+ arg.c_iflag |= IXOFF|IXON;
+ rmtty.c_cc[VSTART] = defarg.c_cc[VSTART];
+ rmtty.c_cc[VSTOP] = defarg.c_cc[VSTOP];
+ } else {
+ rmtty.c_iflag &= ~(IXOFF|IXON);
+ arg.c_iflag &= ~(IXOFF|IXON);
+ }
+ ioctl(FD, TCSETSF, (char *)&rmtty);
+ ioctl(0, TCSETSF, (char *)&arg);
+}
+
+/*
+ * Turn hardwareflow mode on or off for remote tty.
+ */
+hardwareflow(option)
+ char *option;
+{
+ struct termios rmtty;
+
+ ioctl(FD, TCGETS, (char *)&rmtty);
+ if (equal(option, "on")) {
+ rmtty.c_cflag |= (CRTSCTS|CRTSXOFF);
+ } else {
+ rmtty.c_cflag &= ~(CRTSCTS|CRTSXOFF);
+ }
+ ioctl(FD, TCSETSF, (char *)&rmtty);
+}
+
+/*
+ * Turn interrupts from local tty on or off.
+ */
+intr(option)
+ char *option;
+{
+
+ if (equal(option, "on"))
+ arg.c_lflag |= ISIG;
+ else
+ arg.c_lflag &= ~ISIG;
+ ioctl(0, TCSETSF, (char *)&arg);
+}
+
+/*
+ * Send a break.
+ */
+genbrk()
+{
+
+ ioctl(FD, TCSBRK, 0);
+}
+
+/*
+ * Suspend tip
+ */
+suspend(c)
+ char c;
+{
+
+ unraw();
+ kill(c == _CTRL('y') ? getpid() : 0, SIGTSTP);
+ raw();
+}
+
+/*
+ * expand a file name if it includes shell meta characters
+ */
+
+char *
+expand(name)
+ char name[];
+{
+ static char xname[BUFSIZ];
+ char cmdbuf[BUFSIZ];
+ register int pid, l, rc;
+ register char *cp, *Shell;
+ int s, pivec[2];
+ void (*sigint)();
+
+ if (!anyof(name, "~{[*?$`'\"\\"))
+ return (name);
+ /* sigint = signal(SIGINT, SIG_IGN); */
+ if (pipe(pivec) < 0) {
+ perror("pipe");
+ /* signal(SIGINT, sigint) */
+ return (name);
+ }
+ sprintf(cmdbuf, "echo %s", name);
+ if ((pid = vfork()) == 0) {
+ userperm();
+ Shell = value(SHELL);
+ if (Shell == NOSTR)
+ Shell = "/bin/sh";
+ close(pivec[0]);
+ close(1);
+ dup(pivec[1]);
+ close(pivec[1]);
+ close(2);
+ execl(Shell, Shell, "-c", cmdbuf, 0);
+ _exit(1);
+ }
+ if (pid == -1) {
+ perror("fork");
+ close(pivec[0]);
+ close(pivec[1]);
+ return (NOSTR);
+ }
+ close(pivec[1]);
+ l = read(pivec[0], xname, BUFSIZ);
+ close(pivec[0]);
+ while (wait(&s) != pid);
+ ;
+ s &= 0377;
+ if (s != 0 && s != SIGPIPE) {
+ fprintf(stderr, "\"Echo\" failed\n");
+ return (NOSTR);
+ }
+ if (l < 0) {
+ perror("read");
+ return (NOSTR);
+ }
+ if (l == 0) {
+ fprintf(stderr, "\"%s\": No match\n", name);
+ return (NOSTR);
+ }
+ if (l == BUFSIZ) {
+ fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
+ return (NOSTR);
+ }
+ xname[l] = 0;
+ for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
+ ;
+ *++cp = '\0';
+ return (xname);
+}
+
+/*
+ * Are any of the characters in the two strings the same?
+ */
+
+anyof(s1, s2)
+ register char *s1, *s2;
+{
+ register int c;
+
+ while (c = *s1++)
+ if (any(c, s2))
+ return (1);
+ return (0);
+}
diff --git a/usr/src/cmd/tip/cmdtab.c b/usr/src/cmd/tip/cmdtab.c
new file mode 100644
index 0000000000..52857f5685
--- /dev/null
+++ b/usr/src/cmd/tip/cmdtab.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 5.3 5/5/86 */
+
+#include "tip.h"
+
+extern int shell(), getfl(), sendfile(), chdirectory();
+extern int finish(), help(), pipefile(), pipeout(), consh(), variable();
+extern int cu_take(), cu_put(), dollar(), genbrk(), suspend();
+
+esctable_t etable[] = {
+ { '!', NORM, "shell", shell },
+ { '<', NORM, "receive file from remote host", getfl },
+ { '>', NORM, "send file to remote host", sendfile },
+ { 't', NORM, "take file from remote UNIX", cu_take },
+ { 'p', NORM, "put file to remote UNIX", cu_put },
+ { '|', NORM, "pipe remote file", pipefile },
+ { 'C', NORM, "connect program to remote host", consh },
+ { 'c', NORM, "change directory", chdirectory },
+ { '.', NORM, "exit from tip", finish },
+ {_CTRL('d'), NORM, "exit from tip", finish },
+ { '$', NORM, "pipe local command to remote host", pipeout },
+ {_CTRL('y'), NORM, "suspend tip (local only)", suspend },
+ {_CTRL('z'), NORM, "suspend tip (local+remote)", suspend },
+ { 's', NORM, "set variable", variable },
+ { '?', NORM, "get this summary", help },
+ { '#', NORM, "send break", genbrk },
+ { 0, 0, 0 }
+};
diff --git a/usr/src/cmd/tip/cu.c b/usr/src/cmd/tip/cu.c
new file mode 100644
index 0000000000..e67101f8bc
--- /dev/null
+++ b/usr/src/cmd/tip/cu.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 5.2 1/13/86 */
+
+#include "tip.h"
+
+void cleanup();
+void timeout();
+
+/*
+ * Botch the interface to look like cu's
+ */
+cumain(argc, argv)
+ char *argv[];
+{
+ register int i;
+ static char sbuf[12];
+
+ if (argc < 2) {
+usage:
+ fprintf(stderr,
+ "usage: cu telno [-t] [-s speed] [-a acu] [-l line] [-#]\n");
+ exit(8);
+ }
+ CU = DV = NOSTR;
+ for (; argc > 1; argv++, argc--) {
+ if (argv[1][0] != '-')
+ PN = argv[1];
+ else if (argv[1][1] != '\0' && argv[1][2] != '\0') {
+ fprintf(stderr, "cu: extra characters after flag: %s\n",
+ argv[1]);
+ goto usage;
+ } else switch (argv[1][1]) {
+
+ case 't':
+ HW = 1, DU = -1;
+ --argc;
+ continue;
+
+ case 'a':
+ CU = argv[2]; ++argv; --argc;
+ break;
+
+ case 's':
+ if (argc < 3)
+ goto usage;
+ if (speed(atoi(argv[2])) == 0) {
+ fprintf(stderr, "cu: unsupported speed %s\n",
+ argv[2]);
+ exit(3);
+ }
+ BR = atoi(argv[2]); ++argv; --argc;
+ break;
+
+ case 'l':
+ DV = argv[2]; ++argv; --argc;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (CU)
+ CU[strlen(CU)-1] = argv[1][1];
+ if (DV)
+ DV[strlen(DV)-1] = argv[1][1];
+ break;
+
+ default:
+ fprintf(stderr, "cu: bad flag %s\n", argv[1]);
+ goto usage;
+ }
+ }
+ signal(SIGINT, cleanup);
+ signal(SIGQUIT, cleanup);
+ signal(SIGHUP, cleanup);
+ signal(SIGTERM, cleanup);
+
+ /*
+ * The "cu" host name is used to define the
+ * attributes of the generic dialer.
+ */
+ sprintf(sbuf, "cu%d", BR);
+ if ((i = hunt(sbuf)) == 0) {
+ printf("all ports busy\n");
+ exit(3);
+ }
+ if (i == -1) {
+ printf("link down\n");
+ delock(uucplock);
+ exit(3);
+ }
+ setbuf(stdout, NULL);
+ loginit();
+ gid = getgid();
+ egid = getegid();
+ uid = getuid();
+ euid = geteuid();
+ userperm();
+ vinit();
+ setparity("none");
+ boolean(value(VERBOSE)) = 0;
+ if (HW)
+ ttysetup(speed(BR));
+ if (connect()) {
+ printf("Connect failed\n");
+ myperm();
+ delock(uucplock);
+ exit(1);
+ }
+ if (!HW)
+ ttysetup(speed(BR));
+}
diff --git a/usr/src/cmd/tip/etc.remote b/usr/src/cmd/tip/etc.remote
new file mode 100644
index 0000000000..4522fc447b
--- /dev/null
+++ b/usr/src/cmd/tip/etc.remote
@@ -0,0 +1,42 @@
+cuab:dv=/dev/cua/b:br#2400
+dialup1|Dial-up system:\
+ :pn=2015551212:tc=UNIX-2400:
+hardwire:\
+ :dv=/dev/term/b:br#9600:el=^C^S^Q^U^D:ie=%$:oe=^D:
+tip300:tc=UNIX-300:
+tip1200:tc=UNIX-1200:
+tip0|tip2400:tc=UNIX-2400:
+tip9600:tc=UNIX-9600:
+tip19200:tc=UNIX-19200:
+UNIX-300:\
+ :el=^D^U^C^S^Q^O@:du:at=hayes:ie=#$%:oe=^D:br#300:tc=dialers:
+UNIX-1200:\
+ :el=^D^U^C^S^Q^O@:du:at=hayes:ie=#$%:oe=^D:br#1200:tc=dialers:
+UNIX-2400:\
+ :el=^D^U^C^S^Q^O@:du:at=hayes:ie=#$%:oe=^D:br#2400:tc=dialers:
+UNIX-9600:\
+ :el=^D^U^C^S^Q^O@:du:at=hayes:ie=#$%:oe=^D:br#9600:tc=dialers:
+UNIX-19200:\
+ :el=^D^U^C^S^Q^O@:du:at=hayes:ie=#$%:oe=^D:br#19200:tc=dialers:
+VMS-300|TOPS20-300:\
+ :el=^Z^U^C^S^Q^O:du:at=hayes:ie=$@:oe=^Z:br#300:tc=dialers:
+VMS-1200|TOPS20-1200:\
+ :el=^Z^U^C^S^Q^O:du:at=hayes:ie=$@:oe=^Z:br#1200:tc=dialers:
+dialers:\
+ :dv=/dev/cua/b:
+--------------------------------------------------------------------
+The attributes are:
+
+dv device to use for the tty
+el EOL marks (default is NULL)
+du make a call flag (dial up)
+pn phone numbers (@ =>'s search phones file; possibly taken from
+ PHONES environment variable)
+at ACU type
+ie input EOF marks (default is NULL)
+oe output EOF string (default is NULL)
+cu call unit (default is dv)
+br baud rate (defaults to 300)
+fs frame size (default is BUFSIZ) -- used in buffering writes
+ on receive operations
+tc to continue a capability
diff --git a/usr/src/cmd/tip/hunt.c b/usr/src/cmd/tip/hunt.c
new file mode 100644
index 0000000000..77795255c4
--- /dev/null
+++ b/usr/src/cmd/tip/hunt.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.7 6/25/83 */
+
+#include "tip.h"
+
+extern char *getremote();
+extern int errno;
+
+static sigjmp_buf deadline;
+static int deadfl;
+
+void
+dead()
+{
+
+ deadfl = 1;
+ siglongjmp(deadline, 1);
+}
+
+hunt(name)
+ char *name;
+{
+ register char *cp;
+ void (*f)();
+
+ f = signal(SIGALRM, (sig_handler_t)dead);
+ while (cp = getremote(name)) {
+ deadfl = 0;
+ uucplock = cp;
+ if (mlock(uucplock) < 0) {
+ delock(uucplock);
+ continue;
+ }
+ /*
+ * Straight through call units, such as the BIZCOMP,
+ * VADIC and the DF, must indicate they're hardwired in
+ * order to get an open file descriptor placed in FD.
+ * Otherwise, as for a DN-11, the open will have to
+ * be done in the "open" routine.
+ */
+ if (!HW)
+ break;
+ if (sigsetjmp(deadline, 1) == 0) {
+ alarm(10);
+ if (!trusted_device)
+ userperm();
+ errno = 0;
+ if ((FD = open(cp, O_RDWR)) < 0 && errno != EBUSY) {
+ fprintf(stderr, "tip: ");
+ perror(cp);
+ }
+ if (!trusted_device)
+ myperm();
+ if (FD >= 0 && !isatty(FD)) {
+ fprintf(stderr, "tip: %s: not a tty\n", cp);
+ close(FD);
+ FD = -1;
+ }
+ }
+ alarm(0);
+ if (!deadfl && FD >= 0) {
+ struct termios t;
+
+ ioctl(FD, TCGETS, &t);
+ t.c_cflag |= XCLUDE|HUPCL;
+ ioctl(FD, TCSETSF, &t);
+ signal(SIGALRM, f);
+ return ((int)cp);
+ }
+ delock(uucplock);
+ }
+ signal(SIGALRM, f);
+ return (deadfl ? -1 : (int)cp);
+}
diff --git a/usr/src/cmd/tip/log.c b/usr/src/cmd/tip/log.c
new file mode 100644
index 0000000000..6350746d24
--- /dev/null
+++ b/usr/src/cmd/tip/log.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.6 6/25/83 */
+
+#include "tip.h"
+
+static FILE *flog = NULL;
+
+/*
+ * Log file maintenance routines
+ */
+
+logent(group, num, acu, message)
+ char *group, *num, *acu, *message;
+{
+ char *user, *timestamp;
+ struct passwd *pwd;
+ time_t t;
+
+ if (flog == NULL)
+ return;
+#ifndef USG
+ if (flock(fileno(flog), LOCK_EX) < 0) {
+ perror("tip: flock");
+ return;
+ }
+#endif
+ if ((user = getlogin()) == NOSTR)
+ if ((pwd = getpwuid(uid)) == NOPWD)
+ user = "???";
+ else
+ user = pwd->pw_name;
+ t = time(0);
+ timestamp = ctime(&t);
+ timestamp[24] = '\0';
+ fprintf(flog, "%s (%s) <%s, %s, %s> %s\n",
+ user, timestamp, group,
+#ifdef PRISTINE
+ "",
+#else
+ num,
+#endif
+ acu, message);
+ fflush(flog);
+#ifndef USG
+ (void) flock(fileno(flog), LOCK_UN);
+#endif
+}
+
+loginit()
+{
+
+#ifdef ACULOG
+ flog = fopen(value(LOG), "a");
+ if (flog == NULL)
+ fprintf(stderr, "tip: can't open log file %s\r\n", value(LOG));
+#endif
+}
diff --git a/usr/src/cmd/tip/partab.c b/usr/src/cmd/tip/partab.c
new file mode 100644
index 0000000000..818269641d
--- /dev/null
+++ b/usr/src/cmd/tip/partab.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.2 6/25/83 */
+
+/*
+ * Even parity table for 0-0177
+ */
+unsigned char evenpartab[] = {
+ 0000, 0201, 0202, 0003, 0204, 0005, 0006, 0207,
+ 0210, 0011, 0012, 0213, 0014, 0215, 0216, 0017,
+ 0220, 0021, 0022, 0223, 0024, 0225, 0226, 0027,
+ 0030, 0231, 0232, 0033, 0234, 0035, 0036, 0237,
+ 0240, 0041, 0042, 0243, 0044, 0245, 0246, 0047,
+ 0050, 0251, 0252, 0053, 0254, 0055, 0056, 0257,
+ 0060, 0261, 0262, 0063, 0264, 0065, 0066, 0267,
+ 0270, 0071, 0072, 0273, 0074, 0275, 0276, 0077,
+ 0300, 0101, 0102, 0303, 0104, 0305, 0306, 0107,
+ 0110, 0311, 0312, 0113, 0314, 0115, 0116, 0317,
+ 0120, 0321, 0322, 0123, 0324, 0125, 0126, 0327,
+ 0330, 0131, 0132, 0333, 0134, 0335, 0336, 0137,
+ 0140, 0341, 0342, 0143, 0344, 0145, 0146, 0347,
+ 0350, 0151, 0152, 0353, 0154, 0355, 0356, 0157,
+ 0360, 0161, 0162, 0363, 0164, 0365, 0366, 0167,
+ 0170, 0371, 0372, 0173, 0374, 0175, 0176, 0377,
+
+ /*
+ * The following is meaningless for parity
+ * but it lets us share the same table for the
+ * algortithms in tip.c (pwrite()).
+ */
+
+ 0000, 0201, 0202, 0003, 0204, 0005, 0006, 0207,
+ 0210, 0011, 0012, 0213, 0014, 0215, 0216, 0017,
+ 0220, 0021, 0022, 0223, 0024, 0225, 0226, 0027,
+ 0030, 0231, 0232, 0033, 0234, 0035, 0036, 0237,
+ 0240, 0041, 0042, 0243, 0044, 0245, 0246, 0047,
+ 0050, 0251, 0252, 0053, 0254, 0055, 0056, 0257,
+ 0060, 0261, 0262, 0063, 0264, 0065, 0066, 0267,
+ 0270, 0071, 0072, 0273, 0074, 0275, 0276, 0077,
+ 0300, 0101, 0102, 0303, 0104, 0305, 0306, 0107,
+ 0110, 0311, 0312, 0113, 0314, 0115, 0116, 0317,
+ 0120, 0321, 0322, 0123, 0324, 0125, 0126, 0327,
+ 0330, 0131, 0132, 0333, 0134, 0335, 0336, 0137,
+ 0140, 0341, 0342, 0143, 0344, 0145, 0146, 0347,
+ 0350, 0151, 0152, 0353, 0154, 0355, 0356, 0157,
+ 0360, 0161, 0162, 0363, 0164, 0365, 0366, 0167,
+ 0170, 0371, 0372, 0173, 0374, 0175, 0176, 0377
+};
diff --git a/usr/src/cmd/tip/remcap.c b/usr/src/cmd/tip/remcap.c
new file mode 100644
index 0000000000..ee515cf077
--- /dev/null
+++ b/usr/src/cmd/tip/remcap.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2000,2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* from UCB 4.8 6/25/83 */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * remcap - routines for dealing with the remote host data base
+ *
+ * derived from termcap
+ */
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h> /* for O_RDONLY */
+#else
+#include <sys/file.h> /* for O_RDONLY */
+#include <ctype.h>
+#endif
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+#define SYSREMOTE "/etc/remote" /* system remote file */
+
+#define tgetent rgetent
+#define tnchktc rnchktc
+#define tnamatch rnamatch
+#define tgetnum rgetnum
+#define tgetflag rgetflag
+#define tgetstr rgetstr
+#define E_TERMCAP RM = SYSREMOTE
+#define V_TERMCAP "REMOTE"
+#define V_TERM "HOST"
+
+char *RM;
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+char *tskip();
+char *tgetstr();
+char *tdecode();
+char *getenv();
+static char *remotefile;
+
+/*
+ * If we use a user specified entry to get the device name,
+ * we need to open the device as the user.
+ */
+int trusted_device = 0;
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+tgetent(bp, name, len)
+ char *bp, *name;
+ int len;
+{
+ char lbuf[BUFSIZ], *cp, *p;
+ int rc1, rc2;
+
+ trusted_device = 1;
+
+ remotefile = cp = getenv(V_TERMCAP);
+ if (cp == (char *)0 || strcmp(cp, SYSREMOTE) == 0) {
+ remotefile = cp = SYSREMOTE;
+ return (getent(bp, name, cp, len));
+ } else {
+ if ((rc1 = getent(bp, name, cp, len)) != 1)
+ *bp = '\0';
+ remotefile = cp = SYSREMOTE;
+ rc2 = getent(lbuf, name, cp, sizeof (lbuf));
+ if (rc1 != 1 && rc2 != 1)
+ return (rc2);
+ if (rc2 == 1) {
+ p = lbuf;
+ if (rc1 == 1)
+ while (*p++ != ':')
+ ;
+ if (strlen(bp) + strlen(p) >= len) {
+ write(2, "Remcap entry too long\n", 23);
+ return (-1);
+ }
+ strcat(bp, p);
+ }
+ tbuf = bp;
+ return (1);
+ }
+}
+
+getent(bp, name, cp, len)
+ char *bp, *name, *cp;
+ int len;
+{
+ register int c;
+ register int i = 0, cnt = 0;
+ char ibuf[BUFSIZ], *cp2;
+ int tf;
+ int safe = 1; /* reset only when we open the user's $REMOTE */
+
+ tbuf = bp;
+ tf = 0;
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ if (*cp != '/') {
+ cp2 = getenv(V_TERM);
+ if (cp2 == (char *)0 || strcmp(name, cp2) == 0) {
+ if (strstr(cp, "dv=") != 0)
+ trusted_device = 0;
+ strncpy(bp, cp, len-1);
+ bp[len-1] = '\0';
+ return (tnchktc());
+ } else
+ tf = open(E_TERMCAP, O_RDONLY);
+ } else {
+ /* open SYSREMOTE as uucp, other files as user */
+ safe = strcmp(cp, SYSREMOTE) == 0;
+ if (!safe)
+ userperm();
+ tf = open(RM = cp, O_RDONLY);
+ if (!safe)
+ myperm();
+ }
+ }
+ if (tf == 0)
+ tf = open(E_TERMCAP, O_RDONLY);
+ if (tf < 0)
+ return (-1);
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\') {
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+len) {
+ write(2, "Remcap entry too long\n", 23);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ /*
+ * if a dv= entry is obtained from $REMOTE,
+ * switch off trusted_device status
+ */
+ if (!safe && strstr(bp, "dv=") != 0)
+ trusted_device = 0;
+ close(tf);
+ return (tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+tnchktc()
+{
+ register char *p, *q;
+ char tcname[64]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+ char *cp;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p < tbuf) {
+ write(2, "Bad remcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return (1);
+ strlcpy(tcname, p+3, sizeof (tcname));
+ q = tcname;
+ while (*q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(2, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (getent(tcbuf, tcname, remotefile, sizeof (tcbuf)) != 1) {
+ if (strcmp(remotefile, SYSREMOTE) == 0)
+ return (0);
+ else if (getent(tcbuf, tcname, SYSREMOTE, sizeof (tcbuf)) != 1)
+ return (0);
+ }
+ for (q = tcbuf; *q++ != ':'; )
+ ;
+ l = p - holdtbuf + strlen(q);
+ if (l > BUFSIZ) {
+ write(2, "Remcap entry too long\n", 23);
+ q[BUFSIZ - (p-holdtbuf)] = 0;
+ }
+ strcpy(p, q);
+ tbuf = holdtbuf;
+ return (1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+tnamatch(np)
+ char *np;
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return (0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ register char *bp;
+{
+
+ while (*bp && *bp != ':')
+ bp++;
+ if (*bp == ':') {
+ do {
+ bp++;
+ while (isspace(*bp))
+ bp++;
+ } while (*bp == ':');
+ }
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+tgetnum(id)
+ char *id;
+{
+ register int i, base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return (-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+tgetflag(id)
+ char *id;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return (0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return (0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ register char *str;
+ char **area;
+{
+ register char *cp;
+ register int c;
+ register char *dp;
+ int i;
+
+ cp = *area;
+ while ((c = *str++) && c != ':') {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
diff --git a/usr/src/cmd/tip/remote.c b/usr/src/cmd/tip/remote.c
new file mode 100644
index 0000000000..57848eec8f
--- /dev/null
+++ b/usr/src/cmd/tip/remote.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 5.3 4/30/86 */
+
+#include "tip.h"
+
+/*
+ * Attributes to be gleened from remote host description
+ * data base.
+ */
+static char **caps[] = {
+ &AT, &DV, &CM, &CU, &EL, &IE, &OE, &PN, &PR, &DI,
+ &ES, &EX, &FO, &RC, &RE, &PA
+};
+
+static char *capstrings[] = {
+ "at", "dv", "cm", "cu", "el", "ie", "oe", "pn", "pr",
+ "di", "es", "ex", "fo", "rc", "re", "pa", 0
+};
+
+char *rgetstr();
+
+static
+getremcap(host)
+ register char *host;
+{
+ int stat;
+ char tbuf[BUFSIZ];
+ static char buf[BUFSIZ/2];
+ char *bp = buf;
+ register char **p, ***q;
+
+ if ((stat = rgetent(tbuf, host, sizeof (tbuf))) <= 0) {
+ if (DV ||
+ host[0] == '/' && access(DV = host, R_OK | W_OK) == 0) {
+ /*
+ * If the user specifies a device on the commandline,
+ * don't trust it.
+ */
+ if (host[0] == '/')
+ trusted_device = 0;
+ CU = DV;
+ HO = host;
+ HW = 1;
+ DU = 0;
+ if (!BR)
+ BR = DEFBR;
+ FS = DEFFS;
+ RE = (char *)"tip.record";
+ EX = (char *)"\t\n\b\f";
+ DL = 0;
+ CL = 0;
+ ET = 10;
+ return;
+ }
+ fprintf(stderr, stat == 0 ?
+ "tip: unknown host %s\n" :
+ "tip: can't open host description file\n", host);
+ exit(3);
+ }
+
+ for (p = capstrings, q = caps; *p != NULL; p++, q++)
+ if (**q == NULL)
+ **q = rgetstr(*p, &bp);
+ if (!BR && (BR = rgetnum("br")) < 0)
+ BR = DEFBR;
+ if ((FS = rgetnum("fs")) < 0)
+ FS = DEFFS;
+ if (DU < 0)
+ DU = 0;
+ else
+ DU = rgetflag("du");
+ if (DV == NOSTR) {
+ fprintf(stderr, "%s: missing device spec\n", host);
+ exit(3);
+ }
+ if (DU && CU == NOSTR)
+ CU = DV;
+ if (DU && PN == NOSTR) {
+ fprintf(stderr, "%s: missing phone number\n", host);
+ exit(3);
+ }
+ DB = rgetflag("db");
+
+ /*
+ * This effectively eliminates the "hw" attribute
+ * from the description file
+ */
+ if (!HW)
+ HW = (CU == NOSTR) || (DU && equal(DV, CU));
+ HO = host;
+ /*
+ * see if uppercase mode should be turned on initially
+ */
+ if (rgetflag("ra"))
+ boolean(value(RAISE)) = 1;
+ if (rgetflag("ec"))
+ boolean(value(ECHOCHECK)) = 1;
+ if (rgetflag("be"))
+ boolean(value(BEAUTIFY)) = 1;
+ if (rgetflag("nb"))
+ boolean(value(BEAUTIFY)) = 0;
+ if (rgetflag("sc"))
+ boolean(value(SCRIPT)) = 1;
+ if (rgetflag("tb"))
+ boolean(value(TABEXPAND)) = 1;
+ if (rgetflag("vb"))
+ boolean(value(VERBOSE)) = 1;
+ if (rgetflag("nv"))
+ boolean(value(VERBOSE)) = 0;
+ if (rgetflag("ta"))
+ boolean(value(TAND)) = 1;
+ if (rgetflag("nt"))
+ boolean(value(TAND)) = 0;
+ if (rgetflag("rw"))
+ boolean(value(RAWFTP)) = 1;
+ if (rgetflag("hd"))
+ boolean(value(HALFDUPLEX)) = 1;
+ if (rgetflag("hf"))
+ boolean(value(HARDWAREFLOW)) = 1;
+ if (RE == NULL)
+ RE = (char *)"tip.record";
+ if (EX == NULL)
+ EX = (char *)"\t\n\b\f";
+ if (ES != NOSTR)
+ vstring("es", ES);
+ if (FO != NOSTR)
+ vstring("fo", FO);
+ if (PR != NOSTR)
+ vstring("pr", PR);
+ if (RC != NOSTR)
+ vstring("rc", RC);
+ if ((DL = rgetnum("dl")) < 0)
+ DL = 0;
+ if ((CL = rgetnum("cl")) < 0)
+ CL = 0;
+ if ((ET = rgetnum("et")) < 0)
+ ET = 10;
+}
+
+char *
+getremote(host)
+ char *host;
+{
+ register char *cp;
+ static char *next;
+ static int lookedup = 0;
+
+ if (!lookedup) {
+ if (host == NOSTR && (host = getenv("HOST")) == NOSTR) {
+ fprintf(stderr, "tip: no host specified\n");
+ exit(3);
+ }
+ getremcap(host);
+ next = DV;
+ lookedup++;
+ }
+ /*
+ * We return a new device each time we're called (to allow
+ * a rotary action to be simulated)
+ */
+ if (next == NOSTR)
+ return (NOSTR);
+ if ((cp = strchr(next, ',')) == NULL) {
+ DV = next;
+ next = NOSTR;
+ } else {
+ *cp++ = '\0';
+ DV = next;
+ next = cp;
+ }
+ return (DV);
+}
diff --git a/usr/src/cmd/tip/tip.c b/usr/src/cmd/tip/tip.c
new file mode 100644
index 0000000000..87eee957a8
--- /dev/null
+++ b/usr/src/cmd/tip/tip.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 5.4 4/3/86 */
+
+/*
+ * tip - UNIX link to other systems
+ * tip [-v] [-speed] system-name
+ * or
+ * cu phone-number [-s speed] [-l line] [-a acu]
+ */
+#include "tip.h"
+#include <sys/wait.h>
+#include <locale.h>
+
+/*
+ * Baud rate mapping table
+ */
+int bauds[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600,
+ 1200, 1800, 2400, 4800, 9600, 19200, 38400,
+ 57600, 76800, 115200, 153600, 230400, 307200, 460800, -1
+};
+
+void intprompt();
+void timeout();
+void deadkid();
+void cleanup();
+char *sname();
+char PNbuf[256]; /* This limits the size of a number */
+int noparity = 0;
+
+
+main(argc, argv)
+ char *argv[];
+{
+ char *system = NOSTR;
+ register int i;
+ register char *p;
+ char sbuf[12];
+
+ gid = getgid();
+ egid = getegid();
+ uid = getuid();
+ euid = geteuid();
+ if (equal(sname(argv[0]), "cu")) {
+ cumode = 1;
+ cumain(argc, argv);
+ goto cucommon;
+ }
+
+ if (argc > 4) {
+ fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
+ exit(1);
+ }
+ if (!isatty(0)) {
+ fprintf(stderr, "tip: must be interactive\n");
+ exit(1);
+ }
+
+ for (; argc > 1; argv++, argc--) {
+ if (argv[1][0] != '-')
+ system = argv[1];
+ else switch (argv[1][1]) {
+
+ case 'v':
+ vflag++;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ BR = atoi(&argv[1][1]);
+ break;
+
+ default:
+ fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
+ break;
+ }
+ }
+
+ (void) setlocale(LC_CTYPE, "");
+
+ if (system == NOSTR)
+ goto notnumber;
+ for (p = system; *p; p++)
+ if (isalpha(*p))
+ goto notnumber;
+ /*
+ * System name is really a phone number...
+ * Copy the number then stomp on the original (in case the number
+ * is private, we don't want 'ps' or 'w' to find it).
+ */
+ if (strlen(system) > sizeof (PNbuf) - 1) {
+ fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
+ sizeof (PNbuf) - 1);
+ exit(1);
+ }
+ strncpy(PNbuf, system, sizeof (PNbuf) - 1);
+ for (p = system; *p; p++)
+ *p = '\0';
+ PN = PNbuf;
+ sprintf(sbuf, "tip%d", BR);
+ system = sbuf;
+
+notnumber:
+ signal(SIGINT, cleanup);
+ signal(SIGQUIT, cleanup);
+ signal(SIGHUP, cleanup);
+ signal(SIGTERM, cleanup);
+
+ if ((i = hunt(system)) == 0) {
+ printf("all ports busy\n");
+ exit(3);
+ }
+ if (i == -1) {
+ printf("link down\n");
+ delock(uucplock);
+ exit(3);
+ }
+ setbuf(stdout, NULL);
+ loginit();
+
+ /*
+ * Now that we have the logfile and the ACU open
+ * return to the real uid and gid. These things will
+ * be closed on exit. The saved-setuid uid and gid
+ * allows us to get the original setuid permissions back
+ * for removing the uucp lock.
+ */
+ userperm();
+
+ /*
+ * Kludge, there's no easy way to get the initialization
+ * in the right order, so force it here.
+ * Do the open here, before we change back to real uid.
+ * We will check whether the open succeeded later, when
+ * (and if) we actually go to use the file.
+ */
+ if ((PH = getenv("PHONES")) == NOSTR) {
+ myperm();
+ PH = "/etc/phones";
+ }
+ phfd = fopen(PH, "r");
+
+ userperm();
+
+ vinit(); /* init variables */
+ setparity("none"); /* set the parity table */
+ if ((i = speed(number(value(BAUDRATE)))) == NULL) {
+ printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
+ myperm();
+ delock(uucplock);
+ exit(3);
+ }
+
+
+ /*
+ * Hardwired connections require the
+ * line speed set before they make any transmissions
+ * (this is particularly true of things like a DF03-AC)
+ */
+ if (HW)
+ ttysetup(i);
+ if (p = connect()) {
+ printf("\07%s\n[EOT]\n", p);
+ myperm();
+ delock(uucplock);
+ exit(1);
+ }
+
+ /*
+ * Always setup the tty again here in case hardware flow
+ * control was selected, which can only be set after the
+ * connection is made, or in case this is not a hardwired
+ * modem (rare these days) that likewise can only be setup
+ * after the connection is made.
+ */
+ ttysetup(i);
+cucommon:
+ /*
+ * From here down the code is shared with
+ * the "cu" version of tip.
+ */
+
+ ioctl(0, TCGETS, (char *)&defarg);
+ arg = defarg;
+ /* turn off input processing */
+ arg.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
+ arg.c_cc[VMIN] = 1;
+ arg.c_cc[VTIME] = 0;
+ arg.c_iflag &= ~(INPCK|IXON|IXOFF|ICRNL);
+ arg.c_oflag = 0; /* turn off all output processing */
+ /* handle tandem mode in case was set in remote file */
+ if (boolean(value(TAND)))
+ tandem("on");
+ else
+ tandem("off");
+ raw();
+
+ pipe(fildes); pipe(repdes);
+ signal(SIGALRM, timeout);
+
+ /*
+ * Everything's set up now:
+ * connection established (hardwired or dialup)
+ * line conditioned (baud rate, mode, etc.)
+ * internal data structures (variables)
+ * so, fork one process for local side and one for remote.
+ */
+ if (CM != NOSTR) {
+ sleep(2); /* let line settle */
+ parwrite(FD, CM, strlen(CM));
+ }
+ printf(cumode ? "Connected\r\n" : "\07connected\r\n");
+ signal(SIGCHLD, deadkid);
+ if (pid = fork())
+ tipin();
+ else
+ tipout();
+ /*NOTREACHED*/
+}
+
+void
+deadkid()
+{
+
+ if (pid >= 0 && waitpid(pid, NULL, WNOHANG) == pid)
+ abort("Connection Closed");
+}
+
+void
+cleanup()
+{
+
+ if (uid != getuid()) {
+ myperm();
+ }
+ delock(uucplock);
+ exit(0);
+}
+
+/*
+ * put the controlling keyboard into raw mode
+ */
+raw()
+{
+
+ ioctl(0, TCSETSF, (char *)&arg);
+}
+
+
+/*
+ * return keyboard to normal mode
+ */
+unraw()
+{
+
+ ioctl(0, TCSETSF, (char *)&defarg);
+}
+
+/*
+ * switch to using invoking user's permissions
+ */
+userperm()
+{
+
+ setegid(gid);
+ seteuid(uid);
+}
+
+/*
+ * switch to using my special (setuid) permissions
+ */
+myperm()
+{
+
+ setegid(egid);
+ seteuid(euid);
+}
+
+static sigjmp_buf promptbuf;
+
+/*
+ * Print string ``s'', then read a string
+ * in from the terminal. Handles signals & allows use of
+ * normal erase and kill characters.
+ */
+prompt(s, p, len)
+ char *s;
+ register char *p;
+ size_t len;
+{
+ register char *b = p;
+ register int c;
+ void (*ointr)(), (*oquit)();
+
+ stoprompt = 0;
+ ointr = signal(SIGINT, intprompt);
+ oquit = signal(SIGQUIT, SIG_IGN);
+ unraw();
+ printf("%s", s);
+ if (sigsetjmp(promptbuf, 1) == 0)
+ while (p < b + len - 1 &&
+ ((c = getchar()) != EOF) && (c != '\n'))
+ *p++ = c;
+ *p = '\0';
+
+ raw();
+ signal(SIGINT, ointr);
+ signal(SIGQUIT, oquit);
+ return (stoprompt || p == b);
+}
+
+/*
+ * Interrupt service routine during prompting
+ */
+void
+intprompt()
+{
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ stoprompt = 1;
+ printf("\r\n");
+ siglongjmp(promptbuf, 1);
+}
+
+/*
+ * ****TIPIN TIPIN****
+ */
+tipin()
+{
+ unsigned char gch, c;
+ int bol = 1;
+
+ /*
+ * Kinda klugey here...
+ * check for scripting being turned on from the .tiprc file,
+ * but be careful about just using setscript(), as we may
+ * send a SIGEMT before tipout has a chance to set up catching
+ * it; so wait a second, then setscript()
+ */
+ if (boolean(value(SCRIPT))) {
+ sleep(1);
+ setscript();
+ }
+
+ for (;;) {
+ gch = getchar()&0377;
+ if ((gch == character(value(ESCAPE))) && bol) {
+ if (!(gch = escape()))
+ continue;
+ } else if (!cumode && gch == character(value(RAISECHAR))) {
+ boolean(value(RAISE)) = !boolean(value(RAISE));
+ continue;
+ } else if (gch == '\r') {
+ bol = 1;
+ parwrite(FD, &gch, 1);
+ if (boolean(value(HALFDUPLEX)))
+ printf("\r\n");
+ continue;
+ } else if (!cumode && gch == character(value(FORCE)))
+ gch = getchar()&0377;
+ bol = any(gch, value(EOL));
+ if (boolean(value(RAISE)) && islower(gch))
+ gch = toupper(gch);
+ c = gch;
+ parwrite(FD, &gch, 1);
+ if (boolean(value(HALFDUPLEX)))
+ putchar(c);
+ }
+}
+
+/*
+ * Escape handler --
+ * called on recognition of ``escapec'' at the beginning of a line
+ */
+escape()
+{
+ register unsigned char gch;
+ register esctable_t *p;
+ char c = character(value(ESCAPE));
+ extern esctable_t etable[];
+
+ gch = (getchar()&0377);
+ for (p = etable; p->e_char; p++)
+ if (p->e_char == gch) {
+ if ((p->e_flags&PRIV) && uid)
+ continue;
+ printf("%s", ctrl(c));
+ (*p->e_func)(gch);
+ return (0);
+ }
+ /* ESCAPE ESCAPE forces ESCAPE */
+ if (c != gch)
+ parwrite(FD, &c, 1);
+ return (gch);
+}
+
+speed(n)
+ int n;
+{
+ register int *p;
+
+ for (p = bauds; *p != -1; p++)
+ if (*p == n)
+ return (p - bauds);
+ return (NULL);
+}
+
+any(c, p)
+ register char c, *p;
+{
+ while (p && *p)
+ if (*p++ == c)
+ return (1);
+ return (0);
+}
+
+char *
+interp(s)
+ register char *s;
+{
+ static char buf[256];
+ register char *p = buf, c, *q;
+
+ while (c = *s++) {
+ for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
+ if (*q++ == c) {
+ *p++ = '\\'; *p++ = *q;
+ goto next;
+ }
+ if (c < 040) {
+ *p++ = '^'; *p++ = c + 'A'-1;
+ } else if (c == 0177) {
+ *p++ = '^'; *p++ = '?';
+ } else
+ *p++ = c;
+ next:
+ ;
+ }
+ *p = '\0';
+ return (buf);
+}
+
+char *
+ctrl(c)
+ char c;
+{
+ static char s[3];
+
+ if (c < 040 || c == 0177) {
+ s[0] = '^';
+ s[1] = c == 0177 ? '?' : c+'A'-1;
+ s[2] = '\0';
+ } else {
+ s[0] = c;
+ s[1] = '\0';
+ }
+ return (s);
+}
+
+/*
+ * Help command
+ */
+help(c)
+ char c;
+{
+ register esctable_t *p;
+ extern esctable_t etable[];
+
+ printf("%c\r\n", c);
+ for (p = etable; p->e_char; p++) {
+ if ((p->e_flags&PRIV) && uid)
+ continue;
+ printf("%2s", ctrl(character(value(ESCAPE))));
+ printf("%-2s %c %s\r\n", ctrl(p->e_char),
+ p->e_flags&EXP ? '*': ' ', p->e_help);
+ }
+}
+
+/*
+ * Set up the "remote" tty's state
+ */
+ttysetup(speed)
+ int speed;
+{
+ struct termios buf;
+ char *loc;
+
+ ioctl(FD, TCGETS, (char *)&buf);
+ buf.c_cflag &= (CREAD|HUPCL|CLOCAL|CRTSCTS|CRTSXOFF);
+ buf.c_cflag |= CS8;
+ cfsetospeed(&buf, speed);
+ if (boolean(value(HARDWAREFLOW))) {
+ int i = TIOCM_CAR;
+
+ /*
+ * Only set hardware flow control if carrier is up,
+ * because some devices require both CD and RTS to
+ * be up before sending.
+ */
+ ioctl(FD, TIOCMGET, &i);
+ if (i & TIOCM_CAR)
+ buf.c_cflag |= (CRTSCTS|CRTSXOFF);
+ }
+
+ /*
+ * Careful to only penalize the 8-bit users here on the
+ * incoming tty port. The default 7-bit users will
+ * still get the parity bit from the other side's login
+ * process (which happens to be the default for sun tip
+ * configurations).
+ */
+ loc = setlocale(LC_CTYPE, NULL);
+ if (noparity && loc != 0 && strcmp(loc, "C") != 0)
+ buf.c_iflag = 0;
+ else
+ buf.c_iflag = ISTRIP;
+ buf.c_oflag = 0;
+ buf.c_lflag = 0;
+ buf.c_cc[VMIN] = 1;
+ buf.c_cc[VTIME] = 0;
+ ioctl(FD, TCSETSF, (char *)&buf);
+}
+
+/*
+ * Return "simple" name from a file name,
+ * strip leading directories.
+ */
+char *
+sname(s)
+ register char *s;
+{
+ register char *p = s;
+
+ while (*s)
+ if (*s++ == '/')
+ p = s;
+ return (p);
+}
+
+static char partab[0400];
+
+/*
+ * Do a write to the remote machine with the correct parity.
+ * We are doing 8 bit wide output, so we just generate a character
+ * with the right parity and output it.
+ */
+parwrite(fd, buf, n)
+ int fd;
+ unsigned char *buf;
+ register int n;
+{
+ register int i;
+ register unsigned char *bp;
+ extern int errno;
+
+ bp = buf;
+ for (i = 0; i < n; i++) {
+ *bp = partab[(*bp)&0377];
+ bp++;
+ }
+ if (write(fd, buf, n) < 0) {
+ if (errno == EIO || errno == ENXIO)
+ abort("Lost carrier.");
+ /* this is questionable */
+ perror("write");
+ }
+}
+
+/*
+ * Build a parity table with appropriate high-order bit.
+ */
+setparity(defparity)
+ char *defparity;
+{
+ register int i;
+ char *parity;
+ extern char evenpartab[];
+
+ if (value(PARITY) == NOSTR)
+ value(PARITY) = defparity;
+ parity = value(PARITY);
+ for (i = 0; i < 0400; i++)
+ partab[i] = evenpartab[i];
+ if (equal(parity, "even"))
+ ;
+ else if (equal(parity, "odd")) {
+ for (i = 0; i < 0400; i++)
+ partab[i] ^= 0200; /* reverse bit 7 */
+ } else if (equal(parity, "none")) {
+ /* Do nothing so we can pass thru 8-bit chars */
+ noparity = 1;
+ for (i = 0; i < 0400; i++)
+ partab[i] = i;
+ } else if (equal(parity, "zero")) {
+ for (i = 0; i < 0400; i++)
+ partab[i] &= ~0200; /* turn off bit 7 */
+ } else if (equal(parity, "one")) {
+ for (i = 0; i < 0400; i++)
+ partab[i] |= 0200; /* turn on bit 7 */
+ } else {
+ fprintf(stderr, "%s: unknown parity value\n", PA);
+ fflush(stderr);
+ }
+}
diff --git a/usr/src/cmd/tip/tip.h b/usr/src/cmd/tip/tip.h
new file mode 100644
index 0000000000..2fe34824c0
--- /dev/null
+++ b/usr/src/cmd/tip/tip.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * tip - terminal interface program
+ */
+
+#include <sys/types.h>
+#ifdef USG
+#include <fcntl.h> /* for O_RDWR, etc. */
+#include <unistd.h> /* for R_OK, etc. */
+#else
+#include <sys/file.h>
+#endif
+
+#include <sys/termios.h>
+#include <sys/filio.h> /* XXX - for FIONREAD only */
+#include <signal.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/isa_defs.h> /* for ENDIAN defines */
+
+#define _CTRL(c) (c&037)
+
+#ifdef USG
+#define signal(_sig_, _hdlr_) sigset((_sig_), (_hdlr_))
+#endif
+typedef void (*sig_handler_t)(); /* works on BSD and SV */
+
+/*
+ * Remote host attributes
+ */
+char *DV; /* UNIX device(s) to open */
+char *EL; /* chars marking an EOL */
+char *CM; /* initial connection message */
+char *IE; /* EOT to expect on input */
+char *OE; /* EOT to send to complete FT */
+char *CU; /* call unit if making a phone call */
+char *AT; /* acu type */
+char *PN; /* phone number(s) */
+char *DI; /* disconnect string */
+char *PA; /* parity to be generated */
+
+char *PH; /* phone number file */
+char *RM; /* remote file name */
+char *HO; /* host name */
+
+int BR; /* line speed for conversation */
+int FS; /* frame size for transfers */
+
+signed char DU; /* this host is dialed up */
+char HW; /* this device is hardwired, see hunt.c */
+char *ES; /* escape character */
+char *EX; /* exceptions */
+char *FO; /* force (literal next) char */
+char *RC; /* raise character */
+char *RE; /* script record file */
+char *PR; /* remote prompt */
+int DL; /* line delay for file transfers to remote */
+int CL; /* char delay for file transfers to remote */
+int ET; /* echocheck timeout */
+int DB; /* dialback - ignore hangup */
+
+/*
+ * String value table
+ */
+typedef
+ struct {
+ char *v_name; /* whose name is it */
+ char v_type; /* for interpreting set's */
+ char v_access; /* protection of touchy ones */
+ char *v_abrev; /* possible abreviation */
+ char *v_value; /* casted to a union later */
+ }
+ value_t;
+
+#define STRING 01 /* string valued */
+#define BOOL 02 /* true-false value */
+#define NUMBER 04 /* numeric value */
+#define CHAR 010 /* character value */
+
+#define WRITE 01 /* write access to variable */
+#define READ 02 /* read access */
+
+#define CHANGED 01 /* low bit is used to show modification */
+#define PUBLIC 1 /* public access rights */
+#define PRIVATE 03 /* private to definer */
+#define ROOT 05 /* root defined */
+
+#define TRUE 1
+#define FALSE 0
+
+#define ENVIRON 020 /* initialize out of the environment */
+#define IREMOTE 040 /* initialize out of remote structure */
+#define INIT 0100 /* static data space used for initialization */
+#define TMASK 017
+
+/*
+ * Definition of ACU line description
+ */
+typedef
+ struct {
+ char *acu_name;
+ int (*acu_dialer)();
+ int (*acu_disconnect)();
+ int (*acu_abort)();
+ }
+ acu_t;
+
+#define equal(a, b) (strcmp(a, b) == 0) /* A nice function to compare */
+
+/*
+ * variable manipulation stuff --
+ * if we defined the value entry in value_t, then we couldn't
+ * initialize it in vars.c, so we cast it as needed to keep lint
+ * happy.
+ */
+typedef
+ union {
+ int zz_number;
+ int *zz_address;
+#if defined(_LITTLE_ENDIAN)
+ short zz_boolean;
+ char zz_character;
+#endif
+#if defined(_BIG_ENDIAN)
+ int zz_boolean;
+ int zz_character;
+#endif
+ }
+ zzhack;
+
+#define value(v) vtable[v].v_value
+
+#define boolean(v) ((((zzhack *)(&(v))))->zz_boolean)
+#define number(v) ((((zzhack *)(&(v))))->zz_number)
+#define character(v) ((((zzhack *)(&(v))))->zz_character)
+#define address(v) ((((zzhack *)(&(v))))->zz_address)
+
+/*
+ * Escape command table definitions --
+ * lookup in this table is performed when ``escapec'' is recognized
+ * at the begining of a line (as defined by the eolmarks variable).
+ */
+
+typedef
+ struct {
+ char e_char; /* char to match on */
+ char e_flags; /* experimental, priviledged */
+ char *e_help; /* help string */
+ int (*e_func)(); /* command */
+ }
+ esctable_t;
+
+#define NORM 00 /* normal protection, execute anyone */
+#define EXP 01 /* experimental, mark it with a `*' on help */
+#define PRIV 02 /* priviledged, root execute only */
+
+extern int vflag; /* verbose during reading of .tiprc file */
+extern value_t vtable[]; /* variable table */
+extern int noparity;
+
+
+#ifndef ACULOG
+#define logent(a, b, c, d)
+#define loginit()
+#endif
+
+/*
+ * Definition of indices into variable table so
+ * value(DEFINE) turns into a static address.
+ */
+
+#define BEAUTIFY 0
+#define BAUDRATE 1
+#define DIALTIMEOUT 2
+#define EOFREAD 3
+#define EOFWRITE 4
+#define EOL 5
+#define ESCAPE 6
+#define EXCEPTIONS 7
+#define FORCE 8
+#define FRAMESIZE 9
+#define HOST 10
+#define LOG 11
+#define PHONES 12
+#define PROMPT 13
+#define RAISE 14
+#define RAISECHAR 15
+#define RECORD 16
+#define REMOTE 17
+#define SCRIPT 18
+#define TABEXPAND 19
+#define VERBOSE 20
+#define SHELL 21
+#define HOME 22
+#define ECHOCHECK 23
+#define DISCONNECT 24
+#define TAND 25
+#define LDELAY 26
+#define CDELAY 27
+#define ETIMEOUT 28
+#define RAWFTP 29
+#define HALFDUPLEX 30
+#define LECHO 31
+#define PARITY 32
+#define HARDWAREFLOW 33
+
+#define NOVAL ((value_t *)NULL)
+#define NOACU ((acu_t *)NULL)
+#define NOSTR ((char *)NULL)
+#define NOFILE ((FILE *)NULL)
+#define NOPWD ((struct passwd *)0)
+
+struct termios arg; /* current mode of local terminal */
+struct termios defarg; /* initial mode of local terminal */
+
+FILE *fscript; /* FILE for scripting */
+FILE *phfd; /* FILE for PHONES file */
+
+int fildes[2]; /* file transfer synchronization channel */
+int repdes[2]; /* read process sychronization channel */
+int FD; /* open file descriptor to remote host */
+int AC; /* open file descriptor to dialer (v831 only) */
+int vflag; /* print .tiprc initialization sequence */
+int sfd; /* for ~< operation */
+int pid; /* pid of tipout */
+int uid, euid; /* real and effective user id's */
+int gid, egid; /* real and effective group id's */
+int stoprompt; /* for interrupting a prompt session */
+int timedout; /* ~> transfer timedout */
+int cumode; /* simulating the "cu" program */
+
+char fname[80]; /* file name buffer for ~< */
+char copyname[80]; /* file name buffer for ~> */
+char ccc; /* synchronization character */
+char ch; /* for tipout */
+char *uucplock; /* name of lock file for uucp's */
+extern int trusted_device;
+
+extern char *ctrl();
+extern char *ctime();
+extern struct passwd *getpwuid();
+extern char *getlogin();
+extern char *vinterp();
+extern char *getenv();
+extern char *malloc();
+extern char *connect();
diff --git a/usr/src/cmd/tip/tipout.c b/usr/src/cmd/tip/tipout.c
new file mode 100644
index 0000000000..fbfb9212e0
--- /dev/null
+++ b/usr/src/cmd/tip/tipout.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 5.1 4/30/85 */
+
+#include "tip.h"
+/*
+ * tip
+ *
+ * lower fork of tip -- handles passive side
+ * reading from the remote host
+ */
+
+static sigjmp_buf sigbuf;
+
+/*
+ * TIPOUT wait state routine --
+ * sent by TIPIN when it wants to posses the remote host
+ */
+void
+intIOT()
+{
+
+ write(repdes[1], &ccc, 1);
+ read(fildes[0], &ccc, 1);
+ siglongjmp(sigbuf, 1);
+}
+
+/*
+ * Scripting command interpreter --
+ * accepts script file name over the pipe and acts accordingly
+ */
+void
+intEMT()
+{
+ char c, line[256];
+ register char *pline = line;
+ char reply;
+
+ read(fildes[0], &c, 1);
+ while (c != '\n') {
+ *pline++ = c;
+ read(fildes[0], &c, 1);
+ }
+ *pline = '\0';
+ if (boolean(value(SCRIPT)) && fscript != NULL)
+ fclose(fscript);
+ if (pline == line) {
+ boolean(value(SCRIPT)) = FALSE;
+ reply = 'y';
+ } else {
+ if ((fscript = fopen(line, "a")) == NULL)
+ reply = 'n';
+ else {
+ reply = 'y';
+ boolean(value(SCRIPT)) = TRUE;
+ }
+ }
+ write(repdes[1], &reply, 1);
+ siglongjmp(sigbuf, 1);
+}
+
+void
+intTERM()
+{
+
+ if (boolean(value(SCRIPT)) && fscript != NULL)
+ fclose(fscript);
+ exit(0);
+}
+
+void
+intSYS()
+{
+
+ boolean(value(BEAUTIFY)) = !boolean(value(BEAUTIFY));
+ siglongjmp(sigbuf, 1);
+}
+
+/*
+ * ****TIPOUT TIPOUT****
+ */
+tipout()
+{
+ char buf[BUFSIZ];
+ register char *cp;
+ register int cnt;
+ extern int errno;
+ sigset_t omask, bmask, tmask;
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGEMT, (sig_handler_t)intEMT); /* attention from TIPIN */
+ signal(SIGTERM, (sig_handler_t)intTERM); /* time to go signal */
+ signal(SIGIOT, (sig_handler_t)intIOT); /* scripting going on signal */
+ signal(SIGHUP, (sig_handler_t)intTERM); /* for dial-ups */
+ signal(SIGSYS, (sig_handler_t)intSYS); /* beautify toggle */
+ (void) sigsetjmp(sigbuf, 1);
+
+ sigemptyset(&omask);
+ sigemptyset(&bmask);
+ sigaddset(&bmask, SIGEMT);
+ sigaddset(&bmask, SIGTERM);
+ sigaddset(&bmask, SIGIOT);
+ sigaddset(&bmask, SIGSYS);
+ sigemptyset(&tmask);
+ sigaddset(&tmask, SIGTERM);
+ for (;;) {
+ cnt = read(FD, buf, BUFSIZ);
+ if (cnt <= 0) {
+ /*
+ * If dialback is specified, ignore the hangup
+ * and clear the hangup condition on the device.
+ */
+ if (cnt == 0 && DB) {
+ int fd;
+
+ DB = 0;
+ if ((fd = open(DV, O_RDWR)) >= 0) {
+ if (fd != FD)
+ close(fd);
+ }
+ continue;
+ }
+ /* lost carrier */
+ if ((cnt < 0 && errno == EIO) ||
+ (cnt == 0)) {
+ (void) sigprocmask(SIG_BLOCK, &tmask, NULL);
+ intTERM();
+ /*NOTREACHED*/
+ }
+ } else {
+ (void) sigprocmask(SIG_BLOCK, &bmask, &omask);
+ if (!noparity)
+ for (cp = buf; cp < buf + cnt; cp++)
+ *cp &= 0177;
+
+ write(1, buf, cnt);
+ if (boolean(value(SCRIPT)) && fscript != NULL) {
+ if (!boolean(value(BEAUTIFY))) {
+ fwrite(buf, 1, cnt, fscript);
+ } else {
+ for (cp = buf; cp < buf + cnt; cp++)
+ if ((*cp >= ' ' && *cp <= '~')||
+ any(*cp, value(EXCEPTIONS)))
+ putc(*cp, fscript);
+ }
+ }
+ }
+ (void) sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+}
diff --git a/usr/src/cmd/tip/uucplock.c b/usr/src/cmd/tip/uucplock.c
new file mode 100644
index 0000000000..a9b5b5285c
--- /dev/null
+++ b/usr/src/cmd/tip/uucplock.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.6 6/25/83 */
+/*
+ * defs that come from uucp.h
+ */
+#define NAMESIZE 40
+#define FAIL -1
+#define SAME 0
+#define SLCKTIME (8*60*60) /* device timeout (LCK.. files) in seconds */
+#ifdef __STDC__
+#define ASSERT(e, f, v) if (!(e)) {\
+ fprintf(stderr, "AERROR - (%s) ", #e); \
+ fprintf(stderr, f, v); \
+ finish(FAIL); \
+}
+#else
+#define ASSERT(e, f, v) if (!(e)) {\
+ fprintf(stderr, "AERROR - (%s) ", "e"); \
+ fprintf(stderr, f, v); \
+ finish(FAIL); \
+}
+#endif
+#define SIZEOFPID 10 /* maximum number of digits in a pid */
+
+#define LOCKDIR "/var/spool/locks"
+#define LOCKPRE "LK"
+
+/*
+ * This code is taken almost directly from uucp and follows the same
+ * conventions. This is important since uucp and tip should
+ * respect each others locks.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mkdev.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+static void stlock();
+static int onelock();
+static int checkLock();
+
+
+/*
+ * ulockf(file, atime)
+ * char *file;
+ * time_t atime;
+ *
+ * ulockf - this routine will create a lock file (file).
+ * If one already exists, send a signal 0 to the process--if
+ * it fails, then unlink it and make a new one.
+ *
+ * input:
+ * file - name of the lock file
+ * atime - is unused, but we keep it for lint compatibility
+ * with non-ATTSVKILL
+ *
+ * return codes: 0 | FAIL
+ */
+
+static
+ulockf(file, atime)
+ char *file;
+ time_t atime;
+{
+ static char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */
+ static char tempfile[NAMESIZE];
+
+ if (pid[0] == '\0') {
+ (void) sprintf(pid, "%*d\n", SIZEOFPID, getpid());
+ (void) sprintf(tempfile, "%s/LTMP.%d", LOCKDIR, getpid());
+ }
+ if (onelock(pid, tempfile, file) == -1) {
+ /* lock file exists */
+ (void) unlink(tempfile);
+ if (checkLock(file))
+ return (FAIL);
+ else {
+ if (onelock(pid, tempfile, file)) {
+ (void) unlink(tempfile);
+ return (FAIL);
+ }
+ }
+ }
+ stlock(file);
+ return (0);
+}
+
+/*
+ * check to see if the lock file exists and is still active
+ * - use kill(pid, 0) - (this only works on ATTSV and some hacked
+ * BSD systems at this time)
+ * return:
+ * 0 -> success (lock file removed - no longer active)
+ * FAIL -> lock file still active
+ */
+static int
+checkLock(file)
+register char *file;
+{
+ register int ret;
+ int lpid = -1;
+ char alpid[SIZEOFPID+2]; /* +2 for '\n' and NULL */
+ int fd;
+ extern int errno;
+
+ fd = open(file, 0);
+ if (fd == -1) {
+ if (errno == ENOENT) /* file does not exist -- OK */
+ return (0);
+ goto unlk;
+ }
+ ret = read(fd, (char *)alpid, SIZEOFPID+1); /* +1 for '\n' */
+ (void) close(fd);
+ if (ret != (SIZEOFPID+1))
+ goto unlk;
+ lpid = atoi(alpid);
+ if ((ret = kill(lpid, 0)) == 0 || errno == EPERM)
+ return (FAIL);
+
+unlk:
+ if (unlink(file) != 0)
+ return (FAIL);
+ return (0);
+}
+
+#define MAXLOCKS 10 /* maximum number of lock files */
+char *Lockfile[MAXLOCKS];
+int Nlocks = 0;
+
+/*
+ * stlock(name) put name in list of lock files
+ * char *name;
+ *
+ * return codes: none
+ */
+
+static void
+stlock(name)
+ char *name;
+{
+ char *p;
+ extern char *calloc();
+ int i;
+
+ for (i = 0; i < Nlocks; i++) {
+ if (Lockfile[i] == NULL)
+ break;
+ }
+ ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
+ if (i >= Nlocks)
+ i = Nlocks++;
+ p = calloc(strlen(name) + 1, sizeof (char));
+ ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
+ strcpy(p, name);
+ Lockfile[i] = p;
+}
+
+/*
+ * rmlock(name) remove all lock files in list
+ * char *name; or name
+ *
+ * return codes: none
+ */
+
+static
+rmlock(name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; i < Nlocks; i++) {
+ if (Lockfile[i] == NULL)
+ continue;
+ if (name == NULL || strcmp(name, Lockfile[i]) == SAME) {
+ unlink(Lockfile[i]);
+ free(Lockfile[i]);
+ Lockfile[i] = NULL;
+ }
+ }
+}
+
+static
+onelock(pid, tempfile, name)
+ char *pid, *tempfile, *name;
+{
+ int fd;
+ static int first = 1;
+ extern int errno;
+
+ fd = creat(tempfile, 0444);
+ if (fd < 0) {
+ if (first) {
+ if (errno == EACCES) {
+ fprintf(stderr,
+ "tip: can't create files in lock file directory %s\n",
+ LOCKDIR);
+ } else if (access(LOCKDIR, 0) < 0) {
+ fprintf(stderr, "tip: lock file directory %s: ",
+ LOCKDIR);
+ perror("");
+ }
+ first = 0;
+ }
+ if (errno == EMFILE || errno == ENFILE)
+ (void) unlink(tempfile);
+ return (-1);
+ }
+ /* +1 for '\n' */
+ if (write(fd, pid, SIZEOFPID+1) != (SIZEOFPID+1)) {
+ fprintf(stderr,
+ "tip: can't write to files in lock file directory %s: %s\n",
+ LOCKDIR, strerror(errno));
+ (void) unlink(tempfile);
+ return (-1);
+ }
+ fchmod(fd, 0444);
+ close(fd);
+ if (link(tempfile, name) < 0) {
+ unlink(tempfile);
+ return (-1);
+ }
+ unlink(tempfile);
+ return (0);
+}
+
+/*
+ * delock(sys) remove a lock file
+ * char *sys;
+ *
+ * return codes: 0 | FAIL
+ */
+
+delock(sys)
+ char *sys;
+{
+ struct stat sb;
+ char lname[NAMESIZE];
+
+ if (stat(sys, &sb) < 0)
+ return (FAIL);
+ sprintf(lname, "%s/%s.%3.3lu.%3.3lu.%3.3lu", LOCKDIR, LOCKPRE,
+ (unsigned long)major(sb.st_dev),
+ (unsigned long)major(sb.st_rdev),
+ (unsigned long)minor(sb.st_rdev));
+ rmlock(lname);
+}
+
+/*
+ * mlock(sys) create system lock
+ * char *sys;
+ *
+ * return codes: 0 | FAIL
+ */
+
+mlock(sys)
+ char *sys;
+{
+ struct stat sb;
+ char lname[NAMESIZE];
+
+ if (stat(sys, &sb) < 0)
+ return (FAIL);
+ sprintf(lname, "%s/%s.%3.3lu.%3.3lu.%3.3lu", LOCKDIR, LOCKPRE,
+ (unsigned long)major(sb.st_dev),
+ (unsigned long)major(sb.st_rdev),
+ (unsigned long)minor(sb.st_rdev));
+ return (ulockf(lname, (time_t)SLCKTIME) < 0 ? FAIL : 0);
+}
+
+/*
+ * update access and modify times for lock files
+ * return:
+ * none
+ */
+void
+ultouch()
+{
+ register int i;
+ time_t time();
+
+ struct ut {
+ time_t actime;
+ time_t modtime;
+ } ut;
+
+ ut.actime = time(&ut.modtime);
+ for (i = 0; i < Nlocks; i++) {
+ if (Lockfile[i] == NULL)
+ continue;
+ utime(Lockfile[i], &ut);
+ }
+}
diff --git a/usr/src/cmd/tip/value.c b/usr/src/cmd/tip/value.c
new file mode 100644
index 0000000000..a48e0fa764
--- /dev/null
+++ b/usr/src/cmd/tip/value.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* from UCB 4.5 6/25/83 */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "tip.h"
+
+#define MIDDLE 35
+
+static value_t *vlookup();
+static int col = 0;
+
+/*
+ * Variable manipulation
+ */
+vinit()
+{
+ register value_t *p;
+ register char *cp;
+ FILE *f;
+ char file[1024];
+
+ for (p = vtable; p->v_name != NULL; p++) {
+ if (p->v_type&ENVIRON)
+ if (cp = getenv(p->v_name))
+ p->v_value = cp;
+ if (p->v_type&IREMOTE)
+ number(p->v_value) = *address(p->v_value);
+ }
+ /*
+ * Read the .tiprc file in the HOME directory
+ * for sets
+ */
+ if ((cp = value(HOME)) == NULL)
+ cp = "";
+ strlcpy(file, cp, sizeof (file));
+ strlcat(file, "/.tiprc", sizeof (file));
+ if ((f = fopen(file, "r")) != NULL) {
+ register char *tp;
+
+ while (fgets(file, sizeof (file)-1, f) != NULL) {
+ if (file[0] == '#')
+ continue;
+ if (vflag)
+ printf("set %s", file);
+ if (tp = strrchr(file, '\n'))
+ *tp = '\0';
+ vlex(file);
+ }
+ fclose(f);
+ }
+ /*
+ * To allow definition of exception prior to fork
+ */
+ vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC);
+}
+
+/*VARARGS1*/
+vassign(p, v)
+ register value_t *p;
+ char *v;
+{
+
+ if (!vaccess(p->v_access, WRITE)) {
+ printf("access denied\r\n");
+ return;
+ }
+ switch (p->v_type&TMASK) {
+
+ case STRING:
+ if (p->v_value != (char *)NULL) {
+ if (equal(p->v_value, v))
+ return;
+ if (!(p->v_type&(ENVIRON|INIT)))
+ free(p->v_value);
+ }
+ if ((p->v_value = malloc(strlen(v)+1)) == NOSTR) {
+ printf("out of core\r\n");
+ return;
+ }
+ p->v_type &= ~(ENVIRON|INIT);
+ strcpy(p->v_value, v);
+ break;
+
+ case NUMBER:
+ if (number(p->v_value) == number(v))
+ return;
+ number(p->v_value) = number(v);
+ break;
+
+ case BOOL:
+ if (boolean(p->v_value) == (*v != '!'))
+ return;
+ boolean(p->v_value) = (*v != '!');
+ break;
+
+ case CHAR:
+ if (character(p->v_value) == *v)
+ return;
+ character(p->v_value) = *v;
+ }
+ p->v_access |= CHANGED;
+}
+
+vlex(s)
+ register char *s;
+{
+ register value_t *p;
+
+ if (equal(s, "all")) {
+ for (p = vtable; p->v_name; p++)
+ if (vaccess(p->v_access, READ))
+ vprint(p);
+ } else {
+ register char *cp;
+
+ do {
+ if (cp = vinterp(s, ' '))
+ cp++;
+ vtoken(s);
+ s = cp;
+ } while (s);
+ }
+ if (col > 0) {
+ printf("\r\n");
+ col = 0;
+ }
+}
+
+static int
+vtoken(s)
+ register char *s;
+{
+ register value_t *p;
+ register char *cp, *cp2;
+ char *expand();
+
+ if (cp = strchr(s, '=')) {
+ *cp = '\0';
+ if (p = vlookup(s)) {
+ cp++;
+ if (p->v_type&NUMBER)
+ vassign(p, atoi(cp));
+ else {
+ if (strcmp(s, "record") == 0)
+ if ((cp2 = expand(cp)) != NOSTR)
+ cp = cp2;
+ vassign(p, cp);
+ }
+ return;
+ }
+ } else if (cp = strchr(s, '?')) {
+ *cp = '\0';
+ if ((p = vlookup(s)) && vaccess(p->v_access, READ)) {
+ vprint(p);
+ return;
+ }
+ } else {
+ if (*s != '!')
+ p = vlookup(s);
+ else
+ p = vlookup(s+1);
+ if (p != NOVAL) {
+ if (p->v_type&BOOL)
+ vassign(p, s);
+ else
+ printf("%s: no value specified\r\n", s);
+ return;
+ }
+ }
+ printf("%s: unknown variable\r\n", s);
+}
+
+static int
+vprint(p)
+ register value_t *p;
+{
+ register char *cp;
+ extern char *interp(), *ctrl();
+
+ if (col > 0 && col < MIDDLE)
+ while (col++ < MIDDLE)
+ putchar(' ');
+ col += strlen(p->v_name);
+ switch (p->v_type&TMASK) {
+
+ case BOOL:
+ if (boolean(p->v_value) == FALSE) {
+ col++;
+ putchar('!');
+ }
+ printf("%s", p->v_name);
+ break;
+
+ case STRING:
+ printf("%s=", p->v_name);
+ col++;
+ if (p->v_value) {
+ cp = interp(p->v_value, NULL);
+ col += strlen(cp);
+ printf("%s", cp);
+ }
+ break;
+
+ case NUMBER:
+ col += 6;
+ printf("%s=%-5d", p->v_name, number(p->v_value));
+ break;
+
+ case CHAR:
+ printf("%s=", p->v_name);
+ col++;
+ if (p->v_value) {
+ cp = ctrl(character(p->v_value));
+ col += strlen(cp);
+ printf("%s", cp);
+ }
+ break;
+ }
+ if (col >= MIDDLE) {
+ col = 0;
+ printf("\r\n");
+ return;
+ }
+}
+
+
+static int
+vaccess(mode, rw)
+ register unsigned mode, rw;
+{
+ if (mode & (rw<<PUBLIC))
+ return (1);
+ if (mode & (rw<<PRIVATE))
+ return (1);
+ return ((mode & (rw<<ROOT)) && uid == 0);
+}
+
+static value_t *
+vlookup(s)
+ register char *s;
+{
+ register value_t *p;
+
+ for (p = vtable; p->v_name; p++)
+ if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s)))
+ return (p);
+ return (NULL);
+}
+
+char *
+vinterp(s, stop)
+ register char *s;
+ char stop;
+{
+ register char *p = s, c;
+ int num;
+
+ while ((c = *s++) && c != stop)
+ switch (c) {
+
+ case '^':
+ if (*s)
+ *p++ = *s++ - 0100;
+ else
+ *p++ = c;
+ break;
+
+ case '\\':
+ num = 0;
+ c = *s++;
+ if (c >= '0' && c <= '7')
+ num = (num<<3)+(c-'0');
+ else {
+ register char *q = "n\nr\rt\tb\bf\f";
+
+ for (; *q; q++)
+ if (c == *q++) {
+ *p++ = *q;
+ goto cont;
+ }
+ *p++ = c;
+ cont:
+ break;
+ }
+ if ((c = *s++) >= '0' && c <= '7') {
+ num = (num<<3)+(c-'0');
+ if ((c = *s++) >= '0' && c <= '7')
+ num = (num<<3)+(c-'0');
+ else
+ s--;
+ } else
+ s--;
+ *p++ = num;
+ break;
+
+ default:
+ *p++ = c;
+ }
+ *p = '\0';
+ return (c == stop ? s-1 : NULL);
+}
+
+/*
+ * assign variable s with value v (for NUMBER or STRING or CHAR types)
+ */
+
+vstring(s, v)
+ register char *s;
+ register char *v;
+{
+ register value_t *p;
+ char *v2;
+ char *expand();
+
+ p = vlookup(s);
+ if (p == 0)
+ return (1);
+ if (p->v_type&NUMBER)
+ vassign(p, atoi(v));
+ else {
+ if (strcmp(s, "record") == 0)
+ if ((v2 = expand(v)) != NOSTR)
+ v = v2;
+ vassign(p, v);
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/tip/vars.c b/usr/src/cmd/tip/vars.c
new file mode 100644
index 0000000000..4367e28ba5
--- /dev/null
+++ b/usr/src/cmd/tip/vars.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+#ident "%Z%%M% %I% %E% SMI" /* from UCB 4.6 6/25/83 */
+
+#include "tip.h"
+
+/*
+ * Definition of variables
+ */
+value_t vtable[] = {
+ { "beautify", BOOL, (READ|WRITE)<<PUBLIC,
+ "be", (char *)TRUE },
+ { "baudrate", NUMBER|IREMOTE|INIT, (READ<<PUBLIC)|(WRITE<<ROOT),
+ "ba", (char *)&BR },
+ { "dialtimeout", NUMBER, (READ<<PUBLIC)|(WRITE<<ROOT),
+ "dial", (char *)60 },
+ { "eofread", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "eofr", (char *)&IE },
+ { "eofwrite", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "eofw", (char *)&OE },
+ { "eol", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ NOSTR, (char *)&EL },
+ { "escape", CHAR, (READ|WRITE)<<PUBLIC,
+ "es", (char *)'~' },
+ { "exceptions", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
+ "ex", (char *)&EX },
+ { "force", CHAR, (READ|WRITE)<<PUBLIC,
+ "fo", (char *)0377 },
+ { "framesize", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "fr", (char *)&FS },
+ { "host", STRING|IREMOTE|INIT, READ<<PUBLIC,
+ "ho", (char *)&HO },
+ { "log", STRING|INIT, (READ|WRITE)<<ROOT,
+ NOSTR, "/var/adm/aculog" },
+ { "phones", STRING|INIT|IREMOTE, READ<<PUBLIC,
+ NOSTR, (char *)&PH },
+ { "prompt", CHAR, (READ|WRITE)<<PUBLIC,
+ "pr", (char *)'\n' },
+ { "raise", BOOL, (READ|WRITE)<<PUBLIC,
+ "ra", (char *)FALSE },
+ { "raisechar", CHAR, (READ|WRITE)<<PUBLIC,
+ "rc", (char *)0377 },
+ { "record", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
+ "rec", (char *)&RE },
+ { "remote", STRING|INIT|IREMOTE, READ<<PUBLIC,
+ NOSTR, (char *)&RM },
+ { "script", BOOL, (READ|WRITE)<<PUBLIC,
+ "sc", (char *)FALSE },
+ { "tabexpand", BOOL, (READ|WRITE)<<PUBLIC,
+ "tab", (char *)FALSE },
+ { "verbose", BOOL, (READ|WRITE)<<PUBLIC,
+ "verb", (char *)TRUE },
+ { "SHELL", STRING|ENVIRON|INIT, (READ|WRITE)<<PUBLIC,
+ NULL, "/bin/sh" },
+ { "HOME", STRING|ENVIRON, (READ|WRITE)<<PUBLIC,
+ NOSTR, NOSTR },
+ { "echocheck", BOOL, (READ|WRITE)<<PUBLIC,
+ "ec", (char *)FALSE },
+ { "disconnect", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "di", (char *)&DI },
+ { "tandem", BOOL, (READ|WRITE)<<PUBLIC,
+ "ta", (char *)TRUE },
+ { "linedelay", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "ldelay", (char *)&DL },
+ { "chardelay", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "cdelay", (char *)&CL },
+ { "etimeout", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
+ "et", (char *)&ET },
+ { "rawftp", BOOL, (READ|WRITE)<<PUBLIC,
+ "raw", (char *)FALSE },
+ { "halfduplex", BOOL, (READ|WRITE)<<PUBLIC,
+ "hdx", (char *)FALSE },
+ { "localecho", BOOL, (READ|WRITE)<<PUBLIC,
+ "le", (char *)FALSE },
+ { "parity", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
+ "par", (char *)&PA },
+ { "hardwareflow", BOOL, (READ|WRITE)<<PUBLIC,
+ "hf", (char *)FALSE },
+ { NOSTR, NULL, NULL, NOSTR, NOSTR }
+};