1*1bbda10eSjtc /* $NetBSD: main.c,v 1.5 1994/12/08 09:51:26 jtc Exp $ */ 2*1bbda10eSjtc 361f28255Scgd /* 4*1bbda10eSjtc * Copyright (c) 1983, 1993 5*1bbda10eSjtc * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * Redistribution and use in source and binary forms, with or without 861f28255Scgd * modification, are permitted provided that the following conditions 961f28255Scgd * are met: 1061f28255Scgd * 1. Redistributions of source code must retain the above copyright 1161f28255Scgd * notice, this list of conditions and the following disclaimer. 1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1361f28255Scgd * notice, this list of conditions and the following disclaimer in the 1461f28255Scgd * documentation and/or other materials provided with the distribution. 1561f28255Scgd * 3. All advertising materials mentioning features or use of this software 1661f28255Scgd * must display the following acknowledgement: 1761f28255Scgd * This product includes software developed by the University of 1861f28255Scgd * California, Berkeley and its contributors. 1961f28255Scgd * 4. Neither the name of the University nor the names of its contributors 2061f28255Scgd * may be used to endorse or promote products derived from this software 2161f28255Scgd * without specific prior written permission. 2261f28255Scgd * 2361f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2461f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2561f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2661f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2761f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2861f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2961f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3061f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3161f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3261f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3361f28255Scgd * SUCH DAMAGE. 3461f28255Scgd */ 3561f28255Scgd 3661f28255Scgd #ifndef lint 37*1bbda10eSjtc static char copyright[] = 38*1bbda10eSjtc "@(#) Copyright (c) 1983, 1993\n\ 39*1bbda10eSjtc The Regents of the University of California. All rights reserved.\n"; 4061f28255Scgd #endif /* not lint */ 4161f28255Scgd 4261f28255Scgd #ifndef lint 43*1bbda10eSjtc #if 0 44*1bbda10eSjtc static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 45*1bbda10eSjtc #endif 46*1bbda10eSjtc static char rcsid[] = "$NetBSD: main.c,v 1.5 1994/12/08 09:51:26 jtc Exp $"; 4761f28255Scgd #endif /* not lint */ 4861f28255Scgd 4961f28255Scgd /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 5061f28255Scgd 5161f28255Scgd /* 5261f28255Scgd * TFTP User Program -- Command Interface. 5361f28255Scgd */ 5461f28255Scgd #include <sys/types.h> 5561f28255Scgd #include <sys/socket.h> 5661f28255Scgd #include <sys/file.h> 5761f28255Scgd 5861f28255Scgd #include <netinet/in.h> 5961f28255Scgd 60*1bbda10eSjtc #include <arpa/inet.h> 61*1bbda10eSjtc 62*1bbda10eSjtc #include <ctype.h> 63*1bbda10eSjtc #include <errno.h> 64*1bbda10eSjtc #include <netdb.h> 65*1bbda10eSjtc #include <setjmp.h> 6661f28255Scgd #include <signal.h> 6761f28255Scgd #include <stdio.h> 68*1bbda10eSjtc #include <stdlib.h> 69*1bbda10eSjtc #include <string.h> 70*1bbda10eSjtc #include <unistd.h> 71*1bbda10eSjtc 72*1bbda10eSjtc #include "extern.h" 7361f28255Scgd 7461f28255Scgd #define TIMEOUT 5 /* secs between rexmt's */ 7565b04c1fScgd #define LBUFLEN 200 /* size of input buffer */ 7661f28255Scgd 77*1bbda10eSjtc struct sockaddr_in peeraddr; 7861f28255Scgd int f; 7961f28255Scgd short port; 8061f28255Scgd int trace; 8161f28255Scgd int verbose; 8261f28255Scgd int connected; 8361f28255Scgd char mode[32]; 8465b04c1fScgd char line[LBUFLEN]; 8561f28255Scgd int margc; 8661f28255Scgd char *margv[20]; 8761f28255Scgd char *prompt = "tftp"; 8861f28255Scgd jmp_buf toplevel; 8961f28255Scgd void intr(); 9061f28255Scgd struct servent *sp; 9161f28255Scgd 92*1bbda10eSjtc void get __P((int, char **)); 93*1bbda10eSjtc void help __P((int, char **)); 94*1bbda10eSjtc void modecmd __P((int, char **)); 95*1bbda10eSjtc void put __P((int, char **)); 96*1bbda10eSjtc void quit __P((int, char **)); 97*1bbda10eSjtc void setascii __P((int, char **)); 98*1bbda10eSjtc void setbinary __P((int, char **)); 99*1bbda10eSjtc void setpeer __P((int, char **)); 100*1bbda10eSjtc void setrexmt __P((int, char **)); 101*1bbda10eSjtc void settimeout __P((int, char **)); 102*1bbda10eSjtc void settrace __P((int, char **)); 103*1bbda10eSjtc void setverbose __P((int, char **)); 104*1bbda10eSjtc void status __P((int, char **)); 105*1bbda10eSjtc 106*1bbda10eSjtc static __dead void command __P((void)); 107*1bbda10eSjtc 108*1bbda10eSjtc static void getusage __P((char *)); 109*1bbda10eSjtc static void makeargv __P((void)); 110*1bbda10eSjtc static void putusage __P((char *)); 111*1bbda10eSjtc static void settftpmode __P((char *)); 11261f28255Scgd 11361f28255Scgd #define HELPINDENT (sizeof("connect")) 11461f28255Scgd 11561f28255Scgd struct cmd { 11661f28255Scgd char *name; 11761f28255Scgd char *help; 118*1bbda10eSjtc void (*handler) __P((int, char **)); 11961f28255Scgd }; 12061f28255Scgd 12161f28255Scgd char vhelp[] = "toggle verbose mode"; 12261f28255Scgd char thelp[] = "toggle packet tracing"; 12361f28255Scgd char chelp[] = "connect to remote tftp"; 12461f28255Scgd char qhelp[] = "exit tftp"; 12561f28255Scgd char hhelp[] = "print help information"; 12661f28255Scgd char shelp[] = "send file"; 12761f28255Scgd char rhelp[] = "receive file"; 12861f28255Scgd char mhelp[] = "set file transfer mode"; 12961f28255Scgd char sthelp[] = "show current status"; 13061f28255Scgd char xhelp[] = "set per-packet retransmission timeout"; 13161f28255Scgd char ihelp[] = "set total retransmission timeout"; 13261f28255Scgd char ashelp[] = "set mode to netascii"; 13361f28255Scgd char bnhelp[] = "set mode to octet"; 13461f28255Scgd 13561f28255Scgd struct cmd cmdtab[] = { 13661f28255Scgd { "connect", chelp, setpeer }, 13761f28255Scgd { "mode", mhelp, modecmd }, 13861f28255Scgd { "put", shelp, put }, 13961f28255Scgd { "get", rhelp, get }, 14061f28255Scgd { "quit", qhelp, quit }, 14161f28255Scgd { "verbose", vhelp, setverbose }, 14261f28255Scgd { "trace", thelp, settrace }, 14361f28255Scgd { "status", sthelp, status }, 14461f28255Scgd { "binary", bnhelp, setbinary }, 14561f28255Scgd { "ascii", ashelp, setascii }, 14661f28255Scgd { "rexmt", xhelp, setrexmt }, 14761f28255Scgd { "timeout", ihelp, settimeout }, 14861f28255Scgd { "?", hhelp, help }, 149*1bbda10eSjtc { 0 } 15061f28255Scgd }; 15161f28255Scgd 15261f28255Scgd struct cmd *getcmd(); 15361f28255Scgd char *tail(); 15461f28255Scgd char *index(); 15561f28255Scgd char *rindex(); 15661f28255Scgd 157*1bbda10eSjtc int 15861f28255Scgd main(argc, argv) 159*1bbda10eSjtc int argc; 16061f28255Scgd char *argv[]; 16161f28255Scgd { 162e3769df7Smycroft struct sockaddr_in s_in; 16361f28255Scgd 16461f28255Scgd sp = getservbyname("tftp", "udp"); 16561f28255Scgd if (sp == 0) { 16661f28255Scgd fprintf(stderr, "tftp: udp/tftp: unknown service\n"); 16761f28255Scgd exit(1); 16861f28255Scgd } 16961f28255Scgd f = socket(AF_INET, SOCK_DGRAM, 0); 17061f28255Scgd if (f < 0) { 17161f28255Scgd perror("tftp: socket"); 17261f28255Scgd exit(3); 17361f28255Scgd } 174e3769df7Smycroft bzero((char *)&s_in, sizeof (s_in)); 175e3769df7Smycroft s_in.sin_family = AF_INET; 176e3769df7Smycroft if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) { 17761f28255Scgd perror("tftp: bind"); 17861f28255Scgd exit(1); 17961f28255Scgd } 18061f28255Scgd strcpy(mode, "netascii"); 18161f28255Scgd signal(SIGINT, intr); 18261f28255Scgd if (argc > 1) { 18361f28255Scgd if (setjmp(toplevel) != 0) 18461f28255Scgd exit(0); 18561f28255Scgd setpeer(argc, argv); 18661f28255Scgd } 187*1bbda10eSjtc if (setjmp(toplevel) != 0) 188*1bbda10eSjtc (void)putchar('\n'); 189*1bbda10eSjtc command(); 19061f28255Scgd } 19161f28255Scgd 19261f28255Scgd char hostname[100]; 19361f28255Scgd 194*1bbda10eSjtc void 19561f28255Scgd setpeer(argc, argv) 19661f28255Scgd int argc; 19761f28255Scgd char *argv[]; 19861f28255Scgd { 19961f28255Scgd struct hostent *host; 20061f28255Scgd 20161f28255Scgd if (argc < 2) { 20261f28255Scgd strcpy(line, "Connect "); 20361f28255Scgd printf("(to) "); 20465b04c1fScgd fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); 20561f28255Scgd makeargv(); 20661f28255Scgd argc = margc; 20761f28255Scgd argv = margv; 20861f28255Scgd } 20965b04c1fScgd if ((argc < 2) || (argc > 3)) { 21061f28255Scgd printf("usage: %s host-name [port]\n", argv[0]); 21161f28255Scgd return; 21261f28255Scgd } 21361f28255Scgd host = gethostbyname(argv[1]); 21461f28255Scgd if (host) { 215*1bbda10eSjtc peeraddr.sin_family = host->h_addrtype; 216*1bbda10eSjtc bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length); 21761f28255Scgd strcpy(hostname, host->h_name); 21861f28255Scgd } else { 219*1bbda10eSjtc peeraddr.sin_family = AF_INET; 220*1bbda10eSjtc peeraddr.sin_addr.s_addr = inet_addr(argv[1]); 221*1bbda10eSjtc if (peeraddr.sin_addr.s_addr == -1) { 22261f28255Scgd connected = 0; 22361f28255Scgd printf("%s: unknown host\n", argv[1]); 22461f28255Scgd return; 22561f28255Scgd } 22661f28255Scgd strcpy(hostname, argv[1]); 22761f28255Scgd } 22861f28255Scgd port = sp->s_port; 22961f28255Scgd if (argc == 3) { 23061f28255Scgd port = atoi(argv[2]); 23161f28255Scgd if (port < 0) { 23261f28255Scgd printf("%s: bad port number\n", argv[2]); 23361f28255Scgd connected = 0; 23461f28255Scgd return; 23561f28255Scgd } 23661f28255Scgd port = htons(port); 23761f28255Scgd } 23861f28255Scgd connected = 1; 23961f28255Scgd } 24061f28255Scgd 24161f28255Scgd struct modes { 24261f28255Scgd char *m_name; 24361f28255Scgd char *m_mode; 24461f28255Scgd } modes[] = { 24561f28255Scgd { "ascii", "netascii" }, 24661f28255Scgd { "netascii", "netascii" }, 24761f28255Scgd { "binary", "octet" }, 24861f28255Scgd { "image", "octet" }, 24961f28255Scgd { "octet", "octet" }, 25061f28255Scgd /* { "mail", "mail" }, */ 25161f28255Scgd { 0, 0 } 25261f28255Scgd }; 25361f28255Scgd 254*1bbda10eSjtc void 25561f28255Scgd modecmd(argc, argv) 256*1bbda10eSjtc int argc; 25761f28255Scgd char *argv[]; 25861f28255Scgd { 25961f28255Scgd register struct modes *p; 26061f28255Scgd char *sep; 26161f28255Scgd 26261f28255Scgd if (argc < 2) { 26361f28255Scgd printf("Using %s mode to transfer files.\n", mode); 26461f28255Scgd return; 26561f28255Scgd } 26661f28255Scgd if (argc == 2) { 26761f28255Scgd for (p = modes; p->m_name; p++) 26861f28255Scgd if (strcmp(argv[1], p->m_name) == 0) 26961f28255Scgd break; 27061f28255Scgd if (p->m_name) { 271*1bbda10eSjtc settftpmode(p->m_mode); 27261f28255Scgd return; 27361f28255Scgd } 27461f28255Scgd printf("%s: unknown mode\n", argv[1]); 27561f28255Scgd /* drop through and print usage message */ 27661f28255Scgd } 27761f28255Scgd 27861f28255Scgd printf("usage: %s [", argv[0]); 27961f28255Scgd sep = " "; 28061f28255Scgd for (p = modes; p->m_name; p++) { 28161f28255Scgd printf("%s%s", sep, p->m_name); 28261f28255Scgd if (*sep == ' ') 28361f28255Scgd sep = " | "; 28461f28255Scgd } 28561f28255Scgd printf(" ]\n"); 28661f28255Scgd return; 28761f28255Scgd } 28861f28255Scgd 289*1bbda10eSjtc void 29061f28255Scgd setbinary(argc, argv) 291*1bbda10eSjtc int argc; 29261f28255Scgd char *argv[]; 293*1bbda10eSjtc { 294*1bbda10eSjtc 295*1bbda10eSjtc settftpmode("octet"); 29661f28255Scgd } 29761f28255Scgd 298*1bbda10eSjtc void 29961f28255Scgd setascii(argc, argv) 300*1bbda10eSjtc int argc; 30161f28255Scgd char *argv[]; 302*1bbda10eSjtc { 303*1bbda10eSjtc 304*1bbda10eSjtc settftpmode("netascii"); 30561f28255Scgd } 30661f28255Scgd 307*1bbda10eSjtc static void 308*1bbda10eSjtc settftpmode(newmode) 30961f28255Scgd char *newmode; 31061f28255Scgd { 31161f28255Scgd strcpy(mode, newmode); 31261f28255Scgd if (verbose) 31361f28255Scgd printf("mode set to %s\n", mode); 31461f28255Scgd } 31561f28255Scgd 31661f28255Scgd 31761f28255Scgd /* 31861f28255Scgd * Send file(s). 31961f28255Scgd */ 320*1bbda10eSjtc void 32161f28255Scgd put(argc, argv) 322*1bbda10eSjtc int argc; 32361f28255Scgd char *argv[]; 32461f28255Scgd { 32561f28255Scgd int fd; 32661f28255Scgd register int n; 32761f28255Scgd register char *cp, *targ; 32861f28255Scgd 32961f28255Scgd if (argc < 2) { 33061f28255Scgd strcpy(line, "send "); 33161f28255Scgd printf("(file) "); 33265b04c1fScgd fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); 33361f28255Scgd makeargv(); 33461f28255Scgd argc = margc; 33561f28255Scgd argv = margv; 33661f28255Scgd } 33761f28255Scgd if (argc < 2) { 33861f28255Scgd putusage(argv[0]); 33961f28255Scgd return; 34061f28255Scgd } 34161f28255Scgd targ = argv[argc - 1]; 34261f28255Scgd if (index(argv[argc - 1], ':')) { 34361f28255Scgd char *cp; 34461f28255Scgd struct hostent *hp; 34561f28255Scgd 34661f28255Scgd for (n = 1; n < argc - 1; n++) 34761f28255Scgd if (index(argv[n], ':')) { 34861f28255Scgd putusage(argv[0]); 34961f28255Scgd return; 35061f28255Scgd } 35161f28255Scgd cp = argv[argc - 1]; 35261f28255Scgd targ = index(cp, ':'); 35361f28255Scgd *targ++ = 0; 35461f28255Scgd hp = gethostbyname(cp); 35561f28255Scgd if (hp == NULL) { 35661f28255Scgd fprintf(stderr, "tftp: %s: ", cp); 35761f28255Scgd herror((char *)NULL); 35861f28255Scgd return; 35961f28255Scgd } 360*1bbda10eSjtc bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length); 361*1bbda10eSjtc peeraddr.sin_family = hp->h_addrtype; 36261f28255Scgd connected = 1; 36361f28255Scgd strcpy(hostname, hp->h_name); 36461f28255Scgd } 36561f28255Scgd if (!connected) { 36661f28255Scgd printf("No target machine specified.\n"); 36761f28255Scgd return; 36861f28255Scgd } 36961f28255Scgd if (argc < 4) { 37061f28255Scgd cp = argc == 2 ? tail(targ) : argv[1]; 37161f28255Scgd fd = open(cp, O_RDONLY); 37261f28255Scgd if (fd < 0) { 37361f28255Scgd fprintf(stderr, "tftp: "); perror(cp); 37461f28255Scgd return; 37561f28255Scgd } 37661f28255Scgd if (verbose) 37761f28255Scgd printf("putting %s to %s:%s [%s]\n", 37861f28255Scgd cp, hostname, targ, mode); 379*1bbda10eSjtc peeraddr.sin_port = port; 38061f28255Scgd sendfile(fd, targ, mode); 38161f28255Scgd return; 38261f28255Scgd } 38361f28255Scgd /* this assumes the target is a directory */ 38461f28255Scgd /* on a remote unix system. hmmmm. */ 38561f28255Scgd cp = index(targ, '\0'); 38661f28255Scgd *cp++ = '/'; 38761f28255Scgd for (n = 1; n < argc - 1; n++) { 38861f28255Scgd strcpy(cp, tail(argv[n])); 38961f28255Scgd fd = open(argv[n], O_RDONLY); 39061f28255Scgd if (fd < 0) { 39161f28255Scgd fprintf(stderr, "tftp: "); perror(argv[n]); 39261f28255Scgd continue; 39361f28255Scgd } 39461f28255Scgd if (verbose) 39561f28255Scgd printf("putting %s to %s:%s [%s]\n", 39661f28255Scgd argv[n], hostname, targ, mode); 397*1bbda10eSjtc peeraddr.sin_port = port; 39861f28255Scgd sendfile(fd, targ, mode); 39961f28255Scgd } 40061f28255Scgd } 40161f28255Scgd 402*1bbda10eSjtc static void 40361f28255Scgd putusage(s) 40461f28255Scgd char *s; 40561f28255Scgd { 40661f28255Scgd printf("usage: %s file ... host:target, or\n", s); 40761f28255Scgd printf(" %s file ... target (when already connected)\n", s); 40861f28255Scgd } 40961f28255Scgd 41061f28255Scgd /* 41161f28255Scgd * Receive file(s). 41261f28255Scgd */ 413*1bbda10eSjtc void 41461f28255Scgd get(argc, argv) 415*1bbda10eSjtc int argc; 41661f28255Scgd char *argv[]; 41761f28255Scgd { 41861f28255Scgd int fd; 41961f28255Scgd register int n; 42061f28255Scgd register char *cp; 42161f28255Scgd char *src; 42261f28255Scgd 42361f28255Scgd if (argc < 2) { 42461f28255Scgd strcpy(line, "get "); 42561f28255Scgd printf("(files) "); 42665b04c1fScgd fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); 42761f28255Scgd makeargv(); 42861f28255Scgd argc = margc; 42961f28255Scgd argv = margv; 43061f28255Scgd } 43161f28255Scgd if (argc < 2) { 43261f28255Scgd getusage(argv[0]); 43361f28255Scgd return; 43461f28255Scgd } 43561f28255Scgd if (!connected) { 43661f28255Scgd for (n = 1; n < argc ; n++) 43761f28255Scgd if (index(argv[n], ':') == 0) { 43861f28255Scgd getusage(argv[0]); 43961f28255Scgd return; 44061f28255Scgd } 44161f28255Scgd } 44261f28255Scgd for (n = 1; n < argc ; n++) { 44361f28255Scgd src = index(argv[n], ':'); 44461f28255Scgd if (src == NULL) 44561f28255Scgd src = argv[n]; 44661f28255Scgd else { 44761f28255Scgd struct hostent *hp; 44861f28255Scgd 44961f28255Scgd *src++ = 0; 45061f28255Scgd hp = gethostbyname(argv[n]); 45161f28255Scgd if (hp == NULL) { 45261f28255Scgd fprintf(stderr, "tftp: %s: ", argv[n]); 45361f28255Scgd herror((char *)NULL); 45461f28255Scgd continue; 45561f28255Scgd } 456*1bbda10eSjtc bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, 457*1bbda10eSjtc hp->h_length); 458*1bbda10eSjtc peeraddr.sin_family = hp->h_addrtype; 45961f28255Scgd connected = 1; 46061f28255Scgd strcpy(hostname, hp->h_name); 46161f28255Scgd } 46261f28255Scgd if (argc < 4) { 46361f28255Scgd cp = argc == 3 ? argv[2] : tail(src); 46461f28255Scgd fd = creat(cp, 0644); 46561f28255Scgd if (fd < 0) { 46661f28255Scgd fprintf(stderr, "tftp: "); perror(cp); 46761f28255Scgd return; 46861f28255Scgd } 46961f28255Scgd if (verbose) 47061f28255Scgd printf("getting from %s:%s to %s [%s]\n", 47161f28255Scgd hostname, src, cp, mode); 472*1bbda10eSjtc peeraddr.sin_port = port; 47361f28255Scgd recvfile(fd, src, mode); 47461f28255Scgd break; 47561f28255Scgd } 47661f28255Scgd cp = tail(src); /* new .. jdg */ 47761f28255Scgd fd = creat(cp, 0644); 47861f28255Scgd if (fd < 0) { 47961f28255Scgd fprintf(stderr, "tftp: "); perror(cp); 48061f28255Scgd continue; 48161f28255Scgd } 48261f28255Scgd if (verbose) 48361f28255Scgd printf("getting from %s:%s to %s [%s]\n", 48461f28255Scgd hostname, src, cp, mode); 485*1bbda10eSjtc peeraddr.sin_port = port; 48661f28255Scgd recvfile(fd, src, mode); 48761f28255Scgd } 48861f28255Scgd } 48961f28255Scgd 490*1bbda10eSjtc static void 49161f28255Scgd getusage(s) 49261f28255Scgd char *s; 49361f28255Scgd { 49461f28255Scgd printf("usage: %s host:file host:file ... file, or\n", s); 49561f28255Scgd printf(" %s file file ... file if connected\n", s); 49661f28255Scgd } 49761f28255Scgd 49861f28255Scgd int rexmtval = TIMEOUT; 49961f28255Scgd 500*1bbda10eSjtc void 50161f28255Scgd setrexmt(argc, argv) 502*1bbda10eSjtc int argc; 50361f28255Scgd char *argv[]; 50461f28255Scgd { 50561f28255Scgd int t; 50661f28255Scgd 50761f28255Scgd if (argc < 2) { 50861f28255Scgd strcpy(line, "Rexmt-timeout "); 50961f28255Scgd printf("(value) "); 51065b04c1fScgd fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); 51161f28255Scgd makeargv(); 51261f28255Scgd argc = margc; 51361f28255Scgd argv = margv; 51461f28255Scgd } 51561f28255Scgd if (argc != 2) { 51661f28255Scgd printf("usage: %s value\n", argv[0]); 51761f28255Scgd return; 51861f28255Scgd } 51961f28255Scgd t = atoi(argv[1]); 52061f28255Scgd if (t < 0) 521*1bbda10eSjtc printf("%s: bad value\n", argv[1]); 52261f28255Scgd else 52361f28255Scgd rexmtval = t; 52461f28255Scgd } 52561f28255Scgd 52661f28255Scgd int maxtimeout = 5 * TIMEOUT; 52761f28255Scgd 528*1bbda10eSjtc void 52961f28255Scgd settimeout(argc, argv) 530*1bbda10eSjtc int argc; 53161f28255Scgd char *argv[]; 53261f28255Scgd { 53361f28255Scgd int t; 53461f28255Scgd 53561f28255Scgd if (argc < 2) { 53661f28255Scgd strcpy(line, "Maximum-timeout "); 53761f28255Scgd printf("(value) "); 53865b04c1fScgd fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); 53961f28255Scgd makeargv(); 54061f28255Scgd argc = margc; 54161f28255Scgd argv = margv; 54261f28255Scgd } 54361f28255Scgd if (argc != 2) { 54461f28255Scgd printf("usage: %s value\n", argv[0]); 54561f28255Scgd return; 54661f28255Scgd } 54761f28255Scgd t = atoi(argv[1]); 54861f28255Scgd if (t < 0) 549*1bbda10eSjtc printf("%s: bad value\n", argv[1]); 55061f28255Scgd else 55161f28255Scgd maxtimeout = t; 55261f28255Scgd } 55361f28255Scgd 554*1bbda10eSjtc void 55561f28255Scgd status(argc, argv) 556*1bbda10eSjtc int argc; 55761f28255Scgd char *argv[]; 55861f28255Scgd { 55961f28255Scgd if (connected) 56061f28255Scgd printf("Connected to %s.\n", hostname); 56161f28255Scgd else 56261f28255Scgd printf("Not connected.\n"); 56361f28255Scgd printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 56461f28255Scgd verbose ? "on" : "off", trace ? "on" : "off"); 56561f28255Scgd printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", 56661f28255Scgd rexmtval, maxtimeout); 56761f28255Scgd } 56861f28255Scgd 56961f28255Scgd void 57061f28255Scgd intr() 57161f28255Scgd { 572*1bbda10eSjtc 57361f28255Scgd signal(SIGALRM, SIG_IGN); 57461f28255Scgd alarm(0); 57561f28255Scgd longjmp(toplevel, -1); 57661f28255Scgd } 57761f28255Scgd 57861f28255Scgd char * 57961f28255Scgd tail(filename) 58061f28255Scgd char *filename; 58161f28255Scgd { 58261f28255Scgd register char *s; 58361f28255Scgd 58461f28255Scgd while (*filename) { 58561f28255Scgd s = rindex(filename, '/'); 58661f28255Scgd if (s == NULL) 58761f28255Scgd break; 58861f28255Scgd if (s[1]) 58961f28255Scgd return (s + 1); 59061f28255Scgd *s = '\0'; 59161f28255Scgd } 59261f28255Scgd return (filename); 59361f28255Scgd } 59461f28255Scgd 59561f28255Scgd /* 59661f28255Scgd * Command parser. 59761f28255Scgd */ 598*1bbda10eSjtc static __dead void 599*1bbda10eSjtc command() 60061f28255Scgd { 60161f28255Scgd register struct cmd *c; 60261f28255Scgd 60361f28255Scgd for (;;) { 60461f28255Scgd printf("%s> ", prompt); 60565b04c1fScgd if (fgets(line, LBUFLEN, stdin) == 0) { 60661f28255Scgd if (feof(stdin)) { 607*1bbda10eSjtc exit(0); 60861f28255Scgd } else { 60961f28255Scgd continue; 61061f28255Scgd } 61161f28255Scgd } 61265b04c1fScgd if ((line[0] == 0) || (line[0] == '\n')) 61361f28255Scgd continue; 61461f28255Scgd makeargv(); 615*1bbda10eSjtc if (margc == 0) 616*1bbda10eSjtc continue; 61761f28255Scgd c = getcmd(margv[0]); 61861f28255Scgd if (c == (struct cmd *)-1) { 61961f28255Scgd printf("?Ambiguous command\n"); 62061f28255Scgd continue; 62161f28255Scgd } 62261f28255Scgd if (c == 0) { 62361f28255Scgd printf("?Invalid command\n"); 62461f28255Scgd continue; 62561f28255Scgd } 62661f28255Scgd (*c->handler)(margc, margv); 62761f28255Scgd } 62861f28255Scgd } 62961f28255Scgd 63061f28255Scgd struct cmd * 63161f28255Scgd getcmd(name) 63261f28255Scgd register char *name; 63361f28255Scgd { 63461f28255Scgd register char *p, *q; 63561f28255Scgd register struct cmd *c, *found; 63661f28255Scgd register int nmatches, longest; 63761f28255Scgd 63861f28255Scgd longest = 0; 63961f28255Scgd nmatches = 0; 64061f28255Scgd found = 0; 641*1bbda10eSjtc for (c = cmdtab; (p = c->name) != NULL; c++) { 64261f28255Scgd for (q = name; *q == *p++; q++) 64361f28255Scgd if (*q == 0) /* exact match? */ 64461f28255Scgd return (c); 64561f28255Scgd if (!*q) { /* the name was a prefix */ 64661f28255Scgd if (q - name > longest) { 64761f28255Scgd longest = q - name; 64861f28255Scgd nmatches = 1; 64961f28255Scgd found = c; 65061f28255Scgd } else if (q - name == longest) 65161f28255Scgd nmatches++; 65261f28255Scgd } 65361f28255Scgd } 65461f28255Scgd if (nmatches > 1) 65561f28255Scgd return ((struct cmd *)-1); 65661f28255Scgd return (found); 65761f28255Scgd } 65861f28255Scgd 65961f28255Scgd /* 66061f28255Scgd * Slice a string up into argc/argv. 66161f28255Scgd */ 662*1bbda10eSjtc static void 66361f28255Scgd makeargv() 66461f28255Scgd { 66561f28255Scgd register char *cp; 66661f28255Scgd register char **argp = margv; 66761f28255Scgd 66861f28255Scgd margc = 0; 66961f28255Scgd for (cp = line; *cp;) { 67061f28255Scgd while (isspace(*cp)) 67161f28255Scgd cp++; 67261f28255Scgd if (*cp == '\0') 67361f28255Scgd break; 67461f28255Scgd *argp++ = cp; 67561f28255Scgd margc += 1; 67661f28255Scgd while (*cp != '\0' && !isspace(*cp)) 67761f28255Scgd cp++; 67861f28255Scgd if (*cp == '\0') 67961f28255Scgd break; 68061f28255Scgd *cp++ = '\0'; 68161f28255Scgd } 68261f28255Scgd *argp++ = 0; 68361f28255Scgd } 68461f28255Scgd 685*1bbda10eSjtc void 686*1bbda10eSjtc quit(argc, argv) 687*1bbda10eSjtc int argc; 688*1bbda10eSjtc char *argv[]; 68961f28255Scgd { 690*1bbda10eSjtc 69161f28255Scgd exit(0); 69261f28255Scgd } 69361f28255Scgd 69461f28255Scgd /* 69561f28255Scgd * Help command. 69661f28255Scgd */ 697*1bbda10eSjtc void 69861f28255Scgd help(argc, argv) 69961f28255Scgd int argc; 70061f28255Scgd char *argv[]; 70161f28255Scgd { 70261f28255Scgd register struct cmd *c; 70361f28255Scgd 70461f28255Scgd if (argc == 1) { 70561f28255Scgd printf("Commands may be abbreviated. Commands are:\n\n"); 70661f28255Scgd for (c = cmdtab; c->name; c++) 707*1bbda10eSjtc printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); 70861f28255Scgd return; 70961f28255Scgd } 71061f28255Scgd while (--argc > 0) { 71161f28255Scgd register char *arg; 71261f28255Scgd arg = *++argv; 71361f28255Scgd c = getcmd(arg); 71461f28255Scgd if (c == (struct cmd *)-1) 71561f28255Scgd printf("?Ambiguous help command %s\n", arg); 71661f28255Scgd else if (c == (struct cmd *)0) 71761f28255Scgd printf("?Invalid help command %s\n", arg); 71861f28255Scgd else 71961f28255Scgd printf("%s\n", c->help); 72061f28255Scgd } 72161f28255Scgd } 72261f28255Scgd 723*1bbda10eSjtc void 724*1bbda10eSjtc settrace(argc, argv) 725*1bbda10eSjtc int argc; 726*1bbda10eSjtc char **argv; 72761f28255Scgd { 72861f28255Scgd trace = !trace; 72961f28255Scgd printf("Packet tracing %s.\n", trace ? "on" : "off"); 73061f28255Scgd } 73161f28255Scgd 732*1bbda10eSjtc void 733*1bbda10eSjtc setverbose(argc, argv) 734*1bbda10eSjtc int argc; 735*1bbda10eSjtc char **argv; 73661f28255Scgd { 73761f28255Scgd verbose = !verbose; 73861f28255Scgd printf("Verbose mode %s.\n", verbose ? "on" : "off"); 73961f28255Scgd } 740