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> 57*752fa694SWarner Losh #include <sys/sysctl.h> 589b50d902SRodney W. Grimes #include <sys/file.h> 59a716ad66SWarner Losh #include <sys/param.h> 60*752fa694SWarner Losh #include <sys/stat.h> 619b50d902SRodney W. Grimes 629b50d902SRodney W. Grimes #include <netinet/in.h> 639b50d902SRodney W. Grimes #include <arpa/inet.h> 64*752fa694SWarner Losh #include <arpa/tftp.h> 659b50d902SRodney W. Grimes 669b50d902SRodney W. Grimes #include <ctype.h> 67fd129a02SPhilippe Charnier #include <err.h> 688979160aSBruce Evans #include <histedit.h> 699b50d902SRodney W. Grimes #include <netdb.h> 709b50d902SRodney W. Grimes #include <setjmp.h> 719b50d902SRodney W. Grimes #include <signal.h> 729b50d902SRodney W. Grimes #include <stdio.h> 739b50d902SRodney W. Grimes #include <stdlib.h> 749b50d902SRodney W. Grimes #include <string.h> 759b50d902SRodney W. Grimes #include <unistd.h> 769b50d902SRodney W. Grimes 77*752fa694SWarner Losh #include "tftp-utils.h" 78*752fa694SWarner Losh #include "tftp-io.h" 79*752fa694SWarner Losh #include "tftp-options.h" 80*752fa694SWarner Losh #include "tftp.h" 819b50d902SRodney W. Grimes 82c33ed450SMatthew N. Dodd #define MAXLINE 200 838979160aSBruce Evans #define TIMEOUT 5 /* secs between rexmt's */ 84c33ed450SMatthew N. Dodd 85*752fa694SWarner Losh static struct sockaddr_storage peeraddr; 86*752fa694SWarner Losh static int connected; 87*752fa694SWarner Losh static char mode[32]; 889b50d902SRodney W. Grimes jmp_buf toplevel; 8973f899caSBrian S. Dean volatile int txrx_error; 90*752fa694SWarner Losh static int peer; 919b50d902SRodney W. Grimes 92*752fa694SWarner Losh #define MAX_MARGV 20 93*752fa694SWarner Losh static int margc; 94*752fa694SWarner Losh static char *margv[MAX_MARGV]; 95*752fa694SWarner Losh 96*752fa694SWarner Losh int verbose; 97*752fa694SWarner Losh char *port = NULL; 98*752fa694SWarner Losh 99*752fa694SWarner Losh static void get(int, char **); 100*752fa694SWarner Losh static void help(int, char **); 101*752fa694SWarner Losh static void intr(int); 102*752fa694SWarner Losh static void modecmd(int, char **); 103*752fa694SWarner Losh static void put(int, char **); 104*752fa694SWarner Losh static void quit(int, char **); 105*752fa694SWarner Losh static void setascii(int, char **); 106*752fa694SWarner Losh static void setbinary(int, char **); 107*752fa694SWarner Losh static void setpeer0(char *, const char *); 108*752fa694SWarner Losh static void setpeer(int, char **); 109*752fa694SWarner Losh static void settimeoutpacket(int, char **); 110*752fa694SWarner Losh static void settimeoutnetwork(int, char **); 111*752fa694SWarner Losh static void setdebug(int, char **); 112*752fa694SWarner Losh static void setverbose(int, char **); 113*752fa694SWarner Losh static void showstatus(int, char **); 114*752fa694SWarner Losh static void setblocksize(int, char **); 115*752fa694SWarner Losh static void setblocksize2(int, char **); 116*752fa694SWarner Losh static void setoptions(int, char **); 117*752fa694SWarner Losh static void setrollover(int, char **); 118*752fa694SWarner Losh static void setpacketdrop(int, char **); 1199b50d902SRodney W. Grimes 1203f330d7dSWarner Losh static void command(void) __dead2; 1213f330d7dSWarner Losh static const char *command_prompt(void); 1229b50d902SRodney W. Grimes 123*752fa694SWarner Losh static void urihandling(char *URI); 124*752fa694SWarner Losh static void getusage(char *); 125*752fa694SWarner Losh static void makeargv(char *line); 126*752fa694SWarner Losh static void putusage(char *); 1273f330d7dSWarner Losh static void settftpmode(const char *); 1288049f797SMark Murray 129*752fa694SWarner Losh static char *tail(char *); 130*752fa694SWarner Losh static struct cmd *getcmd(char *); 1319b50d902SRodney W. Grimes 1329b50d902SRodney W. Grimes #define HELPINDENT (sizeof("connect")) 1339b50d902SRodney W. Grimes 1349b50d902SRodney W. Grimes struct cmd { 1358049f797SMark Murray const char *name; 1363f330d7dSWarner Losh void (*handler)(int, char **); 137*752fa694SWarner Losh const char *help; 1389b50d902SRodney W. Grimes }; 1399b50d902SRodney W. Grimes 140*752fa694SWarner Losh static struct cmd cmdtab[] = { 141*752fa694SWarner Losh { "connect", setpeer, "connect to remote tftp" }, 142*752fa694SWarner Losh { "mode", modecmd, "set file transfer mode" }, 143*752fa694SWarner Losh { "put", put, "send file" }, 144*752fa694SWarner Losh { "get", get, "receive file" }, 145*752fa694SWarner Losh { "quit", quit, "exit tftp" }, 146*752fa694SWarner Losh { "verbose", setverbose, "toggle verbose mode" }, 147*752fa694SWarner Losh { "status", showstatus, "show current status" }, 148*752fa694SWarner Losh { "binary", setbinary, "set mode to octet" }, 149*752fa694SWarner Losh { "ascii", setascii, "set mode to netascii" }, 150*752fa694SWarner Losh { "rexmt", settimeoutpacket, 151*752fa694SWarner Losh "set per-packet retransmission timeout[-]" }, 152*752fa694SWarner Losh { "timeout", settimeoutnetwork, 153*752fa694SWarner Losh "set total retransmission timeout" }, 154*752fa694SWarner Losh { "trace", setdebug, "enable 'debug packet'[-]" }, 155*752fa694SWarner Losh { "debug", setdebug, "enable verbose output" }, 156*752fa694SWarner Losh { "blocksize", setblocksize, "set blocksize[*]" }, 157*752fa694SWarner Losh { "blocksize2", setblocksize2, "set blocksize as a power of 2[**]" }, 158*752fa694SWarner Losh { "rollover", setrollover, "rollover after 64K packets[**]" }, 159*752fa694SWarner Losh { "options", setoptions, 160*752fa694SWarner Losh "enable or disable RFC2347 style options" }, 161*752fa694SWarner Losh { "help", help, "print help information" }, 162*752fa694SWarner Losh { "packetdrop", setpacketdrop, "artifical packetloss feature" }, 163*752fa694SWarner Losh { "?", help, "print help information" }, 1648049f797SMark Murray { NULL, NULL, NULL } 1659b50d902SRodney W. Grimes }; 1669b50d902SRodney W. Grimes 167*752fa694SWarner Losh static struct modes { 1688049f797SMark Murray const char *m_name; 1698049f797SMark Murray const char *m_mode; 1709b50d902SRodney W. Grimes } modes[] = { 1719b50d902SRodney W. Grimes { "ascii", "netascii" }, 1729b50d902SRodney W. Grimes { "netascii", "netascii" }, 1739b50d902SRodney W. Grimes { "binary", "octet" }, 1749b50d902SRodney W. Grimes { "image", "octet" }, 1759b50d902SRodney W. Grimes { "octet", "octet" }, 176*752fa694SWarner Losh { NULL, NULL } 1779b50d902SRodney W. Grimes }; 1789b50d902SRodney W. Grimes 179*752fa694SWarner Losh int 180*752fa694SWarner Losh main(int argc, char *argv[]) 181*752fa694SWarner Losh { 182*752fa694SWarner Losh 183*752fa694SWarner Losh acting_as_client = 1; 184*752fa694SWarner Losh peer = -1; 185*752fa694SWarner Losh strcpy(mode, "netascii"); 186*752fa694SWarner Losh signal(SIGINT, intr); 187*752fa694SWarner Losh if (argc > 1) { 188*752fa694SWarner Losh if (setjmp(toplevel) != 0) 189*752fa694SWarner Losh exit(txrx_error); 190*752fa694SWarner Losh 191*752fa694SWarner Losh if (strncmp(argv[1], "tftp://", 7) == 0) { 192*752fa694SWarner Losh urihandling(argv[1]); 193*752fa694SWarner Losh exit(txrx_error); 194*752fa694SWarner Losh } 195*752fa694SWarner Losh 196*752fa694SWarner Losh setpeer(argc, argv); 197*752fa694SWarner Losh } 198*752fa694SWarner Losh if (setjmp(toplevel) != 0) 199*752fa694SWarner Losh (void)putchar('\n'); 200*752fa694SWarner Losh 201*752fa694SWarner Losh init_options(); 202*752fa694SWarner Losh command(); 203*752fa694SWarner Losh } 204*752fa694SWarner Losh 205*752fa694SWarner Losh /* 206*752fa694SWarner Losh * RFC3617 handling of TFTP URIs: 207*752fa694SWarner Losh * 208*752fa694SWarner Losh * tftpURI = "tftp://" host "/" file [ mode ] 209*752fa694SWarner Losh * mode = ";" "mode=" ( "netascii" / "octet" ) 210*752fa694SWarner Losh * file = *( unreserved / escaped ) 211*752fa694SWarner Losh * host = <as specified by RFC 2732> 212*752fa694SWarner Losh * unreserved = <as specified in RFC 2396> 213*752fa694SWarner Losh * escaped = <as specified in RFC 2396> 214*752fa694SWarner Losh * 215*752fa694SWarner Losh * We are cheating a little bit by allowing any mode as specified in the 216*752fa694SWarner Losh * modes table defined earlier on in this file and mapping it on the real 217*752fa694SWarner Losh * mode. 218*752fa694SWarner Losh */ 219*752fa694SWarner Losh static void 220*752fa694SWarner Losh urihandling(char *URI) 221*752fa694SWarner Losh { 222*752fa694SWarner Losh char uri[ARG_MAX]; 223*752fa694SWarner Losh char *host = NULL; 224*752fa694SWarner Losh char *path = NULL; 225*752fa694SWarner Losh char *options = NULL; 226*752fa694SWarner Losh char *mode = "octet"; 227*752fa694SWarner Losh char *s; 228*752fa694SWarner Losh char line[MAXLINE]; 229*752fa694SWarner Losh int i; 230*752fa694SWarner Losh 231*752fa694SWarner Losh strncpy(uri, URI, ARG_MAX); 232*752fa694SWarner Losh host = uri + 7; 233*752fa694SWarner Losh 234*752fa694SWarner Losh if ((s = strchr(host, '/')) == NULL) { 235*752fa694SWarner Losh fprintf(stderr, 236*752fa694SWarner Losh "Invalid URI: Couldn't find / after hostname\n"); 237*752fa694SWarner Losh exit(1); 238*752fa694SWarner Losh } 239*752fa694SWarner Losh *s = '\0'; 240*752fa694SWarner Losh path = s + 1; 241*752fa694SWarner Losh 242*752fa694SWarner Losh if ((s = strchr(path, ';')) != NULL) { 243*752fa694SWarner Losh *s = '\0'; 244*752fa694SWarner Losh options = s + 1; 245*752fa694SWarner Losh 246*752fa694SWarner Losh if (strncmp(options, "mode=", 5) == 0) { 247*752fa694SWarner Losh mode = options; 248*752fa694SWarner Losh mode += 5; 249*752fa694SWarner Losh 250*752fa694SWarner Losh for (i = 0; modes[i].m_name != NULL; i++) { 251*752fa694SWarner Losh if (strcmp(modes[i].m_name, mode) == 0) 252*752fa694SWarner Losh break; 253*752fa694SWarner Losh } 254*752fa694SWarner Losh if (modes[i].m_name == NULL) { 255*752fa694SWarner Losh fprintf(stderr, "Invalid mode: '%s'\n", mode); 256*752fa694SWarner Losh exit(1); 257*752fa694SWarner Losh } 258*752fa694SWarner Losh settftpmode(modes[i].m_mode); 259*752fa694SWarner Losh } 260*752fa694SWarner Losh } else { 261*752fa694SWarner Losh settftpmode("octet"); 262*752fa694SWarner Losh } 263*752fa694SWarner Losh 264*752fa694SWarner Losh setpeer0(host, NULL); 265*752fa694SWarner Losh 266*752fa694SWarner Losh sprintf(line, "get %s", path); 267*752fa694SWarner Losh makeargv(line); 268*752fa694SWarner Losh get(margc, margv); 269*752fa694SWarner Losh } 270*752fa694SWarner Losh 271*752fa694SWarner Losh static char hostname[MAXHOSTNAMELEN]; 272*752fa694SWarner Losh 273*752fa694SWarner Losh static void 274*752fa694SWarner Losh setpeer0(char *host, const char *lport) 275*752fa694SWarner Losh { 276*752fa694SWarner Losh struct addrinfo hints, *res0, *res; 277*752fa694SWarner Losh int error; 278*752fa694SWarner Losh const char *cause = "unknown"; 279*752fa694SWarner Losh 280*752fa694SWarner Losh if (connected) { 281*752fa694SWarner Losh close(peer); 282*752fa694SWarner Losh peer = -1; 283*752fa694SWarner Losh } 284*752fa694SWarner Losh connected = 0; 285*752fa694SWarner Losh 286*752fa694SWarner Losh memset(&hints, 0, sizeof(hints)); 287*752fa694SWarner Losh hints.ai_family = PF_UNSPEC; 288*752fa694SWarner Losh hints.ai_socktype = SOCK_DGRAM; 289*752fa694SWarner Losh hints.ai_protocol = IPPROTO_UDP; 290*752fa694SWarner Losh hints.ai_flags = AI_CANONNAME; 291*752fa694SWarner Losh if (!lport) 292*752fa694SWarner Losh lport = "tftp"; 293*752fa694SWarner Losh error = getaddrinfo(host, lport, &hints, &res0); 294*752fa694SWarner Losh if (error) { 295*752fa694SWarner Losh warnx("%s", gai_strerror(error)); 296*752fa694SWarner Losh return; 297*752fa694SWarner Losh } 298*752fa694SWarner Losh 299*752fa694SWarner Losh for (res = res0; res; res = res->ai_next) { 300*752fa694SWarner Losh if (res->ai_addrlen > sizeof(peeraddr)) 301*752fa694SWarner Losh continue; 302*752fa694SWarner Losh peer = socket(res->ai_family, res->ai_socktype, 303*752fa694SWarner Losh res->ai_protocol); 304*752fa694SWarner Losh if (peer < 0) { 305*752fa694SWarner Losh cause = "socket"; 306*752fa694SWarner Losh continue; 307*752fa694SWarner Losh } 308*752fa694SWarner Losh 309*752fa694SWarner Losh memset(&peer_sock, 0, sizeof(peer_sock)); 310*752fa694SWarner Losh peer_sock.ss_family = res->ai_family; 311*752fa694SWarner Losh peer_sock.ss_len = res->ai_addrlen; 312*752fa694SWarner Losh if (bind(peer, (struct sockaddr *)&peer_sock, peer_sock.ss_len) < 0) { 313*752fa694SWarner Losh cause = "bind"; 314*752fa694SWarner Losh close(peer); 315*752fa694SWarner Losh peer = -1; 316*752fa694SWarner Losh continue; 317*752fa694SWarner Losh } 318*752fa694SWarner Losh 319*752fa694SWarner Losh break; 320*752fa694SWarner Losh } 321*752fa694SWarner Losh 322*752fa694SWarner Losh if (peer < 0) 323*752fa694SWarner Losh warn("%s", cause); 324*752fa694SWarner Losh else { 325*752fa694SWarner Losh /* res->ai_addr <= sizeof(peeraddr) is guaranteed */ 326*752fa694SWarner Losh memcpy(&peer_sock, res->ai_addr, res->ai_addrlen); 327*752fa694SWarner Losh if (res->ai_canonname) { 328*752fa694SWarner Losh (void) strncpy(hostname, res->ai_canonname, 329*752fa694SWarner Losh sizeof(hostname)); 330*752fa694SWarner Losh } else 331*752fa694SWarner Losh (void) strncpy(hostname, host, sizeof(hostname)); 332*752fa694SWarner Losh hostname[sizeof(hostname)-1] = 0; 333*752fa694SWarner Losh connected = 1; 334*752fa694SWarner Losh } 335*752fa694SWarner Losh 336*752fa694SWarner Losh freeaddrinfo(res0); 337*752fa694SWarner Losh } 338*752fa694SWarner Losh 339*752fa694SWarner Losh static void 340*752fa694SWarner Losh setpeer(int argc, char *argv[]) 341*752fa694SWarner Losh { 342*752fa694SWarner Losh char line[MAXLINE]; 343*752fa694SWarner Losh 344*752fa694SWarner Losh if (argc < 2) { 345*752fa694SWarner Losh strcpy(line, "Connect "); 346*752fa694SWarner Losh printf("(to) "); 347*752fa694SWarner Losh fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 348*752fa694SWarner Losh makeargv(line); 349*752fa694SWarner Losh argc = margc; 350*752fa694SWarner Losh argv = margv; 351*752fa694SWarner Losh } 352*752fa694SWarner Losh if ((argc < 2) || (argc > 3)) { 353*752fa694SWarner Losh printf("usage: %s [host [port]]\n", argv[0]); 354*752fa694SWarner Losh return; 355*752fa694SWarner Losh } 356*752fa694SWarner Losh if (argc == 3) { 357*752fa694SWarner Losh port = argv[2]; 358*752fa694SWarner Losh setpeer0(argv[1], argv[2]); 359*752fa694SWarner Losh } else 360*752fa694SWarner Losh setpeer0(argv[1], NULL); 361*752fa694SWarner Losh } 362*752fa694SWarner Losh 363*752fa694SWarner Losh static void 3641b0fa6faSXin LI modecmd(int argc, char *argv[]) 3659b50d902SRodney W. Grimes { 3668049f797SMark Murray struct modes *p; 3678049f797SMark Murray const char *sep; 3689b50d902SRodney W. Grimes 3699b50d902SRodney W. Grimes if (argc < 2) { 3709b50d902SRodney W. Grimes printf("Using %s mode to transfer files.\n", mode); 3719b50d902SRodney W. Grimes return; 3729b50d902SRodney W. Grimes } 3739b50d902SRodney W. Grimes if (argc == 2) { 3749b50d902SRodney W. Grimes for (p = modes; p->m_name; p++) 3759b50d902SRodney W. Grimes if (strcmp(argv[1], p->m_name) == 0) 3769b50d902SRodney W. Grimes break; 3779b50d902SRodney W. Grimes if (p->m_name) { 3789b50d902SRodney W. Grimes settftpmode(p->m_mode); 3799b50d902SRodney W. Grimes return; 3809b50d902SRodney W. Grimes } 3819b50d902SRodney W. Grimes printf("%s: unknown mode\n", argv[1]); 3829b50d902SRodney W. Grimes /* drop through and print usage message */ 3839b50d902SRodney W. Grimes } 3849b50d902SRodney W. Grimes 3859b50d902SRodney W. Grimes printf("usage: %s [", argv[0]); 3869b50d902SRodney W. Grimes sep = " "; 387*752fa694SWarner Losh for (p = modes; p->m_name != NULL; p++) { 3889b50d902SRodney W. Grimes printf("%s%s", sep, p->m_name); 3899b50d902SRodney W. Grimes if (*sep == ' ') 3909b50d902SRodney W. Grimes sep = " | "; 3919b50d902SRodney W. Grimes } 3929b50d902SRodney W. Grimes printf(" ]\n"); 3939b50d902SRodney W. Grimes return; 3949b50d902SRodney W. Grimes } 3959b50d902SRodney W. Grimes 396*752fa694SWarner Losh static void 3971b0fa6faSXin LI setbinary(int argc __unused, char *argv[] __unused) 3989b50d902SRodney W. Grimes { 3999b50d902SRodney W. Grimes 4009b50d902SRodney W. Grimes settftpmode("octet"); 4019b50d902SRodney W. Grimes } 4029b50d902SRodney W. Grimes 403*752fa694SWarner Losh static void 4041b0fa6faSXin LI setascii(int argc __unused, char *argv[] __unused) 4059b50d902SRodney W. Grimes { 4069b50d902SRodney W. Grimes 4079b50d902SRodney W. Grimes settftpmode("netascii"); 4089b50d902SRodney W. Grimes } 4099b50d902SRodney W. Grimes 4109b50d902SRodney W. Grimes static void 4111b0fa6faSXin LI settftpmode(const char *newmode) 4129b50d902SRodney W. Grimes { 413*752fa694SWarner Losh 4149b50d902SRodney W. Grimes strcpy(mode, newmode); 4159b50d902SRodney W. Grimes if (verbose) 4169b50d902SRodney W. Grimes printf("mode set to %s\n", mode); 4179b50d902SRodney W. Grimes } 4189b50d902SRodney W. Grimes 4199b50d902SRodney W. Grimes 4209b50d902SRodney W. Grimes /* 4219b50d902SRodney W. Grimes * Send file(s). 4229b50d902SRodney W. Grimes */ 423*752fa694SWarner Losh static void 4241b0fa6faSXin LI put(int argc, char *argv[]) 4259b50d902SRodney W. Grimes { 4269b50d902SRodney W. Grimes int fd; 4278049f797SMark Murray int n; 4288049f797SMark Murray char *cp, *targ; 429*752fa694SWarner Losh char line[MAXLINE]; 430*752fa694SWarner Losh struct stat sb; 4319b50d902SRodney W. Grimes 4329b50d902SRodney W. Grimes if (argc < 2) { 4339b50d902SRodney W. Grimes strcpy(line, "send "); 4349b50d902SRodney W. Grimes printf("(file) "); 435ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 436*752fa694SWarner Losh makeargv(line); 4379b50d902SRodney W. Grimes argc = margc; 4389b50d902SRodney W. Grimes argv = margv; 4399b50d902SRodney W. Grimes } 4409b50d902SRodney W. Grimes if (argc < 2) { 4419b50d902SRodney W. Grimes putusage(argv[0]); 4429b50d902SRodney W. Grimes return; 4439b50d902SRodney W. Grimes } 4449b50d902SRodney W. Grimes targ = argv[argc - 1]; 4454dac6235SHajimu UMEMOTO if (rindex(argv[argc - 1], ':')) { 4468049f797SMark Murray char *lcp; 4479b50d902SRodney W. Grimes 4489b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) 4499b50d902SRodney W. Grimes if (index(argv[n], ':')) { 4509b50d902SRodney W. Grimes putusage(argv[0]); 4519b50d902SRodney W. Grimes return; 4529b50d902SRodney W. Grimes } 4538049f797SMark Murray lcp = argv[argc - 1]; 4544dac6235SHajimu UMEMOTO targ = rindex(lcp, ':'); 4559b50d902SRodney W. Grimes *targ++ = 0; 4564dac6235SHajimu UMEMOTO if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') { 4574dac6235SHajimu UMEMOTO lcp[strlen(lcp) - 1] = '\0'; 4584dac6235SHajimu UMEMOTO lcp++; 4599b50d902SRodney W. Grimes } 4604dac6235SHajimu UMEMOTO setpeer0(lcp, NULL); 4619b50d902SRodney W. Grimes } 4629b50d902SRodney W. Grimes if (!connected) { 4639b50d902SRodney W. Grimes printf("No target machine specified.\n"); 4649b50d902SRodney W. Grimes return; 4659b50d902SRodney W. Grimes } 4669b50d902SRodney W. Grimes if (argc < 4) { 4679b50d902SRodney W. Grimes cp = argc == 2 ? tail(targ) : argv[1]; 4689b50d902SRodney W. Grimes fd = open(cp, O_RDONLY); 4699b50d902SRodney W. Grimes if (fd < 0) { 470fd129a02SPhilippe Charnier warn("%s", cp); 4719b50d902SRodney W. Grimes return; 4729b50d902SRodney W. Grimes } 473*752fa694SWarner Losh 474*752fa694SWarner Losh stat(cp, &sb); 475*752fa694SWarner Losh asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size); 476*752fa694SWarner Losh 4779b50d902SRodney W. Grimes if (verbose) 4789b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 4799b50d902SRodney W. Grimes cp, hostname, targ, mode); 480*752fa694SWarner Losh xmitfile(peer, port, fd, targ, mode); 4819b50d902SRodney W. Grimes return; 4829b50d902SRodney W. Grimes } 4839b50d902SRodney W. Grimes /* this assumes the target is a directory */ 4849b50d902SRodney W. Grimes /* on a remote unix system. hmmmm. */ 4859b50d902SRodney W. Grimes cp = index(targ, '\0'); 4869b50d902SRodney W. Grimes *cp++ = '/'; 4879b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) { 4889b50d902SRodney W. Grimes strcpy(cp, tail(argv[n])); 4899b50d902SRodney W. Grimes fd = open(argv[n], O_RDONLY); 4909b50d902SRodney W. Grimes if (fd < 0) { 491fd129a02SPhilippe Charnier warn("%s", argv[n]); 4929b50d902SRodney W. Grimes continue; 4939b50d902SRodney W. Grimes } 494*752fa694SWarner Losh 495*752fa694SWarner Losh stat(cp, &sb); 496*752fa694SWarner Losh asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size); 497*752fa694SWarner Losh 4989b50d902SRodney W. Grimes if (verbose) 4999b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 5009b50d902SRodney W. Grimes argv[n], hostname, targ, mode); 501*752fa694SWarner Losh xmitfile(peer, port, fd, targ, mode); 5029b50d902SRodney W. Grimes } 5039b50d902SRodney W. Grimes } 5049b50d902SRodney W. Grimes 5059b50d902SRodney W. Grimes static void 506*752fa694SWarner Losh putusage(char *s) 5079b50d902SRodney W. Grimes { 508*752fa694SWarner Losh 509*752fa694SWarner Losh printf("usage: %s file [remotename]\n", s); 510*752fa694SWarner Losh printf(" %s file host:remotename\n", s); 511891ca8cfSSimon L. B. Nielsen printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s); 5129b50d902SRodney W. Grimes } 5139b50d902SRodney W. Grimes 5149b50d902SRodney W. Grimes /* 5159b50d902SRodney W. Grimes * Receive file(s). 5169b50d902SRodney W. Grimes */ 517*752fa694SWarner Losh static void 5181b0fa6faSXin LI get(int argc, char *argv[]) 5199b50d902SRodney W. Grimes { 5209b50d902SRodney W. Grimes int fd; 5218049f797SMark Murray int n; 5228049f797SMark Murray char *cp; 5239b50d902SRodney W. Grimes char *src; 524*752fa694SWarner Losh char line[MAXLINE]; 5259b50d902SRodney W. Grimes 5269b50d902SRodney W. Grimes if (argc < 2) { 5279b50d902SRodney W. Grimes strcpy(line, "get "); 5289b50d902SRodney W. Grimes printf("(files) "); 529ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 530*752fa694SWarner Losh makeargv(line); 5319b50d902SRodney W. Grimes argc = margc; 5329b50d902SRodney W. Grimes argv = margv; 5339b50d902SRodney W. Grimes } 5349b50d902SRodney W. Grimes if (argc < 2) { 5359b50d902SRodney W. Grimes getusage(argv[0]); 5369b50d902SRodney W. Grimes return; 5379b50d902SRodney W. Grimes } 5389b50d902SRodney W. Grimes if (!connected) { 5399b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) 5404dac6235SHajimu UMEMOTO if (rindex(argv[n], ':') == 0) { 541*752fa694SWarner Losh printf("No remote host specified and " 542*752fa694SWarner Losh "no host given for file '%s'\n", argv[n]); 5439b50d902SRodney W. Grimes getusage(argv[0]); 5449b50d902SRodney W. Grimes return; 5459b50d902SRodney W. Grimes } 5469b50d902SRodney W. Grimes } 5479b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) { 5484dac6235SHajimu UMEMOTO src = rindex(argv[n], ':'); 5499b50d902SRodney W. Grimes if (src == NULL) 5509b50d902SRodney W. Grimes src = argv[n]; 5519b50d902SRodney W. Grimes else { 5524dac6235SHajimu UMEMOTO char *lcp; 5539b50d902SRodney W. Grimes 5549b50d902SRodney W. Grimes *src++ = 0; 5554dac6235SHajimu UMEMOTO lcp = argv[n]; 5564dac6235SHajimu UMEMOTO if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') { 5574dac6235SHajimu UMEMOTO lcp[strlen(lcp) - 1] = '\0'; 5584dac6235SHajimu UMEMOTO lcp++; 5599b50d902SRodney W. Grimes } 5604dac6235SHajimu UMEMOTO setpeer0(lcp, NULL); 5614dac6235SHajimu UMEMOTO if (!connected) 5624dac6235SHajimu UMEMOTO continue; 5639b50d902SRodney W. Grimes } 5649b50d902SRodney W. Grimes if (argc < 4) { 5659b50d902SRodney W. Grimes cp = argc == 3 ? argv[2] : tail(src); 5669b50d902SRodney W. Grimes fd = creat(cp, 0644); 5679b50d902SRodney W. Grimes if (fd < 0) { 568fd129a02SPhilippe Charnier warn("%s", cp); 5699b50d902SRodney W. Grimes return; 5709b50d902SRodney W. Grimes } 5719b50d902SRodney W. Grimes if (verbose) 5729b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 5739b50d902SRodney W. Grimes hostname, src, cp, mode); 574*752fa694SWarner Losh recvfile(peer, port, fd, src, mode); 5759b50d902SRodney W. Grimes break; 5769b50d902SRodney W. Grimes } 5779b50d902SRodney W. Grimes cp = tail(src); /* new .. jdg */ 5789b50d902SRodney W. Grimes fd = creat(cp, 0644); 5799b50d902SRodney W. Grimes if (fd < 0) { 580fd129a02SPhilippe Charnier warn("%s", cp); 5819b50d902SRodney W. Grimes continue; 5829b50d902SRodney W. Grimes } 5839b50d902SRodney W. Grimes if (verbose) 5849b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 5859b50d902SRodney W. Grimes hostname, src, cp, mode); 586*752fa694SWarner Losh recvfile(peer, port, fd, src, mode); 5879b50d902SRodney W. Grimes } 5889b50d902SRodney W. Grimes } 5899b50d902SRodney W. Grimes 5909b50d902SRodney W. Grimes static void 591*752fa694SWarner Losh getusage(char *s) 5929b50d902SRodney W. Grimes { 593*752fa694SWarner Losh 594*752fa694SWarner Losh printf("usage: %s file [localname]\n", s); 595*752fa694SWarner Losh printf(" %s [host:]file [localname]\n", s); 596891ca8cfSSimon L. B. Nielsen printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s); 5979b50d902SRodney W. Grimes } 5989b50d902SRodney W. Grimes 599*752fa694SWarner Losh static void 600*752fa694SWarner Losh settimeoutpacket(int argc, char *argv[]) 6019b50d902SRodney W. Grimes { 6029b50d902SRodney W. Grimes int t; 603*752fa694SWarner Losh char line[MAXLINE]; 6049b50d902SRodney W. Grimes 6059b50d902SRodney W. Grimes if (argc < 2) { 606*752fa694SWarner Losh strcpy(line, "Packet timeout "); 6079b50d902SRodney W. Grimes printf("(value) "); 608ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 609*752fa694SWarner Losh makeargv(line); 6109b50d902SRodney W. Grimes argc = margc; 6119b50d902SRodney W. Grimes argv = margv; 6129b50d902SRodney W. Grimes } 6139b50d902SRodney W. Grimes if (argc != 2) { 6149b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 6159b50d902SRodney W. Grimes return; 6169b50d902SRodney W. Grimes } 6179b50d902SRodney W. Grimes t = atoi(argv[1]); 618*752fa694SWarner Losh if (t < 0) { 6199b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 620*752fa694SWarner Losh return; 6219b50d902SRodney W. Grimes } 6229b50d902SRodney W. Grimes 623*752fa694SWarner Losh settimeouts(t, timeoutnetwork, maxtimeouts); 624*752fa694SWarner Losh } 6259b50d902SRodney W. Grimes 626*752fa694SWarner Losh static void 627*752fa694SWarner Losh settimeoutnetwork(int argc, char *argv[]) 6289b50d902SRodney W. Grimes { 6299b50d902SRodney W. Grimes int t; 630*752fa694SWarner Losh char line[MAXLINE]; 6319b50d902SRodney W. Grimes 6329b50d902SRodney W. Grimes if (argc < 2) { 633*752fa694SWarner Losh strcpy(line, "Network timeout "); 6349b50d902SRodney W. Grimes printf("(value) "); 635ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 636*752fa694SWarner Losh makeargv(line); 6379b50d902SRodney W. Grimes argc = margc; 6389b50d902SRodney W. Grimes argv = margv; 6399b50d902SRodney W. Grimes } 6409b50d902SRodney W. Grimes if (argc != 2) { 6419b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 6429b50d902SRodney W. Grimes return; 6439b50d902SRodney W. Grimes } 6449b50d902SRodney W. Grimes t = atoi(argv[1]); 645*752fa694SWarner Losh if (t < 0) { 6469b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 647*752fa694SWarner Losh return; 6489b50d902SRodney W. Grimes } 6499b50d902SRodney W. Grimes 650*752fa694SWarner Losh settimeouts(timeoutpacket, t, maxtimeouts); 651*752fa694SWarner Losh } 652*752fa694SWarner Losh 653*752fa694SWarner Losh static void 654*752fa694SWarner Losh showstatus(int argc __unused, char *argv[] __unused) 6559b50d902SRodney W. Grimes { 656*752fa694SWarner Losh 657*752fa694SWarner Losh printf("Remote host: %s\n", 658*752fa694SWarner Losh connected ? hostname : "none specified yet"); 659*752fa694SWarner Losh printf("RFC2347 Options support: %s\n", 660*752fa694SWarner Losh options_rfc_enabled ? "enabled" : "disabled"); 661*752fa694SWarner Losh printf("Non-RFC defined options support: %s\n", 662*752fa694SWarner Losh options_extra_enabled ? "enabled" : "disabled"); 663*752fa694SWarner Losh printf("Mode: %s\n", mode); 664*752fa694SWarner Losh printf("Verbose: %s\n", verbose ? "on" : "off"); 665*752fa694SWarner Losh printf("Debug: %s\n", debug_show(debug)); 666*752fa694SWarner Losh printf("Artificial packetloss: %d in 100 packets\n", 667*752fa694SWarner Losh packetdroppercentage); 668*752fa694SWarner Losh printf("Segment size: %d bytes\n", segsize); 669*752fa694SWarner Losh printf("Network timeout: %d seconds\n", timeoutpacket); 670*752fa694SWarner Losh printf("Maximum network timeout: %d seconds\n", timeoutnetwork); 671*752fa694SWarner Losh printf("Maximum timeouts: %d \n", maxtimeouts); 6729b50d902SRodney W. Grimes } 6739b50d902SRodney W. Grimes 674*752fa694SWarner Losh static void 6751b0fa6faSXin LI intr(int dummy __unused) 6769b50d902SRodney W. Grimes { 6779b50d902SRodney W. Grimes 6789b50d902SRodney W. Grimes signal(SIGALRM, SIG_IGN); 6799b50d902SRodney W. Grimes alarm(0); 6809b50d902SRodney W. Grimes longjmp(toplevel, -1); 6819b50d902SRodney W. Grimes } 6829b50d902SRodney W. Grimes 683*752fa694SWarner Losh static char * 6841b0fa6faSXin LI tail(char *filename) 6859b50d902SRodney W. Grimes { 6868049f797SMark Murray char *s; 6879b50d902SRodney W. Grimes 6889b50d902SRodney W. Grimes while (*filename) { 6899b50d902SRodney W. Grimes s = rindex(filename, '/'); 6909b50d902SRodney W. Grimes if (s == NULL) 6919b50d902SRodney W. Grimes break; 6929b50d902SRodney W. Grimes if (s[1]) 6939b50d902SRodney W. Grimes return (s + 1); 6949b50d902SRodney W. Grimes *s = '\0'; 6959b50d902SRodney W. Grimes } 6969b50d902SRodney W. Grimes return (filename); 6979b50d902SRodney W. Grimes } 6989b50d902SRodney W. Grimes 699c33ed450SMatthew N. Dodd static const char * 700*752fa694SWarner Losh command_prompt() 7018979160aSBruce Evans { 7028979160aSBruce Evans 703c33ed450SMatthew N. Dodd return ("tftp> "); 704c33ed450SMatthew N. Dodd } 705c33ed450SMatthew N. Dodd 7069b50d902SRodney W. Grimes /* 7079b50d902SRodney W. Grimes * Command parser. 7089b50d902SRodney W. Grimes */ 709eaa86f9dSBruce Evans static void 7101b0fa6faSXin LI command(void) 7119b50d902SRodney W. Grimes { 712c33ed450SMatthew N. Dodd HistEvent he; 7138049f797SMark Murray struct cmd *c; 7148979160aSBruce Evans static EditLine *el; 7158979160aSBruce Evans static History *hist; 716c33ed450SMatthew N. Dodd const char *bp; 7178979160aSBruce Evans char *cp; 7188049f797SMark Murray int len, num, vrbose; 719*752fa694SWarner Losh char line[MAXLINE]; 720c33ed450SMatthew N. Dodd 7218049f797SMark Murray vrbose = isatty(0); 7228049f797SMark Murray if (vrbose) { 723c33ed450SMatthew N. Dodd el = el_init("tftp", stdin, stdout, stderr); 724c33ed450SMatthew N. Dodd hist = history_init(); 7252110d9c3SStefan Farfeleder history(hist, &he, H_SETSIZE, 100); 726c33ed450SMatthew N. Dodd el_set(el, EL_HIST, history, hist); 727c33ed450SMatthew N. Dodd el_set(el, EL_EDITOR, "emacs"); 728c33ed450SMatthew N. Dodd el_set(el, EL_PROMPT, command_prompt); 729c33ed450SMatthew N. Dodd el_set(el, EL_SIGNAL, 1); 730c33ed450SMatthew N. Dodd el_source(el, NULL); 731c33ed450SMatthew N. Dodd } 7329b50d902SRodney W. Grimes for (;;) { 7338049f797SMark Murray if (vrbose) { 734c33ed450SMatthew N. Dodd if ((bp = el_gets(el, &num)) == NULL || num == 0) 735c33ed450SMatthew N. Dodd exit(0); 736c33ed450SMatthew N. Dodd len = (num > MAXLINE) ? MAXLINE : num; 737c33ed450SMatthew N. Dodd memcpy(line, bp, len); 738c33ed450SMatthew N. Dodd line[len] = '\0'; 739c33ed450SMatthew N. Dodd history(hist, &he, H_ENTER, bp); 740c33ed450SMatthew N. Dodd } else { 741*752fa694SWarner Losh line[0] = 0; 742ca22ff9eSJoerg Wunsch if (fgets(line, sizeof line , stdin) == 0) { 7439b50d902SRodney W. Grimes if (feof(stdin)) { 74473f899caSBrian S. Dean exit(txrx_error); 7459b50d902SRodney W. Grimes } else { 7469b50d902SRodney W. Grimes continue; 7479b50d902SRodney W. Grimes } 7489b50d902SRodney W. Grimes } 749c33ed450SMatthew N. Dodd } 750ca22ff9eSJoerg Wunsch if ((cp = strchr(line, '\n'))) 751ca22ff9eSJoerg Wunsch *cp = '\0'; 7529b50d902SRodney W. Grimes if (line[0] == 0) 7539b50d902SRodney W. Grimes continue; 754*752fa694SWarner Losh makeargv(line); 7559b50d902SRodney W. Grimes if (margc == 0) 7569b50d902SRodney W. Grimes continue; 7579b50d902SRodney W. Grimes c = getcmd(margv[0]); 7589b50d902SRodney W. Grimes if (c == (struct cmd *)-1) { 7599b50d902SRodney W. Grimes printf("?Ambiguous command\n"); 7609b50d902SRodney W. Grimes continue; 7619b50d902SRodney W. Grimes } 7629b50d902SRodney W. Grimes if (c == 0) { 7639b50d902SRodney W. Grimes printf("?Invalid command\n"); 7649b50d902SRodney W. Grimes continue; 7659b50d902SRodney W. Grimes } 7669b50d902SRodney W. Grimes (*c->handler)(margc, margv); 7679b50d902SRodney W. Grimes } 7689b50d902SRodney W. Grimes } 7699b50d902SRodney W. Grimes 770*752fa694SWarner Losh static struct cmd * 7711b0fa6faSXin LI getcmd(char *name) 7729b50d902SRodney W. Grimes { 7738049f797SMark Murray const char *p, *q; 7748049f797SMark Murray struct cmd *c, *found; 7758049f797SMark Murray int nmatches, longest; 7769b50d902SRodney W. Grimes 7779b50d902SRodney W. Grimes longest = 0; 7789b50d902SRodney W. Grimes nmatches = 0; 7799b50d902SRodney W. Grimes found = 0; 7809b50d902SRodney W. Grimes for (c = cmdtab; (p = c->name) != NULL; c++) { 7819b50d902SRodney W. Grimes for (q = name; *q == *p++; q++) 7829b50d902SRodney W. Grimes if (*q == 0) /* exact match? */ 7839b50d902SRodney W. Grimes return (c); 7849b50d902SRodney W. Grimes if (!*q) { /* the name was a prefix */ 7859b50d902SRodney W. Grimes if (q - name > longest) { 7869b50d902SRodney W. Grimes longest = q - name; 7879b50d902SRodney W. Grimes nmatches = 1; 7889b50d902SRodney W. Grimes found = c; 7899b50d902SRodney W. Grimes } else if (q - name == longest) 7909b50d902SRodney W. Grimes nmatches++; 7919b50d902SRodney W. Grimes } 7929b50d902SRodney W. Grimes } 7939b50d902SRodney W. Grimes if (nmatches > 1) 7949b50d902SRodney W. Grimes return ((struct cmd *)-1); 7959b50d902SRodney W. Grimes return (found); 7969b50d902SRodney W. Grimes } 7979b50d902SRodney W. Grimes 7989b50d902SRodney W. Grimes /* 7999b50d902SRodney W. Grimes * Slice a string up into argc/argv. 8009b50d902SRodney W. Grimes */ 8019b50d902SRodney W. Grimes static void 802*752fa694SWarner Losh makeargv(char *line) 8039b50d902SRodney W. Grimes { 8048049f797SMark Murray char *cp; 8058049f797SMark Murray char **argp = margv; 8069b50d902SRodney W. Grimes 8079b50d902SRodney W. Grimes margc = 0; 808*752fa694SWarner Losh if ((cp = strchr(line, '\n')) != NULL) 809ca22ff9eSJoerg Wunsch *cp = '\0'; 810*752fa694SWarner Losh for (cp = line; margc < MAX_MARGV - 1 && *cp != '\0';) { 8119b50d902SRodney W. Grimes while (isspace(*cp)) 8129b50d902SRodney W. Grimes cp++; 8139b50d902SRodney W. Grimes if (*cp == '\0') 8149b50d902SRodney W. Grimes break; 8159b50d902SRodney W. Grimes *argp++ = cp; 8169b50d902SRodney W. Grimes margc += 1; 8179b50d902SRodney W. Grimes while (*cp != '\0' && !isspace(*cp)) 8189b50d902SRodney W. Grimes cp++; 8199b50d902SRodney W. Grimes if (*cp == '\0') 8209b50d902SRodney W. Grimes break; 8219b50d902SRodney W. Grimes *cp++ = '\0'; 8229b50d902SRodney W. Grimes } 8239b50d902SRodney W. Grimes *argp++ = 0; 8249b50d902SRodney W. Grimes } 8259b50d902SRodney W. Grimes 826*752fa694SWarner Losh static void 8271b0fa6faSXin LI quit(int argc __unused, char *argv[] __unused) 8289b50d902SRodney W. Grimes { 829*752fa694SWarner Losh 83073f899caSBrian S. Dean exit(txrx_error); 8319b50d902SRodney W. Grimes } 8329b50d902SRodney W. Grimes 8339b50d902SRodney W. Grimes /* 8349b50d902SRodney W. Grimes * Help command. 8359b50d902SRodney W. Grimes */ 836*752fa694SWarner Losh static void 8371b0fa6faSXin LI help(int argc, char *argv[]) 8389b50d902SRodney W. Grimes { 8398049f797SMark Murray struct cmd *c; 8409b50d902SRodney W. Grimes 8419b50d902SRodney W. Grimes if (argc == 1) { 8429b50d902SRodney W. Grimes printf("Commands may be abbreviated. Commands are:\n\n"); 8439b50d902SRodney W. Grimes for (c = cmdtab; c->name; c++) 8449b50d902SRodney W. Grimes printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); 845*752fa694SWarner Losh 846*752fa694SWarner Losh printf("\n[-] : You shouldn't use these ones anymore.\n"); 847*752fa694SWarner Losh printf("[*] : RFC2834 options support required.\n"); 848*752fa694SWarner Losh printf("[**] : Non-standard RFC2834 option.\n"); 8499b50d902SRodney W. Grimes return; 8509b50d902SRodney W. Grimes } 8519b50d902SRodney W. Grimes while (--argc > 0) { 8528049f797SMark Murray char *arg; 8539b50d902SRodney W. Grimes arg = *++argv; 8549b50d902SRodney W. Grimes c = getcmd(arg); 8559b50d902SRodney W. Grimes if (c == (struct cmd *)-1) 856*752fa694SWarner Losh printf("?Ambiguous help command: %s\n", arg); 8579b50d902SRodney W. Grimes else if (c == (struct cmd *)0) 858*752fa694SWarner Losh printf("?Invalid help command: %s\n", arg); 8599b50d902SRodney W. Grimes else 8609b50d902SRodney W. Grimes printf("%s\n", c->help); 8619b50d902SRodney W. Grimes } 8629b50d902SRodney W. Grimes } 8639b50d902SRodney W. Grimes 864*752fa694SWarner Losh static void 865*752fa694SWarner Losh setverbose(int argc __unused, char *argv[] __unused) 8669b50d902SRodney W. Grimes { 8679b50d902SRodney W. Grimes 8689b50d902SRodney W. Grimes verbose = !verbose; 8699b50d902SRodney W. Grimes printf("Verbose mode %s.\n", verbose ? "on" : "off"); 8709b50d902SRodney W. Grimes } 871*752fa694SWarner Losh 872*752fa694SWarner Losh static void 873*752fa694SWarner Losh setoptions(int argc, char *argv[]) 874*752fa694SWarner Losh { 875*752fa694SWarner Losh 876*752fa694SWarner Losh if (argc == 2) { 877*752fa694SWarner Losh if (strcasecmp(argv[1], "enable") == 0 || 878*752fa694SWarner Losh strcasecmp(argv[1], "on") == 0) { 879*752fa694SWarner Losh options_extra_enabled = 1; 880*752fa694SWarner Losh options_rfc_enabled = 1; 881*752fa694SWarner Losh } 882*752fa694SWarner Losh if (strcasecmp(argv[1], "disable") == 0 || 883*752fa694SWarner Losh strcasecmp(argv[1], "off") == 0) { 884*752fa694SWarner Losh options_extra_enabled = 0; 885*752fa694SWarner Losh options_rfc_enabled = 0; 886*752fa694SWarner Losh } 887*752fa694SWarner Losh if (strcasecmp(argv[1], "extra") == 0) 888*752fa694SWarner Losh options_extra_enabled = !options_extra_enabled; 889*752fa694SWarner Losh } 890*752fa694SWarner Losh printf("Support for RFC2347 style options are now %s.\n", 891*752fa694SWarner Losh options_rfc_enabled ? "enabled" : "disabled"); 892*752fa694SWarner Losh printf("Support for non-RFC defined options are now %s.\n", 893*752fa694SWarner Losh options_extra_enabled ? "enabled" : "disabled"); 894*752fa694SWarner Losh 895*752fa694SWarner Losh printf("\nThe following options are available:\n" 896*752fa694SWarner Losh "\toptions on : enable support for RFC2347 style options\n" 897*752fa694SWarner Losh "\toptions off : disable support for RFC2347 style options\n" 898*752fa694SWarner Losh "\toptions extra : toggle support for non-RFC defined options\n" 899*752fa694SWarner Losh ); 900*752fa694SWarner Losh } 901*752fa694SWarner Losh 902*752fa694SWarner Losh static void 903*752fa694SWarner Losh setrollover(int argc, char *argv[]) 904*752fa694SWarner Losh { 905*752fa694SWarner Losh 906*752fa694SWarner Losh if (argc == 2) { 907*752fa694SWarner Losh if (strcasecmp(argv[1], "never") == 0 || 908*752fa694SWarner Losh strcasecmp(argv[1], "none") == 0) { 909*752fa694SWarner Losh free(options[OPT_ROLLOVER].o_request); 910*752fa694SWarner Losh options[OPT_ROLLOVER].o_request = NULL; 911*752fa694SWarner Losh } 912*752fa694SWarner Losh if (strcasecmp(argv[1], "1") == 0) { 913*752fa694SWarner Losh free(options[OPT_ROLLOVER].o_request); 914*752fa694SWarner Losh options[OPT_ROLLOVER].o_request = strdup("1"); 915*752fa694SWarner Losh } 916*752fa694SWarner Losh if (strcasecmp(argv[1], "0") == 0) { 917*752fa694SWarner Losh free(options[OPT_ROLLOVER].o_request); 918*752fa694SWarner Losh options[OPT_ROLLOVER].o_request = strdup("0"); 919*752fa694SWarner Losh } 920*752fa694SWarner Losh } 921*752fa694SWarner Losh printf("Support for the rollover options is %s.\n", 922*752fa694SWarner Losh options[OPT_ROLLOVER].o_request != NULL ? "enabled" : "disabled"); 923*752fa694SWarner Losh if (options[OPT_ROLLOVER].o_request != NULL) 924*752fa694SWarner Losh printf("Block rollover will be to block %s.\n", 925*752fa694SWarner Losh options[OPT_ROLLOVER].o_request); 926*752fa694SWarner Losh 927*752fa694SWarner Losh 928*752fa694SWarner Losh printf("\nThe following rollover options are available:\n" 929*752fa694SWarner Losh "\trollover 0 : rollover to block zero (default)\n" 930*752fa694SWarner Losh "\trollover 1 : rollover to block one\n" 931*752fa694SWarner Losh "\trollover never : do not support the rollover option\n" 932*752fa694SWarner Losh "\trollover none : do not support the rollover option\n" 933*752fa694SWarner Losh ); 934*752fa694SWarner Losh } 935*752fa694SWarner Losh 936*752fa694SWarner Losh static void 937*752fa694SWarner Losh setdebug(int argc, char *argv[]) 938*752fa694SWarner Losh { 939*752fa694SWarner Losh int i; 940*752fa694SWarner Losh 941*752fa694SWarner Losh if (argc != 1) { 942*752fa694SWarner Losh i = 1; 943*752fa694SWarner Losh while (i < argc) 944*752fa694SWarner Losh debug ^= debug_find(argv[i++]); 945*752fa694SWarner Losh } 946*752fa694SWarner Losh printf("The following debugging is enabled: %s\n", debug_show(debug)); 947*752fa694SWarner Losh 948*752fa694SWarner Losh printf("\nThe following debugs are available:\n"); 949*752fa694SWarner Losh i = 0; 950*752fa694SWarner Losh while (debugs[i].name != NULL) { 951*752fa694SWarner Losh printf("\t%s\t%s\n", debugs[i].name, debugs[i].desc); 952*752fa694SWarner Losh i++; 953*752fa694SWarner Losh } 954*752fa694SWarner Losh } 955*752fa694SWarner Losh 956*752fa694SWarner Losh static void 957*752fa694SWarner Losh setblocksize(int argc, char *argv[]) 958*752fa694SWarner Losh { 959*752fa694SWarner Losh 960*752fa694SWarner Losh if (!options_rfc_enabled) 961*752fa694SWarner Losh printf("RFC2347 style options are not enabled " 962*752fa694SWarner Losh "(but proceding anyway)\n"); 963*752fa694SWarner Losh 964*752fa694SWarner Losh if (argc != 1) { 965*752fa694SWarner Losh int size = atoi(argv[1]); 966*752fa694SWarner Losh size_t max; 967*752fa694SWarner Losh char maxbuffer[100]; 968*752fa694SWarner Losh int *maxdgram; 969*752fa694SWarner Losh 970*752fa694SWarner Losh max = sizeof(maxbuffer); 971*752fa694SWarner Losh if (sysctlbyname("net.inet.udp.maxdgram", 972*752fa694SWarner Losh maxbuffer, &max, NULL, 0) < 0) { 973*752fa694SWarner Losh perror("sysctl: net.inet.udp.maxdgram"); 974*752fa694SWarner Losh return; 975*752fa694SWarner Losh } 976*752fa694SWarner Losh maxdgram = (int *)maxbuffer; 977*752fa694SWarner Losh 978*752fa694SWarner Losh if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) { 979*752fa694SWarner Losh printf("Blocksize should be between %d and %d bytes.\n", 980*752fa694SWarner Losh BLKSIZE_MIN, BLKSIZE_MAX); 981*752fa694SWarner Losh return; 982*752fa694SWarner Losh } else if (size > *maxdgram - 4) { 983*752fa694SWarner Losh printf("Blocksize can't be bigger than %d bytes due " 984*752fa694SWarner Losh "to the net.inet.udp.maxdgram sysctl limitation.\n", 985*752fa694SWarner Losh *maxdgram - 4); 986*752fa694SWarner Losh asprintf(&options[OPT_BLKSIZE].o_request, 987*752fa694SWarner Losh "%d", *maxdgram - 4); 988*752fa694SWarner Losh } else { 989*752fa694SWarner Losh asprintf(&options[OPT_BLKSIZE].o_request, "%d", size); 990*752fa694SWarner Losh } 991*752fa694SWarner Losh } 992*752fa694SWarner Losh printf("Blocksize is now %s bytes.\n", options[OPT_BLKSIZE].o_request); 993*752fa694SWarner Losh } 994*752fa694SWarner Losh 995*752fa694SWarner Losh static void 996*752fa694SWarner Losh setblocksize2(int argc, char *argv[]) 997*752fa694SWarner Losh { 998*752fa694SWarner Losh 999*752fa694SWarner Losh if (!options_rfc_enabled || !options_extra_enabled) 1000*752fa694SWarner Losh printf( 1001*752fa694SWarner Losh "RFC2347 style or non-RFC defined options are not enabled " 1002*752fa694SWarner Losh "(but proceding anyway)\n"); 1003*752fa694SWarner Losh 1004*752fa694SWarner Losh if (argc != 1) { 1005*752fa694SWarner Losh int size = atoi(argv[1]); 1006*752fa694SWarner Losh int i; 1007*752fa694SWarner Losh size_t max; 1008*752fa694SWarner Losh char maxbuffer[100]; 1009*752fa694SWarner Losh int *maxdgram; 1010*752fa694SWarner Losh 1011*752fa694SWarner Losh int sizes[] = { 1012*752fa694SWarner Losh 8, 16, 32, 64, 128, 256, 512, 1024, 1013*752fa694SWarner Losh 2048, 4096, 8192, 16384, 32768, 0 1014*752fa694SWarner Losh }; 1015*752fa694SWarner Losh 1016*752fa694SWarner Losh max = sizeof(maxbuffer); 1017*752fa694SWarner Losh if (sysctlbyname("net.inet.udp.maxdgram", 1018*752fa694SWarner Losh maxbuffer, &max, NULL, 0) < 0) { 1019*752fa694SWarner Losh perror("sysctl: net.inet.udp.maxdgram"); 1020*752fa694SWarner Losh return; 1021*752fa694SWarner Losh } 1022*752fa694SWarner Losh maxdgram = (int *)maxbuffer; 1023*752fa694SWarner Losh 1024*752fa694SWarner Losh for (i = 0; sizes[i] != 0; i++) { 1025*752fa694SWarner Losh if (sizes[i] == size) break; 1026*752fa694SWarner Losh } 1027*752fa694SWarner Losh if (sizes[i] == 0) { 1028*752fa694SWarner Losh printf("Blocksize2 should be a power of two between " 1029*752fa694SWarner Losh "8 and 32768.\n"); 1030*752fa694SWarner Losh return; 1031*752fa694SWarner Losh } 1032*752fa694SWarner Losh 1033*752fa694SWarner Losh if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) { 1034*752fa694SWarner Losh printf("Blocksize2 should be between " 1035*752fa694SWarner Losh "%d and %d bytes.\n", BLKSIZE_MIN, BLKSIZE_MAX); 1036*752fa694SWarner Losh return; 1037*752fa694SWarner Losh } else if (size > *maxdgram - 4) { 1038*752fa694SWarner Losh printf("Blocksize2 can't be bigger than %d bytes due " 1039*752fa694SWarner Losh "to the net.inet.udp.maxdgram sysctl limitation.\n", 1040*752fa694SWarner Losh *maxdgram - 4); 1041*752fa694SWarner Losh for (i = 0; sizes[i+1] != 0; i++) { 1042*752fa694SWarner Losh if (*maxdgram < sizes[i+1]) break; 1043*752fa694SWarner Losh } 1044*752fa694SWarner Losh asprintf(&options[OPT_BLKSIZE2].o_request, 1045*752fa694SWarner Losh "%d", sizes[i]); 1046*752fa694SWarner Losh } else { 1047*752fa694SWarner Losh asprintf(&options[OPT_BLKSIZE2].o_request, "%d", size); 1048*752fa694SWarner Losh } 1049*752fa694SWarner Losh } 1050*752fa694SWarner Losh printf("Blocksize2 is now %s bytes.\n", 1051*752fa694SWarner Losh options[OPT_BLKSIZE2].o_request); 1052*752fa694SWarner Losh } 1053*752fa694SWarner Losh 1054*752fa694SWarner Losh static void 1055*752fa694SWarner Losh setpacketdrop(int argc, char *argv[]) 1056*752fa694SWarner Losh { 1057*752fa694SWarner Losh 1058*752fa694SWarner Losh if (argc != 1) 1059*752fa694SWarner Losh packetdroppercentage = atoi(argv[1]); 1060*752fa694SWarner Losh 1061*752fa694SWarner Losh printf("Randomly %d in 100 packets will be dropped\n", 1062*752fa694SWarner Losh packetdroppercentage); 1063*752fa694SWarner Losh } 1064