main.c revision 87708
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1983, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 3487708Smarkm#include <sys/cdefs.h> 3587708Smarkm 3687708Smarkm__FBSDID("$FreeBSD: head/usr.bin/tftp/main.c 87708 2001-12-11 23:43:15Z markm $"); 3787708Smarkm 381590Srgrimes#ifndef lint 3928202Scharnierstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4287708Smarkm#endif 431590Srgrimes 441590Srgrimes#ifndef lint 4587708Smarkmstatic const char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 4628202Scharnier#endif 471590Srgrimes 481590Srgrimes/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 491590Srgrimes 501590Srgrimes/* 511590Srgrimes * TFTP User Program -- Command Interface. 521590Srgrimes */ 5328202Scharnier#include <sys/param.h> 541590Srgrimes#include <sys/types.h> 551590Srgrimes#include <sys/socket.h> 561590Srgrimes#include <sys/file.h> 5736792Simp#include <sys/param.h> 581590Srgrimes 591590Srgrimes#include <netinet/in.h> 601590Srgrimes 611590Srgrimes#include <arpa/inet.h> 621590Srgrimes 631590Srgrimes#include <ctype.h> 6428202Scharnier#include <err.h> 6585155Sbde#include <histedit.h> 661590Srgrimes#include <netdb.h> 671590Srgrimes#include <setjmp.h> 681590Srgrimes#include <signal.h> 691590Srgrimes#include <stdio.h> 701590Srgrimes#include <stdlib.h> 711590Srgrimes#include <string.h> 721590Srgrimes#include <unistd.h> 731590Srgrimes 741590Srgrimes#include "extern.h" 751590Srgrimes 7685155Sbde#define MAXLINE 200 771590Srgrimes#define TIMEOUT 5 /* secs between rexmt's */ 781590Srgrimes 791590Srgrimesstruct sockaddr_in peeraddr; 801590Srgrimesint f; 811590Srgrimesshort port; 821590Srgrimesint trace; 831590Srgrimesint verbose; 841590Srgrimesint connected; 851590Srgrimeschar mode[32]; 8685120Smdoddchar line[MAXLINE]; 871590Srgrimesint margc; 881590Srgrimeschar *margv[20]; 891590Srgrimesjmp_buf toplevel; 901590Srgrimesstruct servent *sp; 911590Srgrimes 921590Srgrimesvoid get __P((int, char **)); 931590Srgrimesvoid help __P((int, char **)); 9487708Smarkmvoid intr __P((int)); 951590Srgrimesvoid modecmd __P((int, char **)); 961590Srgrimesvoid put __P((int, char **)); 971590Srgrimesvoid quit __P((int, char **)); 981590Srgrimesvoid setascii __P((int, char **)); 991590Srgrimesvoid setbinary __P((int, char **)); 1001590Srgrimesvoid setpeer __P((int, char **)); 1011590Srgrimesvoid setrexmt __P((int, char **)); 1021590Srgrimesvoid settimeout __P((int, char **)); 1031590Srgrimesvoid settrace __P((int, char **)); 1041590Srgrimesvoid setverbose __P((int, char **)); 1051590Srgrimesvoid status __P((int, char **)); 1061590Srgrimes 10718286Sbdestatic void command __P((void)) __dead2; 10885155Sbdestatic const char *command_prompt __P((void)); 1091590Srgrimes 1101590Srgrimesstatic void getusage __P((char *)); 1111590Srgrimesstatic void makeargv __P((void)); 1121590Srgrimesstatic void putusage __P((char *)); 11387708Smarkmstatic void settftpmode __P((const char *)); 1141590Srgrimes 11587708Smarkmchar *tail __P((char *)); 11687708Smarkmstruct cmd *getcmd __P((char *)); 11787708Smarkm 1181590Srgrimes#define HELPINDENT (sizeof("connect")) 1191590Srgrimes 1201590Srgrimesstruct cmd { 12187708Smarkm const char *name; 1221590Srgrimes char *help; 1231590Srgrimes void (*handler) __P((int, char **)); 1241590Srgrimes}; 1251590Srgrimes 1261590Srgrimeschar vhelp[] = "toggle verbose mode"; 1271590Srgrimeschar thelp[] = "toggle packet tracing"; 1281590Srgrimeschar chelp[] = "connect to remote tftp"; 1291590Srgrimeschar qhelp[] = "exit tftp"; 1301590Srgrimeschar hhelp[] = "print help information"; 1311590Srgrimeschar shelp[] = "send file"; 1321590Srgrimeschar rhelp[] = "receive file"; 1331590Srgrimeschar mhelp[] = "set file transfer mode"; 1341590Srgrimeschar sthelp[] = "show current status"; 1351590Srgrimeschar xhelp[] = "set per-packet retransmission timeout"; 1361590Srgrimeschar ihelp[] = "set total retransmission timeout"; 1371590Srgrimeschar ashelp[] = "set mode to netascii"; 1381590Srgrimeschar bnhelp[] = "set mode to octet"; 1391590Srgrimes 1401590Srgrimesstruct cmd cmdtab[] = { 1411590Srgrimes { "connect", chelp, setpeer }, 1421590Srgrimes { "mode", mhelp, modecmd }, 1431590Srgrimes { "put", shelp, put }, 1441590Srgrimes { "get", rhelp, get }, 1451590Srgrimes { "quit", qhelp, quit }, 1461590Srgrimes { "verbose", vhelp, setverbose }, 1471590Srgrimes { "trace", thelp, settrace }, 1481590Srgrimes { "status", sthelp, status }, 1491590Srgrimes { "binary", bnhelp, setbinary }, 1501590Srgrimes { "ascii", ashelp, setascii }, 1511590Srgrimes { "rexmt", xhelp, setrexmt }, 1521590Srgrimes { "timeout", ihelp, settimeout }, 1531590Srgrimes { "?", hhelp, help }, 15487708Smarkm { NULL, NULL, NULL } 1551590Srgrimes}; 1561590Srgrimes 1571590Srgrimesint 1581590Srgrimesmain(argc, argv) 1591590Srgrimes int argc; 1601590Srgrimes char *argv[]; 1611590Srgrimes{ 16287708Smarkm struct sockaddr_in lsin; 1631590Srgrimes 1641590Srgrimes sp = getservbyname("tftp", "udp"); 16528202Scharnier if (sp == 0) 16628202Scharnier errx(1, "udp/tftp: unknown service"); 1671590Srgrimes f = socket(AF_INET, SOCK_DGRAM, 0); 16828202Scharnier if (f < 0) 16928202Scharnier err(3, "socket"); 17087708Smarkm bzero((char *)&lsin, sizeof(lsin)); 17187708Smarkm lsin.sin_family = AF_INET; 17287708Smarkm if (bind(f, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) 17328202Scharnier err(1, "bind"); 1741590Srgrimes strcpy(mode, "netascii"); 1751590Srgrimes signal(SIGINT, intr); 1761590Srgrimes if (argc > 1) { 1771590Srgrimes if (setjmp(toplevel) != 0) 1781590Srgrimes exit(0); 1791590Srgrimes setpeer(argc, argv); 1801590Srgrimes } 1811590Srgrimes if (setjmp(toplevel) != 0) 1821590Srgrimes (void)putchar('\n'); 1831590Srgrimes command(); 1841590Srgrimes} 1851590Srgrimes 18628202Scharnierchar hostname[MAXHOSTNAMELEN]; 1871590Srgrimes 1881590Srgrimesvoid 1891590Srgrimessetpeer(argc, argv) 1901590Srgrimes int argc; 1911590Srgrimes char *argv[]; 1921590Srgrimes{ 1931590Srgrimes struct hostent *host; 1941590Srgrimes 1951590Srgrimes if (argc < 2) { 1961590Srgrimes strcpy(line, "Connect "); 1971590Srgrimes printf("(to) "); 19813068Sjoerg fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 1991590Srgrimes makeargv(); 2001590Srgrimes argc = margc; 2011590Srgrimes argv = margv; 2021590Srgrimes } 2031590Srgrimes if (argc > 3) { 2041590Srgrimes printf("usage: %s host-name [port]\n", argv[0]); 2051590Srgrimes return; 2061590Srgrimes } 2071590Srgrimes host = gethostbyname(argv[1]); 2081590Srgrimes if (host) { 2091590Srgrimes peeraddr.sin_family = host->h_addrtype; 21036792Simp bcopy(host->h_addr, &peeraddr.sin_addr, 21136792Simp MIN(sizeof(peeraddr.sin_addr), host->h_length)); 21236792Simp strncpy(hostname, host->h_name, sizeof(hostname)); 2131590Srgrimes } else { 2141590Srgrimes peeraddr.sin_family = AF_INET; 2151590Srgrimes peeraddr.sin_addr.s_addr = inet_addr(argv[1]); 2161590Srgrimes if (peeraddr.sin_addr.s_addr == -1) { 2171590Srgrimes connected = 0; 2181590Srgrimes printf("%s: unknown host\n", argv[1]); 2191590Srgrimes return; 2201590Srgrimes } 22136792Simp strncpy(hostname, argv[1], sizeof(hostname)); 2221590Srgrimes } 22336792Simp hostname[sizeof(hostname) - 1] = '\0'; 2241590Srgrimes port = sp->s_port; 2251590Srgrimes if (argc == 3) { 2261590Srgrimes port = atoi(argv[2]); 2271590Srgrimes if (port < 0) { 2281590Srgrimes printf("%s: bad port number\n", argv[2]); 2291590Srgrimes connected = 0; 2301590Srgrimes return; 2311590Srgrimes } 2321590Srgrimes port = htons(port); 2331590Srgrimes } 2341590Srgrimes connected = 1; 2351590Srgrimes} 2361590Srgrimes 2371590Srgrimesstruct modes { 23887708Smarkm const char *m_name; 23987708Smarkm const char *m_mode; 2401590Srgrimes} modes[] = { 2411590Srgrimes { "ascii", "netascii" }, 2421590Srgrimes { "netascii", "netascii" }, 2431590Srgrimes { "binary", "octet" }, 2441590Srgrimes { "image", "octet" }, 2451590Srgrimes { "octet", "octet" }, 2461590Srgrimes/* { "mail", "mail" }, */ 2471590Srgrimes { 0, 0 } 2481590Srgrimes}; 2491590Srgrimes 2501590Srgrimesvoid 2511590Srgrimesmodecmd(argc, argv) 2521590Srgrimes int argc; 2531590Srgrimes char *argv[]; 2541590Srgrimes{ 25587708Smarkm struct modes *p; 25687708Smarkm const char *sep; 2571590Srgrimes 2581590Srgrimes if (argc < 2) { 2591590Srgrimes printf("Using %s mode to transfer files.\n", mode); 2601590Srgrimes return; 2611590Srgrimes } 2621590Srgrimes if (argc == 2) { 2631590Srgrimes for (p = modes; p->m_name; p++) 2641590Srgrimes if (strcmp(argv[1], p->m_name) == 0) 2651590Srgrimes break; 2661590Srgrimes if (p->m_name) { 2671590Srgrimes settftpmode(p->m_mode); 2681590Srgrimes return; 2691590Srgrimes } 2701590Srgrimes printf("%s: unknown mode\n", argv[1]); 2711590Srgrimes /* drop through and print usage message */ 2721590Srgrimes } 2731590Srgrimes 2741590Srgrimes printf("usage: %s [", argv[0]); 2751590Srgrimes sep = " "; 2761590Srgrimes for (p = modes; p->m_name; p++) { 2771590Srgrimes printf("%s%s", sep, p->m_name); 2781590Srgrimes if (*sep == ' ') 2791590Srgrimes sep = " | "; 2801590Srgrimes } 2811590Srgrimes printf(" ]\n"); 2821590Srgrimes return; 2831590Srgrimes} 2841590Srgrimes 2851590Srgrimesvoid 2861590Srgrimessetbinary(argc, argv) 28787708Smarkm int argc __unused; 28887708Smarkm char *argv[] __unused; 2898874Srgrimes{ 2901590Srgrimes 2911590Srgrimes settftpmode("octet"); 2921590Srgrimes} 2931590Srgrimes 2941590Srgrimesvoid 2951590Srgrimessetascii(argc, argv) 29687708Smarkm int argc __unused; 29787708Smarkm char *argv[] __unused; 2981590Srgrimes{ 2991590Srgrimes 3001590Srgrimes settftpmode("netascii"); 3011590Srgrimes} 3021590Srgrimes 3031590Srgrimesstatic void 3041590Srgrimessettftpmode(newmode) 30587708Smarkm const char *newmode; 3061590Srgrimes{ 3071590Srgrimes strcpy(mode, newmode); 3081590Srgrimes if (verbose) 3091590Srgrimes printf("mode set to %s\n", mode); 3101590Srgrimes} 3111590Srgrimes 3121590Srgrimes 3131590Srgrimes/* 3141590Srgrimes * Send file(s). 3151590Srgrimes */ 3161590Srgrimesvoid 3171590Srgrimesput(argc, argv) 3181590Srgrimes int argc; 3191590Srgrimes char *argv[]; 3201590Srgrimes{ 3211590Srgrimes int fd; 32287708Smarkm int n; 32387708Smarkm char *cp, *targ; 3241590Srgrimes 3251590Srgrimes if (argc < 2) { 3261590Srgrimes strcpy(line, "send "); 3271590Srgrimes printf("(file) "); 32813068Sjoerg fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 3291590Srgrimes makeargv(); 3301590Srgrimes argc = margc; 3311590Srgrimes argv = margv; 3321590Srgrimes } 3331590Srgrimes if (argc < 2) { 3341590Srgrimes putusage(argv[0]); 3351590Srgrimes return; 3361590Srgrimes } 3371590Srgrimes targ = argv[argc - 1]; 3381590Srgrimes if (index(argv[argc - 1], ':')) { 33987708Smarkm char *lcp; 3401590Srgrimes struct hostent *hp; 3411590Srgrimes 3421590Srgrimes for (n = 1; n < argc - 1; n++) 3431590Srgrimes if (index(argv[n], ':')) { 3441590Srgrimes putusage(argv[0]); 3451590Srgrimes return; 3461590Srgrimes } 34787708Smarkm lcp = argv[argc - 1]; 34887708Smarkm targ = index(lcp, ':'); 3491590Srgrimes *targ++ = 0; 35087708Smarkm hp = gethostbyname(lcp); 3511590Srgrimes if (hp == NULL) { 35287708Smarkm fprintf(stderr, "tftp: %s: ", lcp); 3531590Srgrimes herror((char *)NULL); 3541590Srgrimes return; 3551590Srgrimes } 35636792Simp bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, 35736792Simp MIN(sizeof(peeraddr.sin_addr), hp->h_length)); 3581590Srgrimes peeraddr.sin_family = hp->h_addrtype; 3591590Srgrimes connected = 1; 36036792Simp strncpy(hostname, hp->h_name, sizeof(hostname)); 36136792Simp hostname[sizeof(hostname) - 1] = '\0'; 3621590Srgrimes } 3631590Srgrimes if (!connected) { 3641590Srgrimes printf("No target machine specified.\n"); 3651590Srgrimes return; 3661590Srgrimes } 3671590Srgrimes if (argc < 4) { 3681590Srgrimes cp = argc == 2 ? tail(targ) : argv[1]; 3691590Srgrimes fd = open(cp, O_RDONLY); 3701590Srgrimes if (fd < 0) { 37128202Scharnier warn("%s", cp); 3721590Srgrimes return; 3731590Srgrimes } 3741590Srgrimes if (verbose) 3751590Srgrimes printf("putting %s to %s:%s [%s]\n", 3761590Srgrimes cp, hostname, targ, mode); 3771590Srgrimes peeraddr.sin_port = port; 37840765Sdg xmitfile(fd, targ, mode); 3791590Srgrimes return; 3801590Srgrimes } 3811590Srgrimes /* this assumes the target is a directory */ 3821590Srgrimes /* on a remote unix system. hmmmm. */ 3838874Srgrimes cp = index(targ, '\0'); 3841590Srgrimes *cp++ = '/'; 3851590Srgrimes for (n = 1; n < argc - 1; n++) { 3861590Srgrimes strcpy(cp, tail(argv[n])); 3871590Srgrimes fd = open(argv[n], O_RDONLY); 3881590Srgrimes if (fd < 0) { 38928202Scharnier warn("%s", argv[n]); 3901590Srgrimes continue; 3911590Srgrimes } 3921590Srgrimes if (verbose) 3931590Srgrimes printf("putting %s to %s:%s [%s]\n", 3941590Srgrimes argv[n], hostname, targ, mode); 3951590Srgrimes peeraddr.sin_port = port; 39640765Sdg xmitfile(fd, targ, mode); 3971590Srgrimes } 3981590Srgrimes} 3991590Srgrimes 4001590Srgrimesstatic void 4011590Srgrimesputusage(s) 4021590Srgrimes char *s; 4031590Srgrimes{ 4041590Srgrimes printf("usage: %s file ... host:target, or\n", s); 4051590Srgrimes printf(" %s file ... target (when already connected)\n", s); 4061590Srgrimes} 4071590Srgrimes 4081590Srgrimes/* 4091590Srgrimes * Receive file(s). 4101590Srgrimes */ 4111590Srgrimesvoid 4121590Srgrimesget(argc, argv) 4131590Srgrimes int argc; 4141590Srgrimes char *argv[]; 4151590Srgrimes{ 4161590Srgrimes int fd; 41787708Smarkm int n; 41887708Smarkm char *cp; 4191590Srgrimes char *src; 4201590Srgrimes 4211590Srgrimes if (argc < 2) { 4221590Srgrimes strcpy(line, "get "); 4231590Srgrimes printf("(files) "); 42413068Sjoerg fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 4251590Srgrimes makeargv(); 4261590Srgrimes argc = margc; 4271590Srgrimes argv = margv; 4281590Srgrimes } 4291590Srgrimes if (argc < 2) { 4301590Srgrimes getusage(argv[0]); 4311590Srgrimes return; 4321590Srgrimes } 4331590Srgrimes if (!connected) { 4341590Srgrimes for (n = 1; n < argc ; n++) 4351590Srgrimes if (index(argv[n], ':') == 0) { 4361590Srgrimes getusage(argv[0]); 4371590Srgrimes return; 4381590Srgrimes } 4391590Srgrimes } 4401590Srgrimes for (n = 1; n < argc ; n++) { 4411590Srgrimes src = index(argv[n], ':'); 4421590Srgrimes if (src == NULL) 4431590Srgrimes src = argv[n]; 4441590Srgrimes else { 4451590Srgrimes struct hostent *hp; 4461590Srgrimes 4471590Srgrimes *src++ = 0; 4481590Srgrimes hp = gethostbyname(argv[n]); 4491590Srgrimes if (hp == NULL) { 4501590Srgrimes fprintf(stderr, "tftp: %s: ", argv[n]); 4511590Srgrimes herror((char *)NULL); 4521590Srgrimes continue; 4531590Srgrimes } 4541590Srgrimes bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, 45536792Simp MIN(sizeof(peeraddr.sin_addr), hp->h_length)); 4561590Srgrimes peeraddr.sin_family = hp->h_addrtype; 4571590Srgrimes connected = 1; 45836792Simp strncpy(hostname, hp->h_name, sizeof(hostname)); 45936792Simp hostname[sizeof(hostname) - 1] = '\0'; 4601590Srgrimes } 4611590Srgrimes if (argc < 4) { 4621590Srgrimes cp = argc == 3 ? argv[2] : tail(src); 4631590Srgrimes fd = creat(cp, 0644); 4641590Srgrimes if (fd < 0) { 46528202Scharnier warn("%s", cp); 4661590Srgrimes return; 4671590Srgrimes } 4681590Srgrimes if (verbose) 4691590Srgrimes printf("getting from %s:%s to %s [%s]\n", 4701590Srgrimes hostname, src, cp, mode); 4711590Srgrimes peeraddr.sin_port = port; 4721590Srgrimes recvfile(fd, src, mode); 4731590Srgrimes break; 4741590Srgrimes } 4751590Srgrimes cp = tail(src); /* new .. jdg */ 4761590Srgrimes fd = creat(cp, 0644); 4771590Srgrimes if (fd < 0) { 47828202Scharnier warn("%s", cp); 4791590Srgrimes continue; 4801590Srgrimes } 4811590Srgrimes if (verbose) 4821590Srgrimes printf("getting from %s:%s to %s [%s]\n", 4831590Srgrimes hostname, src, cp, mode); 4841590Srgrimes peeraddr.sin_port = port; 4851590Srgrimes recvfile(fd, src, mode); 4861590Srgrimes } 4871590Srgrimes} 4881590Srgrimes 4891590Srgrimesstatic void 4901590Srgrimesgetusage(s) 4911590Srgrimes char *s; 4921590Srgrimes{ 4931590Srgrimes printf("usage: %s host:file host:file ... file, or\n", s); 4941590Srgrimes printf(" %s file file ... file if connected\n", s); 4951590Srgrimes} 4961590Srgrimes 4971590Srgrimesint rexmtval = TIMEOUT; 4981590Srgrimes 4991590Srgrimesvoid 5001590Srgrimessetrexmt(argc, argv) 5011590Srgrimes int argc; 5021590Srgrimes char *argv[]; 5031590Srgrimes{ 5041590Srgrimes int t; 5051590Srgrimes 5061590Srgrimes if (argc < 2) { 5071590Srgrimes strcpy(line, "Rexmt-timeout "); 5081590Srgrimes printf("(value) "); 50913068Sjoerg fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 5101590Srgrimes makeargv(); 5111590Srgrimes argc = margc; 5121590Srgrimes argv = margv; 5131590Srgrimes } 5141590Srgrimes if (argc != 2) { 5151590Srgrimes printf("usage: %s value\n", argv[0]); 5161590Srgrimes return; 5171590Srgrimes } 5181590Srgrimes t = atoi(argv[1]); 5191590Srgrimes if (t < 0) 5201590Srgrimes printf("%s: bad value\n", argv[1]); 5211590Srgrimes else 5221590Srgrimes rexmtval = t; 5231590Srgrimes} 5241590Srgrimes 5251590Srgrimesint maxtimeout = 5 * TIMEOUT; 5261590Srgrimes 5271590Srgrimesvoid 5281590Srgrimessettimeout(argc, argv) 5291590Srgrimes int argc; 5301590Srgrimes char *argv[]; 5311590Srgrimes{ 5321590Srgrimes int t; 5331590Srgrimes 5341590Srgrimes if (argc < 2) { 5351590Srgrimes strcpy(line, "Maximum-timeout "); 5361590Srgrimes printf("(value) "); 53713068Sjoerg fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 5381590Srgrimes makeargv(); 5391590Srgrimes argc = margc; 5401590Srgrimes argv = margv; 5411590Srgrimes } 5421590Srgrimes if (argc != 2) { 5431590Srgrimes printf("usage: %s value\n", argv[0]); 5441590Srgrimes return; 5451590Srgrimes } 5461590Srgrimes t = atoi(argv[1]); 5471590Srgrimes if (t < 0) 5481590Srgrimes printf("%s: bad value\n", argv[1]); 5491590Srgrimes else 5501590Srgrimes maxtimeout = t; 5511590Srgrimes} 5521590Srgrimes 5531590Srgrimesvoid 5541590Srgrimesstatus(argc, argv) 55587708Smarkm int argc __unused; 55687708Smarkm char *argv[] __unused; 5571590Srgrimes{ 5581590Srgrimes if (connected) 5591590Srgrimes printf("Connected to %s.\n", hostname); 5601590Srgrimes else 5611590Srgrimes printf("Not connected.\n"); 5621590Srgrimes printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 5631590Srgrimes verbose ? "on" : "off", trace ? "on" : "off"); 5641590Srgrimes printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", 5651590Srgrimes rexmtval, maxtimeout); 5661590Srgrimes} 5671590Srgrimes 5681590Srgrimesvoid 56987708Smarkmintr(dummy) 57087708Smarkm int dummy __unused; 5711590Srgrimes{ 5721590Srgrimes 5731590Srgrimes signal(SIGALRM, SIG_IGN); 5741590Srgrimes alarm(0); 5751590Srgrimes longjmp(toplevel, -1); 5761590Srgrimes} 5771590Srgrimes 5781590Srgrimeschar * 5791590Srgrimestail(filename) 5801590Srgrimes char *filename; 5811590Srgrimes{ 58287708Smarkm char *s; 5838874Srgrimes 5841590Srgrimes while (*filename) { 5851590Srgrimes s = rindex(filename, '/'); 5861590Srgrimes if (s == NULL) 5871590Srgrimes break; 5881590Srgrimes if (s[1]) 5891590Srgrimes return (s + 1); 5901590Srgrimes *s = '\0'; 5911590Srgrimes } 5921590Srgrimes return (filename); 5931590Srgrimes} 5941590Srgrimes 59585120Smdoddstatic const char * 59685155Sbdecommand_prompt() 59785155Sbde{ 59885155Sbde 59985120Smdodd return ("tftp> "); 60085120Smdodd} 60185120Smdodd 6021590Srgrimes/* 6031590Srgrimes * Command parser. 6041590Srgrimes */ 60518286Sbdestatic void 6061590Srgrimescommand() 6071590Srgrimes{ 60885155Sbde HistEvent he; 60987708Smarkm struct cmd *c; 61085155Sbde static EditLine *el; 61185155Sbde static History *hist; 61285155Sbde const char *bp; 61313068Sjoerg char *cp; 61487708Smarkm int len, num, vrbose; 6151590Srgrimes 61687708Smarkm vrbose = isatty(0); 61787708Smarkm if (vrbose) { 61885120Smdodd el = el_init("tftp", stdin, stdout, stderr); 61985120Smdodd hist = history_init(); 62085120Smdodd history(hist, &he, H_EVENT, 100); 62185120Smdodd el_set(el, EL_HIST, history, hist); 62285120Smdodd el_set(el, EL_EDITOR, "emacs"); 62385120Smdodd el_set(el, EL_PROMPT, command_prompt); 62485120Smdodd el_set(el, EL_SIGNAL, 1); 62585120Smdodd el_source(el, NULL); 62685120Smdodd } 6271590Srgrimes for (;;) { 62887708Smarkm if (vrbose) { 62985120Smdodd if ((bp = el_gets(el, &num)) == NULL || num == 0) 63085120Smdodd exit(0); 63185120Smdodd len = (num > MAXLINE) ? MAXLINE : num; 63285120Smdodd memcpy(line, bp, len); 63385120Smdodd line[len] = '\0'; 63485120Smdodd history(hist, &he, H_ENTER, bp); 63585120Smdodd } else { 63685120Smdodd if (fgets(line, sizeof line , stdin) == 0) { 63785120Smdodd if (feof(stdin)) { 63885120Smdodd exit(0); 63985120Smdodd } else { 64085120Smdodd continue; 64185120Smdodd } 6421590Srgrimes } 6431590Srgrimes } 64413068Sjoerg if ((cp = strchr(line, '\n'))) 64513068Sjoerg *cp = '\0'; 6461590Srgrimes if (line[0] == 0) 6471590Srgrimes continue; 6481590Srgrimes makeargv(); 6491590Srgrimes if (margc == 0) 6501590Srgrimes continue; 6511590Srgrimes c = getcmd(margv[0]); 6521590Srgrimes if (c == (struct cmd *)-1) { 6531590Srgrimes printf("?Ambiguous command\n"); 6541590Srgrimes continue; 6551590Srgrimes } 6561590Srgrimes if (c == 0) { 6571590Srgrimes printf("?Invalid command\n"); 6581590Srgrimes continue; 6591590Srgrimes } 6601590Srgrimes (*c->handler)(margc, margv); 6611590Srgrimes } 6621590Srgrimes} 6631590Srgrimes 6641590Srgrimesstruct cmd * 6651590Srgrimesgetcmd(name) 66687708Smarkm char *name; 6671590Srgrimes{ 66887708Smarkm const char *p, *q; 66987708Smarkm struct cmd *c, *found; 67087708Smarkm int nmatches, longest; 6711590Srgrimes 6721590Srgrimes longest = 0; 6731590Srgrimes nmatches = 0; 6741590Srgrimes found = 0; 6751590Srgrimes for (c = cmdtab; (p = c->name) != NULL; c++) { 6761590Srgrimes for (q = name; *q == *p++; q++) 6771590Srgrimes if (*q == 0) /* exact match? */ 6781590Srgrimes return (c); 6791590Srgrimes if (!*q) { /* the name was a prefix */ 6801590Srgrimes if (q - name > longest) { 6811590Srgrimes longest = q - name; 6821590Srgrimes nmatches = 1; 6831590Srgrimes found = c; 6841590Srgrimes } else if (q - name == longest) 6851590Srgrimes nmatches++; 6861590Srgrimes } 6871590Srgrimes } 6881590Srgrimes if (nmatches > 1) 6891590Srgrimes return ((struct cmd *)-1); 6901590Srgrimes return (found); 6911590Srgrimes} 6921590Srgrimes 6931590Srgrimes/* 6941590Srgrimes * Slice a string up into argc/argv. 6951590Srgrimes */ 6961590Srgrimesstatic void 6971590Srgrimesmakeargv() 6981590Srgrimes{ 69987708Smarkm char *cp; 70087708Smarkm char **argp = margv; 7011590Srgrimes 7021590Srgrimes margc = 0; 70313068Sjoerg if ((cp = strchr(line, '\n'))) 70413068Sjoerg *cp = '\0'; 7051590Srgrimes for (cp = line; *cp;) { 7061590Srgrimes while (isspace(*cp)) 7071590Srgrimes cp++; 7081590Srgrimes if (*cp == '\0') 7091590Srgrimes break; 7101590Srgrimes *argp++ = cp; 7111590Srgrimes margc += 1; 7121590Srgrimes while (*cp != '\0' && !isspace(*cp)) 7131590Srgrimes cp++; 7141590Srgrimes if (*cp == '\0') 7151590Srgrimes break; 7161590Srgrimes *cp++ = '\0'; 7171590Srgrimes } 7181590Srgrimes *argp++ = 0; 7191590Srgrimes} 7201590Srgrimes 7211590Srgrimesvoid 7221590Srgrimesquit(argc, argv) 72387708Smarkm int argc __unused; 72487708Smarkm char *argv[] __unused; 7251590Srgrimes{ 7261590Srgrimes 7271590Srgrimes exit(0); 7281590Srgrimes} 7291590Srgrimes 7301590Srgrimes/* 7311590Srgrimes * Help command. 7321590Srgrimes */ 7331590Srgrimesvoid 7341590Srgrimeshelp(argc, argv) 7351590Srgrimes int argc; 7361590Srgrimes char *argv[]; 7371590Srgrimes{ 73887708Smarkm struct cmd *c; 7391590Srgrimes 7401590Srgrimes if (argc == 1) { 7411590Srgrimes printf("Commands may be abbreviated. Commands are:\n\n"); 7421590Srgrimes for (c = cmdtab; c->name; c++) 7431590Srgrimes printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); 7441590Srgrimes return; 7451590Srgrimes } 7461590Srgrimes while (--argc > 0) { 74787708Smarkm char *arg; 7481590Srgrimes arg = *++argv; 7491590Srgrimes c = getcmd(arg); 7501590Srgrimes if (c == (struct cmd *)-1) 7511590Srgrimes printf("?Ambiguous help command %s\n", arg); 7521590Srgrimes else if (c == (struct cmd *)0) 7531590Srgrimes printf("?Invalid help command %s\n", arg); 7541590Srgrimes else 7551590Srgrimes printf("%s\n", c->help); 7561590Srgrimes } 7571590Srgrimes} 7581590Srgrimes 7591590Srgrimesvoid 7601590Srgrimessettrace(argc, argv) 76187708Smarkm int argc __unused; 76287708Smarkm char **argv __unused; 7631590Srgrimes{ 7641590Srgrimes trace = !trace; 7651590Srgrimes printf("Packet tracing %s.\n", trace ? "on" : "off"); 7661590Srgrimes} 7671590Srgrimes 7681590Srgrimesvoid 7691590Srgrimessetverbose(argc, argv) 77087708Smarkm int argc __unused; 77187708Smarkm char **argv __unused; 7721590Srgrimes{ 7731590Srgrimes verbose = !verbose; 7741590Srgrimes printf("Verbose mode %s.\n", verbose ? "on" : "off"); 7751590Srgrimes} 776