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 359b50d902SRodney W. Grimes static char copyright[] = 369b50d902SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\ 379b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 389b50d902SRodney W. Grimes #endif /* not lint */ 399b50d902SRodney W. Grimes 409b50d902SRodney W. Grimes #ifndef lint 419b50d902SRodney W. Grimes static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 429b50d902SRodney W. Grimes #endif /* not lint */ 439b50d902SRodney W. Grimes 449b50d902SRodney W. Grimes /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 459b50d902SRodney W. Grimes 469b50d902SRodney W. Grimes /* 479b50d902SRodney W. Grimes * TFTP User Program -- Command Interface. 489b50d902SRodney W. Grimes */ 499b50d902SRodney W. Grimes #include <sys/types.h> 509b50d902SRodney W. Grimes #include <sys/socket.h> 519b50d902SRodney W. Grimes #include <sys/file.h> 529b50d902SRodney W. Grimes 539b50d902SRodney W. Grimes #include <netinet/in.h> 549b50d902SRodney W. Grimes 559b50d902SRodney W. Grimes #include <arpa/inet.h> 569b50d902SRodney W. Grimes 579b50d902SRodney W. Grimes #include <ctype.h> 589b50d902SRodney W. Grimes #include <errno.h> 599b50d902SRodney W. Grimes #include <netdb.h> 609b50d902SRodney W. Grimes #include <setjmp.h> 619b50d902SRodney W. Grimes #include <signal.h> 629b50d902SRodney W. Grimes #include <stdio.h> 639b50d902SRodney W. Grimes #include <stdlib.h> 649b50d902SRodney W. Grimes #include <string.h> 659b50d902SRodney W. Grimes #include <unistd.h> 669b50d902SRodney W. Grimes 679b50d902SRodney W. Grimes #include "extern.h" 689b50d902SRodney W. Grimes 699b50d902SRodney W. Grimes #define TIMEOUT 5 /* secs between rexmt's */ 709b50d902SRodney W. Grimes 719b50d902SRodney W. Grimes struct sockaddr_in peeraddr; 729b50d902SRodney W. Grimes int f; 739b50d902SRodney W. Grimes short port; 749b50d902SRodney W. Grimes int trace; 759b50d902SRodney W. Grimes int verbose; 769b50d902SRodney W. Grimes int connected; 779b50d902SRodney W. Grimes char mode[32]; 789b50d902SRodney W. Grimes char line[200]; 799b50d902SRodney W. Grimes int margc; 809b50d902SRodney W. Grimes char *margv[20]; 819b50d902SRodney W. Grimes char *prompt = "tftp"; 829b50d902SRodney W. Grimes jmp_buf toplevel; 839b50d902SRodney W. Grimes void intr(); 849b50d902SRodney W. Grimes struct servent *sp; 859b50d902SRodney W. Grimes 869b50d902SRodney W. Grimes void get __P((int, char **)); 879b50d902SRodney W. Grimes void help __P((int, char **)); 889b50d902SRodney W. Grimes void modecmd __P((int, char **)); 899b50d902SRodney W. Grimes void put __P((int, char **)); 909b50d902SRodney W. Grimes void quit __P((int, char **)); 919b50d902SRodney W. Grimes void setascii __P((int, char **)); 929b50d902SRodney W. Grimes void setbinary __P((int, char **)); 939b50d902SRodney W. Grimes void setpeer __P((int, char **)); 949b50d902SRodney W. Grimes void setrexmt __P((int, char **)); 959b50d902SRodney W. Grimes void settimeout __P((int, char **)); 969b50d902SRodney W. Grimes void settrace __P((int, char **)); 979b50d902SRodney W. Grimes void setverbose __P((int, char **)); 989b50d902SRodney W. Grimes void status __P((int, char **)); 999b50d902SRodney W. Grimes 100eaa86f9dSBruce Evans static void command __P((void)) __dead2; 1019b50d902SRodney W. Grimes 1029b50d902SRodney W. Grimes static void getusage __P((char *)); 1039b50d902SRodney W. Grimes static void makeargv __P((void)); 1049b50d902SRodney W. Grimes static void putusage __P((char *)); 1059b50d902SRodney W. Grimes static void settftpmode __P((char *)); 1069b50d902SRodney W. Grimes 1079b50d902SRodney W. Grimes #define HELPINDENT (sizeof("connect")) 1089b50d902SRodney W. Grimes 1099b50d902SRodney W. Grimes struct cmd { 1109b50d902SRodney W. Grimes char *name; 1119b50d902SRodney W. Grimes char *help; 1129b50d902SRodney W. Grimes void (*handler) __P((int, char **)); 1139b50d902SRodney W. Grimes }; 1149b50d902SRodney W. Grimes 1159b50d902SRodney W. Grimes char vhelp[] = "toggle verbose mode"; 1169b50d902SRodney W. Grimes char thelp[] = "toggle packet tracing"; 1179b50d902SRodney W. Grimes char chelp[] = "connect to remote tftp"; 1189b50d902SRodney W. Grimes char qhelp[] = "exit tftp"; 1199b50d902SRodney W. Grimes char hhelp[] = "print help information"; 1209b50d902SRodney W. Grimes char shelp[] = "send file"; 1219b50d902SRodney W. Grimes char rhelp[] = "receive file"; 1229b50d902SRodney W. Grimes char mhelp[] = "set file transfer mode"; 1239b50d902SRodney W. Grimes char sthelp[] = "show current status"; 1249b50d902SRodney W. Grimes char xhelp[] = "set per-packet retransmission timeout"; 1259b50d902SRodney W. Grimes char ihelp[] = "set total retransmission timeout"; 1269b50d902SRodney W. Grimes char ashelp[] = "set mode to netascii"; 1279b50d902SRodney W. Grimes char bnhelp[] = "set mode to octet"; 1289b50d902SRodney W. Grimes 1299b50d902SRodney W. Grimes struct cmd cmdtab[] = { 1309b50d902SRodney W. Grimes { "connect", chelp, setpeer }, 1319b50d902SRodney W. Grimes { "mode", mhelp, modecmd }, 1329b50d902SRodney W. Grimes { "put", shelp, put }, 1339b50d902SRodney W. Grimes { "get", rhelp, get }, 1349b50d902SRodney W. Grimes { "quit", qhelp, quit }, 1359b50d902SRodney W. Grimes { "verbose", vhelp, setverbose }, 1369b50d902SRodney W. Grimes { "trace", thelp, settrace }, 1379b50d902SRodney W. Grimes { "status", sthelp, status }, 1389b50d902SRodney W. Grimes { "binary", bnhelp, setbinary }, 1399b50d902SRodney W. Grimes { "ascii", ashelp, setascii }, 1409b50d902SRodney W. Grimes { "rexmt", xhelp, setrexmt }, 1419b50d902SRodney W. Grimes { "timeout", ihelp, settimeout }, 1429b50d902SRodney W. Grimes { "?", hhelp, help }, 1439b50d902SRodney W. Grimes { 0 } 1449b50d902SRodney W. Grimes }; 1459b50d902SRodney W. Grimes 1469b50d902SRodney W. Grimes struct cmd *getcmd(); 1479b50d902SRodney W. Grimes char *tail(); 1489b50d902SRodney W. Grimes char *index(); 1499b50d902SRodney W. Grimes char *rindex(); 1509b50d902SRodney W. Grimes 1519b50d902SRodney W. Grimes int 1529b50d902SRodney W. Grimes main(argc, argv) 1539b50d902SRodney W. Grimes int argc; 1549b50d902SRodney W. Grimes char *argv[]; 1559b50d902SRodney W. Grimes { 1569b50d902SRodney W. Grimes struct sockaddr_in sin; 1579b50d902SRodney W. Grimes 1589b50d902SRodney W. Grimes sp = getservbyname("tftp", "udp"); 1599b50d902SRodney W. Grimes if (sp == 0) { 1609b50d902SRodney W. Grimes fprintf(stderr, "tftp: udp/tftp: unknown service\n"); 1619b50d902SRodney W. Grimes exit(1); 1629b50d902SRodney W. Grimes } 1639b50d902SRodney W. Grimes f = socket(AF_INET, SOCK_DGRAM, 0); 1649b50d902SRodney W. Grimes if (f < 0) { 1659b50d902SRodney W. Grimes perror("tftp: socket"); 1669b50d902SRodney W. Grimes exit(3); 1679b50d902SRodney W. Grimes } 1689b50d902SRodney W. Grimes bzero((char *)&sin, sizeof(sin)); 1699b50d902SRodney W. Grimes sin.sin_family = AF_INET; 1709b50d902SRodney W. Grimes if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 1719b50d902SRodney W. Grimes perror("tftp: bind"); 1729b50d902SRodney W. Grimes exit(1); 1739b50d902SRodney W. Grimes } 1749b50d902SRodney W. Grimes strcpy(mode, "netascii"); 1759b50d902SRodney W. Grimes signal(SIGINT, intr); 1769b50d902SRodney W. Grimes if (argc > 1) { 1779b50d902SRodney W. Grimes if (setjmp(toplevel) != 0) 1789b50d902SRodney W. Grimes exit(0); 1799b50d902SRodney W. Grimes setpeer(argc, argv); 1809b50d902SRodney W. Grimes } 1819b50d902SRodney W. Grimes if (setjmp(toplevel) != 0) 1829b50d902SRodney W. Grimes (void)putchar('\n'); 1839b50d902SRodney W. Grimes command(); 1849b50d902SRodney W. Grimes } 1859b50d902SRodney W. Grimes 1869b50d902SRodney W. Grimes char hostname[100]; 1879b50d902SRodney W. Grimes 1889b50d902SRodney W. Grimes void 1899b50d902SRodney W. Grimes setpeer(argc, argv) 1909b50d902SRodney W. Grimes int argc; 1919b50d902SRodney W. Grimes char *argv[]; 1929b50d902SRodney W. Grimes { 1939b50d902SRodney W. Grimes struct hostent *host; 1949b50d902SRodney W. Grimes 1959b50d902SRodney W. Grimes if (argc < 2) { 1969b50d902SRodney W. Grimes strcpy(line, "Connect "); 1979b50d902SRodney W. Grimes printf("(to) "); 198ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 1999b50d902SRodney W. Grimes makeargv(); 2009b50d902SRodney W. Grimes argc = margc; 2019b50d902SRodney W. Grimes argv = margv; 2029b50d902SRodney W. Grimes } 2039b50d902SRodney W. Grimes if (argc > 3) { 2049b50d902SRodney W. Grimes printf("usage: %s host-name [port]\n", argv[0]); 2059b50d902SRodney W. Grimes return; 2069b50d902SRodney W. Grimes } 2079b50d902SRodney W. Grimes host = gethostbyname(argv[1]); 2089b50d902SRodney W. Grimes if (host) { 2099b50d902SRodney W. Grimes peeraddr.sin_family = host->h_addrtype; 2109b50d902SRodney W. Grimes bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length); 2119b50d902SRodney W. Grimes strcpy(hostname, host->h_name); 2129b50d902SRodney W. Grimes } else { 2139b50d902SRodney W. Grimes peeraddr.sin_family = AF_INET; 2149b50d902SRodney W. Grimes peeraddr.sin_addr.s_addr = inet_addr(argv[1]); 2159b50d902SRodney W. Grimes if (peeraddr.sin_addr.s_addr == -1) { 2169b50d902SRodney W. Grimes connected = 0; 2179b50d902SRodney W. Grimes printf("%s: unknown host\n", argv[1]); 2189b50d902SRodney W. Grimes return; 2199b50d902SRodney W. Grimes } 2209b50d902SRodney W. Grimes strcpy(hostname, argv[1]); 2219b50d902SRodney W. Grimes } 2229b50d902SRodney W. Grimes port = sp->s_port; 2239b50d902SRodney W. Grimes if (argc == 3) { 2249b50d902SRodney W. Grimes port = atoi(argv[2]); 2259b50d902SRodney W. Grimes if (port < 0) { 2269b50d902SRodney W. Grimes printf("%s: bad port number\n", argv[2]); 2279b50d902SRodney W. Grimes connected = 0; 2289b50d902SRodney W. Grimes return; 2299b50d902SRodney W. Grimes } 2309b50d902SRodney W. Grimes port = htons(port); 2319b50d902SRodney W. Grimes } 2329b50d902SRodney W. Grimes connected = 1; 2339b50d902SRodney W. Grimes } 2349b50d902SRodney W. Grimes 2359b50d902SRodney W. Grimes struct modes { 2369b50d902SRodney W. Grimes char *m_name; 2379b50d902SRodney W. Grimes char *m_mode; 2389b50d902SRodney W. Grimes } modes[] = { 2399b50d902SRodney W. Grimes { "ascii", "netascii" }, 2409b50d902SRodney W. Grimes { "netascii", "netascii" }, 2419b50d902SRodney W. Grimes { "binary", "octet" }, 2429b50d902SRodney W. Grimes { "image", "octet" }, 2439b50d902SRodney W. Grimes { "octet", "octet" }, 2449b50d902SRodney W. Grimes /* { "mail", "mail" }, */ 2459b50d902SRodney W. Grimes { 0, 0 } 2469b50d902SRodney W. Grimes }; 2479b50d902SRodney W. Grimes 2489b50d902SRodney W. Grimes void 2499b50d902SRodney W. Grimes modecmd(argc, argv) 2509b50d902SRodney W. Grimes int argc; 2519b50d902SRodney W. Grimes char *argv[]; 2529b50d902SRodney W. Grimes { 2539b50d902SRodney W. Grimes register struct modes *p; 2549b50d902SRodney W. Grimes char *sep; 2559b50d902SRodney W. Grimes 2569b50d902SRodney W. Grimes if (argc < 2) { 2579b50d902SRodney W. Grimes printf("Using %s mode to transfer files.\n", mode); 2589b50d902SRodney W. Grimes return; 2599b50d902SRodney W. Grimes } 2609b50d902SRodney W. Grimes if (argc == 2) { 2619b50d902SRodney W. Grimes for (p = modes; p->m_name; p++) 2629b50d902SRodney W. Grimes if (strcmp(argv[1], p->m_name) == 0) 2639b50d902SRodney W. Grimes break; 2649b50d902SRodney W. Grimes if (p->m_name) { 2659b50d902SRodney W. Grimes settftpmode(p->m_mode); 2669b50d902SRodney W. Grimes return; 2679b50d902SRodney W. Grimes } 2689b50d902SRodney W. Grimes printf("%s: unknown mode\n", argv[1]); 2699b50d902SRodney W. Grimes /* drop through and print usage message */ 2709b50d902SRodney W. Grimes } 2719b50d902SRodney W. Grimes 2729b50d902SRodney W. Grimes printf("usage: %s [", argv[0]); 2739b50d902SRodney W. Grimes sep = " "; 2749b50d902SRodney W. Grimes for (p = modes; p->m_name; p++) { 2759b50d902SRodney W. Grimes printf("%s%s", sep, p->m_name); 2769b50d902SRodney W. Grimes if (*sep == ' ') 2779b50d902SRodney W. Grimes sep = " | "; 2789b50d902SRodney W. Grimes } 2799b50d902SRodney W. Grimes printf(" ]\n"); 2809b50d902SRodney W. Grimes return; 2819b50d902SRodney W. Grimes } 2829b50d902SRodney W. Grimes 2839b50d902SRodney W. Grimes void 2849b50d902SRodney W. Grimes setbinary(argc, argv) 2859b50d902SRodney W. Grimes int argc; 2869b50d902SRodney W. Grimes char *argv[]; 2879b50d902SRodney W. Grimes { 2889b50d902SRodney W. Grimes 2899b50d902SRodney W. Grimes settftpmode("octet"); 2909b50d902SRodney W. Grimes } 2919b50d902SRodney W. Grimes 2929b50d902SRodney W. Grimes void 2939b50d902SRodney W. Grimes setascii(argc, argv) 2949b50d902SRodney W. Grimes int argc; 2959b50d902SRodney W. Grimes char *argv[]; 2969b50d902SRodney W. Grimes { 2979b50d902SRodney W. Grimes 2989b50d902SRodney W. Grimes settftpmode("netascii"); 2999b50d902SRodney W. Grimes } 3009b50d902SRodney W. Grimes 3019b50d902SRodney W. Grimes static void 3029b50d902SRodney W. Grimes settftpmode(newmode) 3039b50d902SRodney W. Grimes char *newmode; 3049b50d902SRodney W. Grimes { 3059b50d902SRodney W. Grimes strcpy(mode, newmode); 3069b50d902SRodney W. Grimes if (verbose) 3079b50d902SRodney W. Grimes printf("mode set to %s\n", mode); 3089b50d902SRodney W. Grimes } 3099b50d902SRodney W. Grimes 3109b50d902SRodney W. Grimes 3119b50d902SRodney W. Grimes /* 3129b50d902SRodney W. Grimes * Send file(s). 3139b50d902SRodney W. Grimes */ 3149b50d902SRodney W. Grimes void 3159b50d902SRodney W. Grimes put(argc, argv) 3169b50d902SRodney W. Grimes int argc; 3179b50d902SRodney W. Grimes char *argv[]; 3189b50d902SRodney W. Grimes { 3199b50d902SRodney W. Grimes int fd; 3209b50d902SRodney W. Grimes register int n; 3219b50d902SRodney W. Grimes register char *cp, *targ; 3229b50d902SRodney W. Grimes 3239b50d902SRodney W. Grimes if (argc < 2) { 3249b50d902SRodney W. Grimes strcpy(line, "send "); 3259b50d902SRodney W. Grimes printf("(file) "); 326ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 3279b50d902SRodney W. Grimes makeargv(); 3289b50d902SRodney W. Grimes argc = margc; 3299b50d902SRodney W. Grimes argv = margv; 3309b50d902SRodney W. Grimes } 3319b50d902SRodney W. Grimes if (argc < 2) { 3329b50d902SRodney W. Grimes putusage(argv[0]); 3339b50d902SRodney W. Grimes return; 3349b50d902SRodney W. Grimes } 3359b50d902SRodney W. Grimes targ = argv[argc - 1]; 3369b50d902SRodney W. Grimes if (index(argv[argc - 1], ':')) { 3379b50d902SRodney W. Grimes char *cp; 3389b50d902SRodney W. Grimes struct hostent *hp; 3399b50d902SRodney W. Grimes 3409b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) 3419b50d902SRodney W. Grimes if (index(argv[n], ':')) { 3429b50d902SRodney W. Grimes putusage(argv[0]); 3439b50d902SRodney W. Grimes return; 3449b50d902SRodney W. Grimes } 3459b50d902SRodney W. Grimes cp = argv[argc - 1]; 3469b50d902SRodney W. Grimes targ = index(cp, ':'); 3479b50d902SRodney W. Grimes *targ++ = 0; 3489b50d902SRodney W. Grimes hp = gethostbyname(cp); 3499b50d902SRodney W. Grimes if (hp == NULL) { 3509b50d902SRodney W. Grimes fprintf(stderr, "tftp: %s: ", cp); 3519b50d902SRodney W. Grimes herror((char *)NULL); 3529b50d902SRodney W. Grimes return; 3539b50d902SRodney W. Grimes } 3549b50d902SRodney W. Grimes bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length); 3559b50d902SRodney W. Grimes peeraddr.sin_family = hp->h_addrtype; 3569b50d902SRodney W. Grimes connected = 1; 3579b50d902SRodney W. Grimes strcpy(hostname, hp->h_name); 3589b50d902SRodney W. Grimes } 3599b50d902SRodney W. Grimes if (!connected) { 3609b50d902SRodney W. Grimes printf("No target machine specified.\n"); 3619b50d902SRodney W. Grimes return; 3629b50d902SRodney W. Grimes } 3639b50d902SRodney W. Grimes if (argc < 4) { 3649b50d902SRodney W. Grimes cp = argc == 2 ? tail(targ) : argv[1]; 3659b50d902SRodney W. Grimes fd = open(cp, O_RDONLY); 3669b50d902SRodney W. Grimes if (fd < 0) { 3679b50d902SRodney W. Grimes fprintf(stderr, "tftp: "); perror(cp); 3689b50d902SRodney W. Grimes return; 3699b50d902SRodney W. Grimes } 3709b50d902SRodney W. Grimes if (verbose) 3719b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 3729b50d902SRodney W. Grimes cp, hostname, targ, mode); 3739b50d902SRodney W. Grimes peeraddr.sin_port = port; 3749b50d902SRodney W. Grimes sendfile(fd, targ, mode); 3759b50d902SRodney W. Grimes return; 3769b50d902SRodney W. Grimes } 3779b50d902SRodney W. Grimes /* this assumes the target is a directory */ 3789b50d902SRodney W. Grimes /* on a remote unix system. hmmmm. */ 3799b50d902SRodney W. Grimes cp = index(targ, '\0'); 3809b50d902SRodney W. Grimes *cp++ = '/'; 3819b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) { 3829b50d902SRodney W. Grimes strcpy(cp, tail(argv[n])); 3839b50d902SRodney W. Grimes fd = open(argv[n], O_RDONLY); 3849b50d902SRodney W. Grimes if (fd < 0) { 3859b50d902SRodney W. Grimes fprintf(stderr, "tftp: "); perror(argv[n]); 3869b50d902SRodney W. Grimes continue; 3879b50d902SRodney W. Grimes } 3889b50d902SRodney W. Grimes if (verbose) 3899b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 3909b50d902SRodney W. Grimes argv[n], hostname, targ, mode); 3919b50d902SRodney W. Grimes peeraddr.sin_port = port; 3929b50d902SRodney W. Grimes sendfile(fd, targ, mode); 3939b50d902SRodney W. Grimes } 3949b50d902SRodney W. Grimes } 3959b50d902SRodney W. Grimes 3969b50d902SRodney W. Grimes static void 3979b50d902SRodney W. Grimes putusage(s) 3989b50d902SRodney W. Grimes char *s; 3999b50d902SRodney W. Grimes { 4009b50d902SRodney W. Grimes printf("usage: %s file ... host:target, or\n", s); 4019b50d902SRodney W. Grimes printf(" %s file ... target (when already connected)\n", s); 4029b50d902SRodney W. Grimes } 4039b50d902SRodney W. Grimes 4049b50d902SRodney W. Grimes /* 4059b50d902SRodney W. Grimes * Receive file(s). 4069b50d902SRodney W. Grimes */ 4079b50d902SRodney W. Grimes void 4089b50d902SRodney W. Grimes get(argc, argv) 4099b50d902SRodney W. Grimes int argc; 4109b50d902SRodney W. Grimes char *argv[]; 4119b50d902SRodney W. Grimes { 4129b50d902SRodney W. Grimes int fd; 4139b50d902SRodney W. Grimes register int n; 4149b50d902SRodney W. Grimes register char *cp; 4159b50d902SRodney W. Grimes char *src; 4169b50d902SRodney W. Grimes 4179b50d902SRodney W. Grimes if (argc < 2) { 4189b50d902SRodney W. Grimes strcpy(line, "get "); 4199b50d902SRodney W. Grimes printf("(files) "); 420ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 4219b50d902SRodney W. Grimes makeargv(); 4229b50d902SRodney W. Grimes argc = margc; 4239b50d902SRodney W. Grimes argv = margv; 4249b50d902SRodney W. Grimes } 4259b50d902SRodney W. Grimes if (argc < 2) { 4269b50d902SRodney W. Grimes getusage(argv[0]); 4279b50d902SRodney W. Grimes return; 4289b50d902SRodney W. Grimes } 4299b50d902SRodney W. Grimes if (!connected) { 4309b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) 4319b50d902SRodney W. Grimes if (index(argv[n], ':') == 0) { 4329b50d902SRodney W. Grimes getusage(argv[0]); 4339b50d902SRodney W. Grimes return; 4349b50d902SRodney W. Grimes } 4359b50d902SRodney W. Grimes } 4369b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) { 4379b50d902SRodney W. Grimes src = index(argv[n], ':'); 4389b50d902SRodney W. Grimes if (src == NULL) 4399b50d902SRodney W. Grimes src = argv[n]; 4409b50d902SRodney W. Grimes else { 4419b50d902SRodney W. Grimes struct hostent *hp; 4429b50d902SRodney W. Grimes 4439b50d902SRodney W. Grimes *src++ = 0; 4449b50d902SRodney W. Grimes hp = gethostbyname(argv[n]); 4459b50d902SRodney W. Grimes if (hp == NULL) { 4469b50d902SRodney W. Grimes fprintf(stderr, "tftp: %s: ", argv[n]); 4479b50d902SRodney W. Grimes herror((char *)NULL); 4489b50d902SRodney W. Grimes continue; 4499b50d902SRodney W. Grimes } 4509b50d902SRodney W. Grimes bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, 4519b50d902SRodney W. Grimes hp->h_length); 4529b50d902SRodney W. Grimes peeraddr.sin_family = hp->h_addrtype; 4539b50d902SRodney W. Grimes connected = 1; 4549b50d902SRodney W. Grimes strcpy(hostname, hp->h_name); 4559b50d902SRodney W. Grimes } 4569b50d902SRodney W. Grimes if (argc < 4) { 4579b50d902SRodney W. Grimes cp = argc == 3 ? argv[2] : tail(src); 4589b50d902SRodney W. Grimes fd = creat(cp, 0644); 4599b50d902SRodney W. Grimes if (fd < 0) { 4609b50d902SRodney W. Grimes fprintf(stderr, "tftp: "); perror(cp); 4619b50d902SRodney W. Grimes return; 4629b50d902SRodney W. Grimes } 4639b50d902SRodney W. Grimes if (verbose) 4649b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 4659b50d902SRodney W. Grimes hostname, src, cp, mode); 4669b50d902SRodney W. Grimes peeraddr.sin_port = port; 4679b50d902SRodney W. Grimes recvfile(fd, src, mode); 4689b50d902SRodney W. Grimes break; 4699b50d902SRodney W. Grimes } 4709b50d902SRodney W. Grimes cp = tail(src); /* new .. jdg */ 4719b50d902SRodney W. Grimes fd = creat(cp, 0644); 4729b50d902SRodney W. Grimes if (fd < 0) { 4739b50d902SRodney W. Grimes fprintf(stderr, "tftp: "); perror(cp); 4749b50d902SRodney W. Grimes continue; 4759b50d902SRodney W. Grimes } 4769b50d902SRodney W. Grimes if (verbose) 4779b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 4789b50d902SRodney W. Grimes hostname, src, cp, mode); 4799b50d902SRodney W. Grimes peeraddr.sin_port = port; 4809b50d902SRodney W. Grimes recvfile(fd, src, mode); 4819b50d902SRodney W. Grimes } 4829b50d902SRodney W. Grimes } 4839b50d902SRodney W. Grimes 4849b50d902SRodney W. Grimes static void 4859b50d902SRodney W. Grimes getusage(s) 4869b50d902SRodney W. Grimes char *s; 4879b50d902SRodney W. Grimes { 4889b50d902SRodney W. Grimes printf("usage: %s host:file host:file ... file, or\n", s); 4899b50d902SRodney W. Grimes printf(" %s file file ... file if connected\n", s); 4909b50d902SRodney W. Grimes } 4919b50d902SRodney W. Grimes 4929b50d902SRodney W. Grimes int rexmtval = TIMEOUT; 4939b50d902SRodney W. Grimes 4949b50d902SRodney W. Grimes void 4959b50d902SRodney W. Grimes setrexmt(argc, argv) 4969b50d902SRodney W. Grimes int argc; 4979b50d902SRodney W. Grimes char *argv[]; 4989b50d902SRodney W. Grimes { 4999b50d902SRodney W. Grimes int t; 5009b50d902SRodney W. Grimes 5019b50d902SRodney W. Grimes if (argc < 2) { 5029b50d902SRodney W. Grimes strcpy(line, "Rexmt-timeout "); 5039b50d902SRodney W. Grimes printf("(value) "); 504ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 5059b50d902SRodney W. Grimes makeargv(); 5069b50d902SRodney W. Grimes argc = margc; 5079b50d902SRodney W. Grimes argv = margv; 5089b50d902SRodney W. Grimes } 5099b50d902SRodney W. Grimes if (argc != 2) { 5109b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 5119b50d902SRodney W. Grimes return; 5129b50d902SRodney W. Grimes } 5139b50d902SRodney W. Grimes t = atoi(argv[1]); 5149b50d902SRodney W. Grimes if (t < 0) 5159b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 5169b50d902SRodney W. Grimes else 5179b50d902SRodney W. Grimes rexmtval = t; 5189b50d902SRodney W. Grimes } 5199b50d902SRodney W. Grimes 5209b50d902SRodney W. Grimes int maxtimeout = 5 * TIMEOUT; 5219b50d902SRodney W. Grimes 5229b50d902SRodney W. Grimes void 5239b50d902SRodney W. Grimes settimeout(argc, argv) 5249b50d902SRodney W. Grimes int argc; 5259b50d902SRodney W. Grimes char *argv[]; 5269b50d902SRodney W. Grimes { 5279b50d902SRodney W. Grimes int t; 5289b50d902SRodney W. Grimes 5299b50d902SRodney W. Grimes if (argc < 2) { 5309b50d902SRodney W. Grimes strcpy(line, "Maximum-timeout "); 5319b50d902SRodney W. Grimes printf("(value) "); 532ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 5339b50d902SRodney W. Grimes makeargv(); 5349b50d902SRodney W. Grimes argc = margc; 5359b50d902SRodney W. Grimes argv = margv; 5369b50d902SRodney W. Grimes } 5379b50d902SRodney W. Grimes if (argc != 2) { 5389b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 5399b50d902SRodney W. Grimes return; 5409b50d902SRodney W. Grimes } 5419b50d902SRodney W. Grimes t = atoi(argv[1]); 5429b50d902SRodney W. Grimes if (t < 0) 5439b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 5449b50d902SRodney W. Grimes else 5459b50d902SRodney W. Grimes maxtimeout = t; 5469b50d902SRodney W. Grimes } 5479b50d902SRodney W. Grimes 5489b50d902SRodney W. Grimes void 5499b50d902SRodney W. Grimes status(argc, argv) 5509b50d902SRodney W. Grimes int argc; 5519b50d902SRodney W. Grimes char *argv[]; 5529b50d902SRodney W. Grimes { 5539b50d902SRodney W. Grimes if (connected) 5549b50d902SRodney W. Grimes printf("Connected to %s.\n", hostname); 5559b50d902SRodney W. Grimes else 5569b50d902SRodney W. Grimes printf("Not connected.\n"); 5579b50d902SRodney W. Grimes printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 5589b50d902SRodney W. Grimes verbose ? "on" : "off", trace ? "on" : "off"); 5599b50d902SRodney W. Grimes printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", 5609b50d902SRodney W. Grimes rexmtval, maxtimeout); 5619b50d902SRodney W. Grimes } 5629b50d902SRodney W. Grimes 5639b50d902SRodney W. Grimes void 5649b50d902SRodney W. Grimes intr() 5659b50d902SRodney W. Grimes { 5669b50d902SRodney W. Grimes 5679b50d902SRodney W. Grimes signal(SIGALRM, SIG_IGN); 5689b50d902SRodney W. Grimes alarm(0); 5699b50d902SRodney W. Grimes longjmp(toplevel, -1); 5709b50d902SRodney W. Grimes } 5719b50d902SRodney W. Grimes 5729b50d902SRodney W. Grimes char * 5739b50d902SRodney W. Grimes tail(filename) 5749b50d902SRodney W. Grimes char *filename; 5759b50d902SRodney W. Grimes { 5769b50d902SRodney W. Grimes register char *s; 5779b50d902SRodney W. Grimes 5789b50d902SRodney W. Grimes while (*filename) { 5799b50d902SRodney W. Grimes s = rindex(filename, '/'); 5809b50d902SRodney W. Grimes if (s == NULL) 5819b50d902SRodney W. Grimes break; 5829b50d902SRodney W. Grimes if (s[1]) 5839b50d902SRodney W. Grimes return (s + 1); 5849b50d902SRodney W. Grimes *s = '\0'; 5859b50d902SRodney W. Grimes } 5869b50d902SRodney W. Grimes return (filename); 5879b50d902SRodney W. Grimes } 5889b50d902SRodney W. Grimes 5899b50d902SRodney W. Grimes /* 5909b50d902SRodney W. Grimes * Command parser. 5919b50d902SRodney W. Grimes */ 592eaa86f9dSBruce Evans static void 5939b50d902SRodney W. Grimes command() 5949b50d902SRodney W. Grimes { 5959b50d902SRodney W. Grimes register struct cmd *c; 596ca22ff9eSJoerg Wunsch char *cp; 5979b50d902SRodney W. Grimes 5989b50d902SRodney W. Grimes for (;;) { 5999b50d902SRodney W. Grimes printf("%s> ", prompt); 600ca22ff9eSJoerg Wunsch if (fgets(line, sizeof line , stdin) == 0) { 6019b50d902SRodney W. Grimes if (feof(stdin)) { 6029b50d902SRodney W. Grimes exit(0); 6039b50d902SRodney W. Grimes } else { 6049b50d902SRodney W. Grimes continue; 6059b50d902SRodney W. Grimes } 6069b50d902SRodney W. Grimes } 607ca22ff9eSJoerg Wunsch if ((cp = strchr(line, '\n'))) 608ca22ff9eSJoerg Wunsch *cp = '\0'; 6099b50d902SRodney W. Grimes if (line[0] == 0) 6109b50d902SRodney W. Grimes continue; 6119b50d902SRodney W. Grimes makeargv(); 6129b50d902SRodney W. Grimes if (margc == 0) 6139b50d902SRodney W. Grimes continue; 6149b50d902SRodney W. Grimes c = getcmd(margv[0]); 6159b50d902SRodney W. Grimes if (c == (struct cmd *)-1) { 6169b50d902SRodney W. Grimes printf("?Ambiguous command\n"); 6179b50d902SRodney W. Grimes continue; 6189b50d902SRodney W. Grimes } 6199b50d902SRodney W. Grimes if (c == 0) { 6209b50d902SRodney W. Grimes printf("?Invalid command\n"); 6219b50d902SRodney W. Grimes continue; 6229b50d902SRodney W. Grimes } 6239b50d902SRodney W. Grimes (*c->handler)(margc, margv); 6249b50d902SRodney W. Grimes } 6259b50d902SRodney W. Grimes } 6269b50d902SRodney W. Grimes 6279b50d902SRodney W. Grimes struct cmd * 6289b50d902SRodney W. Grimes getcmd(name) 6299b50d902SRodney W. Grimes register char *name; 6309b50d902SRodney W. Grimes { 6319b50d902SRodney W. Grimes register char *p, *q; 6329b50d902SRodney W. Grimes register struct cmd *c, *found; 6339b50d902SRodney W. Grimes register int nmatches, longest; 6349b50d902SRodney W. Grimes 6359b50d902SRodney W. Grimes longest = 0; 6369b50d902SRodney W. Grimes nmatches = 0; 6379b50d902SRodney W. Grimes found = 0; 6389b50d902SRodney W. Grimes for (c = cmdtab; (p = c->name) != NULL; c++) { 6399b50d902SRodney W. Grimes for (q = name; *q == *p++; q++) 6409b50d902SRodney W. Grimes if (*q == 0) /* exact match? */ 6419b50d902SRodney W. Grimes return (c); 6429b50d902SRodney W. Grimes if (!*q) { /* the name was a prefix */ 6439b50d902SRodney W. Grimes if (q - name > longest) { 6449b50d902SRodney W. Grimes longest = q - name; 6459b50d902SRodney W. Grimes nmatches = 1; 6469b50d902SRodney W. Grimes found = c; 6479b50d902SRodney W. Grimes } else if (q - name == longest) 6489b50d902SRodney W. Grimes nmatches++; 6499b50d902SRodney W. Grimes } 6509b50d902SRodney W. Grimes } 6519b50d902SRodney W. Grimes if (nmatches > 1) 6529b50d902SRodney W. Grimes return ((struct cmd *)-1); 6539b50d902SRodney W. Grimes return (found); 6549b50d902SRodney W. Grimes } 6559b50d902SRodney W. Grimes 6569b50d902SRodney W. Grimes /* 6579b50d902SRodney W. Grimes * Slice a string up into argc/argv. 6589b50d902SRodney W. Grimes */ 6599b50d902SRodney W. Grimes static void 6609b50d902SRodney W. Grimes makeargv() 6619b50d902SRodney W. Grimes { 6629b50d902SRodney W. Grimes register char *cp; 6639b50d902SRodney W. Grimes register char **argp = margv; 6649b50d902SRodney W. Grimes 6659b50d902SRodney W. Grimes margc = 0; 666ca22ff9eSJoerg Wunsch if ((cp = strchr(line, '\n'))) 667ca22ff9eSJoerg Wunsch *cp = '\0'; 6689b50d902SRodney W. Grimes for (cp = line; *cp;) { 6699b50d902SRodney W. Grimes while (isspace(*cp)) 6709b50d902SRodney W. Grimes cp++; 6719b50d902SRodney W. Grimes if (*cp == '\0') 6729b50d902SRodney W. Grimes break; 6739b50d902SRodney W. Grimes *argp++ = cp; 6749b50d902SRodney W. Grimes margc += 1; 6759b50d902SRodney W. Grimes while (*cp != '\0' && !isspace(*cp)) 6769b50d902SRodney W. Grimes cp++; 6779b50d902SRodney W. Grimes if (*cp == '\0') 6789b50d902SRodney W. Grimes break; 6799b50d902SRodney W. Grimes *cp++ = '\0'; 6809b50d902SRodney W. Grimes } 6819b50d902SRodney W. Grimes *argp++ = 0; 6829b50d902SRodney W. Grimes } 6839b50d902SRodney W. Grimes 6849b50d902SRodney W. Grimes void 6859b50d902SRodney W. Grimes quit(argc, argv) 6869b50d902SRodney W. Grimes int argc; 6879b50d902SRodney W. Grimes char *argv[]; 6889b50d902SRodney W. Grimes { 6899b50d902SRodney W. Grimes 6909b50d902SRodney W. Grimes exit(0); 6919b50d902SRodney W. Grimes } 6929b50d902SRodney W. Grimes 6939b50d902SRodney W. Grimes /* 6949b50d902SRodney W. Grimes * Help command. 6959b50d902SRodney W. Grimes */ 6969b50d902SRodney W. Grimes void 6979b50d902SRodney W. Grimes help(argc, argv) 6989b50d902SRodney W. Grimes int argc; 6999b50d902SRodney W. Grimes char *argv[]; 7009b50d902SRodney W. Grimes { 7019b50d902SRodney W. Grimes register struct cmd *c; 7029b50d902SRodney W. Grimes 7039b50d902SRodney W. Grimes if (argc == 1) { 7049b50d902SRodney W. Grimes printf("Commands may be abbreviated. Commands are:\n\n"); 7059b50d902SRodney W. Grimes for (c = cmdtab; c->name; c++) 7069b50d902SRodney W. Grimes printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); 7079b50d902SRodney W. Grimes return; 7089b50d902SRodney W. Grimes } 7099b50d902SRodney W. Grimes while (--argc > 0) { 7109b50d902SRodney W. Grimes register char *arg; 7119b50d902SRodney W. Grimes arg = *++argv; 7129b50d902SRodney W. Grimes c = getcmd(arg); 7139b50d902SRodney W. Grimes if (c == (struct cmd *)-1) 7149b50d902SRodney W. Grimes printf("?Ambiguous help command %s\n", arg); 7159b50d902SRodney W. Grimes else if (c == (struct cmd *)0) 7169b50d902SRodney W. Grimes printf("?Invalid help command %s\n", arg); 7179b50d902SRodney W. Grimes else 7189b50d902SRodney W. Grimes printf("%s\n", c->help); 7199b50d902SRodney W. Grimes } 7209b50d902SRodney W. Grimes } 7219b50d902SRodney W. Grimes 7229b50d902SRodney W. Grimes void 7239b50d902SRodney W. Grimes settrace(argc, argv) 7249b50d902SRodney W. Grimes int argc; 7259b50d902SRodney W. Grimes char **argv; 7269b50d902SRodney W. Grimes { 7279b50d902SRodney W. Grimes trace = !trace; 7289b50d902SRodney W. Grimes printf("Packet tracing %s.\n", trace ? "on" : "off"); 7299b50d902SRodney W. Grimes } 7309b50d902SRodney W. Grimes 7319b50d902SRodney W. Grimes void 7329b50d902SRodney W. Grimes setverbose(argc, argv) 7339b50d902SRodney W. Grimes int argc; 7349b50d902SRodney W. Grimes char **argv; 7359b50d902SRodney W. Grimes { 7369b50d902SRodney W. Grimes verbose = !verbose; 7379b50d902SRodney W. Grimes printf("Verbose mode %s.\n", verbose ? "on" : "off"); 7389b50d902SRodney W. Grimes } 739