diff --git a/tip/GNUmakefile b/tip/GNUmakefile new file mode 100644 index 0000000000000000000000000000000000000000..55e40bf22492f954bf5d318536356589c8d18410 --- /dev/null +++ b/tip/GNUmakefile @@ -0,0 +1,27 @@ +CC = gcc -g + +# for BSD +#CFLAGS = -O +#LIBS= -lutil + +# for Linux +CFLAGS = -O -DLINUX +LIBS= -ldb + +OBJS = acu.o acutab.o cmds.o cmdtab.o cu.o hunt.o log.o partab.o \ + remote.o tip.o tipout.o value.o vars.o getcap.o +DESTDIR = /usr/site + +all: tip + +tip: $(OBJS) + $(CC) -o tip $(OBJS) $(LIBS) + +tip.static: $(OBJS) + $(CC) -static -o tip.static $(OBJS) $(LIBS) + +install: + install -s -c tip $(DESTDIR)/bin/tip + +clean: + rm -f $(OBJS) tip tip.static diff --git a/tip/acu.c b/tip/acu.c new file mode 100644 index 0000000000000000000000000000000000000000..865b6fad8403a0da484aab9d4a9789c590dbfd51 --- /dev/null +++ b/tip/acu.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)acu.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: acu.c,v 1.1 2000-12-22 18:48:46 mike Exp $"; +#endif /* not lint */ + +#include "tipconf.h" +#include "tip.h" + +#if UNIDIALER +acu_t* unidialer_getmodem (const char *modem_name); +#endif + +static acu_t *acu = NOACU; +static int conflag; +static void acuabort(); +static acu_t *acutype(); +static jmp_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]; + FILE *fd; + int tried = 0; + + if (!DU) { /* regular connect message */ + if (CM != NOSTR) + xpwrite(FD, CM, size(CM)); + logent(value(HOST), "", DV, "call completed"); + return (NOSTR); + } + /* + * @ =>'s use data base in PHONES environment variable + * otherwise, use /etc/phones + */ + signal(SIGINT, acuabort); + signal(SIGQUIT, acuabort); + if (setjmp(jmpbuf)) { + 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)(); + } + return ("interrupt"); + } + 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))) { + if (CM != NOSTR) + xpwrite(FD, CM, size(CM)); + logent(value(HOST), phnum, acu->acu_name, + "call completed"); + return (NOSTR); + } else + logent(value(HOST), phnum, acu->acu_name, + "call failed"); + tried++; + } + } else { + if ((fd = fopen(PH, "r")) == NOFILE) { + printf("%s: ", PH); + return ("can't open phone number file"); + } + while (fgets(string, sizeof(string), fd) != NOSTR) { + for (cp = string; !any(*cp, " \t\n"); cp++) + ; + if (*cp == '\n') { + fclose(fd); + return ("unrecognizable host name"); + } + *cp++ = '\0'; + if (strcmp(string, value(HOST))) + continue; + while (any(*cp, " \t")) + cp++; + if (*cp == '\n') { + fclose(fd); + return ("missing phone number"); + } + for (phnum = cp; *cp && *cp != ',' && *cp != '\n'; cp++) + ; + if (*cp) + *cp++ = '\0'; + + if ((conflag = (*acu->acu_dialer)(phnum, CU))) { + fclose(fd); + if (CM != NOSTR) + xpwrite(FD, CM, size(CM)); + logent(value(HOST), phnum, acu->acu_name, + "call completed"); + return (NOSTR); + } else + logent(value(HOST), phnum, acu->acu_name, + "call failed"); + tried++; + } + fclose(fd); + } + if (!tried) + logent(value(HOST), "", acu->acu_name, "missing phone number"); + else + (*acu->acu_abort)(); + return (tried ? "call failed" : "missing phone number"); +} + +void +disconnect(reason) + char *reason; +{ + if (!conflag) { + logent(value(HOST), "", DV, "call terminated"); + 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); + longjmp(jmpbuf, 1); +} + +static acu_t * +acutype(s) + register char *s; +{ + register acu_t *p; + extern acu_t acutable[]; + + for (p = acutable; p->acu_name != '\0'; p++) + if (!strcmp(s, p->acu_name)) + return (p); + + #if UNIDIALER + return unidialer_getmodem (s); + #else + return (NOACU); + #endif +} diff --git a/tip/acutab.c b/tip/acutab.c new file mode 100644 index 0000000000000000000000000000000000000000..0c1c41af72f1dead212643226ff45c8c2af2143d --- /dev/null +++ b/tip/acutab.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)acutab.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: acutab.c,v 1.1 2000-12-22 18:48:46 mike Exp $"; +#endif /* not lint */ + +#include "tipconf.h" +#include "tip.h" + +extern int df02_dialer(), df03_dialer(), + biz31f_dialer(), + biz31w_dialer(), + biz22f_dialer(), + biz22w_dialer(), + ven_dialer(), + hay_dialer(), + cour_dialer(), + multitech_dialer(), + t3000_dialer(), + v3451_dialer(), + v831_dialer(), + dn_dialer(); + +extern void df_disconnect(), df_abort(), + biz31_disconnect(), biz31_abort(), + biz22_disconnect(), biz22_abort(), + ven_disconnect(), ven_abort(), + hay_disconnect(), hay_abort(), + cour_disconnect(), cour_abort(), + multitech_disconnect(), multitech_abort(), + t3000_disconnect(), t3000_abort(), + v3451_disconnect(), v3451_abort(), + v831_disconnect(), v831_abort(), + 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 +#if VENTEL + "ventel",ven_dialer, ven_disconnect, ven_abort, +#endif +#if HAYES + "hayes",hay_dialer, hay_disconnect, hay_abort, +#endif +#if COURIER + "courier",cour_dialer, cour_disconnect, cour_abort, +#endif +#if MULTITECH + "multitech",multitech_dialer, multitech_disconnect, multitech_abort, +#endif +#if T3000 + "t3000",t3000_dialer, t3000_disconnect, t3000_abort, +#endif +#if V3451 +#if !V831 + "vadic",v3451_dialer, v3451_disconnect, v3451_abort, +#endif + "v3451",v3451_dialer, v3451_disconnect, v3451_abort, +#endif +#if V831 +#if !V3451 + "vadic",v831_dialer, v831_disconnect, v831_abort, +#endif + "v831",v831_dialer, v831_disconnect, v831_abort, +#endif + 0, 0, 0, 0 +}; + diff --git a/tip/cmds.c b/tip/cmds.c new file mode 100644 index 0000000000000000000000000000000000000000..2ad298b1ab183bd45e3c701c10a5a3c3c24c031b --- /dev/null +++ b/tip/cmds.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: cmds.c,v 1.1 2000-12-22 18:48:46 mike Exp $"; +#endif /* not lint */ + +#include "tipconf.h" +#include "tip.h" +#include "pathnames.h" + +#include <sys/types.h> +#include <sys/wait.h> +#include <err.h> +#ifndef LINUX +#include <libutil.h> +#endif +#include <stdio.h> +#include <unistd.h> + +/* + * 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 */ + +void timeout(); /* timeout function called on alarm */ +static void stopsnd(); /* SIGINT handler during file transfers */ +static void intcopy(); /* interrupt routine for file transfers */ + +void suspend __P((char)); +void genbrk __P((void)); +void variable __P((void)); +void finish __P((void)); +void tipabort __P((char *)); +void chdirectory __P((void)); +void shell __P((void)); +void cu_put __P((char)); +void sendfile __P((char)); +void pipefile __P((void)); +void cu_take __P((char)); +void getfl __P((char)); + +static int anyof __P((char *, char *)); +static void tandem __P((char *)); +static void prtime __P((char *, time_t)); +static int args __P((char *, char **, int)); +static void execute __P((char *)); +static void send __P((char)); +static void transmit __P((FILE *, char *, char *)); +static void transfer __P((char *, int, char *)); +static void xfer __P((char *, int, char *)); + +void +usedefchars () +{ +#if HAVE_TERMIOS + int cnt; + struct termios ttermios; + ttermios = ctermios; + for (cnt = 0; cnt < NCCS; cnt++) + ttermios.c_cc [cnt] = otermios.c_cc [cnt]; + tcsetattr (0, TCSANOW, &ttermios); +#else + ioctl(0, TIOCSETC, &defchars); +#endif +} + +void +usetchars () +{ +#if HAVE_TERMIOS + tcsetattr (0, TCSANOW, &ctermios); +#else + ioctl(0, TIOCSETC, &tchars); +#endif +} + +void +flush_remote () +{ +#ifdef TIOCFLUSH + int cmd = 0; + ioctl (FD, TIOCFLUSH, &cmd); +#else +#if HAVE_TERMIOS + tcflush (FD, TCIOFLUSH); +#else + struct sgttyb buf; + ioctl (FD, TIOCGETP, &buf); /* this does a */ + ioctl (FD, TIOCSETP, &buf); /* wflushtty */ +#endif +#endif +} + +/* + * FTP - remote ==> local + * get a file from the remote host + */ +void +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 ((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 + */ +void +cu_take(cc) + char cc; +{ + int fd, argc; + char line[BUFSIZ], *expand(), *cp; + + if (prompt("[take] ", copyname, sizeof(copyname))) + return; + if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) { + printf("usage: <take> from [to]\r\n"); + return; + } + if (argc == 1) + argv[1] = argv[0]; + cp = expand(argv[1]); + if ((fd = creat(cp, 0666)) < 0) { + printf("\r\n%s: cannot create\r\n", argv[1]); + return; + } + (void)snprintf(line, sizeof(line), "cat %s ; echo \"\" ; echo ___tip_end_of_file_marker___", argv[0]); + xfer(line, fd, "\n___tip_end_of_file_marker___\n"); +} + +static jmp_buf intbuf; + +static void +xfer(buf, fd, eofchars) + char *buf, *eofchars; +{ + int ct; + char c, *match; + int cnt, eof, v; + time_t start; + sig_t f; + char r; + FILE *ff; + + v = boolean(value(VERBOSE)); + + if ((ff = fdopen (fd, "w")) == NULL) { + warn("file open"); + return; + } + if ((cnt = number(value(FRAMESIZE))) != BUFSIZ) + if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) { + warn("file allocation"); + (void)fclose(ff); + return; + } + + xpwrite(FD, buf, size(buf)); + quit = 0; + kill(pid, SIGIOT); + read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ + + /* + * finish command + */ + r = '\r'; + xpwrite(FD, &r, 1); + do + read(FD, &c, 1); + while ((c&0177) != '\n'); + + usedefchars (); + + (void) setjmp(intbuf); + f = signal(SIGINT, intcopy); + start = time(0); + match = eofchars; + for (ct = 0; !quit;) { + eof = read(FD, &c, 1) <= 0; + c &= 0177; + if (quit) + continue; + if (eof) + break; + if (c == 0) + continue; /* ignore nulls */ + if (c == '\r') + continue; + if (c != *match && match > eofchars) { + register char *p = eofchars; + while (p < match) { + if (*p == '\n'&& v) + (void)printf("\r%d", ++ct); + fputc(*p++, ff); + } + match = eofchars; + } + if (c == *match) { + if (*++match == '\0') + break; + } else { + if (c == '\n' && v) + (void)printf("\r%d", ++ct); + fputc(c, ff); + } + } + if (v) + prtime(" lines transferred in ", time(0)-start); + usetchars (); + write(fildes[1], (char *)&ccc, 1); + signal(SIGINT, f); + (void)fclose(ff); +} + +/* + * Bulk transfer routine -- + * used by getfl(), cu_take(), and pipefile() + */ +static void +transfer(buf, fd, eofchars) + char *buf, *eofchars; +{ + register int ct; + char c; + register int cnt, eof, v; + time_t start; + sig_t f; + char r; + FILE *ff; + + v = boolean(value(VERBOSE)); + + if ((ff = fdopen (fd, "w")) == NULL) { + warn("file open"); + return; + } + if ((cnt = number(value(FRAMESIZE))) != BUFSIZ) + if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) { + warn("file allocation"); + (void)fclose(ff); + return; + } + + xpwrite(FD, buf, size(buf)); + quit = 0; + kill(pid, SIGIOT); + read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ + + /* + * finish command + */ + r = '\r'; + xpwrite(FD, &r, 1); + do + read(FD, &c, 1); + while ((c&0177) != '\n'); + usedefchars (); + (void) setjmp(intbuf); + f = signal(SIGINT, intcopy); + start = time(0); + for (ct = 0; !quit;) { + eof = read(FD, &c, 1) <= 0; + c &= 0177; + if (quit) + continue; + if (eof || any(c, eofchars)) + break; + if (c == 0) + continue; /* ignore nulls */ + if (c == '\r') + continue; + if (c == '\n' && v) + printf("\r%d", ++ct); + fputc(c, ff); + } + if (v) + prtime(" lines transferred in ", time(0)-start); + usetchars (); + write(fildes[1], (char *)&ccc, 1); + signal(SIGINT, f); + (void)fclose(ff); +} + +/* + * FTP - remote ==> local process + * send remote input to local process via pipe + */ +void +pipefile() +{ + int cpid, pdes[2]; + char buf[256]; + int status, p; + + 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; + + 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); + } +} + +/* + * Interrupt service routine for FTP + */ +void +stopsnd() +{ + + stop = 1; + signal(SIGINT, SIG_IGN); +} + +/* + * FTP - local ==> remote + * send local file to remote host + * terminate transmission with pseudo EOF sequence + */ +void +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 ((fd = fopen(fnamex, "r")) == NULL) { + printf("%s: cannot open\r\n", fname); + return; + } + transmit(fd, value(EOFWRITE), NULL); + if (!boolean(value(ECHOCHECK))) { + flush_remote (); + } +} + +/* + * Bulk transfer routine to remote host -- + * used by sendfile() and cu_put() + */ +static void +transmit(fd, eofchars, command) + FILE *fd; + char *eofchars, *command; +{ + char *pc, lastc; + int c, ccount, lcount; + time_t start_t, stop_t; + sig_t f; + + kill(pid, SIGIOT); /* put TIPOUT into a wait state */ + stop = 0; + f = signal(SIGINT, stopsnd); + usedefchars (); + 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 { + flush_remote (); + sleep(5); /* wait for remote stty to take effect */ + } + } + lcount = 0; + lastc = '\0'; + start_t = time(0); + while (1) { + ccount = 0; + do { + c = getc(fd); + if (stop) + goto out; + if (c == EOF) + goto out; + if (c == 0177 && !boolean(value(RAWFTP))) + continue; + lastc = c; + if (c < 040) { + if (c == '\n') { + if (!boolean(value(RAWFTP))) + c = '\r'; + } + else if (c == '\t') { + if (!boolean(value(RAWFTP))) { + if (boolean(value(TABEXPAND))) { + send(' '); + while ((++ccount % 8) != 0) + send(' '); + continue; + } + } + } else + if (!boolean(value(RAWFTP))) + continue; + } + send(c); + } while (c != '\r' && !boolean(value(RAWFTP))); + if (boolean(value(VERBOSE))) + printf("\r%d", ++lcount); + if (boolean(value(ECHOCHECK))) { + timedout = 0; + alarm(number(value(ETIMEOUT))); + do { /* wait for prompt */ + read(FD, (char *)&c, 1); + if (timedout || stop) { + if (timedout) + printf("\r\ntimed out at eol\r\n"); + alarm(0); + goto out; + } + } while ((c&0177) != character(value(PROMPT))); + alarm(0); + } + } +out: + if (lastc != '\n' && !boolean(value(RAWFTP))) + send('\r'); + for (pc = eofchars; pc && *pc; pc++) + send(*pc); + stop_t = time(0); + fclose(fd); + signal(SIGINT, f); + 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); + usetchars (); +} + +/* + * Cu-like put command + */ +void +cu_put(cc) + char cc; +{ + FILE *fd; + char line[BUFSIZ]; + int argc; + char *expand(); + char *copynamex; + + if (prompt("[put] ", copyname, sizeof(copyname))) + return; + if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) { + printf("usage: <put> from [to]\r\n"); + return; + } + if (argc == 1) + argv[1] = argv[0]; + copynamex = expand(argv[0]); + if ((fd = fopen(copynamex, "r")) == NULL) { + printf("%s: cannot open\r\n", copynamex); + return; + } + if (boolean(value(ECHOCHECK))) + snprintf(line, sizeof(line), "cat>%s\r", argv[1]); + else + snprintf(line, sizeof(line), "stty -echo;cat>%s;stty echo\r", argv[1]); + transmit(fd, "\04", line); +} + + +static void +nap(msec) + int msec; /* milliseconds */ +{ + usleep(msec*1000); +} + + +/* + * FTP - send single character + * wait for echo & handle timeout + */ +static void +send(c) + char c; +{ + char cc; + int retry = 0; + + cc = c; + xpwrite(FD, &cc, 1); + if (number(value(CDELAY)) > 0 && c != '\r') + nap(number(value(CDELAY))); + if (!boolean(value(ECHOCHECK))) { + if (number(value(LDELAY)) > 0 && c == '\r') + nap(number(value(LDELAY))); + return; + } +tryagain: + timedout = 0; + alarm(number(value(ETIMEOUT))); + read(FD, &cc, 1); + alarm(0); + if (timedout) { + printf("\r\ntimeout error (%s)\r\n", ctrl(c)); + if (retry++ > 3) + return; + xpwrite(FD, &null, 1); /* poke it */ + goto tryagain; + } +} + +void +timeout() +{ + signal(SIGALRM, timeout); + timedout = 1; +} + +/* + * Stolen from consh() -- puts a remote file on the output of a local command. + * Identical to consh() except for where stdout goes. + */ +void +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); + usedefchars (); + 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; + + 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); + usetchars (); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); +} + +#if CONNECT + +int +tiplink (char *cmd, unsigned int flags) +{ + int cpid, status, p; + time_t start; + + if (flags & TL_SIGNAL_TIPOUT) { + kill(pid, SIGIOT); /* put TIPOUT into a wait state */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + usedefchars (); + 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 fd; + + dup2(FD, 0); + dup2(3, 1); + for (fd = 3; fd < 20; fd++) + close (fd); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + execute (cmd); + printf("can't find `%s'\r\n", cmd); + exit(0); + } + + if (flags & TL_VERBOSE && boolean(value(VERBOSE))) + prtime("away for ", time(0)-start); + + if (flags & TL_SIGNAL_TIPOUT) { + write(fildes[1], (char *)&ccc, 1); + usetchars (); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + } + + return 0; +} + +/* + * Fork a program with: + * 0 <-> remote tty in + * 1 <-> remote tty out + * 2 <-> local tty out + */ +int +consh(c) +{ + char buf[256]; + putchar(c); + if (prompt("Local command? ", buf, sizeof(buf))) + return; + tiplink (buf, TL_SIGNAL_TIPOUT | TL_VERBOSE); + return 0; +} +#endif + +/* + * Escape to local shell + */ +void +shell() +{ + int shpid, status; + char *cp; + + printf("[sh]\r\n"); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + unraw(); + if ((shpid = fork())) { + while (shpid != wait(&status)); + raw(); + printf("\r\n!\r\n"); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + return; + } else { + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + if ((cp = rindex(value(SHELL), '/')) == NULL) + cp = value(SHELL); + else + cp++; + shell_uid(); + execl(value(SHELL), cp, 0); + printf("\r\ncan't execl!\r\n"); + exit(1); + } +} + +/* + * TIPIN portion of scripting + * initiate the conversation with TIPOUT + */ +void +setscript() +{ + char c; + /* + * enable TIPOUT side for dialogue + */ + kill(pid, SIGEMT); + if (boolean(value(SCRIPT))) + write(fildes[1], value(RECORD), size(value(RECORD))); + write(fildes[1], "\n", 1); + /* + * wait for TIPOUT to finish + */ + read(repdes[0], &c, 1); + if (c == 'n') + printf("can't create %s\r\n", value(RECORD)); +} + +/* + * Change current working directory of + * local portion of tip + */ +void +chdirectory() +{ + char dirname[PATH_MAX]; + 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"); +} + +void +tipabort(msg) + char *msg; +{ + + kill(pid, SIGTERM); + disconnect(msg); + if (msg != NOSTR) + printf("\r\n%s", msg); + printf("\r\n[EOT]\r\n"); + daemon_uid(); + (void)uu_unlock(uucplock); + unraw(); + exit(0); +} + +void +finish() +{ + char *abortmsg = NOSTR, *dismsg; + + if (LO != NOSTR && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) { + abortmsg = "logout failed"; + } + + if ((dismsg = value(DISCONNECT)) != NOSTR) { + write(FD, dismsg, strlen(dismsg)); + sleep (2); + } + tipabort(abortmsg); +} + +void +intcopy() +{ + raw(); + quit = 1; + longjmp(intbuf, 1); +} + +static void +execute(s) + char *s; +{ + register char *cp; + + if ((cp = rindex(value(SHELL), '/')) == NULL) + cp = value(SHELL); + else + cp++; + shell_uid(); + execl(value(SHELL), cp, "-c", s, 0); +} + +static int +args(buf, a, num) + char *buf, *a[]; + int num; +{ + register char *p = buf, *start; + register char **parg = a; + register int n = 0; + + while (*p && n < num) { + 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'; + } + return(n); +} + +static void +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"); +} + +void +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; + HD = boolean(value(LECHO)); + } + if (vtable[PARITY].v_access&CHANGED) { + vtable[PARITY].v_access &= ~CHANGED; + setparity(value(PARITY)); + } +} + +/* + * Turn tandem mode on or off for remote tty. + */ +static void +tandem(option) + char *option; +{ +#if HAVE_TERMIOS + struct termios ttermios; + tcgetattr (FD, &ttermios); + if (strcmp(option,"on") == 0) { + ttermios.c_iflag |= IXOFF; + ctermios.c_iflag |= IXOFF; + } + else { + ttermios.c_iflag &= ~IXOFF; + ctermios.c_iflag &= ~IXOFF; + } + tcsetattr (FD, TCSANOW, &ttermios); + tcsetattr (0, TCSANOW, &ctermios); +#else /* HAVE_TERMIOS */ + struct sgttyb rmtty; + + ioctl(FD, TIOCGETP, &rmtty); + if (strcmp(option,"on") == 0) { + rmtty.sg_flags |= TANDEM; + arg.sg_flags |= TANDEM; + } else { + rmtty.sg_flags &= ~TANDEM; + arg.sg_flags &= ~TANDEM; + } + ioctl(FD, TIOCSETP, &rmtty); + ioctl(0, TIOCSETP, &arg); +#endif /* HAVE_TERMIOS */ +} + +/* + * Send a break. + */ +void +genbrk() +{ + + ioctl(FD, TIOCSBRK, NULL); + sleep(1); + ioctl(FD, TIOCCBRK, NULL); +} + +/* + * Suspend tip + */ +void +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; + register char *cp, *Shell; + int s, pivec[2] /*, (*sigint)()*/; + + if (!anyof(name, "~{[*?$`'\"\\")) + return(name); + /* sigint = signal(SIGINT, SIG_IGN); */ + if (pipe(pivec) < 0) { + warn("pipe"); + /* signal(SIGINT, sigint) */ + return(name); + } + snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name); + if ((pid = vfork()) == 0) { + Shell = value(SHELL); + if (Shell == NOSTR) + Shell = _PATH_BSHELL; + close(pivec[0]); + close(1); + dup(pivec[1]); + close(pivec[1]); + close(2); + shell_uid(); + execl(Shell, Shell, "-c", cmdbuf, 0); + _exit(1); + } + if (pid == -1) { + warn("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) { + warn("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? + */ + +static int +anyof(s1, s2) + register char *s1, *s2; +{ + register int c; + + while ((c = *s1++)) + if (any(c, s2)) + return(1); + return(0); +} diff --git a/tip/cmdtab.c b/tip/cmdtab.c new file mode 100644 index 0000000000000000000000000000000000000000..5997ffffd426471ef3a63b369f56b6dfe786a4ea --- /dev/null +++ b/tip/cmdtab.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: cmdtab.c,v 1.1 2000-12-22 18:48:47 mike Exp $"; +#endif /* not lint */ + +#include "tipconf.h" +#include "tip.h" + +extern int shell(), getfl(), sendfile(), chdirectory(); +extern int finish(), help(), pipefile(), pipeout(), 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 }, + { '$', NORM, "pipe local command to remote host", pipeout }, +#if CONNECT + { 'C', NORM, "connect program to remote host",consh }, +#endif + { 'c', NORM, "change directory", chdirectory }, + { '.', NORM, "exit from tip", finish }, + {CTRL('d'),NORM,"exit from tip", finish }, + {CTRL('y'),NORM,"suspend tip (local+remote)", suspend }, + {CTRL('z'),NORM,"suspend tip (local only)", suspend }, + { 's', NORM, "set variable", variable }, + { '?', NORM, "get this summary", help }, + { '#', NORM, "send break", genbrk }, + { 0, 0, 0 } +}; diff --git a/tip/cu.c b/tip/cu.c new file mode 100644 index 0000000000000000000000000000000000000000..cc6c1637d9f21155c2782c640f48e82281de7fbc --- /dev/null +++ b/tip/cu.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cu.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: cu.c,v 1.1 2000-12-22 18:48:47 mike Exp $"; +#endif /* not lint */ + +#include "tipconf.h" +#include "tip.h" + +void cleanup(); + +#if INCLUDE_CU_INTERFACE + +/* + * Botch the interface to look like cu's + */ +cumain(argc, argv) + char *argv[]; +{ + register int i; + static char sbuf[12]; + + if (argc < 2) { + printf("usage: cu telno [-t] [-s speed] [-a acu] [-l line] [-#]\n"); + exit(8); + } + CU = DV = NOSTR; + BR = DEFBR; + for (; argc > 1; argv++, argc--) { + if (argv[1][0] != '-') + PN = argv[1]; + 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 || 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: + printf("Bad flag %s", argv[1]); + break; + } + } + 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. + */ + (void)snprintf(sbuf, sizeof(sbuf), "cu%d", BR); + if ((i = hunt(sbuf)) == 0) { + printf("all ports busy\n"); + exit(3); + } + if (i == -1) { + printf("link down\n"); + (void)uu_unlock(uucplock); + exit(3); + } + setbuf(stdout, NULL); + loginit(); + user_uid(); + vinit(); + setparity("none"); + boolean(value(VERBOSE)) = 0; + if (HW) + ttysetup(speed(BR)); + if (connect()) { + printf("Connect failed\n"); + daemon_uid(); + (void)uu_unlock(uucplock); + exit(1); + } + if (!HW) + ttysetup(speed(BR)); +} +#endif /* INCLUDE_CU_INTERFACE */ diff --git a/tip/getcap.c b/tip/getcap.c new file mode 100644 index 0000000000000000000000000000000000000000..dda084fb2e76a238fdc22ffc8f377578ac4590f5 --- /dev/null +++ b/tip/getcap.c @@ -0,0 +1,1079 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Casey Leedom of Lawrence Livermore National Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> + +#include <ctype.h> +#include <db.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +#ifdef LINUX +#define dbopen(a1,a2,a3,a4,a5) NULL +#endif + + +#define BFRAG 1024 +#define BSIZE 1024 +#define ESC ('[' & 037) /* ASCII ESC */ +#define MAX_RECURSION 32 /* maximum getent recursion */ +#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ + +#define RECOK (char)0 +#define TCERR (char)1 +#define SHADOW (char)2 + +static size_t topreclen; /* toprec length */ +static char *toprec; /* Additional record specified by cgetset() */ +static int gottoprec; /* Flag indicating retrieval of toprecord */ + +static int cdbget __P((DB *, char **, char *)); +static int getent __P((char **, u_int *, char **, int, char *, int, char *)); +static int nfcmp __P((char *, char *)); + +#ifdef LINUX +char * +fgetln(FILE *stream, size_t *len) +{ + static char buf[1024]; + + fgets(buf, sizeof buf, stream); + *len = strlen(buf); + return buf; +} +#endif + +/* + * Cgetset() allows the addition of a user specified buffer to be added + * to the database array, in effect "pushing" the buffer on top of the + * virtual database. 0 is returned on success, -1 on failure. + */ +int +cgetset(ent) + char *ent; +{ + if (ent == NULL) { + if (toprec) + free(toprec); + toprec = NULL; + topreclen = 0; + return (0); + } + topreclen = strlen(ent); + if ((toprec = malloc (topreclen + 1)) == NULL) { + errno = ENOMEM; + return (-1); + } + gottoprec = 0; + (void)strcpy(toprec, ent); + return (0); +} + +/* + * Cgetcap searches the capability record buf for the capability cap with + * type `type'. A pointer to the value of cap is returned on success, NULL + * if the requested capability couldn't be found. + * + * Specifying a type of ':' means that nothing should follow cap (:cap:). + * In this case a pointer to the terminating ':' or NUL will be returned if + * cap is found. + * + * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) + * return NULL. + */ +char * +cgetcap(buf, cap, type) + char *buf, *cap; + int type; +{ + register char *bp, *cp; + + bp = buf; + for (;;) { + /* + * Skip past the current capability field - it's either the + * name field if this is the first time through the loop, or + * the remainder of a field whose name failed to match cap. + */ + for (;;) + if (*bp == '\0') + return (NULL); + else + if (*bp++ == ':') + break; + + /* + * Try to match (cap, type) in buf. + */ + for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) + continue; + if (*cp != '\0') + continue; + if (*bp == '@') + return (NULL); + if (type == ':') { + if (*bp != '\0' && *bp != ':') + continue; + return(bp); + } + if (*bp != type) + continue; + bp++; + return (*bp == '@' ? NULL : bp); + } + /* NOTREACHED */ +} + +/* + * Cgetent extracts the capability record name from the NULL terminated file + * array db_array and returns a pointer to a malloc'd copy of it in buf. + * Buf must be retained through all subsequent calls to cgetcap, cgetnum, + * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, + * -1 if the requested record couldn't be found, -2 if a system error was + * encountered (couldn't open/read a file, etc.), and -3 if a potential + * reference loop is detected. + */ +int +cgetent(buf, db_array, name) + char **buf, **db_array, *name; +{ + u_int dummy; + + return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); +} + +/* + * Getent implements the functions of cgetent. If fd is non-negative, + * *db_array has already been opened and fd is the open file descriptor. We + * do this to save time and avoid using up file descriptors for tc= + * recursions. + * + * Getent returns the same success/failure codes as cgetent. On success, a + * pointer to a malloc'ed capability record with all tc= capabilities fully + * expanded and its length (not including trailing ASCII NUL) are left in + * *cap and *len. + * + * Basic algorithm: + * + Allocate memory incrementally as needed in chunks of size BFRAG + * for capability buffer. + * + Recurse for each tc=name and interpolate result. Stop when all + * names interpolated, a name can't be found, or depth exceeds + * MAX_RECURSION. + */ +static int +getent(cap, len, db_array, fd, name, depth, nfield) + char **cap, **db_array, *name, *nfield; + u_int *len; + int fd, depth; +{ + DB *capdbp; + register char *r_end, *rp, **db_p; + int myfd, eof, foundit, retval, clen; + char *record, *cbuf; + int tc_not_resolved; + char pbuf[_POSIX_PATH_MAX]; + + /* + * Return with ``loop detected'' error if we've recursed more than + * MAX_RECURSION times. + */ + if (depth > MAX_RECURSION) + return (-3); + + /* + * Check if we have a top record from cgetset(). + */ + if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { + if ((record = malloc (topreclen + BFRAG)) == NULL) { + errno = ENOMEM; + return (-2); + } + (void)strcpy(record, toprec); + myfd = 0; + db_p = db_array; + rp = record + topreclen + 1; + r_end = rp + BFRAG; + goto tc_exp; + } + /* + * Allocate first chunk of memory. + */ + if ((record = malloc(BFRAG)) == NULL) { + errno = ENOMEM; + return (-2); + } + r_end = record + BFRAG; + foundit = 0; + /* + * Loop through database array until finding the record. + */ + + for (db_p = db_array; *db_p != NULL; db_p++) { + eof = 0; + + /* + * Open database if not already open. + */ + + if (fd >= 0) { + (void)lseek(fd, (off_t)0, SEEK_SET); + myfd = 0; + } else { + (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); + if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) + != NULL) { + free(record); + retval = cdbget(capdbp, &record, name); + if (retval < 0) { + /* no record available */ +#ifndef LINUX + (void)capdbp->close(capdbp); +#else + (void)capdbp->close(capdbp, 0); +#endif + return (retval); + } + /* save the data; close frees it */ + clen = strlen(record); + cbuf = malloc(clen + 1); + memcpy(cbuf, record, clen + 1); +#ifndef LINUX + if (capdbp->close(capdbp) < 0) { +#else + if (capdbp->close(capdbp, 0) < 0) { +#endif + free(cbuf); + return (-2); + } + *len = clen; + *cap = cbuf; + return (retval); + } else { + fd = open(*db_p, O_RDONLY, 0); + if (fd < 0) { + /* No error on unfound file. */ + if (errno == ENOENT) + continue; + free(record); + return (-2); + } + myfd = 1; + } + } + /* + * Find the requested capability record ... + */ + { + char buf[BUFSIZ]; + register char *b_end, *bp; + register int c; + + /* + * Loop invariants: + * There is always room for one more character in record. + * R_end always points just past end of record. + * Rp always points just past last character in record. + * B_end always points just past last character in buf. + * Bp always points at next character in buf. + */ + b_end = buf; + bp = buf; + for (;;) { + + /* + * Read in a line implementing (\, newline) + * line continuation. + */ + rp = record; + for (;;) { + if (bp >= b_end) { + int n; + + n = read(fd, buf, sizeof(buf)); + if (n <= 0) { + if (myfd) + (void)close(fd); + if (n < 0) { + free(record); + return (-2); + } else { + fd = -1; + eof = 1; + break; + } + } + b_end = buf+n; + bp = buf; + } + + c = *bp++; + if (c == '\n') { + if (rp > record && *(rp-1) == '\\') { + rp--; + continue; + } else + break; + } + *rp++ = c; + + /* + * Enforce loop invariant: if no room + * left in record buffer, try to get + * some more. + */ + if (rp >= r_end) { + u_int pos; + size_t newsize; + + pos = rp - record; + newsize = r_end - record + BFRAG; + record = realloc(record, newsize); + if (record == NULL) { + errno = ENOMEM; + if (myfd) + (void)close(fd); + return (-2); + } + r_end = record + newsize; + rp = record + pos; + } + } + /* loop invariant let's us do this */ + *rp++ = '\0'; + + /* + * If encountered eof check next file. + */ + if (eof) + break; + + /* + * Toss blank lines and comments. + */ + if (*record == '\0' || *record == '#') + continue; + + /* + * See if this is the record we want ... + */ + if (cgetmatch(record, name) == 0) { + if (nfield == NULL || !nfcmp(nfield, record)) { + foundit = 1; + break; /* found it! */ + } + } + } + } + if (foundit) + break; + } + + if (!foundit) + return (-1); + + /* + * Got the capability record, but now we have to expand all tc=name + * references in it ... + */ +tc_exp: { + register char *newicap, *s; + register int newilen; + u_int ilen; + int diff, iret, tclen; + char *icap, *scan, *tc, *tcstart, *tcend; + + /* + * Loop invariants: + * There is room for one more character in record. + * R_end points just past end of record. + * Rp points just past last character in record. + * Scan points at remainder of record that needs to be + * scanned for tc=name constructs. + */ + scan = record; + tc_not_resolved = 0; + for (;;) { + if ((tc = cgetcap(scan, "tc", '=')) == NULL) + break; + + /* + * Find end of tc=name and stomp on the trailing `:' + * (if present) so we can use it to call ourselves. + */ + s = tc; + for (;;) + if (*s == '\0') + break; + else + if (*s++ == ':') { + *(s - 1) = '\0'; + break; + } + tcstart = tc - 3; + tclen = s - tcstart; + tcend = s; + + iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, + NULL); + newicap = icap; /* Put into a register. */ + newilen = ilen; + if (iret != 0) { + /* an error */ + if (iret < -1) { + if (myfd) + (void)close(fd); + free(record); + return (iret); + } + if (iret == 1) + tc_not_resolved = 1; + /* couldn't resolve tc */ + if (iret == -1) { + *(s - 1) = ':'; + scan = s - 1; + tc_not_resolved = 1; + continue; + + } + } + /* not interested in name field of tc'ed record */ + s = newicap; + for (;;) + if (*s == '\0') + break; + else + if (*s++ == ':') + break; + newilen -= s - newicap; + newicap = s; + + /* make sure interpolated record is `:'-terminated */ + s += newilen; + if (*(s-1) != ':') { + *s = ':'; /* overwrite NUL with : */ + newilen++; + } + + /* + * Make sure there's enough room to insert the + * new record. + */ + diff = newilen - tclen; + if (diff >= r_end - rp) { + u_int pos, tcpos, tcposend; + size_t newsize; + + pos = rp - record; + newsize = r_end - record + diff + BFRAG; + tcpos = tcstart - record; + tcposend = tcend - record; + record = realloc(record, newsize); + if (record == NULL) { + errno = ENOMEM; + if (myfd) + (void)close(fd); + free(icap); + return (-2); + } + r_end = record + newsize; + rp = record + pos; + tcstart = record + tcpos; + tcend = record + tcposend; + } + + /* + * Insert tc'ed record into our record. + */ + s = tcstart + newilen; + bcopy(tcend, s, rp - tcend); + bcopy(newicap, tcstart, newilen); + rp += diff; + free(icap); + + /* + * Start scan on `:' so next cgetcap works properly + * (cgetcap always skips first field). + */ + scan = s-1; + } + + } + /* + * Close file (if we opened it), give back any extra memory, and + * return capability, length and success. + */ + if (myfd) + (void)close(fd); + *len = rp - record - 1; /* don't count NUL */ + if (r_end > rp) + if ((record = + realloc(record, (size_t)(rp - record))) == NULL) { + errno = ENOMEM; + return (-2); + } + + *cap = record; + if (tc_not_resolved) + return (1); + return (0); +} + +static int +cdbget(capdbp, bp, name) + DB *capdbp; + char **bp, *name; +{ + DBT key, data; + + key.data = name; + key.size = strlen(name); + + for (;;) { + /* Get the reference. */ +#ifndef LINUX + switch(capdbp->get(capdbp, &key, &data, 0)) { +#else + switch(capdbp->get(capdbp, 0, &key, &data, 0)) { +#endif + case -1: + return (-2); + case 1: + return (-1); + } + + /* If not an index to another record, leave. */ + if (((char *)data.data)[0] != SHADOW) + break; + + key.data = (char *)data.data + 1; + key.size = data.size - 1; + } + + *bp = (char *)data.data + 1; + return (((char *)(data.data))[0] == TCERR ? 1 : 0); +} + +/* + * Cgetmatch will return 0 if name is one of the names of the capability + * record buf, -1 if not. + */ +int +cgetmatch(buf, name) + char *buf, *name; +{ + register char *np, *bp; + + /* + * Start search at beginning of record. + */ + bp = buf; + for (;;) { + /* + * Try to match a record name. + */ + np = name; + for (;;) + if (*np == '\0') + if (*bp == '|' || *bp == ':' || *bp == '\0') + return (0); + else + break; + else + if (*bp++ != *np++) + break; + + /* + * Match failed, skip to next name in record. + */ + bp--; /* a '|' or ':' may have stopped the match */ + for (;;) + if (*bp == '\0' || *bp == ':') + return (-1); /* match failed totally */ + else + if (*bp++ == '|') + break; /* found next name */ + } +} + + + + + +int +cgetfirst(buf, db_array) + char **buf, **db_array; +{ + (void)cgetclose(); + return (cgetnext(buf, db_array)); +} + +static FILE *pfp; +static int slash; +static char **dbp; + +int +cgetclose() +{ + if (pfp != NULL) { + (void)fclose(pfp); + pfp = NULL; + } + dbp = NULL; + gottoprec = 0; + slash = 0; + return(0); +} + +/* + * Cgetnext() gets either the first or next entry in the logical database + * specified by db_array. It returns 0 upon completion of the database, 1 + * upon returning an entry with more remaining, and -1 if an error occurs. + */ +int +cgetnext(bp, db_array) + register char **bp; + char **db_array; +{ + size_t len; + int status, i, done; + char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; + u_int dummy; + + if (dbp == NULL) + dbp = db_array; + + if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { + (void)cgetclose(); + return (-1); + } + for(;;) { + if (toprec && !gottoprec) { + gottoprec = 1; + line = toprec; + } else { + line = fgetln(pfp, &len); + if (line == NULL && pfp) { + (void)fclose(pfp); + if (ferror(pfp)) { + (void)cgetclose(); + return (-1); + } else { + if (*++dbp == NULL) { + (void)cgetclose(); + return (0); + } else if ((pfp = + fopen(*dbp, "r")) == NULL) { + (void)cgetclose(); + return (-1); + } else + continue; + } + } else + line[len - 1] = '\0'; + if (len == 1) { + slash = 0; + continue; + } + if (isspace(*line) || + *line == ':' || *line == '#' || slash) { + if (line[len - 2] == '\\') + slash = 1; + else + slash = 0; + continue; + } + if (line[len - 2] == '\\') + slash = 1; + else + slash = 0; + } + + + /* + * Line points to a name line. + */ + i = 0; + done = 0; + np = nbuf; + for (;;) { + for (cp = line; *cp != '\0'; cp++) { + if (*cp == ':') { + *np++ = ':'; + done = 1; + break; + } + if (*cp == '\\') + break; + *np++ = *cp; + } + if (done) { + *np = '\0'; + break; + } else { /* name field extends beyond the line */ + line = fgetln(pfp, &len); + if (line == NULL && pfp) { + (void)fclose(pfp); + if (ferror(pfp)) { + (void)cgetclose(); + return (-1); + } + } else + line[len - 1] = '\0'; + } + } + rp = buf; + for(cp = nbuf; *cp != '\0'; cp++) + if (*cp == '|' || *cp == ':') + break; + else + *rp++ = *cp; + + *rp = '\0'; + /* + * XXX + * Last argument of getent here should be nbuf if we want true + * sequential access in the case of duplicates. + * With NULL, getent will return the first entry found + * rather than the duplicate entry record. This is a + * matter of semantics that should be resolved. + */ + status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); + if (status == -2 || status == -3) + (void)cgetclose(); + + return (status + 1); + } + /* NOTREACHED */ +} + +/* + * Cgetstr retrieves the value of the string capability cap from the + * capability record pointed to by buf. A pointer to a decoded, NUL + * terminated, malloc'd copy of the string is returned in the char * + * pointed to by str. The length of the string not including the trailing + * NUL is returned on success, -1 if the requested string capability + * couldn't be found, -2 if a system error was encountered (storage + * allocation failure). + */ +int +cgetstr(buf, cap, str) + char *buf, *cap; + char **str; +{ + register u_int m_room; + register char *bp, *mp; + int len; + char *mem; + + /* + * Find string capability cap + */ + bp = cgetcap(buf, cap, '='); + if (bp == NULL) + return (-1); + + /* + * Conversion / storage allocation loop ... Allocate memory in + * chunks SFRAG in size. + */ + if ((mem = malloc(SFRAG)) == NULL) { + errno = ENOMEM; + return (-2); /* couldn't even allocate the first fragment */ + } + m_room = SFRAG; + mp = mem; + + while (*bp != ':' && *bp != '\0') { + /* + * Loop invariants: + * There is always room for one more character in mem. + * Mp always points just past last character in mem. + * Bp always points at next character in buf. + */ + if (*bp == '^') { + bp++; + if (*bp == ':' || *bp == '\0') + break; /* drop unfinished escape */ + if (*bp == '?') { + *mp++ = '\177'; + bp++; + } else + *mp++ = *bp++ & 037; + } else if (*bp == '\\') { + bp++; + if (*bp == ':' || *bp == '\0') + break; /* drop unfinished escape */ + if ('0' <= *bp && *bp <= '7') { + register int n, i; + + n = 0; + i = 3; /* maximum of three octal digits */ + do { + n = n * 8 + (*bp++ - '0'); + } while (--i && '0' <= *bp && *bp <= '7'); + *mp++ = n; + } + else switch (*bp++) { + case 'b': case 'B': + *mp++ = '\b'; + break; + case 't': case 'T': + *mp++ = '\t'; + break; + case 'n': case 'N': + *mp++ = '\n'; + break; + case 'f': case 'F': + *mp++ = '\f'; + break; + case 'r': case 'R': + *mp++ = '\r'; + break; + case 'e': case 'E': + *mp++ = ESC; + break; + case 'c': case 'C': + *mp++ = ':'; + break; + default: + /* + * Catches '\', '^', and + * everything else. + */ + *mp++ = *(bp-1); + break; + } + } else + *mp++ = *bp++; + m_room--; + + /* + * Enforce loop invariant: if no room left in current + * buffer, try to get some more. + */ + if (m_room == 0) { + size_t size = mp - mem; + + if ((mem = realloc(mem, size + SFRAG)) == NULL) + return (-2); + m_room = SFRAG; + mp = mem + size; + } + } + *mp++ = '\0'; /* loop invariant let's us do this */ + m_room--; + len = mp - mem - 1; + + /* + * Give back any extra memory and return value and success. + */ + if (m_room != 0) + if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL) + return (-2); + *str = mem; + return (len); +} + +/* + * Cgetustr retrieves the value of the string capability cap from the + * capability record pointed to by buf. The difference between cgetustr() + * and cgetstr() is that cgetustr does not decode escapes but rather treats + * all characters literally. A pointer to a NUL terminated malloc'd + * copy of the string is returned in the char pointed to by str. The + * length of the string not including the trailing NUL is returned on success, + * -1 if the requested string capability couldn't be found, -2 if a system + * error was encountered (storage allocation failure). + */ +int +cgetustr(buf, cap, str) + char *buf, *cap, **str; +{ + register u_int m_room; + register char *bp, *mp; + int len; + char *mem; + + /* + * Find string capability cap + */ + if ((bp = cgetcap(buf, cap, '=')) == NULL) + return (-1); + + /* + * Conversion / storage allocation loop ... Allocate memory in + * chunks SFRAG in size. + */ + if ((mem = malloc(SFRAG)) == NULL) { + errno = ENOMEM; + return (-2); /* couldn't even allocate the first fragment */ + } + m_room = SFRAG; + mp = mem; + + while (*bp != ':' && *bp != '\0') { + /* + * Loop invariants: + * There is always room for one more character in mem. + * Mp always points just past last character in mem. + * Bp always points at next character in buf. + */ + *mp++ = *bp++; + m_room--; + + /* + * Enforce loop invariant: if no room left in current + * buffer, try to get some more. + */ + if (m_room == 0) { + size_t size = mp - mem; + + if ((mem = realloc(mem, size + SFRAG)) == NULL) + return (-2); + m_room = SFRAG; + mp = mem + size; + } + } + *mp++ = '\0'; /* loop invariant let's us do this */ + m_room--; + len = mp - mem - 1; + + /* + * Give back any extra memory and return value and success. + */ + if (m_room != 0) + if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL) + return (-2); + *str = mem; + return (len); +} + +/* + * Cgetnum retrieves the value of the numeric capability cap from the + * capability record pointed to by buf. The numeric value is returned in + * the long pointed to by num. 0 is returned on success, -1 if the requested + * numeric capability couldn't be found. + */ +int +cgetnum(buf, cap, num) + char *buf, *cap; + long *num; +{ + register long n; + register int base, digit; + register char *bp; + + /* + * Find numeric capability cap + */ + bp = cgetcap(buf, cap, '#'); + if (bp == NULL) + return (-1); + + /* + * Look at value and determine numeric base: + * 0x... or 0X... hexadecimal, + * else 0... octal, + * else decimal. + */ + if (*bp == '0') { + bp++; + if (*bp == 'x' || *bp == 'X') { + bp++; + base = 16; + } else + base = 8; + } else + base = 10; + + /* + * Conversion loop ... + */ + n = 0; + for (;;) { + if ('0' <= *bp && *bp <= '9') + digit = *bp - '0'; + else if ('a' <= *bp && *bp <= 'f') + digit = 10 + *bp - 'a'; + else if ('A' <= *bp && *bp <= 'F') + digit = 10 + *bp - 'A'; + else + break; + + if (digit >= base) + break; + + n = n * base + digit; + bp++; + } + + /* + * Return value and success. + */ + *num = n; + return (0); +} + + +/* + * Compare name field of record. + */ +static int +nfcmp(nf, rec) + char *nf, *rec; +{ + char *cp, tmp; + int ret; + + for (cp = rec; *cp != ':'; cp++) + ; + + tmp = *(cp + 1); + *(cp + 1) = '\0'; + ret = strcmp(nf, rec); + *(cp + 1) = tmp; + + return (ret); +} diff --git a/tip/hunt.c b/tip/hunt.c new file mode 100644 index 0000000000000000000000000000000000000000..df2a1c12fc05003278d17a8b3fce0f92cc050240 --- /dev/null +++ b/tip/hunt.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)hunt.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: hunt.c,v 1.1 2000-12-22 18:48:47 mike Exp $"; +#endif /* not lint */ + +#include <sys/types.h> +#include <err.h> +#ifndef LINUX +#include <libutil.h> +#endif +#include "tipconf.h" +#include "tip.h" + +extern char *getremote(); +extern char *rindex(); + +static jmp_buf deadline; +static int deadfl; + +void +dead() +{ + deadfl = 1; + longjmp(deadline, 1); +} + +int +hunt(name) + char *name; +{ + register char *cp; + sig_t f; + int res; + + f = signal(SIGALRM, dead); + while ((cp = getremote(name))) { + deadfl = 0; + uucplock = rindex(cp, '/')+1; + if ((res = uu_lock(uucplock)) != UU_LOCK_OK) { + if (res != UU_LOCK_INUSE) + fprintf(stderr, "uu_lock: %s\n", uu_lockerr(res)); + 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 (setjmp(deadline) == 0) { + alarm(10); + FD = open(cp, O_RDWR); + } + alarm(0); + if (FD < 0) { + warn("%s", cp); + deadfl = 1; + } + if (!deadfl) { + ioctl(FD, TIOCEXCL, 0); +#if HAVE_TERMIOS + { + struct termios t; + if (tcgetattr(FD, &t) == 0) { + t.c_cflag |= HUPCL; + (void)tcsetattr(FD, TCSANOW, &t); + } + } +#else /* HAVE_TERMIOS */ +#ifdef TIOCHPCL + ioctl(FD, TIOCHPCL, 0); +#endif +#endif /* HAVE_TERMIOS */ + signal(SIGALRM, SIG_DFL); + return ((int)cp); + } + (void)uu_unlock(uucplock); + } + signal(SIGALRM, f); + return (deadfl ? -1 : (int)cp); +} diff --git a/tip/log.c b/tip/log.c new file mode 100644 index 0000000000000000000000000000000000000000..65b25ceb336fc678bec3899e3d199974eccf5dc8 --- /dev/null +++ b/tip/log.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)log.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: log.c,v 1.1 2000-12-22 18:48:48 mike Exp $"; +#endif /* not lint */ + +#include "tipconf.h" +#include "tip.h" +#include <err.h> + +#if ACULOG +static FILE *flog = NULL; + +/* + * Log file maintenance routines + */ + +void +logent(group, num, acu, message) + char *group, *num, *acu, *message; +{ + char *user, *timestamp; + struct passwd *pwd; + time_t t; + + if (flog == NULL) + return; + if (flock(fileno(flog), LOCK_EX) < 0) { + warn("flock"); + return; + } + if ((user = getlogin()) == NOSTR) + if ((pwd = getpwuid(getuid())) == 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, +#if PRISTINE + "", +#else + num, +#endif + acu, message); + (void) fflush(flog); + (void) flock(fileno(flog), LOCK_UN); +} + +void +loginit() +{ + flog = fopen(value(LOG), "a"); + if (flog == NULL) + fprintf(stderr, "can't open log file %s.\r\n", value(LOG)); +} +#endif diff --git a/tip/modems.5 b/tip/modems.5 new file mode 100644 index 0000000000000000000000000000000000000000..7fd347433cc02bba62881d7981a0f30dc6c3ead7 --- /dev/null +++ b/tip/modems.5 @@ -0,0 +1,141 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)modems.5 3/24/95 +.\" +.Dd March 24, 1995 +.Dt MODEMS 5 +.Os BSD 4.4 +.Sh NAME +.Nm modems +.Nd modem configuration data base +.Sh DESCRIPTION +The modems known by +.Xr tip 1 +and their attributes are stored in an +.Tn ASCII +file which +is structured somewhat like the +.Xr termcap 5 +file. Each line in the file provides a description for a single +.Em modem . +Fields are separated by a colon (``:''). +Lines ending in a \e character with an immediately following newline are +continued on the next line. +.Pp +The first entry is the name(s) of the modem. If there is more +than one name for a modem, the names are separated by vertical bars. +After the name of the modem comes the fields of the description. A +field name followed by an `=' sign indicates a string value follows. A field +name followed by a `#' sign indicates a following numeric value. +.Pp +When +.Xr tip 1 +is invoked, an entry for a remote system is looked up in the +.Pa /etc/remote +database. +If the entry includes an "ACU" type capability (abbreviated at), +.Xr tip 1 +looks up the specified modem in +.Pa /etc/modems. +If a modem entry is found, +the corresponding capabilities determine how +.Xr tip 1 +programs the modem when connecting to and disconnecting from the +remote system. +.Sh CAPABILITIES +Capabilities are either strings (str), numbers (num), or boolean +flags (bool). A string capability is specified by +.Em capability Ns Ar = Ns Em value ; +for example, ``reset_command=ATZ\\r''. A numeric capability is specified by +.Em capability Ns Ar # Ns Em value ; +for example, ``intercharacter_delay#50''. A boolean capability is specified +by simply listing the capability. +.Bl -tag -width intercharacter_delay indent +.It Cm \&dial_command +(str) +AT command used to dial remote system (typically, "ATDT") +.It Cm \&echo_off_command +(str) +AT command to turn off command echo. +.It Cm \&escape_guard_time +(num) +The delay, expressed in milliseconds, used to frame return-to-command +escape sequences. +.It Cm \&escape_sequence +(str) +The return-to-command escape sequence. +.It Cm \&hangup_command +(str) +AT command used to hangup modem. +.It Cm \&hw_flow_control +(bool) +Enable hardware (RTS/CTS) flow control between computer and modem (DTE/DCE). +.It Cm \&init_string +(str) +AT command used to initialize modem before dialing. +.It Cm \&intercharacter_delay +(num) +Delay value, expressed in milliseconds, between characters when sending commands +to the modem. +.It Cm \&intercommand_delay +(num) +Minimum delay value, expressed in milliseconds, to impose between commands +issued to the modem. +.It Cm \&lock_baud +(bool) +Use a fixed bit rate between the computer and the modem (DTE / DCE). The +bit rate is specified in +.Pa /etc/remote. +.It Cm \&reset_command +(str) +AT command to reset the modem. +.It Cm \&reset_delay +(num) +The time, expressed in milliseconds, required by the modem to complete +a reset and return to a ready condition. +.Sh FILES +.Bl -tag -width /etc/modems -compact +.It Pa /etc/modems +The +.Nm modems +configuration database file +resides in +.Pa /etc . +.El +.Sh SEE ALSO +.Xr tip 1 , +.Xr remote 5 +.Sh HISTORY +The +.Nm +file format appeared in +.Bx 4.4 . diff --git a/tip/partab.c b/tip/partab.c new file mode 100644 index 0000000000000000000000000000000000000000..577d2fca875f9c2df14cf7e09de2b2c45650f1b6 --- /dev/null +++ b/tip/partab.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)partab.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: partab.c,v 1.1 2000-12-22 18:48:48 mike Exp $"; +#endif /* not lint */ + +/* + * Even parity table for 0-0177 + */ +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, +}; diff --git a/tip/pathnames.h b/tip/pathnames.h new file mode 100644 index 0000000000000000000000000000000000000000..0f9a15b1fa0f0ba6593d89d3d48a4daffd843d0f --- /dev/null +++ b/tip/pathnames.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include <paths.h> + +/* + Specify path to ACU (modem) log +*/ +#define _PATH_ACULOG "/var/log/aculog" + +/* + Specify path and format of lock files +*/ +/* #define _PATH_LOCKDIRNAME "/usr/spool/uucp/LCK..%s" */ +/* #define _PATH_LOCKDIRNAME "/etc/locks/LCK..%s" */ +/* #define _PATH_LOCKDIRNAME "/usr/spool/locks/LCK..%s" */ +/* #define _PATH_LOCKDIRNAME "/usr/spool/uucp/LCK/LCK..%s" */ +#define _PATH_LOCKDIRNAME _PATH_UUCPLOCK "LCK..%s" + +/* + Specify location for system wide databases +*/ +#define _PATH_MODEMS "/etc/modems" +#define _PATH_PHONES "/etc/phones" +#define _PATH_REMOTE "/etc/remote" + diff --git a/tip/remcap.c b/tip/remcap.c new file mode 100644 index 0000000000000000000000000000000000000000..7a7e0c2732ca6469cd27cbab536162db4be01e18 --- /dev/null +++ b/tip/remcap.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)remcap.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * remcap - routines for dealing with the remote host data base + * + * derived from termcap + */ +#include <sys/types.h> +#include <fcntl.h> +#include <ctype.h> +#include <stdlib.h> +#include "pathnames.h" + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif +#define MAXHOP 32 /* max number of tc= indirections */ + +#define tgetent rgetent +#define tnchktc rnchktc +#define tnamatch rnamatch +#define tgetnum rgetnum +#define tgetflag rgetflag +#define tgetstr rgetstr +#define E_TERMCAP RM = _PATH_REMOTE +#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 */ +static char *tskip(); +char *tgetstr(); +static char *tdecode(); +static char *remotefile; + +/* + * 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) + char *bp, *name; +{ + char lbuf[BUFSIZ], *cp, *p; + int rc1, rc2; + + remotefile = cp = getenv(V_TERMCAP); + if (cp == (char *)0 || strcmp(cp, _PATH_REMOTE) == 0) { + remotefile = cp = _PATH_REMOTE; + return (getent(bp, name, cp)); + } else { + if ((rc1 = getent(bp, name, cp)) != 1) + *bp = '\0'; + remotefile = cp = _PATH_REMOTE; + rc2 = getent(lbuf, name, cp); + if (rc1 != 1 && rc2 != 1) + return (rc2); + if (rc2 == 1) { + p = lbuf; + if (rc1 == 1) + while (*p++ != ':') + ; + if (strlen(bp) + strlen(p) > BUFSIZ) { + write(2, "Remcap entry too long\n", 23); + return (-1); + } + strcat(bp, p); + } + tbuf = bp; + return (1); + } +} + +getent(bp, name, cp) + char *bp, *name, *cp; +{ + register int c; + register int i = 0, cnt = 0; + char ibuf[BUFSIZ], *cp2; + int tf; + + 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) { + strcpy(bp,cp); + return (tnchktc()); + } else + tf = open(E_TERMCAP, O_RDONLY); + } else + tf = open(RM = cp, O_RDONLY); + } + 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+BUFSIZ) { + write(2,"Remcap entry too long\n", 23); + break; + } else + *cp++ = c; + } + *cp = 0; + + /* + * The real work for the match. + */ + if (tnamatch(name)) { + 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[16]; /* 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); + strcpy(tcname, p+3); + 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) != 1) { + if (strcmp(remotefile, _PATH_REMOTE) == 0) + return (0); + else if (getent(tcbuf, tcname, _PATH_REMOTE) != 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 == ':') + 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/tip/remote.c b/tip/remote.c new file mode 100644 index 0000000000000000000000000000000000000000..0eba8545252bcb78f016113207d41c0cad011052 --- /dev/null +++ b/tip/remote.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)remote.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: remote.c,v 1.1 2000-12-22 18:48:48 mike Exp $"; +#endif /* not lint */ + +#ifndef LINUX +#include <sys/syslimits.h> +#endif +#include <err.h> +#include <stdio.h> +#include <stdlib.h> + +#include "tipconf.h" +#include "tip.h" +#include "pathnames.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, &LI, &LO +}; + +static char *capstrings[] = { + "at", "dv", "cm", "cu", "el", "ie", "oe", "pn", "pr", + "di", "es", "ex", "fo", "rc", "re", "pa", "li", "lo", 0 +}; + +static char *db_array[3] = { _PATH_REMOTE, 0, 0 }; + +char *cgetcap __P((char *, char *, int)); + +#define cgetflag(f) (cgetcap(bp, f, ':') != NULL) + +static void getremcap __P((char *)); + +/* + Expand the start tilde sequence at the start of the + specified path. Optionally, free space allocated to + path before reinitializing it. +*/ +static int +expand_tilde (char **path, void (*free) (char *p)) +{ + int rc = 0; + char buffer [PATH_MAX]; + char *tailp; + if ((tailp = strchr (*path + 1, '/')) != NULL) + { + struct passwd *pwd; + *tailp++ = '\0'; + if (*(*path + 1) == '\0') + strcpy (buffer, getlogin ()); + else + strcpy (buffer, *path + 1); + if ((pwd = getpwnam (buffer)) != NULL) + { + strcpy (buffer, pwd->pw_dir); + strcat (buffer, "/"); + strcat (buffer, tailp); + if (free) + free (*path); + *path = strdup (buffer); + rc++; + } + return rc; + } + return (-1); +} + +static void +getremcap(host) + register char *host; +{ + register char **p, ***q; + char *bp; + char *rempath; + int stat; + + rempath = getenv("REMOTE"); + if (rempath != NULL) + if (*rempath != '/') + /* we have an entry */ + cgetset(rempath); + else { /* we have a path */ + db_array[1] = rempath; + db_array[2] = _PATH_REMOTE; + } + + if ((stat = cgetent(&bp, db_array, host)) < 0) { + if (DV || + (host[0] == '/' && access(DV = host, R_OK | W_OK) == 0)) { + CU = DV; + HO = host; + HW = 1; + DU = 0; + if (!BR) + BR = DEFBR; + FS = DEFFS; + return; + } + switch(stat) { + case -1: + warnx("unknown host %s", host); + break; + case -2: + warnx("can't open host description file"); + break; + case -3: + warnx("possible reference loop in host description file"); + break; + } + exit(3); + } + + for (p = capstrings, q = caps; *p != NULL; p++, q++) + if (**q == NULL) + cgetstr(bp, *p, *q); + if (!BR && (cgetnum(bp, "br", &BR) == -1)) + BR = DEFBR; + if (cgetnum(bp, "fs", &FS) == -1) + FS = DEFFS; + if (DU < 0) + DU = 0; + else + DU = cgetflag("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); + } + + HD = cgetflag("hd"); + + /* + * This effectively eliminates the "hw" attribute + * from the description file + */ + if (!HW) + HW = (CU == NOSTR) || (DU && equal(DV, CU)); + HO = host; + + /* + If login script, verify access + */ + if (LI != NOSTR) { + if (*LI == '~') + (void) expand_tilde (&LI, NULL); + if (access (LI, F_OK | X_OK) != 0) { + printf("tip (warning): can't open login script \"%s\"\n", LI); + LI = NOSTR; + } + } + + /* + If logout script, verify access + */ + if (LO != NOSTR) { + if (*LO == '~') + (void) expand_tilde (&LO, NULL); + if (access (LO, F_OK | X_OK) != 0) { + printf("tip (warning): can't open logout script \"%s\"\n", LO); + LO = NOSTR; + } + } + + /* + * see if uppercase mode should be turned on initially + */ + if (cgetflag("ra")) + boolean(value(RAISE)) = 1; + if (cgetflag("ec")) + boolean(value(ECHOCHECK)) = 1; + if (cgetflag("be")) + boolean(value(BEAUTIFY)) = 1; + if (cgetflag("nb")) + boolean(value(BEAUTIFY)) = 0; + if (cgetflag("sc")) + boolean(value(SCRIPT)) = 1; + if (cgetflag("tb")) + boolean(value(TABEXPAND)) = 1; + if (cgetflag("vb")) + boolean(value(VERBOSE)) = 1; + if (cgetflag("nv")) + boolean(value(VERBOSE)) = 0; + if (cgetflag("ta")) + boolean(value(TAND)) = 1; + if (cgetflag("nt")) + boolean(value(TAND)) = 0; + if (cgetflag("rw")) + boolean(value(RAWFTP)) = 1; + if (cgetflag("hd")) + boolean(value(HALFDUPLEX)) = 1; + if (RE == NOSTR) + RE = (char *)"tip.record"; + if (EX == NOSTR) + 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 (cgetnum(bp, "dl", &DL) == -1) + DL = 0; + if (cgetnum(bp, "cl", &CL) == -1) + CL = 0; + if (cgetnum(bp, "et", &ET) == -1) + 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) + errx(3, "no host specified"); + 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 = index(next, ',')) == NULL) { + DV = next; + next = NOSTR; + } else { + *cp++ = '\0'; + DV = next; + next = cp; + } + return (DV); +} diff --git a/tip/tip.1 b/tip/tip.1 new file mode 100644 index 0000000000000000000000000000000000000000..687fda9886670f9238b6764e7605eb0b9c10a925 --- /dev/null +++ b/tip/tip.1 @@ -0,0 +1,442 @@ +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tip.1 8.4 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt TIP 1 +.Os BSD 4 +.Sh NAME +.Nm tip +.Nd connect to a remote system +.Sh SYNOPSIS +.Nm tip +.Op Fl v +.Fl Ns Ns Ar speed +.Ar system\-name +.Nm tip +.Op Fl v +.Fl Ns Ns Ar speed +.Ar phone\-number +.Sh DESCRIPTION +.Nm Tip +establish a full-duplex connection to another machine, +giving the appearance of being logged in directly on the +remote cpu. It goes without saying that you must have a login +on the machine (or equivalent) to which you wish to connect. +.Pp +Available Option: +.Bl -tag -width indent +.It Fl v +Set verbose mode. +.El +.Pp +Typed characters are normally transmitted directly to the remote +machine (which does the echoing as well). A tilde (`~') appearing +as the first character of a line is an escape signal; the following +are recognized: +.Bl -tag -width flag +.It Ic \&~^D No or Ic \&~ . +Drop the connection and exit +(you may still be logged in on the +remote machine). +.It Ic \&~c Op Ar name +Change directory to +.Ar name +(no argument +implies change to your home directory). +.It Ic \&~! +Escape to a shell (exiting the shell will +return you to tip). +.It Ic \&~> +Copy file from local to remote. +.Nm Tip +prompts for the name of a local file to transmit. +.It Ic \&~< +Copy file from remote to local. +.Nm Tip +prompts first for the name of the file to be sent, then for +a command to be executed on the remote machine. +.It Ic \&~p Ar from Op Ar to +Send a file to a remote +.Ux +host. The put command causes the remote +.Ux +system to run the command string ``cat > 'to''', while +.Nm tip +sends it the ``from'' +file. If the ``to'' file isn't specified the ``from'' file name is used. +This command is actually a +.Ux +specific version of the ``~>'' command. +.It Ic \&~t Ar from Op Ar to +Take a file from a remote +.Ux +host. +As in the put command the ``to'' file +defaults to the ``from'' file name if it isn't specified. +The remote host +executes the command string ``cat 'from';echo ^A'' to send the file to +.Nm tip . +.It Ic \&~| +Pipe the output from a remote command to a local +.Ux +process. +The command string sent to the local +.Ux +system is processed by the shell. +.It Ic \&~$ +Pipe the output from a local +.Ux +process to the remote host. +The command string sent to the local +.Ux +system is processed by the shell. +.It Ic \&~C +Fork a child process on the local system to perform special protocols +such as \s-1XMODEM\s+1. The child program will be run with the following +somewhat unusual arrangement of file descriptors: +.nf +.in +1i +0 <-> local tty in +1 <-> local tty out +2 <-> local tty out +3 <-> remote tty in +4 <-> remote tty out +.in -1i +.fi +.It Ic \&~# +Send a +.Dv BREAK +to the remote system. +For systems which don't support the +necessary +.Ar ioctl +call the break is simulated by a sequence of line speed changes +and +.Dv DEL +characters. +.It Ic \&~s +Set a variable (see the discussion below). +.It Ic \&~^Z +Stop +.Nm tip +(only available with job control). +.It Ic \&~^Y +Stop only the ``local side'' of +.Nm tip +(only available with job control); +the ``remote side'' of +.Nm tip , +the side that displays output from the remote host, is left running. +.It Ic \&~? +Get a summary of the tilde escapes +.El +.Pp +.Nm Tip +uses the file +.Pa /etc/remote +to find how to reach a particular +system and to find out how it should operate while talking +to the system; +refer to +.Xr remote 5 +for a full description. +Each system has a default baud rate with which to +establish a connection. If this value is not suitable, the baud rate +to be used may be specified on the command line, e.g. +.Ql "tip -300 mds" . +.Pp +When +.Nm tip +establishes a connection it sends out a +connection message to the remote system; the default value, if any, +is defined in +.Pa /etc/remote +(see +.Xr remote 5 ) . +.Pp +When +.Nm tip +prompts for an argument (e.g. during setup of +a file transfer) the line typed may be edited with the standard +erase and kill characters. A null line in response to a prompt, +or an interrupt, will abort the dialogue and return you to the +remote machine. +.Pp +.Nm Tip +guards against multiple users connecting to a remote system +by opening modems and terminal lines with exclusive access, +and by honoring the locking protocol used by +.Xr uucico 8 . +.Pp +During file transfers +.Nm tip +provides a running count of the number of lines transferred. +When using the ~> and ~< commands, the ``eofread'' and ``eofwrite'' +variables are used to recognize end-of-file when reading, and +specify end-of-file when writing (see below). File transfers +normally depend on tandem mode for flow control. If the remote +system does not support tandem mode, ``echocheck'' may be set +to indicate +.Nm tip +should synchronize with the remote system on the echo of each +transmitted character. +.Pp +When +.Nm tip +must dial a phone number to connect to a system it will print +various messages indicating its actions. +.Nm Tip +supports modems that use the AT command set. +.Nm Tip +uses the file +.Pa /etc/modems +to find out how to operate with a particular +modem; refer to +.Xr modems 5 +for a full description. +.Ss VARIABLES +.Nm Tip +maintains a set of +.Ar variables +which control its operation. +Some of these variables are read-only to normal users (root is allowed +to change anything of interest). Variables may be displayed +and set through the ``s'' escape. The syntax for variables is patterned +after +.Xr vi 1 +and +.Xr Mail 1 . +Supplying ``all'' +as an argument to the set command displays all variables readable by +the user. Alternatively, the user may request display of a particular +variable by attaching a `?' to the end. For example ``escape?'' +displays the current escape character. +.Pp +Variables are numeric, string, character, or boolean values. Boolean +variables are set merely by specifying their name; they may be reset +by prepending a `!' to the name. Other variable types are set by +concatenating an `=' and the value. The entire assignment must not +have any blanks in it. A single set command may be used to interrogate +as well as set a number of variables. +Variables may be initialized at run time by placing set commands +(without the ``~s'' prefix in a file +.Pa .tiprc +in one's home directory). The +.Fl v +option causes +.Nm tip +to display the sets as they are made. +Certain common variables have abbreviations. +The following is a list of common variables, +their abbreviations, and their default values. +.Bl -tag -width Ar +.It Ar beautify +(bool) Discard unprintable characters when a session is being scripted; +abbreviated +.Ar be . +.It Ar baudrate +(num) The baud rate at which the connection was established; +abbreviated +.Ar ba . +.It Ar dialtimeout +(num) When dialing a phone number, the time (in seconds) +to wait for a connection to be established; abbreviated +.Ar dial . +.It Ar echocheck +(bool) Synchronize with the remote host during file transfer by +waiting for the echo of the last character transmitted; default is +.Ar off . +.It Ar eofread +(str) The set of characters which signify an end-of-transmission +during a ~< file transfer command; abbreviated +.Ar eofr . +.It Ar eofwrite +(str) The string sent to indicate end-of-transmission during +a ~> file transfer command; abbreviated +.Ar eofw . +.It Ar eol +(str) The set of characters which indicate an end-of-line. +.Nm Tip +will recognize escape characters only after an end-of-line. +.It Ar escape +(char) The command prefix (escape) character; abbreviated +.Ar es ; +default value is `~'. +.It Ar exceptions +(str) The set of characters which should not be discarded +due to the beautification switch; abbreviated +.Ar ex ; +default value is ``\et\en\ef\eb''. +.It Ar force +(char) The character used to force literal data transmission; +abbreviated +.Ar fo ; +default value is `^P'. +.It Ar framesize +(num) The amount of data (in bytes) to buffer between file system +writes when receiving files; abbreviated +.Ar fr . +.It Ar host +(str) The name of the host to which you are connected; abbreviated +.Ar ho . +.It Ar login +(str) Pathname of a login shell script to run once connected; standard input +and output are redirected to the remote host. Leading tildes in the pathname +are expanded expansion; abbreviated +.Ar li . +.It Ar logout +(str) Pathname of a shell script to run before disconnecting; standard input +and output are redirected to the remote host. Leading tildes in the pathname +are expanded expansion; abbreviated +.Ar lo . +.It Ar prompt +(char) The character which indicates an end-of-line on the remote +host; abbreviated +.Ar pr ; +default value is `\en'. This value is used to synchronize during +data transfers. The count of lines transferred during a file transfer +command is based on receipt of this character. +.It Ar raise +(bool) Upper case mapping mode; abbreviated +.Ar ra ; +default value is +.Ar off . +When this mode is enabled, all lower case letters will be mapped to +upper case by +.Nm tip +for transmission to the remote machine. +.It Ar raisechar +(char) The input character used to toggle upper case mapping mode; +abbreviated +.Ar rc ; +default value is `^A'. +.It Ar record +(str) The name of the file in which a session script is recorded; +abbreviated +.Ar rec ; +default value is ``tip.record''. +.It Ar script +(bool) Session scripting mode; abbreviated +.Ar sc ; +default is +.Ar off . +When +.Ar script +is +.Li true , +.Nm tip +will record everything transmitted by the remote machine in +the script record file specified in +.Ar record . +If the +.Ar beautify +switch is on, only printable +.Tn ASCII +characters will be included in +the script file (those characters between 040 and 0177). The +variable +.Ar exceptions +is used to indicate characters which are an exception to the normal +beautification rules. +.It Ar tabexpand +(bool) Expand tabs to spaces during file transfers; abbreviated +.Ar tab ; +default value is +.Ar false . +Each tab is expanded to 8 spaces. +.It Ar verbose +(bool) Verbose mode; abbreviated +.Ar verb ; +default is +.Ar true . +When verbose mode is enabled, +.Nm tip +prints messages while dialing, shows the current number +of lines transferred during a file transfer operations, +and more. +.El +.Sh ENVIRONMENT +.Nm Tip +uses the following environment variables: +.Bl -tag -width Fl +.It Ev SHELL +(str) The name of the shell to use for the ~! command; default +value is ``/bin/sh'', or taken from the environment. +.It Ev HOME +(str) The home directory to use for the ~c command; default +value is taken from the environment. +.It Ev HOST +Check for a default host if none specified. +.El +.Pp +The variables +.Ev ${REMOTE} +and +.Ev ${PHONES} +are also exported. +.Sh FILES +.Bl -tag -width /var/spool/lock/LCK..* -compact +.It Pa /etc/modems +Global modem configuration data base. +.It Pa /etc/remote +Global system descriptions. +.It Pa /etc/phones +Global phone number data base. +.It ${REMOTE} +Private system descriptions. +.It ${PHONES} +Private phone numbers. +.It ~/.tiprc +Initialization file. +.It Pa tip.record +Record file. +.It /var/log/aculog +Line access log. +.It Pa /var/spool/lock/LCK..* +Lock file to avoid conflicts with +.Xr uucp . +.El +.Sh DIAGNOSTICS +Diagnostics are, hopefully, self explanatory. +.Sh SEE ALSO +.Xr cu 1 , +.Xr phones 5 , +.Xr remote 5 +.Sh HISTORY +The +.Nm tip +appeared command in +.Bx 4.2 . +.Sh BUGS +The full set of variables is undocumented and should, probably, be +pared down. diff --git a/tip/tip.c b/tip/tip.c new file mode 100644 index 0000000000000000000000000000000000000000..00bc079b7e9633ca38394ff9f26681b92c583bb2 --- /dev/null +++ b/tip/tip.c @@ -0,0 +1,777 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)tip.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: tip.c,v 1.1 2000-12-22 18:48:49 mike Exp $"; +#endif /* not lint */ + +/* + Forward declarations +*/ +void ttysetup (int speed); + +/* + * tip - UNIX link to other systems + * tip [-v] [-speed] system-name + * or + * cu phone-number [-s speed] [-l line] [-a acu] + */ + +#include <err.h> +#include <errno.h> +#include <sys/types.h> +#ifndef LINUX +#include <libutil.h> +#endif +#include "tipconf.h" +#include "tip.h" +#include "pathnames.h" + +/* + * Baud rate mapping table + */ +#ifndef LINUX +#if !HAVE_TERMIOS +CONST int bauds[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, + 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, -1 +}; +#endif +#else +struct baudmap { + CONST int BR; + CONST int bval; +} baudmap[] = { + { 0, B0 }, + { 50, B50 }, + { 75, B75 }, + { 110, B110 }, + { 134, B134 }, + { 150, B150 }, + { 200, B200 }, + { 300, B300 }, + { 600, B600 }, + { 1200, B1200 }, + { 1800, B1800 }, + { 2400, B2400 }, + { 4800, B4800 }, + { 9600, B9600 }, + { 19200, B19200 }, + { 38400, B38400 }, + { 57600, B57600 }, + { 115200, B115200 }, + { -1, 0 } +}; +#endif + +#if !HAVE_TERMIOS +int disc = OTTYDISC; /* tip normally runs this way */ +#endif + +void intprompt(); +void timeout(); +void cleanup(); +void tipdone(); +char *sname(); +char PNbuf[256]; /* This limits the size of a number */ + +static void usage __P((void)); +void setparity __P((char *)); +void xpwrite __P((int, char *, int)); +char escape __P((void)); +void tipin __P((void)); +int prompt __P((char *, char *, size_t)); +void unraw __P((void)); +void shell_uid __P((void)); +void daemon_uid __P((void)); +void user_uid __P((void)); +int speed __P((int)); + +int +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 INCLUDE_CU_INTERFACE + if (equal(sname(argv[0]), "cu")) { + cumode = 1; + cumain(argc, argv); + goto cucommon; + } +#endif /* INCLUDE_CU_INTERFACE */ + + if (argc > 4) + usage(); + if (!isatty(0)) + errx(1, "must be interactive"); + + 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: + warnx("%s, unknown option", argv[1]); + break; + } + } + + if (system == NOSTR) + goto notnumber; + if (isalpha(*system)) + 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) + errx(1, "phone number too long (max = %d bytes)", sizeof PNbuf - 1); + strncpy(PNbuf, system, sizeof(PNbuf) - 1); + for (p = system; *p; p++) + *p = '\0'; + PN = PNbuf; + (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR); + system = sbuf; + +notnumber: + (void)signal(SIGINT, cleanup); + (void)signal(SIGQUIT, cleanup); + (void)signal(SIGHUP, cleanup); + (void)signal(SIGTERM, cleanup); + (void)signal(SIGUSR1, tipdone); + + if ((i = hunt(system)) == 0) { + printf("all ports busy\n"); + exit(3); + } + if (i == -1) { + printf("link down\n"); + (void)uu_unlock(uucplock); + exit(3); + } + setbuf(stdout, NULL); + loginit(); + + /* + * Kludge, their's no easy way to get the initialization + * in the right order, so force it here + */ + if ((PH = getenv("PHONES")) == NOSTR) + PH = _PATH_PHONES; + vinit(); /* init variables */ + setparity("even"); /* set the parity table */ + if ((i = speed(number(value(BAUDRATE)))) == 0) { + printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); + (void)uu_unlock(uucplock); + exit(3); + } + + /* + * Now that we have the logfile and the ACU open + * return to the real uid and gid. These things will + * be closed on exit. Swap real and effective uid's + * so we can get the original permissions back + * for removing the uucp lock. + */ + user_uid(); + + /* + * 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); + daemon_uid(); + (void)uu_unlock(uucplock); + exit(1); + } + if (!HW) + ttysetup(i); +/* cucommon:*/ + /* + * From here down the code is shared with + * the "cu" version of tip. + */ + +#if HAVE_TERMIOS + tcgetattr (0, &otermios); + ctermios = otermios; +#ifndef _POSIX_SOURCE + ctermios.c_iflag = (IMAXBEL|IXANY|ISTRIP|IXON|BRKINT); + ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOCTL|ECHOE|ECHOKE); +#else + ctermios.c_iflag = (ISTRIP|IXON|BRKINT); + ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOE); +#endif + ctermios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8); + ctermios.c_cc[VINTR] = ctermios.c_cc[VQUIT] = -1; + ctermios.c_cc[VSUSP] = ctermios.c_cc[VDISCARD] = + ctermios.c_cc[VLNEXT] = -1; +#ifdef VDSUSP + ctermios.c_cc[VDSUSP] = -1; +#endif +#else /* HAVE_TERMIOS */ + ioctl(0, TIOCGETP, (char *)&defarg); + ioctl(0, TIOCGETC, (char *)&defchars); + ioctl(0, TIOCGLTC, (char *)&deflchars); + ioctl(0, TIOCGETD, (char *)&odisc); + arg = defarg; + arg.sg_flags = ANYP | CBREAK; + tchars = defchars; + tchars.t_intrc = tchars.t_quitc = -1; + ltchars = deflchars; + ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc + = ltchars.t_lnextc = -1; +#endif /* HAVE_TERMIOS */ + raw(); + + pipe(fildes); pipe(repdes); + (void)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. + */ + printf(cumode ? "Connected\r\n" : "\07connected\r\n"); + + if (LI != NOSTR && tiplink (LI, 0) != 0) { + tipabort ("login failed"); + } + + if ((pid = fork())) + tipin(); + else + tipout(); + /*NOTREACHED*/ +} + +static void +usage() +{ + fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); + exit(1); +} + +void +cleanup() +{ + + daemon_uid(); + (void)uu_unlock(uucplock); +#if !HAVE_TERMIOS + if (odisc) + ioctl(0, TIOCSETD, (char *)&odisc); +#endif + exit(0); +} + +void +tipdone() +{ + tipabort("Hangup."); +} +/* + * Muck with user ID's. We are setuid to the owner of the lock + * directory when we start. user_uid() reverses real and effective + * ID's after startup, to run with the user's permissions. + * daemon_uid() switches back to the privileged uid for unlocking. + * Finally, to avoid running a shell with the wrong real uid, + * shell_uid() sets real and effective uid's to the user's real ID. + */ +static int uidswapped; + +void +user_uid() +{ + if (uidswapped == 0) { + seteuid(uid); + uidswapped = 1; + } +} + +void +daemon_uid() +{ + if (uidswapped) { + seteuid(euid); + uidswapped = 0; + } +} + +void +shell_uid() +{ + setegid(gid); + seteuid(uid); +} + +/* + * put the controlling keyboard into raw mode + */ +void +raw () +{ +#if HAVE_TERMIOS + tcsetattr (0, TCSANOW, &ctermios); +#else /* HAVE_TERMIOS */ + + ioctl(0, TIOCSETP, &arg); + ioctl(0, TIOCSETC, &tchars); + ioctl(0, TIOCSLTC, <chars); + ioctl(0, TIOCSETD, (char *)&disc); +#endif /* HAVE_TERMIOS */ +} + + +/* + * return keyboard to normal mode + */ +void +unraw() +{ +#if HAVE_TERMIOS + tcsetattr (0, TCSANOW, &otermios); +#else /* HAVE_TERMIOS */ + + ioctl(0, TIOCSETD, (char *)&odisc); + ioctl(0, TIOCSETP, (char *)&defarg); + ioctl(0, TIOCSETC, (char *)&defchars); + ioctl(0, TIOCSLTC, (char *)&deflchars); +#endif /* HAVE_TERMIOS */ +} + +static jmp_buf promptbuf; + +/* + * Print string ``s'', then read a string + * in from the terminal. Handles signals & allows use of + * normal erase and kill characters. + */ +int +prompt(s, p, sz) + char *s; + register char *p; + size_t sz; +{ + register char *b = p; + sig_t oint, oquit; + + stoprompt = 0; + oint = signal(SIGINT, intprompt); + oquit = signal(SIGQUIT, SIG_IGN); + unraw(); + printf("%s", s); + if (setjmp(promptbuf) == 0) + while ((*p = getchar()) != EOF && *p != '\n' && --sz > 0) + p++; + *p = '\0'; + + raw(); + (void)signal(SIGINT, oint); + (void)signal(SIGQUIT, oquit); + return (stoprompt || p == b); +} + +/* + * Interrupt service routine during prompting + */ +void +intprompt() +{ + + (void)signal(SIGINT, SIG_IGN); + stoprompt = 1; + printf("\r\n"); + longjmp(promptbuf, 1); +} + +/* + * ****TIPIN TIPIN**** + */ +void +tipin() +{ + int i; + char gch, 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(); + } + + while (1) { + i = tipgetchar(); + if (i == EOF) + break; + gch = i&0177; + 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; + xpwrite(FD, &gch, 1); + if (boolean(value(HALFDUPLEX))) + printf("\r\n"); + continue; + } else if (!cumode && gch == character(value(FORCE))) { + i = tipgetchar(); + if (i == EOF) + break; + gch = i & 0177; + } + bol = any(gch, value(EOL)); + if (boolean(value(RAISE)) && islower(gch)) + gch = toupper(gch); + xpwrite(FD, &gch, 1); + if (boolean(value(HALFDUPLEX))) + printf("%c", gch); + } +} + +extern esctable_t etable[]; + +/* + * Escape handler -- + * called on recognition of ``escapec'' at the beginning of a line + */ +char +escape() +{ + register char gch; + register esctable_t *p; + char c = character(value(ESCAPE)); + int i; + + i = tipgetchar(); + if (i == EOF) + return 0; + gch = (i&0177); + 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) + xpwrite(FD, &c, 1); + return (gch); +} + +int +speed(n) + int n; +{ +#ifndef LINUX +#if HAVE_TERMIOS + return (n); +#else + register CONST int *p; + + for (p = bauds; *p != -1; p++) + if (*p == n) + return (p - bauds); + return (0); +#endif +#else + struct baudmap *p; + + for (p = baudmap; p->BR != -1; p++) + if (p->BR == n) + return (p->bval); + return (0); +#endif +} + +int +any(c, p) + register char c, *p; +{ + while (p && *p) + if (*p++ == c) + return (1); + return (0); +} + +int +size(s) + register char *s; +{ + register int i = 0; + + while (s && *s++) + i++; + return (i); +} + +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 + */ +void +help(c) + char c; +{ + register esctable_t *p; + + 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 + */ +void +ttysetup (int speed) +{ +#if HAVE_TERMIOS + struct termios termios; + tcgetattr (FD, &termios); + if (boolean(value(TAND))) + termios.c_iflag = IXOFF; + else + termios.c_iflag = 0; +#ifndef _POSIX_SOURCE + termios.c_lflag = (PENDIN|ECHOKE|ECHOE); +#else + termios.c_lflag = (PENDIN|ECHOE); +#endif + termios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8); + cfsetispeed(&termios, speed); + cfsetospeed(&termios, speed); + tcsetattr (FD, TCSANOW, &termios); +#else /* HAVE_TERMIOS */ + unsigned bits = LDECCTQ; + + arg.sg_ispeed = arg.sg_ospeed = speed; + arg.sg_flags = RAW; + if (boolean(value(TAND))) + arg.sg_flags |= TANDEM; + ioctl(FD, TIOCSETP, (char *)&arg); + ioctl(FD, TIOCLBIS, (char *)&bits); +#endif /* HAVE_TERMIOS */ +} + +/* + * 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[0200]; +static int bits8; + +/* + * 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. + */ +void +xpwrite(fd, buf, n) + int fd; + char *buf; + register int n; +{ + register int i; + register char *bp; + + bp = buf; + if (bits8 == 0) + for (i = 0; i < n; i++) { + *bp = partab[(*bp) & 0177]; + bp++; + } + if (write(fd, buf, n) < 0) { + if (errno == EIO) + tipabort("Lost carrier."); + if (errno == ENODEV) + tipabort("tty not available."); + tipabort("Something wrong..."); + } +} + +/* + * Build a parity table with appropriate high-order bit. + */ +void +setparity(defparity) + char *defparity; +{ + register int i, flip, clr, set; + char *parity; + extern char evenpartab[]; + + if (value(PARITY) == NOSTR) + value(PARITY) = defparity; + parity = value(PARITY); + if (equal(parity, "none")) { + bits8 = 1; + return; + } + bits8 = 0; + flip = 0; + clr = 0377; + set = 0; + if (equal(parity, "odd")) + flip = 0200; /* reverse bit 7 */ + else if (equal(parity, "zero")) + clr = 0177; /* turn off bit 7 */ + else if (equal(parity, "one")) + set = 0200; /* turn on bit 7 */ + else if (!equal(parity, "even")) { + (void) fprintf(stderr, "%s: unknown parity value\r\n", parity); + (void) fflush(stderr); + } + for (i = 0; i < 0200; i++) + partab[i] = (evenpartab[i] ^ flip) | (set & clr); +} + + +/* + * getchar with EOF check + */ +tipgetchar() +{ + char gch; + + gch = getchar(); + if (gch == EOF && feof(stdin)) + finish(); + return gch; +} + diff --git a/tip/tip.h b/tip/tip.h new file mode 100644 index 0000000000000000000000000000000000000000..67f539426efbef1d869e8a734495abb56162c196 --- /dev/null +++ b/tip/tip.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tip.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * tip - terminal interface program + */ + +#ifdef LINUX +/* signals */ +#define SIGEMT SIGUSR1 +#define SIGSYS SIGUSR2 + +/* uucp stuff */ +#define uu_lock(x) (0) +#define uu_unlock(x) (0) +#define UU_LOCK_OK 0 +#define UU_LOCK_INUSE 1 + +#define HAVE_TERMIOS 1 /* XXX */ +#endif + +#include <sys/types.h> +#ifndef LINUX +#include <machine/endian.h> +#else +#define BYTE_ORDER __BYTE_ORDER +#endif +#include <sys/file.h> +#include <sys/time.h> +#include <limits.h> + +#if HAVE_TERMIOS +#include <sys/ioctl.h> /* for TIOCHPCL */ +#ifndef LINUX +#include <sys/filio.h> /* for FIONREAD */ +#endif +#include <sys/termios.h> +#else +#include <sgtty.h> +#endif + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pwd.h> +#include <ctype.h> +#include <setjmp.h> +#include <unistd.h> +#include <errno.h> + +/* + * 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 */ + +char *LI; /* login script */ +char *LO; /* logout script */ + +long BR; /* line speed for conversation */ +long FS; /* frame size for transfers */ + +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 */ +long DL; /* line delay for file transfers to remote */ +long CL; /* char delay for file transfers to remote */ +long ET; /* echocheck timeout */ +char HD; /* this host is half duplex - do local echo */ + +/* + * 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)(); + void (*acu_disconnect)(); + void (*acu_abort)(); + } + acu_t; + +#define equal(a, b) (strcmp(a,b)==0)/* A nice function to string 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; + short zz_boolean[2]; + char zz_character[4]; + int *zz_address; + } + zzhack; + +#define value(v) vtable[v].v_value + +#define number(v) ((((zzhack *)(&(v))))->zz_number) + +#if BYTE_ORDER == LITTLE_ENDIAN +#define boolean(v) ((((zzhack *)(&(v))))->zz_boolean[0]) +#define character(v) ((((zzhack *)(&(v))))->zz_character[0]) +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define boolean(v) ((((zzhack *)(&(v))))->zz_boolean[1]) +#define character(v) ((((zzhack *)(&(v))))->zz_character[3]) +#endif + +#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 */ + +#if !ACULOG +#define logent(a, b, c, d) +#define loginit() +#else +void logent __P((char *, char *, char *, char*)); +#endif + +/* + * Definition of indices into variable table so + * value(DEFINE) turns into a static address. + */ + +/* +'a,.!awk '{ printf("\%s \%s \%d\n", $1, $2, NR - 1); }' +*/ + +#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 LOGIN 12 +#define LOGOUT 13 +#define PHONES 14 +#define PROMPT 15 +#define RAISE 16 +#define RAISECHAR 17 +#define RECORD 18 +#define REMOTE 19 +#define SCRIPT 20 +#define TABEXPAND 21 +#define VERBOSE 22 +#define SHELL 23 +#define HOME 24 +#define ECHOCHECK 25 +#define DISCONNECT 26 +#define TAND 27 +#define LDELAY 28 +#define CDELAY 29 +#define ETIMEOUT 30 +#define RAWFTP 31 +#define HALFDUPLEX 32 +#define LECHO 33 +#define PARITY 34 +#define NOVAL ((value_t *)NULL) +#define NOACU ((acu_t *)NULL) +#define NOSTR ((char *)NULL) +#ifdef NOFILE +#undef NOFILE +#endif +#define NOFILE ((FILE *)NULL) +#define NOPWD ((struct passwd *)0) + +#if HAVE_TERMIOS +struct termios otermios; +struct termios ctermios; +#else /* HAVE_TERMIOS */ +struct sgttyb arg; /* current mode of local terminal */ +struct sgttyb defarg; /* initial mode of local terminal */ +struct tchars tchars; /* current state of terminal */ +struct tchars defchars; /* initial state of terminal */ +struct ltchars ltchars; /* current local characters of terminal */ +struct ltchars deflchars; /* initial local characters of terminal */ +#endif /* HAVE_TERMIOS */ + +FILE *fscript; /* FILE for scripting */ + +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 */ +uid_t uid, euid; /* real and effective user id's */ +gid_t gid, egid; /* real and effective group id's */ +int stop; /* stop transfer session flag */ +int quit; /* same; but on other end */ +int intflag; /* recognized interrupt */ +int stoprompt; /* for interrupting a prompt session */ +int timedout; /* ~> transfer timedout */ +int cumode; /* simulating the "cu" program */ + +char fname[PATH_MAX]; /* file name buffer for ~< */ +char copyname[PATH_MAX]; /* file name buffer for ~> */ +char ccc; /* synchronization character */ +char ch; /* for tipout */ +char *uucplock; /* name of lock file for uucp's */ + +int odisc; /* initial tty line discipline */ +extern int disc; /* current tty discpline */ + +extern char *ctrl(); +extern char *vinterp(); +extern char *connect(); +extern int size __P((char *)); +extern int any __P((char, char *)); +extern void setscript __P((void)); +extern void tipout __P((void)); +extern void vinit __P((void)); +extern void loginit __P((void)); +extern int hunt __P((char *)); +extern int vstring __P((char *, char *)); +extern void setparity __P((char *)); +extern void vlex __P((char *)); +extern void daemon_uid __P((void)); +extern void disconnect __P((char *)); +extern void shell_uid __P((void)); +extern void unraw __P((void)); +extern void xpwrite __P((int, char *, int)); +extern int prompt __P((char *, char *, size_t)); +extern int consh __P((int)); +extern void tipabort __P((char *)); + +#define TL_VERBOSE 0x00000001 +#define TL_SIGNAL_TIPOUT 0x00000002 + +int tiplink (char *cmd, unsigned int flags); +void raw (); + +/* end of tip.h */ diff --git a/tip/tipconf.h b/tip/tipconf.h new file mode 100644 index 0000000000000000000000000000000000000000..a0890b8f71f6c79b318662abccad635baf9d1b40 --- /dev/null +++ b/tip/tipconf.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tipconf.h 8.1 (Berkeley) 3/25/95 + */ + +#ifndef tipconf_h_included +#define tipconf_h_included + +/* + Define constness +*/ +#define CONST const + +/* + Specify default bit rate for connections +*/ +#define DEFBR 1200 + +/* + Default frame size for file transfer buffering of writes + on local side +*/ +#ifndef BUFSIZ +#define DEFFS 1024 +#else +#define DEFFS BUFSIZ +#endif + +/* + Enable logging of ACU use +*/ +#define ACULOG 1 + +/* + Strip phone #s from ACU log file +*/ +#define PRISTINE 1 + +/* + Enable command to "connect" remote with local process +*/ +#define CONNECT 1 + +/* + Specify style of UUCP lock files +*/ +#define HAVE_V2_LOCKFILES 0 +#define HAVE_HDB_LOCKFILES 1 + +/* + System has a millisecond based sleep function +*/ +#define HAVE_USLEEP 0 + +/* + System has select +*/ +#define HAVE_SELECT 1 + +/* + System has termios tty interface +*/ +#define HAVE_TERMIOS 1 + +/* + Include configurable modem driver +*/ +#define UNIDIALER 0 + +/* + Specify builtin modem drivers to include +*/ +#define BIZ1031 0 +#define BIZ1022 0 +#define COURIER 0 +#define DF02 0 +#define DF03 0 +#define DN11 0 +#define HAYES 0 +#define MULTITECH 0 +#define T3000 0 +#define V3451 0 +#define V831 0 +#define VENTEL 0 + +/* + Include cu interface so that, when tip is linked to cu and then + invoked as cu, it behaves like cu. +*/ +#define INCLUDE_CU_INTERFACE 0 + +#endif + +/* end of tipconf.h */ diff --git a/tip/tipout.c b/tip/tipout.c new file mode 100644 index 0000000000000000000000000000000000000000..6a77903250ec27c41833e5481d16e5482650ebdb --- /dev/null +++ b/tip/tipout.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)tipout.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: tipout.c,v 1.1 2000-12-22 18:48:49 mike Exp $"; +#endif /* not lint */ + +#include "tip.h" +#include <errno.h> +/* + * tip + * + * lower fork of tip -- handles passive side + * reading from the remote host + */ + +static jmp_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); + longjmp(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 - line < sizeof(line)) { + *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); + longjmp(sigbuf, 1); +} + +void +intTERM() +{ + + if (boolean(value(SCRIPT)) && fscript != NULL) + fclose(fscript); + exit(0); +} + +void +intSYS() +{ + + boolean(value(BEAUTIFY)) = !boolean(value(BEAUTIFY)); + longjmp(sigbuf, 1); +} + +/* + * ****TIPOUT TIPOUT**** + */ +void +tipout() +{ + char buf[BUFSIZ]; + register char *cp; + register int cnt; + int omask; + + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGEMT, intEMT); /* attention from TIPIN */ + signal(SIGTERM, intTERM); /* time to go signal */ + signal(SIGIOT, intIOT); /* scripting going on signal */ + signal(SIGHUP, intTERM); /* for dial-ups */ + signal(SIGSYS, intSYS); /* beautify toggle */ + (void) setjmp(sigbuf); + for (omask = 0;; sigsetmask(omask)) { + cnt = read(FD, buf, BUFSIZ); + if (cnt <= 0) { + /* lost carrier */ + if (cnt < 0 && errno == EIO) { + sigblock(sigmask(SIGTERM)); + intTERM(); + /*NOTREACHED*/ + } else if (cnt == 0 && errno == ENOENT) { + if (getppid() != 1) + kill(getppid(),SIGUSR1); + sigblock(sigmask(SIGTERM)); + intTERM(); + /*NOTREACHED*/ + } else if (cnt < 0) { + if (getppid() != 1) + kill(getppid(),SIGUSR1); + sigblock(sigmask(SIGTERM)); + intTERM(); + /*NOTREACHED*/ + } + continue; + } +#define ALLSIGS sigmask(SIGEMT)|sigmask(SIGTERM)|sigmask(SIGIOT)|sigmask(SIGSYS) + omask = sigblock(ALLSIGS); + 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); + continue; + } + for (cp = buf; cp < buf + cnt; cp++) + if ((*cp >= ' ' && *cp <= '~') || + any(*cp, value(EXCEPTIONS))) + putc(*cp, fscript); + } + } +} diff --git a/tip/value.c b/tip/value.c new file mode 100644 index 0000000000000000000000000000000000000000..7faa1039d88ddf52aac42f6b38a557deec05ce75 --- /dev/null +++ b/tip/value.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)value.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: value.c,v 1.1 2000-12-22 18:48:50 mike Exp $"; +#endif /* not lint */ + +#include "tip.h" + +#define MIDDLE 35 + +static value_t *vlookup(); +int vstring __P((char *, char *)); +void vlex __P((char *)); +void vassign __P((value_t *, char *)); + +static int col = 0; + +/* + * Variable manipulation + */ +void +vinit() +{ + register value_t *p; + register char *cp; + FILE *f; + char file[256]; + + 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) + if (p->v_type&STRING) + p->v_value = *(char **) address(p->v_value); + else + number(p->v_value) = *address(p->v_value); + } + /* + * Read the .tiprc file in the HOME directory + * for sets + */ + strcpy(file, value(HOME)); + strcat(file, "/.tiprc"); + if ((f = fopen(file, "r")) != NULL) { + register char *tp; + + while (fgets(file, sizeof(file)-1, f) != NULL) { + if (vflag) + printf("set %s", file); + if ((tp = rindex(file, '\n'))) + *tp = '\0'; + vlex(file); + } + fclose(f); + } + /* + * To allow definition of exception prior to fork + */ + vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC); +} + +static int vaccess(); + +/*VARARGS1*/ +void +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 && equal(p->v_value, v)) + return; + if (!(p->v_type&(ENVIRON|INIT))) + free(p->v_value); + if ((p->v_value = malloc(size(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; +} + +static void vprint(); + +void +vlex(s) + register char *s; +{ + register value_t *p; + static void vtoken(); + + 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 void +vtoken(s) + register char *s; +{ + register value_t *p; + register char *cp; + char *expand(); + + if ((cp = index(s, '='))) { + *cp = '\0'; + if ((p = vlookup(s))) { + cp++; + if (p->v_type&NUMBER) + vassign(p, (char *) atoi(cp)); + else { + if (strcmp(s, "record") == 0) + cp = expand(cp); + vassign(p, cp); + } + return; + } + } else if ((cp = index(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) { + vassign(p, s); + return; + } + } + printf("%s: unknown variable\r\n", s); +} + +static void +vprint(p) + register value_t *p; +{ + register char *cp; + extern char *interp(), *ctrl(); + + if (col > 0 && col < MIDDLE) + while (col++ < MIDDLE) + putchar(' '); + col += size(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 += size(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 += size(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)) && getuid() == 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) + */ + +int +vstring(s,v) + register char *s; + register char *v; +{ + register value_t *p; + char *expand(); + + p = vlookup(s); + if (p == 0) + return (1); + if (p->v_type&NUMBER) + vassign(p, (char *) atoi(v)); + else { + if (strcmp(s, "record") == 0) + v = expand(v); + vassign(p, v); + } + return (0); +} diff --git a/tip/vars.c b/tip/vars.c new file mode 100644 index 0000000000000000000000000000000000000000..e07459f7a7bcd039e25c88e79dca34bd90324f8f --- /dev/null +++ b/tip/vars.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: vars.c,v 1.2 2000-12-27 00:49:36 mike Exp $"; +#endif /* not lint */ + +#include "tipconf.h" +#include "tip.h" +#include "pathnames.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 *)CTRL('p') }, + { "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, _PATH_ACULOG }, + { "login", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC, + "li", (char *)&LI }, + { "logout", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC, + "lo", (char *)&LO }, + { "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 *)CTRL('a') }, + { "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, _PATH_BSHELL }, + { "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 }, + { NOSTR, 0, 0, NOSTR, NOSTR } +};