19b50d902SRodney W. Grimes /* 29b50d902SRodney W. Grimes * Copyright (c) 1983, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 349b50d902SRodney W. Grimes #ifndef lint 35fd129a02SPhilippe Charnier static const char copyright[] = 369b50d902SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\ 379b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 388049f797SMark Murray #endif 399b50d902SRodney W. Grimes 408f4c8256SDavid Malone #if 0 419b50d902SRodney W. Grimes #ifndef lint 428f4c8256SDavid Malone static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 43fd129a02SPhilippe Charnier #endif 448f4c8256SDavid Malone #endif 458f4c8256SDavid Malone 468f4c8256SDavid Malone #include <sys/cdefs.h> 478f4c8256SDavid Malone __FBSDID("$FreeBSD$"); 489b50d902SRodney W. Grimes 499b50d902SRodney W. Grimes /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 509b50d902SRodney W. Grimes 519b50d902SRodney W. Grimes /* 529b50d902SRodney W. Grimes * TFTP User Program -- Command Interface. 539b50d902SRodney W. Grimes */ 54fd129a02SPhilippe Charnier #include <sys/param.h> 559b50d902SRodney W. Grimes #include <sys/types.h> 569b50d902SRodney W. Grimes #include <sys/socket.h> 579b50d902SRodney W. Grimes #include <sys/file.h> 58a716ad66SWarner Losh #include <sys/param.h> 599b50d902SRodney W. Grimes 609b50d902SRodney W. Grimes #include <netinet/in.h> 619b50d902SRodney W. Grimes 629b50d902SRodney W. Grimes #include <arpa/inet.h> 639b50d902SRodney W. Grimes 649b50d902SRodney W. Grimes #include <ctype.h> 65fd129a02SPhilippe Charnier #include <err.h> 668979160aSBruce Evans #include <histedit.h> 679b50d902SRodney W. Grimes #include <netdb.h> 689b50d902SRodney W. Grimes #include <setjmp.h> 699b50d902SRodney W. Grimes #include <signal.h> 709b50d902SRodney W. Grimes #include <stdio.h> 719b50d902SRodney W. Grimes #include <stdlib.h> 729b50d902SRodney W. Grimes #include <string.h> 739b50d902SRodney W. Grimes #include <unistd.h> 749b50d902SRodney W. Grimes 759b50d902SRodney W. Grimes #include "extern.h" 769b50d902SRodney W. Grimes 77c33ed450SMatthew N. Dodd #define MAXLINE 200 788979160aSBruce Evans #define TIMEOUT 5 /* secs between rexmt's */ 79c33ed450SMatthew N. Dodd 804dac6235SHajimu UMEMOTO struct sockaddr_storage peeraddr; 819b50d902SRodney W. Grimes int f; 829b50d902SRodney W. Grimes int trace; 839b50d902SRodney W. Grimes int verbose; 849b50d902SRodney W. Grimes int connected; 859b50d902SRodney W. Grimes char mode[32]; 86c33ed450SMatthew N. Dodd char line[MAXLINE]; 879b50d902SRodney W. Grimes int margc; 887f3a5689STim J. Robbins #define MAX_MARGV 20 897f3a5689STim J. Robbins char *margv[MAX_MARGV]; 909b50d902SRodney W. Grimes jmp_buf toplevel; 9173f899caSBrian S. Dean volatile int txrx_error; 929b50d902SRodney W. Grimes 933f330d7dSWarner Losh void get(int, char **); 943f330d7dSWarner Losh void help(int, char **); 953f330d7dSWarner Losh void intr(int); 963f330d7dSWarner Losh void modecmd(int, char **); 973f330d7dSWarner Losh void put(int, char **); 983f330d7dSWarner Losh void quit(int, char **); 993f330d7dSWarner Losh void setascii(int, char **); 1003f330d7dSWarner Losh void setbinary(int, char **); 1018da9a6b0SDavid Malone void setpeer0(char *, const char *); 1023f330d7dSWarner Losh void setpeer(int, char **); 1033f330d7dSWarner Losh void setrexmt(int, char **); 1043f330d7dSWarner Losh void settimeout(int, char **); 1053f330d7dSWarner Losh void settrace(int, char **); 1063f330d7dSWarner Losh void setverbose(int, char **); 1073f330d7dSWarner Losh void status(int, char **); 1089b50d902SRodney W. Grimes 1093f330d7dSWarner Losh static void command(void) __dead2; 1103f330d7dSWarner Losh static const char *command_prompt(void); 1119b50d902SRodney W. Grimes 1121b0fa6faSXin LI static void getusage(const char *); 1133f330d7dSWarner Losh static void makeargv(void); 1141b0fa6faSXin LI static void putusage(const char *); 1153f330d7dSWarner Losh static void settftpmode(const char *); 1168049f797SMark Murray 1173f330d7dSWarner Losh char *tail(char *); 1183f330d7dSWarner Losh struct cmd *getcmd(char *); 1199b50d902SRodney W. Grimes 1209b50d902SRodney W. Grimes #define HELPINDENT (sizeof("connect")) 1219b50d902SRodney W. Grimes 1229b50d902SRodney W. Grimes struct cmd { 1238049f797SMark Murray const char *name; 1249b50d902SRodney W. Grimes char *help; 1253f330d7dSWarner Losh void (*handler)(int, char **); 1269b50d902SRodney W. Grimes }; 1279b50d902SRodney W. Grimes 1289b50d902SRodney W. Grimes char vhelp[] = "toggle verbose mode"; 1299b50d902SRodney W. Grimes char thelp[] = "toggle packet tracing"; 1309b50d902SRodney W. Grimes char chelp[] = "connect to remote tftp"; 1319b50d902SRodney W. Grimes char qhelp[] = "exit tftp"; 1329b50d902SRodney W. Grimes char hhelp[] = "print help information"; 1339b50d902SRodney W. Grimes char shelp[] = "send file"; 1349b50d902SRodney W. Grimes char rhelp[] = "receive file"; 1359b50d902SRodney W. Grimes char mhelp[] = "set file transfer mode"; 1369b50d902SRodney W. Grimes char sthelp[] = "show current status"; 1379b50d902SRodney W. Grimes char xhelp[] = "set per-packet retransmission timeout"; 1389b50d902SRodney W. Grimes char ihelp[] = "set total retransmission timeout"; 1399b50d902SRodney W. Grimes char ashelp[] = "set mode to netascii"; 1409b50d902SRodney W. Grimes char bnhelp[] = "set mode to octet"; 1419b50d902SRodney W. Grimes 1429b50d902SRodney W. Grimes struct cmd cmdtab[] = { 1439b50d902SRodney W. Grimes { "connect", chelp, setpeer }, 1449b50d902SRodney W. Grimes { "mode", mhelp, modecmd }, 1459b50d902SRodney W. Grimes { "put", shelp, put }, 1469b50d902SRodney W. Grimes { "get", rhelp, get }, 1479b50d902SRodney W. Grimes { "quit", qhelp, quit }, 1489b50d902SRodney W. Grimes { "verbose", vhelp, setverbose }, 1499b50d902SRodney W. Grimes { "trace", thelp, settrace }, 1509b50d902SRodney W. Grimes { "status", sthelp, status }, 1519b50d902SRodney W. Grimes { "binary", bnhelp, setbinary }, 1529b50d902SRodney W. Grimes { "ascii", ashelp, setascii }, 1539b50d902SRodney W. Grimes { "rexmt", xhelp, setrexmt }, 1549b50d902SRodney W. Grimes { "timeout", ihelp, settimeout }, 1559b50d902SRodney W. Grimes { "?", hhelp, help }, 1568049f797SMark Murray { NULL, NULL, NULL } 1579b50d902SRodney W. Grimes }; 1589b50d902SRodney W. Grimes 1599b50d902SRodney W. Grimes int 1601b0fa6faSXin LI main(int argc, char *argv[]) 1619b50d902SRodney W. Grimes { 1624dac6235SHajimu UMEMOTO f = -1; 1639b50d902SRodney W. Grimes strcpy(mode, "netascii"); 1649b50d902SRodney W. Grimes signal(SIGINT, intr); 1659b50d902SRodney W. Grimes if (argc > 1) { 1669b50d902SRodney W. Grimes if (setjmp(toplevel) != 0) 16773f899caSBrian S. Dean exit(txrx_error); 1689b50d902SRodney W. Grimes setpeer(argc, argv); 1699b50d902SRodney W. Grimes } 1709b50d902SRodney W. Grimes if (setjmp(toplevel) != 0) 1719b50d902SRodney W. Grimes (void)putchar('\n'); 1729b50d902SRodney W. Grimes command(); 1739b50d902SRodney W. Grimes } 1749b50d902SRodney W. Grimes 175fd129a02SPhilippe Charnier char hostname[MAXHOSTNAMELEN]; 1769b50d902SRodney W. Grimes 1779b50d902SRodney W. Grimes void 1781b0fa6faSXin LI setpeer0(char *host, const char *port) 1794dac6235SHajimu UMEMOTO { 1804dac6235SHajimu UMEMOTO struct addrinfo hints, *res0, *res; 1814dac6235SHajimu UMEMOTO int error; 1824dac6235SHajimu UMEMOTO struct sockaddr_storage ss; 1838da9a6b0SDavid Malone const char *cause = "unknown"; 1844dac6235SHajimu UMEMOTO 1854dac6235SHajimu UMEMOTO if (connected) { 1864dac6235SHajimu UMEMOTO close(f); 1874dac6235SHajimu UMEMOTO f = -1; 1884dac6235SHajimu UMEMOTO } 1894dac6235SHajimu UMEMOTO connected = 0; 1904dac6235SHajimu UMEMOTO 1914dac6235SHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 1924dac6235SHajimu UMEMOTO hints.ai_family = PF_UNSPEC; 1934dac6235SHajimu UMEMOTO hints.ai_socktype = SOCK_DGRAM; 1944dac6235SHajimu UMEMOTO hints.ai_protocol = IPPROTO_UDP; 1954dac6235SHajimu UMEMOTO hints.ai_flags = AI_CANONNAME; 1964dac6235SHajimu UMEMOTO if (!port) 1974dac6235SHajimu UMEMOTO port = "tftp"; 1984dac6235SHajimu UMEMOTO error = getaddrinfo(host, port, &hints, &res0); 1994dac6235SHajimu UMEMOTO if (error) { 2004dac6235SHajimu UMEMOTO warnx("%s", gai_strerror(error)); 2014dac6235SHajimu UMEMOTO return; 2024dac6235SHajimu UMEMOTO } 2034dac6235SHajimu UMEMOTO 2044dac6235SHajimu UMEMOTO for (res = res0; res; res = res->ai_next) { 2054dac6235SHajimu UMEMOTO if (res->ai_addrlen > sizeof(peeraddr)) 2064dac6235SHajimu UMEMOTO continue; 2074dac6235SHajimu UMEMOTO f = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 2084dac6235SHajimu UMEMOTO if (f < 0) { 2094dac6235SHajimu UMEMOTO cause = "socket"; 2104dac6235SHajimu UMEMOTO continue; 2114dac6235SHajimu UMEMOTO } 2124dac6235SHajimu UMEMOTO 2134dac6235SHajimu UMEMOTO memset(&ss, 0, sizeof(ss)); 2144dac6235SHajimu UMEMOTO ss.ss_family = res->ai_family; 2154dac6235SHajimu UMEMOTO ss.ss_len = res->ai_addrlen; 2164dac6235SHajimu UMEMOTO if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) { 2174dac6235SHajimu UMEMOTO cause = "bind"; 2184dac6235SHajimu UMEMOTO close(f); 2194dac6235SHajimu UMEMOTO f = -1; 2204dac6235SHajimu UMEMOTO continue; 2214dac6235SHajimu UMEMOTO } 2224dac6235SHajimu UMEMOTO 2234dac6235SHajimu UMEMOTO break; 2244dac6235SHajimu UMEMOTO } 2254dac6235SHajimu UMEMOTO 2264dac6235SHajimu UMEMOTO if (f < 0) 2274dac6235SHajimu UMEMOTO warn("%s", cause); 2284dac6235SHajimu UMEMOTO else { 2294dac6235SHajimu UMEMOTO /* res->ai_addr <= sizeof(peeraddr) is guaranteed */ 2304dac6235SHajimu UMEMOTO memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); 2314dac6235SHajimu UMEMOTO if (res->ai_canonname) { 2323a4e1f47SXin LI (void) strlcpy(hostname, res->ai_canonname, 2334dac6235SHajimu UMEMOTO sizeof(hostname)); 2344dac6235SHajimu UMEMOTO } else 2353a4e1f47SXin LI (void) strlcpy(hostname, host, sizeof(hostname)); 2364dac6235SHajimu UMEMOTO connected = 1; 2374dac6235SHajimu UMEMOTO } 2384dac6235SHajimu UMEMOTO 2394dac6235SHajimu UMEMOTO freeaddrinfo(res0); 2404dac6235SHajimu UMEMOTO } 2414dac6235SHajimu UMEMOTO 2424dac6235SHajimu UMEMOTO void 2431b0fa6faSXin LI setpeer(int argc, char *argv[]) 2449b50d902SRodney W. Grimes { 2459b50d902SRodney W. Grimes 2469b50d902SRodney W. Grimes if (argc < 2) { 2479b50d902SRodney W. Grimes strcpy(line, "Connect "); 2489b50d902SRodney W. Grimes printf("(to) "); 249ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 2509b50d902SRodney W. Grimes makeargv(); 2519b50d902SRodney W. Grimes argc = margc; 2529b50d902SRodney W. Grimes argv = margv; 2539b50d902SRodney W. Grimes } 254b50764b0SGuido van Rooij if ((argc < 2) || (argc > 3)) { 255891ca8cfSSimon L. B. Nielsen printf("usage: %s [host [port]]\n", argv[0]); 2569b50d902SRodney W. Grimes return; 2579b50d902SRodney W. Grimes } 2584dac6235SHajimu UMEMOTO if (argc == 3) 2594dac6235SHajimu UMEMOTO setpeer0(argv[1], argv[2]); 2602e34a0f4SJonathan Chen else 2612e34a0f4SJonathan Chen setpeer0(argv[1], NULL); 2629b50d902SRodney W. Grimes } 2639b50d902SRodney W. Grimes 2649b50d902SRodney W. Grimes struct modes { 2658049f797SMark Murray const char *m_name; 2668049f797SMark Murray const char *m_mode; 2679b50d902SRodney W. Grimes } modes[] = { 2689b50d902SRodney W. Grimes { "ascii", "netascii" }, 2699b50d902SRodney W. Grimes { "netascii", "netascii" }, 2709b50d902SRodney W. Grimes { "binary", "octet" }, 2719b50d902SRodney W. Grimes { "image", "octet" }, 2729b50d902SRodney W. Grimes { "octet", "octet" }, 2739b50d902SRodney W. Grimes /* { "mail", "mail" }, */ 2749b50d902SRodney W. Grimes { 0, 0 } 2759b50d902SRodney W. Grimes }; 2769b50d902SRodney W. Grimes 2779b50d902SRodney W. Grimes void 2781b0fa6faSXin LI modecmd(int argc, char *argv[]) 2799b50d902SRodney W. Grimes { 2808049f797SMark Murray struct modes *p; 2818049f797SMark Murray const char *sep; 2829b50d902SRodney W. Grimes 2839b50d902SRodney W. Grimes if (argc < 2) { 2849b50d902SRodney W. Grimes printf("Using %s mode to transfer files.\n", mode); 2859b50d902SRodney W. Grimes return; 2869b50d902SRodney W. Grimes } 2879b50d902SRodney W. Grimes if (argc == 2) { 2889b50d902SRodney W. Grimes for (p = modes; p->m_name; p++) 2899b50d902SRodney W. Grimes if (strcmp(argv[1], p->m_name) == 0) 2909b50d902SRodney W. Grimes break; 2919b50d902SRodney W. Grimes if (p->m_name) { 2929b50d902SRodney W. Grimes settftpmode(p->m_mode); 2939b50d902SRodney W. Grimes return; 2949b50d902SRodney W. Grimes } 2959b50d902SRodney W. Grimes printf("%s: unknown mode\n", argv[1]); 2969b50d902SRodney W. Grimes /* drop through and print usage message */ 2979b50d902SRodney W. Grimes } 2989b50d902SRodney W. Grimes 2999b50d902SRodney W. Grimes printf("usage: %s [", argv[0]); 3009b50d902SRodney W. Grimes sep = " "; 3019b50d902SRodney W. Grimes for (p = modes; p->m_name; p++) { 3029b50d902SRodney W. Grimes printf("%s%s", sep, p->m_name); 3039b50d902SRodney W. Grimes if (*sep == ' ') 3049b50d902SRodney W. Grimes sep = " | "; 3059b50d902SRodney W. Grimes } 3069b50d902SRodney W. Grimes printf(" ]\n"); 3079b50d902SRodney W. Grimes return; 3089b50d902SRodney W. Grimes } 3099b50d902SRodney W. Grimes 3109b50d902SRodney W. Grimes void 3111b0fa6faSXin LI setbinary(int argc __unused, char *argv[] __unused) 3129b50d902SRodney W. Grimes { 3139b50d902SRodney W. Grimes 3149b50d902SRodney W. Grimes settftpmode("octet"); 3159b50d902SRodney W. Grimes } 3169b50d902SRodney W. Grimes 3179b50d902SRodney W. Grimes void 3181b0fa6faSXin LI setascii(int argc __unused, char *argv[] __unused) 3199b50d902SRodney W. Grimes { 3209b50d902SRodney W. Grimes 3219b50d902SRodney W. Grimes settftpmode("netascii"); 3229b50d902SRodney W. Grimes } 3239b50d902SRodney W. Grimes 3249b50d902SRodney W. Grimes static void 3251b0fa6faSXin LI settftpmode(const char *newmode) 3269b50d902SRodney W. Grimes { 3279b50d902SRodney W. Grimes strcpy(mode, newmode); 3289b50d902SRodney W. Grimes if (verbose) 3299b50d902SRodney W. Grimes printf("mode set to %s\n", mode); 3309b50d902SRodney W. Grimes } 3319b50d902SRodney W. Grimes 3329b50d902SRodney W. Grimes 3339b50d902SRodney W. Grimes /* 3349b50d902SRodney W. Grimes * Send file(s). 3359b50d902SRodney W. Grimes */ 3369b50d902SRodney W. Grimes void 3371b0fa6faSXin LI put(int argc, char *argv[]) 3389b50d902SRodney W. Grimes { 3399b50d902SRodney W. Grimes int fd; 3408049f797SMark Murray int n; 3418049f797SMark Murray char *cp, *targ; 3429b50d902SRodney W. Grimes 3439b50d902SRodney W. Grimes if (argc < 2) { 3449b50d902SRodney W. Grimes strcpy(line, "send "); 3459b50d902SRodney W. Grimes printf("(file) "); 346ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 3479b50d902SRodney W. Grimes makeargv(); 3489b50d902SRodney W. Grimes argc = margc; 3499b50d902SRodney W. Grimes argv = margv; 3509b50d902SRodney W. Grimes } 3519b50d902SRodney W. Grimes if (argc < 2) { 3529b50d902SRodney W. Grimes putusage(argv[0]); 3539b50d902SRodney W. Grimes return; 3549b50d902SRodney W. Grimes } 3559b50d902SRodney W. Grimes targ = argv[argc - 1]; 3564dac6235SHajimu UMEMOTO if (rindex(argv[argc - 1], ':')) { 3578049f797SMark Murray char *lcp; 3589b50d902SRodney W. Grimes 3599b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) 3609b50d902SRodney W. Grimes if (index(argv[n], ':')) { 3619b50d902SRodney W. Grimes putusage(argv[0]); 3629b50d902SRodney W. Grimes return; 3639b50d902SRodney W. Grimes } 3648049f797SMark Murray lcp = argv[argc - 1]; 3654dac6235SHajimu UMEMOTO targ = rindex(lcp, ':'); 3669b50d902SRodney W. Grimes *targ++ = 0; 3674dac6235SHajimu UMEMOTO if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') { 3684dac6235SHajimu UMEMOTO lcp[strlen(lcp) - 1] = '\0'; 3694dac6235SHajimu UMEMOTO lcp++; 3709b50d902SRodney W. Grimes } 3714dac6235SHajimu UMEMOTO setpeer0(lcp, NULL); 3729b50d902SRodney W. Grimes } 3739b50d902SRodney W. Grimes if (!connected) { 3749b50d902SRodney W. Grimes printf("No target machine specified.\n"); 3759b50d902SRodney W. Grimes return; 3769b50d902SRodney W. Grimes } 3779b50d902SRodney W. Grimes if (argc < 4) { 3789b50d902SRodney W. Grimes cp = argc == 2 ? tail(targ) : argv[1]; 3799b50d902SRodney W. Grimes fd = open(cp, O_RDONLY); 3809b50d902SRodney W. Grimes if (fd < 0) { 381fd129a02SPhilippe Charnier warn("%s", cp); 3829b50d902SRodney W. Grimes return; 3839b50d902SRodney W. Grimes } 3849b50d902SRodney W. Grimes if (verbose) 3859b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 3869b50d902SRodney W. Grimes cp, hostname, targ, mode); 3878692ad46SDavid Greenman xmitfile(fd, targ, mode); 3889b50d902SRodney W. Grimes return; 3899b50d902SRodney W. Grimes } 3909b50d902SRodney W. Grimes /* this assumes the target is a directory */ 3919b50d902SRodney W. Grimes /* on a remote unix system. hmmmm. */ 3929b50d902SRodney W. Grimes cp = index(targ, '\0'); 3939b50d902SRodney W. Grimes *cp++ = '/'; 3949b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) { 3959b50d902SRodney W. Grimes strcpy(cp, tail(argv[n])); 3969b50d902SRodney W. Grimes fd = open(argv[n], O_RDONLY); 3979b50d902SRodney W. Grimes if (fd < 0) { 398fd129a02SPhilippe Charnier warn("%s", argv[n]); 3999b50d902SRodney W. Grimes continue; 4009b50d902SRodney W. Grimes } 4019b50d902SRodney W. Grimes if (verbose) 4029b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 4039b50d902SRodney W. Grimes argv[n], hostname, targ, mode); 4048692ad46SDavid Greenman xmitfile(fd, targ, mode); 4059b50d902SRodney W. Grimes } 4069b50d902SRodney W. Grimes } 4079b50d902SRodney W. Grimes 4089b50d902SRodney W. Grimes static void 4091b0fa6faSXin LI putusage(const char *s) 4109b50d902SRodney W. Grimes { 411891ca8cfSSimon L. B. Nielsen printf("usage: %s file [[host:]remotename]\n", s); 412891ca8cfSSimon L. B. Nielsen printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s); 4139b50d902SRodney W. Grimes } 4149b50d902SRodney W. Grimes 4159b50d902SRodney W. Grimes /* 4169b50d902SRodney W. Grimes * Receive file(s). 4179b50d902SRodney W. Grimes */ 4189b50d902SRodney W. Grimes void 4191b0fa6faSXin LI get(int argc, char *argv[]) 4209b50d902SRodney W. Grimes { 4219b50d902SRodney W. Grimes int fd; 4228049f797SMark Murray int n; 4238049f797SMark Murray char *cp; 4249b50d902SRodney W. Grimes char *src; 4259b50d902SRodney W. Grimes 4269b50d902SRodney W. Grimes if (argc < 2) { 4279b50d902SRodney W. Grimes strcpy(line, "get "); 4289b50d902SRodney W. Grimes printf("(files) "); 429ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 4309b50d902SRodney W. Grimes makeargv(); 4319b50d902SRodney W. Grimes argc = margc; 4329b50d902SRodney W. Grimes argv = margv; 4339b50d902SRodney W. Grimes } 4349b50d902SRodney W. Grimes if (argc < 2) { 4359b50d902SRodney W. Grimes getusage(argv[0]); 4369b50d902SRodney W. Grimes return; 4379b50d902SRodney W. Grimes } 4389b50d902SRodney W. Grimes if (!connected) { 4399b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) 4404dac6235SHajimu UMEMOTO if (rindex(argv[n], ':') == 0) { 4419b50d902SRodney W. Grimes getusage(argv[0]); 4429b50d902SRodney W. Grimes return; 4439b50d902SRodney W. Grimes } 4449b50d902SRodney W. Grimes } 4459b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) { 4464dac6235SHajimu UMEMOTO src = rindex(argv[n], ':'); 4479b50d902SRodney W. Grimes if (src == NULL) 4489b50d902SRodney W. Grimes src = argv[n]; 4499b50d902SRodney W. Grimes else { 4504dac6235SHajimu UMEMOTO char *lcp; 4519b50d902SRodney W. Grimes 4529b50d902SRodney W. Grimes *src++ = 0; 4534dac6235SHajimu UMEMOTO lcp = argv[n]; 4544dac6235SHajimu UMEMOTO if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') { 4554dac6235SHajimu UMEMOTO lcp[strlen(lcp) - 1] = '\0'; 4564dac6235SHajimu UMEMOTO lcp++; 4579b50d902SRodney W. Grimes } 4584dac6235SHajimu UMEMOTO setpeer0(lcp, NULL); 4594dac6235SHajimu UMEMOTO if (!connected) 4604dac6235SHajimu UMEMOTO continue; 4619b50d902SRodney W. Grimes } 4629b50d902SRodney W. Grimes if (argc < 4) { 4639b50d902SRodney W. Grimes cp = argc == 3 ? argv[2] : tail(src); 4649b50d902SRodney W. Grimes fd = creat(cp, 0644); 4659b50d902SRodney W. Grimes if (fd < 0) { 466fd129a02SPhilippe Charnier warn("%s", cp); 4679b50d902SRodney W. Grimes return; 4689b50d902SRodney W. Grimes } 4699b50d902SRodney W. Grimes if (verbose) 4709b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 4719b50d902SRodney W. Grimes hostname, src, cp, mode); 4729b50d902SRodney W. Grimes recvfile(fd, src, mode); 4739b50d902SRodney W. Grimes break; 4749b50d902SRodney W. Grimes } 4759b50d902SRodney W. Grimes cp = tail(src); /* new .. jdg */ 4769b50d902SRodney W. Grimes fd = creat(cp, 0644); 4779b50d902SRodney W. Grimes if (fd < 0) { 478fd129a02SPhilippe Charnier warn("%s", cp); 4799b50d902SRodney W. Grimes continue; 4809b50d902SRodney W. Grimes } 4819b50d902SRodney W. Grimes if (verbose) 4829b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 4839b50d902SRodney W. Grimes hostname, src, cp, mode); 4849b50d902SRodney W. Grimes recvfile(fd, src, mode); 4859b50d902SRodney W. Grimes } 4869b50d902SRodney W. Grimes } 4879b50d902SRodney W. Grimes 4889b50d902SRodney W. Grimes static void 4891b0fa6faSXin LI getusage(const char *s) 4909b50d902SRodney W. Grimes { 491891ca8cfSSimon L. B. Nielsen printf("usage: %s [host:]file [localname]\n", s); 492891ca8cfSSimon L. B. Nielsen printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s); 4939b50d902SRodney W. Grimes } 4949b50d902SRodney W. Grimes 4959b50d902SRodney W. Grimes int rexmtval = TIMEOUT; 4969b50d902SRodney W. Grimes 4979b50d902SRodney W. Grimes void 4981b0fa6faSXin LI setrexmt(int argc, char *argv[]) 4999b50d902SRodney W. Grimes { 5009b50d902SRodney W. Grimes int t; 5019b50d902SRodney W. Grimes 5029b50d902SRodney W. Grimes if (argc < 2) { 5039b50d902SRodney W. Grimes strcpy(line, "Rexmt-timeout "); 5049b50d902SRodney W. Grimes printf("(value) "); 505ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 5069b50d902SRodney W. Grimes makeargv(); 5079b50d902SRodney W. Grimes argc = margc; 5089b50d902SRodney W. Grimes argv = margv; 5099b50d902SRodney W. Grimes } 5109b50d902SRodney W. Grimes if (argc != 2) { 5119b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 5129b50d902SRodney W. Grimes return; 5139b50d902SRodney W. Grimes } 5149b50d902SRodney W. Grimes t = atoi(argv[1]); 5159b50d902SRodney W. Grimes if (t < 0) 5169b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 5179b50d902SRodney W. Grimes else 5189b50d902SRodney W. Grimes rexmtval = t; 5199b50d902SRodney W. Grimes } 5209b50d902SRodney W. Grimes 5219b50d902SRodney W. Grimes int maxtimeout = 5 * TIMEOUT; 5229b50d902SRodney W. Grimes 5239b50d902SRodney W. Grimes void 5241b0fa6faSXin LI settimeout(int argc, char *argv[]) 5259b50d902SRodney W. Grimes { 5269b50d902SRodney W. Grimes int t; 5279b50d902SRodney W. Grimes 5289b50d902SRodney W. Grimes if (argc < 2) { 5299b50d902SRodney W. Grimes strcpy(line, "Maximum-timeout "); 5309b50d902SRodney W. Grimes printf("(value) "); 531ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 5329b50d902SRodney W. Grimes makeargv(); 5339b50d902SRodney W. Grimes argc = margc; 5349b50d902SRodney W. Grimes argv = margv; 5359b50d902SRodney W. Grimes } 5369b50d902SRodney W. Grimes if (argc != 2) { 5379b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 5389b50d902SRodney W. Grimes return; 5399b50d902SRodney W. Grimes } 5409b50d902SRodney W. Grimes t = atoi(argv[1]); 5419b50d902SRodney W. Grimes if (t < 0) 5429b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 5439b50d902SRodney W. Grimes else 5449b50d902SRodney W. Grimes maxtimeout = t; 5459b50d902SRodney W. Grimes } 5469b50d902SRodney W. Grimes 5479b50d902SRodney W. Grimes void 5481b0fa6faSXin LI status(int argc __unused, char *argv[] __unused) 5499b50d902SRodney W. Grimes { 5509b50d902SRodney W. Grimes if (connected) 5519b50d902SRodney W. Grimes printf("Connected to %s.\n", hostname); 5529b50d902SRodney W. Grimes else 5539b50d902SRodney W. Grimes printf("Not connected.\n"); 5549b50d902SRodney W. Grimes printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 5559b50d902SRodney W. Grimes verbose ? "on" : "off", trace ? "on" : "off"); 5569b50d902SRodney W. Grimes printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", 5579b50d902SRodney W. Grimes rexmtval, maxtimeout); 5589b50d902SRodney W. Grimes } 5599b50d902SRodney W. Grimes 5609b50d902SRodney W. Grimes void 5611b0fa6faSXin LI intr(int dummy __unused) 5629b50d902SRodney W. Grimes { 5639b50d902SRodney W. Grimes 5649b50d902SRodney W. Grimes signal(SIGALRM, SIG_IGN); 5659b50d902SRodney W. Grimes alarm(0); 5669b50d902SRodney W. Grimes longjmp(toplevel, -1); 5679b50d902SRodney W. Grimes } 5689b50d902SRodney W. Grimes 5699b50d902SRodney W. Grimes char * 5701b0fa6faSXin LI tail(char *filename) 5719b50d902SRodney W. Grimes { 5728049f797SMark Murray char *s; 5739b50d902SRodney W. Grimes 5749b50d902SRodney W. Grimes while (*filename) { 5759b50d902SRodney W. Grimes s = rindex(filename, '/'); 5769b50d902SRodney W. Grimes if (s == NULL) 5779b50d902SRodney W. Grimes break; 5789b50d902SRodney W. Grimes if (s[1]) 5799b50d902SRodney W. Grimes return (s + 1); 5809b50d902SRodney W. Grimes *s = '\0'; 5819b50d902SRodney W. Grimes } 5829b50d902SRodney W. Grimes return (filename); 5839b50d902SRodney W. Grimes } 5849b50d902SRodney W. Grimes 585c33ed450SMatthew N. Dodd static const char * 5861b0fa6faSXin LI command_prompt(void) 5878979160aSBruce Evans { 5888979160aSBruce Evans 589c33ed450SMatthew N. Dodd return ("tftp> "); 590c33ed450SMatthew N. Dodd } 591c33ed450SMatthew N. Dodd 5929b50d902SRodney W. Grimes /* 5939b50d902SRodney W. Grimes * Command parser. 5949b50d902SRodney W. Grimes */ 595eaa86f9dSBruce Evans static void 5961b0fa6faSXin LI command(void) 5979b50d902SRodney W. Grimes { 598c33ed450SMatthew N. Dodd HistEvent he; 5998049f797SMark Murray struct cmd *c; 6008979160aSBruce Evans static EditLine *el; 6018979160aSBruce Evans static History *hist; 602c33ed450SMatthew N. Dodd const char *bp; 6038979160aSBruce Evans char *cp; 6048049f797SMark Murray int len, num, vrbose; 605c33ed450SMatthew N. Dodd 6068049f797SMark Murray vrbose = isatty(0); 6078049f797SMark Murray if (vrbose) { 608c33ed450SMatthew N. Dodd el = el_init("tftp", stdin, stdout, stderr); 609c33ed450SMatthew N. Dodd hist = history_init(); 6102110d9c3SStefan Farfeleder history(hist, &he, H_SETSIZE, 100); 611c33ed450SMatthew N. Dodd el_set(el, EL_HIST, history, hist); 612c33ed450SMatthew N. Dodd el_set(el, EL_EDITOR, "emacs"); 613c33ed450SMatthew N. Dodd el_set(el, EL_PROMPT, command_prompt); 614c33ed450SMatthew N. Dodd el_set(el, EL_SIGNAL, 1); 615c33ed450SMatthew N. Dodd el_source(el, NULL); 616c33ed450SMatthew N. Dodd } 6179b50d902SRodney W. Grimes for (;;) { 6188049f797SMark Murray if (vrbose) { 619c33ed450SMatthew N. Dodd if ((bp = el_gets(el, &num)) == NULL || num == 0) 620c33ed450SMatthew N. Dodd exit(0); 621c33ed450SMatthew N. Dodd len = (num > MAXLINE) ? MAXLINE : num; 622c33ed450SMatthew N. Dodd memcpy(line, bp, len); 623c33ed450SMatthew N. Dodd line[len] = '\0'; 624c33ed450SMatthew N. Dodd history(hist, &he, H_ENTER, bp); 625c33ed450SMatthew N. Dodd } else { 626ca22ff9eSJoerg Wunsch if (fgets(line, sizeof line , stdin) == 0) { 6279b50d902SRodney W. Grimes if (feof(stdin)) { 62873f899caSBrian S. Dean exit(txrx_error); 6299b50d902SRodney W. Grimes } else { 6309b50d902SRodney W. Grimes continue; 6319b50d902SRodney W. Grimes } 6329b50d902SRodney W. Grimes } 633c33ed450SMatthew N. Dodd } 634ca22ff9eSJoerg Wunsch if ((cp = strchr(line, '\n'))) 635ca22ff9eSJoerg Wunsch *cp = '\0'; 6369b50d902SRodney W. Grimes if (line[0] == 0) 6379b50d902SRodney W. Grimes continue; 6389b50d902SRodney W. Grimes makeargv(); 6399b50d902SRodney W. Grimes if (margc == 0) 6409b50d902SRodney W. Grimes continue; 6419b50d902SRodney W. Grimes c = getcmd(margv[0]); 6429b50d902SRodney W. Grimes if (c == (struct cmd *)-1) { 6439b50d902SRodney W. Grimes printf("?Ambiguous command\n"); 6449b50d902SRodney W. Grimes continue; 6459b50d902SRodney W. Grimes } 6469b50d902SRodney W. Grimes if (c == 0) { 6479b50d902SRodney W. Grimes printf("?Invalid command\n"); 6489b50d902SRodney W. Grimes continue; 6499b50d902SRodney W. Grimes } 6509b50d902SRodney W. Grimes (*c->handler)(margc, margv); 6519b50d902SRodney W. Grimes } 6529b50d902SRodney W. Grimes } 6539b50d902SRodney W. Grimes 6549b50d902SRodney W. Grimes struct cmd * 6551b0fa6faSXin LI getcmd(char *name) 6569b50d902SRodney W. Grimes { 6578049f797SMark Murray const char *p, *q; 6588049f797SMark Murray struct cmd *c, *found; 6598049f797SMark Murray int nmatches, longest; 6609b50d902SRodney W. Grimes 6619b50d902SRodney W. Grimes longest = 0; 6629b50d902SRodney W. Grimes nmatches = 0; 6639b50d902SRodney W. Grimes found = 0; 6649b50d902SRodney W. Grimes for (c = cmdtab; (p = c->name) != NULL; c++) { 6659b50d902SRodney W. Grimes for (q = name; *q == *p++; q++) 6669b50d902SRodney W. Grimes if (*q == 0) /* exact match? */ 6679b50d902SRodney W. Grimes return (c); 6689b50d902SRodney W. Grimes if (!*q) { /* the name was a prefix */ 6699b50d902SRodney W. Grimes if (q - name > longest) { 6709b50d902SRodney W. Grimes longest = q - name; 6719b50d902SRodney W. Grimes nmatches = 1; 6729b50d902SRodney W. Grimes found = c; 6739b50d902SRodney W. Grimes } else if (q - name == longest) 6749b50d902SRodney W. Grimes nmatches++; 6759b50d902SRodney W. Grimes } 6769b50d902SRodney W. Grimes } 6779b50d902SRodney W. Grimes if (nmatches > 1) 6789b50d902SRodney W. Grimes return ((struct cmd *)-1); 6799b50d902SRodney W. Grimes return (found); 6809b50d902SRodney W. Grimes } 6819b50d902SRodney W. Grimes 6829b50d902SRodney W. Grimes /* 6839b50d902SRodney W. Grimes * Slice a string up into argc/argv. 6849b50d902SRodney W. Grimes */ 6859b50d902SRodney W. Grimes static void 6861b0fa6faSXin LI makeargv(void) 6879b50d902SRodney W. Grimes { 6888049f797SMark Murray char *cp; 6898049f797SMark Murray char **argp = margv; 6909b50d902SRodney W. Grimes 6919b50d902SRodney W. Grimes margc = 0; 692ca22ff9eSJoerg Wunsch if ((cp = strchr(line, '\n'))) 693ca22ff9eSJoerg Wunsch *cp = '\0'; 6947f3a5689STim J. Robbins for (cp = line; margc < MAX_MARGV - 1 && *cp;) { 6959b50d902SRodney W. Grimes while (isspace(*cp)) 6969b50d902SRodney W. Grimes cp++; 6979b50d902SRodney W. Grimes if (*cp == '\0') 6989b50d902SRodney W. Grimes break; 6999b50d902SRodney W. Grimes *argp++ = cp; 7009b50d902SRodney W. Grimes margc += 1; 7019b50d902SRodney W. Grimes while (*cp != '\0' && !isspace(*cp)) 7029b50d902SRodney W. Grimes cp++; 7039b50d902SRodney W. Grimes if (*cp == '\0') 7049b50d902SRodney W. Grimes break; 7059b50d902SRodney W. Grimes *cp++ = '\0'; 7069b50d902SRodney W. Grimes } 7079b50d902SRodney W. Grimes *argp++ = 0; 7089b50d902SRodney W. Grimes } 7099b50d902SRodney W. Grimes 7109b50d902SRodney W. Grimes void 7111b0fa6faSXin LI quit(int argc __unused, char *argv[] __unused) 7129b50d902SRodney W. Grimes { 71373f899caSBrian S. Dean exit(txrx_error); 7149b50d902SRodney W. Grimes } 7159b50d902SRodney W. Grimes 7169b50d902SRodney W. Grimes /* 7179b50d902SRodney W. Grimes * Help command. 7189b50d902SRodney W. Grimes */ 7199b50d902SRodney W. Grimes void 7201b0fa6faSXin LI help(int argc, char *argv[]) 7219b50d902SRodney W. Grimes { 7228049f797SMark Murray struct cmd *c; 7239b50d902SRodney W. Grimes 7249b50d902SRodney W. Grimes if (argc == 1) { 7259b50d902SRodney W. Grimes printf("Commands may be abbreviated. Commands are:\n\n"); 7269b50d902SRodney W. Grimes for (c = cmdtab; c->name; c++) 7279b50d902SRodney W. Grimes printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); 7289b50d902SRodney W. Grimes return; 7299b50d902SRodney W. Grimes } 7309b50d902SRodney W. Grimes while (--argc > 0) { 7318049f797SMark Murray char *arg; 7329b50d902SRodney W. Grimes arg = *++argv; 7339b50d902SRodney W. Grimes c = getcmd(arg); 7349b50d902SRodney W. Grimes if (c == (struct cmd *)-1) 7359b50d902SRodney W. Grimes printf("?Ambiguous help command %s\n", arg); 7369b50d902SRodney W. Grimes else if (c == (struct cmd *)0) 7379b50d902SRodney W. Grimes printf("?Invalid help command %s\n", arg); 7389b50d902SRodney W. Grimes else 7399b50d902SRodney W. Grimes printf("%s\n", c->help); 7409b50d902SRodney W. Grimes } 7419b50d902SRodney W. Grimes } 7429b50d902SRodney W. Grimes 7439b50d902SRodney W. Grimes void 7441b0fa6faSXin LI settrace(int argc __unused, char **argv __unused) 7459b50d902SRodney W. Grimes { 7469b50d902SRodney W. Grimes trace = !trace; 7479b50d902SRodney W. Grimes printf("Packet tracing %s.\n", trace ? "on" : "off"); 7489b50d902SRodney W. Grimes } 7499b50d902SRodney W. Grimes 7509b50d902SRodney W. Grimes void 7511b0fa6faSXin LI setverbose(int argc __unused, char **argv __unused) 7529b50d902SRodney W. Grimes { 7539b50d902SRodney W. Grimes verbose = !verbose; 7549b50d902SRodney W. Grimes printf("Verbose mode %s.\n", verbose ? "on" : "off"); 7559b50d902SRodney W. Grimes } 756