18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 49b50d902SRodney W. Grimes * Copyright (c) 1983, 1993 59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 69b50d902SRodney W. Grimes * 79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 99b50d902SRodney W. Grimes * are met: 109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 179b50d902SRodney W. Grimes * without specific prior written permission. 189b50d902SRodney W. Grimes * 199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 299b50d902SRodney W. Grimes * SUCH DAMAGE. 309b50d902SRodney W. Grimes */ 319b50d902SRodney W. Grimes 329b50d902SRodney W. Grimes #ifndef lint 33fd129a02SPhilippe Charnier static const char copyright[] = 349b50d902SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\ 359b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 368049f797SMark Murray #endif 379b50d902SRodney W. Grimes 388f4c8256SDavid Malone #if 0 399b50d902SRodney W. Grimes #ifndef lint 408f4c8256SDavid Malone static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 41fd129a02SPhilippe Charnier #endif 428f4c8256SDavid Malone #endif 438f4c8256SDavid Malone 448f4c8256SDavid Malone #include <sys/cdefs.h> 458f4c8256SDavid Malone __FBSDID("$FreeBSD$"); 469b50d902SRodney W. Grimes 479b50d902SRodney W. Grimes /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 489b50d902SRodney W. Grimes 499b50d902SRodney W. Grimes /* 509b50d902SRodney W. Grimes * TFTP User Program -- Command Interface. 519b50d902SRodney W. Grimes */ 52fd129a02SPhilippe Charnier #include <sys/param.h> 539b50d902SRodney W. Grimes #include <sys/types.h> 549b50d902SRodney W. Grimes #include <sys/socket.h> 55752fa694SWarner Losh #include <sys/sysctl.h> 569b50d902SRodney W. Grimes #include <sys/file.h> 57752fa694SWarner Losh #include <sys/stat.h> 589b50d902SRodney W. Grimes 599b50d902SRodney W. Grimes #include <netinet/in.h> 609b50d902SRodney W. Grimes #include <arpa/inet.h> 61752fa694SWarner Losh #include <arpa/tftp.h> 629b50d902SRodney W. Grimes 639b50d902SRodney W. Grimes #include <ctype.h> 64fd129a02SPhilippe Charnier #include <err.h> 658979160aSBruce Evans #include <histedit.h> 669b50d902SRodney W. Grimes #include <netdb.h> 679b50d902SRodney W. Grimes #include <setjmp.h> 689b50d902SRodney W. Grimes #include <signal.h> 6949fb0615SConrad Meyer #include <stdbool.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 75752fa694SWarner Losh #include "tftp-utils.h" 76752fa694SWarner Losh #include "tftp-io.h" 77752fa694SWarner Losh #include "tftp-options.h" 78752fa694SWarner Losh #include "tftp.h" 799b50d902SRodney W. Grimes 800f8d6cfcSMarcel Moolenaar #define MAXLINE (2 * MAXPATHLEN) 818979160aSBruce Evans #define TIMEOUT 5 /* secs between rexmt's */ 82c33ed450SMatthew N. Dodd 837c9acc77SXin LI typedef struct sockaddr_storage peeraddr; 84752fa694SWarner Losh static int connected; 85752fa694SWarner Losh static char mode[32]; 86bf70beceSEd Schouten static jmp_buf toplevel; 8773f899caSBrian S. Dean volatile int txrx_error; 88752fa694SWarner Losh static int peer; 899b50d902SRodney W. Grimes 90752fa694SWarner Losh #define MAX_MARGV 20 91752fa694SWarner Losh static int margc; 92752fa694SWarner Losh static char *margv[MAX_MARGV]; 93752fa694SWarner Losh 94752fa694SWarner Losh int verbose; 95bf70beceSEd Schouten static char *port = NULL; 96752fa694SWarner Losh 97752fa694SWarner Losh static void get(int, char **); 98752fa694SWarner Losh static void help(int, char **); 99752fa694SWarner Losh static void intr(int); 100752fa694SWarner Losh static void modecmd(int, char **); 101752fa694SWarner Losh static void put(int, char **); 102752fa694SWarner Losh static void quit(int, char **); 103752fa694SWarner Losh static void setascii(int, char **); 104752fa694SWarner Losh static void setbinary(int, char **); 105752fa694SWarner Losh static void setpeer0(char *, const char *); 106752fa694SWarner Losh static void setpeer(int, char **); 107752fa694SWarner Losh static void settimeoutpacket(int, char **); 108752fa694SWarner Losh static void settimeoutnetwork(int, char **); 109752fa694SWarner Losh static void setdebug(int, char **); 110752fa694SWarner Losh static void setverbose(int, char **); 111752fa694SWarner Losh static void showstatus(int, char **); 112752fa694SWarner Losh static void setblocksize(int, char **); 113752fa694SWarner Losh static void setblocksize2(int, char **); 114752fa694SWarner Losh static void setoptions(int, char **); 115752fa694SWarner Losh static void setrollover(int, char **); 116752fa694SWarner Losh static void setpacketdrop(int, char **); 117fdf929ffSJohn Baldwin static void setwindowsize(int, char **); 1189b50d902SRodney W. Grimes 11949fb0615SConrad Meyer static void command(bool, EditLine *, History *, HistEvent *) __dead2; 1203f330d7dSWarner Losh static const char *command_prompt(void); 1219b50d902SRodney W. Grimes 122752fa694SWarner Losh static void urihandling(char *URI); 123752fa694SWarner Losh static void getusage(char *); 124752fa694SWarner Losh static void makeargv(char *line); 125752fa694SWarner Losh static void putusage(char *); 1263f330d7dSWarner Losh static void settftpmode(const char *); 1278049f797SMark Murray 128752fa694SWarner Losh static char *tail(char *); 129752fa694SWarner Losh static struct cmd *getcmd(char *); 1309b50d902SRodney W. Grimes 1319b50d902SRodney W. Grimes #define HELPINDENT (sizeof("connect")) 1329b50d902SRodney W. Grimes 1339b50d902SRodney W. Grimes struct cmd { 1348049f797SMark Murray const char *name; 1353f330d7dSWarner Losh void (*handler)(int, char **); 136752fa694SWarner Losh const char *help; 1379b50d902SRodney W. Grimes }; 1389b50d902SRodney W. Grimes 139752fa694SWarner Losh static struct cmd cmdtab[] = { 140752fa694SWarner Losh { "connect", setpeer, "connect to remote tftp" }, 141752fa694SWarner Losh { "mode", modecmd, "set file transfer mode" }, 142752fa694SWarner Losh { "put", put, "send file" }, 143752fa694SWarner Losh { "get", get, "receive file" }, 144752fa694SWarner Losh { "quit", quit, "exit tftp" }, 145752fa694SWarner Losh { "verbose", setverbose, "toggle verbose mode" }, 146752fa694SWarner Losh { "status", showstatus, "show current status" }, 147752fa694SWarner Losh { "binary", setbinary, "set mode to octet" }, 148752fa694SWarner Losh { "ascii", setascii, "set mode to netascii" }, 149752fa694SWarner Losh { "rexmt", settimeoutpacket, 150752fa694SWarner Losh "set per-packet retransmission timeout[-]" }, 151752fa694SWarner Losh { "timeout", settimeoutnetwork, 152752fa694SWarner Losh "set total retransmission timeout" }, 153752fa694SWarner Losh { "trace", setdebug, "enable 'debug packet'[-]" }, 154752fa694SWarner Losh { "debug", setdebug, "enable verbose output" }, 155752fa694SWarner Losh { "blocksize", setblocksize, "set blocksize[*]" }, 156752fa694SWarner Losh { "blocksize2", setblocksize2, "set blocksize as a power of 2[**]" }, 157752fa694SWarner Losh { "rollover", setrollover, "rollover after 64K packets[**]" }, 158752fa694SWarner Losh { "options", setoptions, 159752fa694SWarner Losh "enable or disable RFC2347 style options" }, 160752fa694SWarner Losh { "help", help, "print help information" }, 161f471745aSWarner Losh { "packetdrop", setpacketdrop, "artificial packetloss feature" }, 162fdf929ffSJohn Baldwin { "windowsize", setwindowsize, "set windowsize[*]" }, 163752fa694SWarner Losh { "?", help, "print help information" }, 1648049f797SMark Murray { NULL, NULL, NULL } 1659b50d902SRodney W. Grimes }; 1669b50d902SRodney W. Grimes 167752fa694SWarner 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" }, 176752fa694SWarner Losh { NULL, NULL } 1779b50d902SRodney W. Grimes }; 1789b50d902SRodney W. Grimes 179752fa694SWarner Losh int 180752fa694SWarner Losh main(int argc, char *argv[]) 181752fa694SWarner Losh { 18249fb0615SConrad Meyer HistEvent he; 183e4803b1cSJustin Hibbits static EditLine *el; 184e4803b1cSJustin Hibbits static History *hist; 18549fb0615SConrad Meyer bool interactive; 186752fa694SWarner Losh 187752fa694SWarner Losh acting_as_client = 1; 188752fa694SWarner Losh peer = -1; 1897dbe228cSAlan Somers strcpy(mode, "octet"); 190752fa694SWarner Losh signal(SIGINT, intr); 19149fb0615SConrad Meyer 19249fb0615SConrad Meyer interactive = isatty(STDIN_FILENO); 19349fb0615SConrad Meyer if (interactive) { 19449fb0615SConrad Meyer el = el_init("tftp", stdin, stdout, stderr); 19549fb0615SConrad Meyer hist = history_init(); 19649fb0615SConrad Meyer history(hist, &he, H_SETSIZE, 100); 19749fb0615SConrad Meyer el_set(el, EL_HIST, history, hist); 19849fb0615SConrad Meyer el_set(el, EL_EDITOR, "emacs"); 19949fb0615SConrad Meyer el_set(el, EL_PROMPT, command_prompt); 20049fb0615SConrad Meyer el_set(el, EL_SIGNAL, 1); 20149fb0615SConrad Meyer el_source(el, NULL); 20249fb0615SConrad Meyer } 20349fb0615SConrad Meyer 204752fa694SWarner Losh if (argc > 1) { 205752fa694SWarner Losh if (setjmp(toplevel) != 0) 206752fa694SWarner Losh exit(txrx_error); 207752fa694SWarner Losh 208752fa694SWarner Losh if (strncmp(argv[1], "tftp://", 7) == 0) { 209752fa694SWarner Losh urihandling(argv[1]); 210752fa694SWarner Losh exit(txrx_error); 211752fa694SWarner Losh } 212752fa694SWarner Losh 213752fa694SWarner Losh setpeer(argc, argv); 214752fa694SWarner Losh } 21549fb0615SConrad Meyer 21649fb0615SConrad Meyer if (setjmp(toplevel) != 0) { 21749fb0615SConrad Meyer if (interactive) 21849fb0615SConrad Meyer el_reset(el); 219752fa694SWarner Losh (void)putchar('\n'); 22049fb0615SConrad Meyer } 221752fa694SWarner Losh 222752fa694SWarner Losh init_options(); 22349fb0615SConrad Meyer command(interactive, el, hist, &he); 224752fa694SWarner Losh } 225752fa694SWarner Losh 226752fa694SWarner Losh /* 227752fa694SWarner Losh * RFC3617 handling of TFTP URIs: 228752fa694SWarner Losh * 229752fa694SWarner Losh * tftpURI = "tftp://" host "/" file [ mode ] 230752fa694SWarner Losh * mode = ";" "mode=" ( "netascii" / "octet" ) 231752fa694SWarner Losh * file = *( unreserved / escaped ) 232752fa694SWarner Losh * host = <as specified by RFC 2732> 233752fa694SWarner Losh * unreserved = <as specified in RFC 2396> 234752fa694SWarner Losh * escaped = <as specified in RFC 2396> 235752fa694SWarner Losh * 236752fa694SWarner Losh * We are cheating a little bit by allowing any mode as specified in the 237752fa694SWarner Losh * modes table defined earlier on in this file and mapping it on the real 238752fa694SWarner Losh * mode. 239752fa694SWarner Losh */ 240752fa694SWarner Losh static void 241752fa694SWarner Losh urihandling(char *URI) 242752fa694SWarner Losh { 243752fa694SWarner Losh char uri[ARG_MAX]; 244752fa694SWarner Losh char *host = NULL; 245752fa694SWarner Losh char *path = NULL; 24604ebad38SMarius Strobl char *opts = NULL; 24704ebad38SMarius Strobl const char *tmode = "octet"; 248752fa694SWarner Losh char *s; 249752fa694SWarner Losh char line[MAXLINE]; 250752fa694SWarner Losh int i; 251752fa694SWarner Losh 25232e49abeSXin LI strlcpy(uri, URI, ARG_MAX); 253752fa694SWarner Losh host = uri + 7; 254752fa694SWarner Losh 255752fa694SWarner Losh if ((s = strchr(host, '/')) == NULL) { 256752fa694SWarner Losh fprintf(stderr, 257752fa694SWarner Losh "Invalid URI: Couldn't find / after hostname\n"); 258752fa694SWarner Losh exit(1); 259752fa694SWarner Losh } 260752fa694SWarner Losh *s = '\0'; 261752fa694SWarner Losh path = s + 1; 262752fa694SWarner Losh 263752fa694SWarner Losh if ((s = strchr(path, ';')) != NULL) { 264752fa694SWarner Losh *s = '\0'; 26504ebad38SMarius Strobl opts = s + 1; 266752fa694SWarner Losh 26704ebad38SMarius Strobl if (strncmp(opts, "mode=", 5) == 0) { 26804ebad38SMarius Strobl tmode = opts; 26904ebad38SMarius Strobl tmode += 5; 270752fa694SWarner Losh 271752fa694SWarner Losh for (i = 0; modes[i].m_name != NULL; i++) { 27204ebad38SMarius Strobl if (strcmp(modes[i].m_name, tmode) == 0) 273752fa694SWarner Losh break; 274752fa694SWarner Losh } 275752fa694SWarner Losh if (modes[i].m_name == NULL) { 276752fa694SWarner Losh fprintf(stderr, "Invalid mode: '%s'\n", mode); 277752fa694SWarner Losh exit(1); 278752fa694SWarner Losh } 279752fa694SWarner Losh settftpmode(modes[i].m_mode); 280752fa694SWarner Losh } 281752fa694SWarner Losh } else { 282752fa694SWarner Losh settftpmode("octet"); 283752fa694SWarner Losh } 284752fa694SWarner Losh 285752fa694SWarner Losh setpeer0(host, NULL); 286752fa694SWarner Losh 287752fa694SWarner Losh sprintf(line, "get %s", path); 288752fa694SWarner Losh makeargv(line); 289752fa694SWarner Losh get(margc, margv); 290752fa694SWarner Losh } 291752fa694SWarner Losh 292752fa694SWarner Losh static char hostname[MAXHOSTNAMELEN]; 293752fa694SWarner Losh 294752fa694SWarner Losh static void 295752fa694SWarner Losh setpeer0(char *host, const char *lport) 296752fa694SWarner Losh { 297752fa694SWarner Losh struct addrinfo hints, *res0, *res; 298752fa694SWarner Losh int error; 299752fa694SWarner Losh const char *cause = "unknown"; 300752fa694SWarner Losh 301752fa694SWarner Losh if (connected) { 302752fa694SWarner Losh close(peer); 303752fa694SWarner Losh peer = -1; 304752fa694SWarner Losh } 305752fa694SWarner Losh connected = 0; 306752fa694SWarner Losh 307752fa694SWarner Losh memset(&hints, 0, sizeof(hints)); 308752fa694SWarner Losh hints.ai_family = PF_UNSPEC; 309752fa694SWarner Losh hints.ai_socktype = SOCK_DGRAM; 310752fa694SWarner Losh hints.ai_protocol = IPPROTO_UDP; 311752fa694SWarner Losh hints.ai_flags = AI_CANONNAME; 312752fa694SWarner Losh if (!lport) 313752fa694SWarner Losh lport = "tftp"; 314752fa694SWarner Losh error = getaddrinfo(host, lport, &hints, &res0); 315752fa694SWarner Losh if (error) { 316752fa694SWarner Losh warnx("%s", gai_strerror(error)); 317752fa694SWarner Losh return; 318752fa694SWarner Losh } 319752fa694SWarner Losh 320752fa694SWarner Losh for (res = res0; res; res = res->ai_next) { 321752fa694SWarner Losh if (res->ai_addrlen > sizeof(peeraddr)) 322752fa694SWarner Losh continue; 323752fa694SWarner Losh peer = socket(res->ai_family, res->ai_socktype, 324752fa694SWarner Losh res->ai_protocol); 325752fa694SWarner Losh if (peer < 0) { 326752fa694SWarner Losh cause = "socket"; 327752fa694SWarner Losh continue; 328752fa694SWarner Losh } 329752fa694SWarner Losh 330752fa694SWarner Losh memset(&peer_sock, 0, sizeof(peer_sock)); 331752fa694SWarner Losh peer_sock.ss_family = res->ai_family; 332752fa694SWarner Losh peer_sock.ss_len = res->ai_addrlen; 333752fa694SWarner Losh if (bind(peer, (struct sockaddr *)&peer_sock, peer_sock.ss_len) < 0) { 334752fa694SWarner Losh cause = "bind"; 335752fa694SWarner Losh close(peer); 336752fa694SWarner Losh peer = -1; 337752fa694SWarner Losh continue; 338752fa694SWarner Losh } 339752fa694SWarner Losh 340752fa694SWarner Losh break; 341752fa694SWarner Losh } 342752fa694SWarner Losh 343752fa694SWarner Losh if (peer < 0) 344752fa694SWarner Losh warn("%s", cause); 345752fa694SWarner Losh else { 346752fa694SWarner Losh /* res->ai_addr <= sizeof(peeraddr) is guaranteed */ 347752fa694SWarner Losh memcpy(&peer_sock, res->ai_addr, res->ai_addrlen); 348752fa694SWarner Losh if (res->ai_canonname) { 34932e49abeSXin LI (void) strlcpy(hostname, res->ai_canonname, 350752fa694SWarner Losh sizeof(hostname)); 351752fa694SWarner Losh } else 35232e49abeSXin LI (void) strlcpy(hostname, host, sizeof(hostname)); 353752fa694SWarner Losh connected = 1; 354752fa694SWarner Losh } 355752fa694SWarner Losh 356752fa694SWarner Losh freeaddrinfo(res0); 357752fa694SWarner Losh } 358752fa694SWarner Losh 359752fa694SWarner Losh static void 360752fa694SWarner Losh setpeer(int argc, char *argv[]) 361752fa694SWarner Losh { 362752fa694SWarner Losh char line[MAXLINE]; 363752fa694SWarner Losh 364752fa694SWarner Losh if (argc < 2) { 365752fa694SWarner Losh strcpy(line, "Connect "); 366752fa694SWarner Losh printf("(to) "); 367752fa694SWarner Losh fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 368752fa694SWarner Losh makeargv(line); 369752fa694SWarner Losh argc = margc; 370752fa694SWarner Losh argv = margv; 371752fa694SWarner Losh } 372752fa694SWarner Losh if ((argc < 2) || (argc > 3)) { 373752fa694SWarner Losh printf("usage: %s [host [port]]\n", argv[0]); 374752fa694SWarner Losh return; 375752fa694SWarner Losh } 376752fa694SWarner Losh if (argc == 3) { 377752fa694SWarner Losh port = argv[2]; 378752fa694SWarner Losh setpeer0(argv[1], argv[2]); 379752fa694SWarner Losh } else 380752fa694SWarner Losh setpeer0(argv[1], NULL); 381752fa694SWarner Losh } 382752fa694SWarner Losh 383752fa694SWarner Losh static void 3841b0fa6faSXin LI modecmd(int argc, char *argv[]) 3859b50d902SRodney W. Grimes { 3868049f797SMark Murray struct modes *p; 3878049f797SMark Murray const char *sep; 3889b50d902SRodney W. Grimes 3899b50d902SRodney W. Grimes if (argc < 2) { 3909b50d902SRodney W. Grimes printf("Using %s mode to transfer files.\n", mode); 3919b50d902SRodney W. Grimes return; 3929b50d902SRodney W. Grimes } 3939b50d902SRodney W. Grimes if (argc == 2) { 3949b50d902SRodney W. Grimes for (p = modes; p->m_name; p++) 3959b50d902SRodney W. Grimes if (strcmp(argv[1], p->m_name) == 0) 3969b50d902SRodney W. Grimes break; 3979b50d902SRodney W. Grimes if (p->m_name) { 3989b50d902SRodney W. Grimes settftpmode(p->m_mode); 3999b50d902SRodney W. Grimes return; 4009b50d902SRodney W. Grimes } 4019b50d902SRodney W. Grimes printf("%s: unknown mode\n", argv[1]); 4029b50d902SRodney W. Grimes /* drop through and print usage message */ 4039b50d902SRodney W. Grimes } 4049b50d902SRodney W. Grimes 4059b50d902SRodney W. Grimes printf("usage: %s [", argv[0]); 4069b50d902SRodney W. Grimes sep = " "; 407752fa694SWarner Losh for (p = modes; p->m_name != NULL; p++) { 4089b50d902SRodney W. Grimes printf("%s%s", sep, p->m_name); 4099b50d902SRodney W. Grimes if (*sep == ' ') 4109b50d902SRodney W. Grimes sep = " | "; 4119b50d902SRodney W. Grimes } 4129b50d902SRodney W. Grimes printf(" ]\n"); 4139b50d902SRodney W. Grimes return; 4149b50d902SRodney W. Grimes } 4159b50d902SRodney W. Grimes 416752fa694SWarner Losh static void 4171b0fa6faSXin LI setbinary(int argc __unused, char *argv[] __unused) 4189b50d902SRodney W. Grimes { 4199b50d902SRodney W. Grimes 4209b50d902SRodney W. Grimes settftpmode("octet"); 4219b50d902SRodney W. Grimes } 4229b50d902SRodney W. Grimes 423752fa694SWarner Losh static void 4241b0fa6faSXin LI setascii(int argc __unused, char *argv[] __unused) 4259b50d902SRodney W. Grimes { 4269b50d902SRodney W. Grimes 4279b50d902SRodney W. Grimes settftpmode("netascii"); 4289b50d902SRodney W. Grimes } 4299b50d902SRodney W. Grimes 4309b50d902SRodney W. Grimes static void 4311b0fa6faSXin LI settftpmode(const char *newmode) 4329b50d902SRodney W. Grimes { 433752fa694SWarner Losh 434ca2d3691SAlan Somers strlcpy(mode, newmode, sizeof(mode)); 4359b50d902SRodney W. Grimes if (verbose) 4369b50d902SRodney W. Grimes printf("mode set to %s\n", mode); 4379b50d902SRodney W. Grimes } 4389b50d902SRodney W. Grimes 4399b50d902SRodney W. Grimes 4409b50d902SRodney W. Grimes /* 4419b50d902SRodney W. Grimes * Send file(s). 4429b50d902SRodney W. Grimes */ 443752fa694SWarner Losh static void 4441b0fa6faSXin LI put(int argc, char *argv[]) 4459b50d902SRodney W. Grimes { 4469b50d902SRodney W. Grimes int fd; 4478049f797SMark Murray int n; 4489f9544fdSDag-Erling Smørgrav char *cp, *targ, *path; 449752fa694SWarner Losh char line[MAXLINE]; 450752fa694SWarner Losh struct stat sb; 4519b50d902SRodney W. Grimes 4529b50d902SRodney W. Grimes if (argc < 2) { 4539b50d902SRodney W. Grimes strcpy(line, "send "); 4549b50d902SRodney W. Grimes printf("(file) "); 455ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 456752fa694SWarner Losh makeargv(line); 4579b50d902SRodney W. Grimes argc = margc; 4589b50d902SRodney W. Grimes argv = margv; 4599b50d902SRodney W. Grimes } 4609b50d902SRodney W. Grimes if (argc < 2) { 4619b50d902SRodney W. Grimes putusage(argv[0]); 4629b50d902SRodney W. Grimes return; 4639b50d902SRodney W. Grimes } 4649b50d902SRodney W. Grimes targ = argv[argc - 1]; 465b3608ae1SEd Schouten if (strrchr(argv[argc - 1], ':')) { 4668049f797SMark Murray char *lcp; 4679b50d902SRodney W. Grimes 4689b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) 469b3608ae1SEd Schouten if (strchr(argv[n], ':')) { 4709b50d902SRodney W. Grimes putusage(argv[0]); 4719b50d902SRodney W. Grimes return; 4729b50d902SRodney W. Grimes } 4738049f797SMark Murray lcp = argv[argc - 1]; 474b3608ae1SEd Schouten targ = strrchr(lcp, ':'); 4759b50d902SRodney W. Grimes *targ++ = 0; 4764dac6235SHajimu UMEMOTO if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') { 4774dac6235SHajimu UMEMOTO lcp[strlen(lcp) - 1] = '\0'; 4784dac6235SHajimu UMEMOTO lcp++; 4799b50d902SRodney W. Grimes } 4804dac6235SHajimu UMEMOTO setpeer0(lcp, NULL); 4819b50d902SRodney W. Grimes } 4829b50d902SRodney W. Grimes if (!connected) { 4839b50d902SRodney W. Grimes printf("No target machine specified.\n"); 4849b50d902SRodney W. Grimes return; 4859b50d902SRodney W. Grimes } 4869b50d902SRodney W. Grimes if (argc < 4) { 4879b50d902SRodney W. Grimes cp = argc == 2 ? tail(targ) : argv[1]; 4889b50d902SRodney W. Grimes fd = open(cp, O_RDONLY); 4899b50d902SRodney W. Grimes if (fd < 0) { 490fd129a02SPhilippe Charnier warn("%s", cp); 4919b50d902SRodney W. Grimes return; 4929b50d902SRodney W. Grimes } 493752fa694SWarner Losh 494ca2d3691SAlan Somers if (fstat(fd, &sb) < 0) { 495ca2d3691SAlan Somers warn("%s", cp); 496123d18b5SAlan Somers close(fd); 497ca2d3691SAlan Somers return; 498ca2d3691SAlan Somers } 499*b15e052eSDag-Erling Smørgrav options_set_request(OPT_TSIZE, "%ju", (uintmax_t)sb.st_size); 500752fa694SWarner Losh 5019b50d902SRodney W. Grimes if (verbose) 5029b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 5039b50d902SRodney W. Grimes cp, hostname, targ, mode); 504752fa694SWarner Losh xmitfile(peer, port, fd, targ, mode); 505e4036974SAlan Somers close(fd); 5069b50d902SRodney W. Grimes return; 5079b50d902SRodney W. Grimes } 5089b50d902SRodney W. Grimes /* this assumes the target is a directory */ 5099b50d902SRodney W. Grimes /* on a remote unix system. hmmmm. */ 5109b50d902SRodney W. Grimes for (n = 1; n < argc - 1; n++) { 5119f9544fdSDag-Erling Smørgrav if (asprintf(&path, "%s/%s", targ, tail(argv[n])) < 0) 5129f9544fdSDag-Erling Smørgrav err(1, "malloc"); 5139f9544fdSDag-Erling Smørgrav 5149b50d902SRodney W. Grimes fd = open(argv[n], O_RDONLY); 5159b50d902SRodney W. Grimes if (fd < 0) { 516fd129a02SPhilippe Charnier warn("%s", argv[n]); 5179f9544fdSDag-Erling Smørgrav free(path); 5189b50d902SRodney W. Grimes continue; 5199b50d902SRodney W. Grimes } 520752fa694SWarner Losh 521ca2d3691SAlan Somers if (fstat(fd, &sb) < 0) { 522ca2d3691SAlan Somers warn("%s", argv[n]); 5239f9544fdSDag-Erling Smørgrav close(fd); 5249f9544fdSDag-Erling Smørgrav free(path); 525ca2d3691SAlan Somers continue; 526ca2d3691SAlan Somers } 527*b15e052eSDag-Erling Smørgrav options_set_request(OPT_TSIZE, "%ju", (uintmax_t)sb.st_size); 528752fa694SWarner Losh 5299b50d902SRodney W. Grimes if (verbose) 5309b50d902SRodney W. Grimes printf("putting %s to %s:%s [%s]\n", 5319f9544fdSDag-Erling Smørgrav argv[n], hostname, path, mode); 5329f9544fdSDag-Erling Smørgrav xmitfile(peer, port, fd, path, mode); 5339f9544fdSDag-Erling Smørgrav close(fd); 5349f9544fdSDag-Erling Smørgrav 5359f9544fdSDag-Erling Smørgrav free(path); 5369b50d902SRodney W. Grimes } 5379b50d902SRodney W. Grimes } 5389b50d902SRodney W. Grimes 5399b50d902SRodney W. Grimes static void 540752fa694SWarner Losh putusage(char *s) 5419b50d902SRodney W. Grimes { 542752fa694SWarner Losh 543752fa694SWarner Losh printf("usage: %s file [remotename]\n", s); 544752fa694SWarner Losh printf(" %s file host:remotename\n", s); 545891ca8cfSSimon L. B. Nielsen printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s); 5469b50d902SRodney W. Grimes } 5479b50d902SRodney W. Grimes 5489b50d902SRodney W. Grimes /* 5499b50d902SRodney W. Grimes * Receive file(s). 5509b50d902SRodney W. Grimes */ 551752fa694SWarner Losh static void 5521b0fa6faSXin LI get(int argc, char *argv[]) 5539b50d902SRodney W. Grimes { 5549b50d902SRodney W. Grimes int fd; 5558049f797SMark Murray int n; 5568049f797SMark Murray char *cp; 5579b50d902SRodney W. Grimes char *src; 558752fa694SWarner Losh char line[MAXLINE]; 5599b50d902SRodney W. Grimes 5609b50d902SRodney W. Grimes if (argc < 2) { 5619b50d902SRodney W. Grimes strcpy(line, "get "); 5629b50d902SRodney W. Grimes printf("(files) "); 563ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 564752fa694SWarner Losh makeargv(line); 5659b50d902SRodney W. Grimes argc = margc; 5669b50d902SRodney W. Grimes argv = margv; 5679b50d902SRodney W. Grimes } 5689b50d902SRodney W. Grimes if (argc < 2) { 5699b50d902SRodney W. Grimes getusage(argv[0]); 5709b50d902SRodney W. Grimes return; 5719b50d902SRodney W. Grimes } 5729b50d902SRodney W. Grimes if (!connected) { 5739b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) 574b3608ae1SEd Schouten if (strrchr(argv[n], ':') == 0) { 575752fa694SWarner Losh printf("No remote host specified and " 576752fa694SWarner Losh "no host given for file '%s'\n", argv[n]); 5779b50d902SRodney W. Grimes getusage(argv[0]); 5789b50d902SRodney W. Grimes return; 5799b50d902SRodney W. Grimes } 5809b50d902SRodney W. Grimes } 5819b50d902SRodney W. Grimes for (n = 1; n < argc ; n++) { 582b3608ae1SEd Schouten src = strrchr(argv[n], ':'); 5839b50d902SRodney W. Grimes if (src == NULL) 5849b50d902SRodney W. Grimes src = argv[n]; 5859b50d902SRodney W. Grimes else { 5864dac6235SHajimu UMEMOTO char *lcp; 5879b50d902SRodney W. Grimes 5889b50d902SRodney W. Grimes *src++ = 0; 5894dac6235SHajimu UMEMOTO lcp = argv[n]; 5904dac6235SHajimu UMEMOTO if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') { 5914dac6235SHajimu UMEMOTO lcp[strlen(lcp) - 1] = '\0'; 5924dac6235SHajimu UMEMOTO lcp++; 5939b50d902SRodney W. Grimes } 5944dac6235SHajimu UMEMOTO setpeer0(lcp, NULL); 5954dac6235SHajimu UMEMOTO if (!connected) 5964dac6235SHajimu UMEMOTO continue; 5979b50d902SRodney W. Grimes } 5989b50d902SRodney W. Grimes if (argc < 4) { 5999b50d902SRodney W. Grimes cp = argc == 3 ? argv[2] : tail(src); 6009b50d902SRodney W. Grimes fd = creat(cp, 0644); 6019b50d902SRodney W. Grimes if (fd < 0) { 602fd129a02SPhilippe Charnier warn("%s", cp); 6039b50d902SRodney W. Grimes return; 6049b50d902SRodney W. Grimes } 6059b50d902SRodney W. Grimes if (verbose) 6069b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 6079b50d902SRodney W. Grimes hostname, src, cp, mode); 608752fa694SWarner Losh recvfile(peer, port, fd, src, mode); 6099b50d902SRodney W. Grimes break; 6109b50d902SRodney W. Grimes } 6119b50d902SRodney W. Grimes cp = tail(src); /* new .. jdg */ 6129b50d902SRodney W. Grimes fd = creat(cp, 0644); 6139b50d902SRodney W. Grimes if (fd < 0) { 614fd129a02SPhilippe Charnier warn("%s", cp); 6159b50d902SRodney W. Grimes continue; 6169b50d902SRodney W. Grimes } 6179b50d902SRodney W. Grimes if (verbose) 6189b50d902SRodney W. Grimes printf("getting from %s:%s to %s [%s]\n", 6199b50d902SRodney W. Grimes hostname, src, cp, mode); 620752fa694SWarner Losh recvfile(peer, port, fd, src, mode); 6219b50d902SRodney W. Grimes } 6229b50d902SRodney W. Grimes } 6239b50d902SRodney W. Grimes 6249b50d902SRodney W. Grimes static void 625752fa694SWarner Losh getusage(char *s) 6269b50d902SRodney W. Grimes { 627752fa694SWarner Losh 628752fa694SWarner Losh printf("usage: %s file [localname]\n", s); 629752fa694SWarner Losh printf(" %s [host:]file [localname]\n", s); 630891ca8cfSSimon L. B. Nielsen printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s); 6319b50d902SRodney W. Grimes } 6329b50d902SRodney W. Grimes 633752fa694SWarner Losh static void 634752fa694SWarner Losh settimeoutpacket(int argc, char *argv[]) 6359b50d902SRodney W. Grimes { 6369b50d902SRodney W. Grimes int t; 637752fa694SWarner Losh char line[MAXLINE]; 6389b50d902SRodney W. Grimes 6399b50d902SRodney W. Grimes if (argc < 2) { 640752fa694SWarner Losh strcpy(line, "Packet timeout "); 6419b50d902SRodney W. Grimes printf("(value) "); 642ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 643752fa694SWarner Losh makeargv(line); 6449b50d902SRodney W. Grimes argc = margc; 6459b50d902SRodney W. Grimes argv = margv; 6469b50d902SRodney W. Grimes } 6479b50d902SRodney W. Grimes if (argc != 2) { 6489b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 6499b50d902SRodney W. Grimes return; 6509b50d902SRodney W. Grimes } 6519b50d902SRodney W. Grimes t = atoi(argv[1]); 652752fa694SWarner Losh if (t < 0) { 6539b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 654752fa694SWarner Losh return; 6559b50d902SRodney W. Grimes } 6569b50d902SRodney W. Grimes 657752fa694SWarner Losh settimeouts(t, timeoutnetwork, maxtimeouts); 658752fa694SWarner Losh } 6599b50d902SRodney W. Grimes 660752fa694SWarner Losh static void 661752fa694SWarner Losh settimeoutnetwork(int argc, char *argv[]) 6629b50d902SRodney W. Grimes { 6639b50d902SRodney W. Grimes int t; 664752fa694SWarner Losh char line[MAXLINE]; 6659b50d902SRodney W. Grimes 6669b50d902SRodney W. Grimes if (argc < 2) { 667752fa694SWarner Losh strcpy(line, "Network timeout "); 6689b50d902SRodney W. Grimes printf("(value) "); 669ca22ff9eSJoerg Wunsch fgets(&line[strlen(line)], sizeof line - strlen(line), stdin); 670752fa694SWarner Losh makeargv(line); 6719b50d902SRodney W. Grimes argc = margc; 6729b50d902SRodney W. Grimes argv = margv; 6739b50d902SRodney W. Grimes } 6749b50d902SRodney W. Grimes if (argc != 2) { 6759b50d902SRodney W. Grimes printf("usage: %s value\n", argv[0]); 6769b50d902SRodney W. Grimes return; 6779b50d902SRodney W. Grimes } 6789b50d902SRodney W. Grimes t = atoi(argv[1]); 679752fa694SWarner Losh if (t < 0) { 6809b50d902SRodney W. Grimes printf("%s: bad value\n", argv[1]); 681752fa694SWarner Losh return; 6829b50d902SRodney W. Grimes } 6839b50d902SRodney W. Grimes 684752fa694SWarner Losh settimeouts(timeoutpacket, t, maxtimeouts); 685752fa694SWarner Losh } 686752fa694SWarner Losh 687752fa694SWarner Losh static void 688752fa694SWarner Losh showstatus(int argc __unused, char *argv[] __unused) 6899b50d902SRodney W. Grimes { 690752fa694SWarner Losh 691752fa694SWarner Losh printf("Remote host: %s\n", 692752fa694SWarner Losh connected ? hostname : "none specified yet"); 693752fa694SWarner Losh printf("RFC2347 Options support: %s\n", 694752fa694SWarner Losh options_rfc_enabled ? "enabled" : "disabled"); 695752fa694SWarner Losh printf("Non-RFC defined options support: %s\n", 696752fa694SWarner Losh options_extra_enabled ? "enabled" : "disabled"); 697752fa694SWarner Losh printf("Mode: %s\n", mode); 698752fa694SWarner Losh printf("Verbose: %s\n", verbose ? "on" : "off"); 699752fa694SWarner Losh printf("Debug: %s\n", debug_show(debug)); 700752fa694SWarner Losh printf("Artificial packetloss: %d in 100 packets\n", 701752fa694SWarner Losh packetdroppercentage); 702752fa694SWarner Losh printf("Segment size: %d bytes\n", segsize); 703752fa694SWarner Losh printf("Network timeout: %d seconds\n", timeoutpacket); 704752fa694SWarner Losh printf("Maximum network timeout: %d seconds\n", timeoutnetwork); 705752fa694SWarner Losh printf("Maximum timeouts: %d \n", maxtimeouts); 7069b50d902SRodney W. Grimes } 7079b50d902SRodney W. Grimes 708752fa694SWarner Losh static void 7091b0fa6faSXin LI intr(int dummy __unused) 7109b50d902SRodney W. Grimes { 7119b50d902SRodney W. Grimes 7129b50d902SRodney W. Grimes signal(SIGALRM, SIG_IGN); 7139b50d902SRodney W. Grimes alarm(0); 7149b50d902SRodney W. Grimes longjmp(toplevel, -1); 7159b50d902SRodney W. Grimes } 7169b50d902SRodney W. Grimes 717752fa694SWarner Losh static char * 7181b0fa6faSXin LI tail(char *filename) 7199b50d902SRodney W. Grimes { 7208049f797SMark Murray char *s; 7219b50d902SRodney W. Grimes 7229b50d902SRodney W. Grimes while (*filename) { 723b3608ae1SEd Schouten s = strrchr(filename, '/'); 7249b50d902SRodney W. Grimes if (s == NULL) 7259b50d902SRodney W. Grimes break; 7269b50d902SRodney W. Grimes if (s[1]) 7279b50d902SRodney W. Grimes return (s + 1); 7289b50d902SRodney W. Grimes *s = '\0'; 7299b50d902SRodney W. Grimes } 7309b50d902SRodney W. Grimes return (filename); 7319b50d902SRodney W. Grimes } 7329b50d902SRodney W. Grimes 733c33ed450SMatthew N. Dodd static const char * 73404ebad38SMarius Strobl command_prompt(void) 7358979160aSBruce Evans { 7368979160aSBruce Evans 737c33ed450SMatthew N. Dodd return ("tftp> "); 738c33ed450SMatthew N. Dodd } 739c33ed450SMatthew N. Dodd 7409b50d902SRodney W. Grimes /* 7419b50d902SRodney W. Grimes * Command parser. 7429b50d902SRodney W. Grimes */ 743eaa86f9dSBruce Evans static void 74449fb0615SConrad Meyer command(bool interactive, EditLine *el, History *hist, HistEvent *hep) 7459b50d902SRodney W. Grimes { 7468049f797SMark Murray struct cmd *c; 747c33ed450SMatthew N. Dodd const char *bp; 7488979160aSBruce Evans char *cp; 74949fb0615SConrad Meyer int len, num; 750752fa694SWarner Losh char line[MAXLINE]; 751c33ed450SMatthew N. Dodd 7529b50d902SRodney W. Grimes for (;;) { 75349fb0615SConrad Meyer if (interactive) { 754c33ed450SMatthew N. Dodd if ((bp = el_gets(el, &num)) == NULL || num == 0) 755c33ed450SMatthew N. Dodd exit(0); 756a9a46bd9SMarcelo Araujo len = MIN(MAXLINE, num); 757c33ed450SMatthew N. Dodd memcpy(line, bp, len); 758123d18b5SAlan Somers line[len - 1] = '\0'; 75949fb0615SConrad Meyer history(hist, hep, H_ENTER, bp); 760c33ed450SMatthew N. Dodd } else { 761752fa694SWarner Losh line[0] = 0; 762a3a2bf4bSKevin Lo if (fgets(line, sizeof line , stdin) == NULL) { 7639b50d902SRodney W. Grimes if (feof(stdin)) { 76473f899caSBrian S. Dean exit(txrx_error); 7659b50d902SRodney W. Grimes } else { 7669b50d902SRodney W. Grimes continue; 7679b50d902SRodney W. Grimes } 7689b50d902SRodney W. Grimes } 769c33ed450SMatthew N. Dodd } 770ca22ff9eSJoerg Wunsch if ((cp = strchr(line, '\n'))) 771ca22ff9eSJoerg Wunsch *cp = '\0'; 7729b50d902SRodney W. Grimes if (line[0] == 0) 7739b50d902SRodney W. Grimes continue; 774752fa694SWarner Losh makeargv(line); 7759b50d902SRodney W. Grimes if (margc == 0) 7769b50d902SRodney W. Grimes continue; 7779b50d902SRodney W. Grimes c = getcmd(margv[0]); 7789b50d902SRodney W. Grimes if (c == (struct cmd *)-1) { 7799b50d902SRodney W. Grimes printf("?Ambiguous command\n"); 7809b50d902SRodney W. Grimes continue; 7819b50d902SRodney W. Grimes } 782b4b3d271SMarcelo Araujo if (c == NULL) { 7839b50d902SRodney W. Grimes printf("?Invalid command\n"); 7849b50d902SRodney W. Grimes continue; 7859b50d902SRodney W. Grimes } 7869b50d902SRodney W. Grimes (*c->handler)(margc, margv); 7879b50d902SRodney W. Grimes } 7889b50d902SRodney W. Grimes } 7899b50d902SRodney W. Grimes 790752fa694SWarner Losh static struct cmd * 7911b0fa6faSXin LI getcmd(char *name) 7929b50d902SRodney W. Grimes { 7938049f797SMark Murray const char *p, *q; 7948049f797SMark Murray struct cmd *c, *found; 7958049f797SMark Murray int nmatches, longest; 7969b50d902SRodney W. Grimes 7979b50d902SRodney W. Grimes longest = 0; 7989b50d902SRodney W. Grimes nmatches = 0; 7999b50d902SRodney W. Grimes found = 0; 8009b50d902SRodney W. Grimes for (c = cmdtab; (p = c->name) != NULL; c++) { 8019b50d902SRodney W. Grimes for (q = name; *q == *p++; q++) 8029b50d902SRodney W. Grimes if (*q == 0) /* exact match? */ 8039b50d902SRodney W. Grimes return (c); 8049b50d902SRodney W. Grimes if (!*q) { /* the name was a prefix */ 8059b50d902SRodney W. Grimes if (q - name > longest) { 8069b50d902SRodney W. Grimes longest = q - name; 8079b50d902SRodney W. Grimes nmatches = 1; 8089b50d902SRodney W. Grimes found = c; 8099b50d902SRodney W. Grimes } else if (q - name == longest) 8109b50d902SRodney W. Grimes nmatches++; 8119b50d902SRodney W. Grimes } 8129b50d902SRodney W. Grimes } 8139b50d902SRodney W. Grimes if (nmatches > 1) 8149b50d902SRodney W. Grimes return ((struct cmd *)-1); 8159b50d902SRodney W. Grimes return (found); 8169b50d902SRodney W. Grimes } 8179b50d902SRodney W. Grimes 8189b50d902SRodney W. Grimes /* 8199b50d902SRodney W. Grimes * Slice a string up into argc/argv. 8209b50d902SRodney W. Grimes */ 8219b50d902SRodney W. Grimes static void 822752fa694SWarner Losh makeargv(char *line) 8239b50d902SRodney W. Grimes { 8248049f797SMark Murray char *cp; 8258049f797SMark Murray char **argp = margv; 8269b50d902SRodney W. Grimes 8279b50d902SRodney W. Grimes margc = 0; 828752fa694SWarner Losh if ((cp = strchr(line, '\n')) != NULL) 829ca22ff9eSJoerg Wunsch *cp = '\0'; 830752fa694SWarner Losh for (cp = line; margc < MAX_MARGV - 1 && *cp != '\0';) { 8319b50d902SRodney W. Grimes while (isspace(*cp)) 8329b50d902SRodney W. Grimes cp++; 8339b50d902SRodney W. Grimes if (*cp == '\0') 8349b50d902SRodney W. Grimes break; 8359b50d902SRodney W. Grimes *argp++ = cp; 8369b50d902SRodney W. Grimes margc += 1; 8379b50d902SRodney W. Grimes while (*cp != '\0' && !isspace(*cp)) 8389b50d902SRodney W. Grimes cp++; 8399b50d902SRodney W. Grimes if (*cp == '\0') 8409b50d902SRodney W. Grimes break; 8419b50d902SRodney W. Grimes *cp++ = '\0'; 8429b50d902SRodney W. Grimes } 8439b50d902SRodney W. Grimes *argp++ = 0; 8449b50d902SRodney W. Grimes } 8459b50d902SRodney W. Grimes 846752fa694SWarner Losh static void 8471b0fa6faSXin LI quit(int argc __unused, char *argv[] __unused) 8489b50d902SRodney W. Grimes { 849752fa694SWarner Losh 85073f899caSBrian S. Dean exit(txrx_error); 8519b50d902SRodney W. Grimes } 8529b50d902SRodney W. Grimes 8539b50d902SRodney W. Grimes /* 8549b50d902SRodney W. Grimes * Help command. 8559b50d902SRodney W. Grimes */ 856752fa694SWarner Losh static void 8571b0fa6faSXin LI help(int argc, char *argv[]) 8589b50d902SRodney W. Grimes { 8598049f797SMark Murray struct cmd *c; 8609b50d902SRodney W. Grimes 8619b50d902SRodney W. Grimes if (argc == 1) { 8629b50d902SRodney W. Grimes printf("Commands may be abbreviated. Commands are:\n\n"); 8639b50d902SRodney W. Grimes for (c = cmdtab; c->name; c++) 8649b50d902SRodney W. Grimes printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); 865752fa694SWarner Losh 866752fa694SWarner Losh printf("\n[-] : You shouldn't use these ones anymore.\n"); 867f4b7e64dSCraig Rodrigues printf("[*] : RFC2347 options support required.\n"); 868f4b7e64dSCraig Rodrigues printf("[**] : Non-standard RFC2347 option.\n"); 8699b50d902SRodney W. Grimes return; 8709b50d902SRodney W. Grimes } 8719b50d902SRodney W. Grimes while (--argc > 0) { 8728049f797SMark Murray char *arg; 8739b50d902SRodney W. Grimes arg = *++argv; 8749b50d902SRodney W. Grimes c = getcmd(arg); 8759b50d902SRodney W. Grimes if (c == (struct cmd *)-1) 876752fa694SWarner Losh printf("?Ambiguous help command: %s\n", arg); 8779b50d902SRodney W. Grimes else if (c == (struct cmd *)0) 878752fa694SWarner Losh printf("?Invalid help command: %s\n", arg); 8799b50d902SRodney W. Grimes else 8809b50d902SRodney W. Grimes printf("%s\n", c->help); 8819b50d902SRodney W. Grimes } 8829b50d902SRodney W. Grimes } 8839b50d902SRodney W. Grimes 884752fa694SWarner Losh static void 885752fa694SWarner Losh setverbose(int argc __unused, char *argv[] __unused) 8869b50d902SRodney W. Grimes { 8879b50d902SRodney W. Grimes 8889b50d902SRodney W. Grimes verbose = !verbose; 8899b50d902SRodney W. Grimes printf("Verbose mode %s.\n", verbose ? "on" : "off"); 8909b50d902SRodney W. Grimes } 891752fa694SWarner Losh 892752fa694SWarner Losh static void 893752fa694SWarner Losh setoptions(int argc, char *argv[]) 894752fa694SWarner Losh { 895752fa694SWarner Losh 896752fa694SWarner Losh if (argc == 2) { 897752fa694SWarner Losh if (strcasecmp(argv[1], "enable") == 0 || 898752fa694SWarner Losh strcasecmp(argv[1], "on") == 0) { 899752fa694SWarner Losh options_extra_enabled = 1; 900752fa694SWarner Losh options_rfc_enabled = 1; 901752fa694SWarner Losh } 902752fa694SWarner Losh if (strcasecmp(argv[1], "disable") == 0 || 903752fa694SWarner Losh strcasecmp(argv[1], "off") == 0) { 904752fa694SWarner Losh options_extra_enabled = 0; 905752fa694SWarner Losh options_rfc_enabled = 0; 906752fa694SWarner Losh } 907752fa694SWarner Losh if (strcasecmp(argv[1], "extra") == 0) 908752fa694SWarner Losh options_extra_enabled = !options_extra_enabled; 909752fa694SWarner Losh } 910752fa694SWarner Losh printf("Support for RFC2347 style options are now %s.\n", 911752fa694SWarner Losh options_rfc_enabled ? "enabled" : "disabled"); 912752fa694SWarner Losh printf("Support for non-RFC defined options are now %s.\n", 913752fa694SWarner Losh options_extra_enabled ? "enabled" : "disabled"); 914752fa694SWarner Losh 915752fa694SWarner Losh printf("\nThe following options are available:\n" 916752fa694SWarner Losh "\toptions on : enable support for RFC2347 style options\n" 917752fa694SWarner Losh "\toptions off : disable support for RFC2347 style options\n" 918752fa694SWarner Losh "\toptions extra : toggle support for non-RFC defined options\n" 919752fa694SWarner Losh ); 920752fa694SWarner Losh } 921752fa694SWarner Losh 922752fa694SWarner Losh static void 923752fa694SWarner Losh setrollover(int argc, char *argv[]) 924752fa694SWarner Losh { 925752fa694SWarner Losh 926752fa694SWarner Losh if (argc == 2) { 927752fa694SWarner Losh if (strcasecmp(argv[1], "never") == 0 || 928752fa694SWarner Losh strcasecmp(argv[1], "none") == 0) { 929*b15e052eSDag-Erling Smørgrav options_set_request(OPT_ROLLOVER, NULL); 930752fa694SWarner Losh } 931752fa694SWarner Losh if (strcasecmp(argv[1], "1") == 0) { 932*b15e052eSDag-Erling Smørgrav options_set_request(OPT_ROLLOVER, "1"); 933752fa694SWarner Losh } 934752fa694SWarner Losh if (strcasecmp(argv[1], "0") == 0) { 935*b15e052eSDag-Erling Smørgrav options_set_request(OPT_ROLLOVER, "0"); 936752fa694SWarner Losh } 937752fa694SWarner Losh } 938752fa694SWarner Losh printf("Support for the rollover options is %s.\n", 939752fa694SWarner Losh options[OPT_ROLLOVER].o_request != NULL ? "enabled" : "disabled"); 940752fa694SWarner Losh if (options[OPT_ROLLOVER].o_request != NULL) 941752fa694SWarner Losh printf("Block rollover will be to block %s.\n", 942752fa694SWarner Losh options[OPT_ROLLOVER].o_request); 943752fa694SWarner Losh 944752fa694SWarner Losh 945752fa694SWarner Losh printf("\nThe following rollover options are available:\n" 946752fa694SWarner Losh "\trollover 0 : rollover to block zero (default)\n" 947752fa694SWarner Losh "\trollover 1 : rollover to block one\n" 948752fa694SWarner Losh "\trollover never : do not support the rollover option\n" 949752fa694SWarner Losh "\trollover none : do not support the rollover option\n" 950752fa694SWarner Losh ); 951752fa694SWarner Losh } 952752fa694SWarner Losh 953752fa694SWarner Losh static void 954752fa694SWarner Losh setdebug(int argc, char *argv[]) 955752fa694SWarner Losh { 956752fa694SWarner Losh int i; 957752fa694SWarner Losh 958752fa694SWarner Losh if (argc != 1) { 959752fa694SWarner Losh i = 1; 960752fa694SWarner Losh while (i < argc) 961752fa694SWarner Losh debug ^= debug_find(argv[i++]); 962752fa694SWarner Losh } 963752fa694SWarner Losh printf("The following debugging is enabled: %s\n", debug_show(debug)); 964752fa694SWarner Losh 965752fa694SWarner Losh printf("\nThe following debugs are available:\n"); 966752fa694SWarner Losh i = 0; 967752fa694SWarner Losh while (debugs[i].name != NULL) { 968752fa694SWarner Losh printf("\t%s\t%s\n", debugs[i].name, debugs[i].desc); 969752fa694SWarner Losh i++; 970752fa694SWarner Losh } 971752fa694SWarner Losh } 972752fa694SWarner Losh 973752fa694SWarner Losh static void 974752fa694SWarner Losh setblocksize(int argc, char *argv[]) 975752fa694SWarner Losh { 976752fa694SWarner Losh 977752fa694SWarner Losh if (!options_rfc_enabled) 978752fa694SWarner Losh printf("RFC2347 style options are not enabled " 979f471745aSWarner Losh "(but proceeding anyway)\n"); 980752fa694SWarner Losh 981752fa694SWarner Losh if (argc != 1) { 982752fa694SWarner Losh int size = atoi(argv[1]); 983752fa694SWarner Losh size_t max; 98404ebad38SMarius Strobl u_long maxdgram; 985752fa694SWarner Losh 98604ebad38SMarius Strobl max = sizeof(maxdgram); 987752fa694SWarner Losh if (sysctlbyname("net.inet.udp.maxdgram", 98804ebad38SMarius Strobl &maxdgram, &max, NULL, 0) < 0) { 989752fa694SWarner Losh perror("sysctl: net.inet.udp.maxdgram"); 990752fa694SWarner Losh return; 991752fa694SWarner Losh } 992752fa694SWarner Losh 993752fa694SWarner Losh if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) { 994752fa694SWarner Losh printf("Blocksize should be between %d and %d bytes.\n", 995752fa694SWarner Losh BLKSIZE_MIN, BLKSIZE_MAX); 996752fa694SWarner Losh return; 99704ebad38SMarius Strobl } else if (size > (int)maxdgram - 4) { 99804ebad38SMarius Strobl printf("Blocksize can't be bigger than %ld bytes due " 999752fa694SWarner Losh "to the net.inet.udp.maxdgram sysctl limitation.\n", 100004ebad38SMarius Strobl maxdgram - 4); 1001*b15e052eSDag-Erling Smørgrav options_set_request(OPT_BLKSIZE, "%ld", maxdgram - 4); 1002752fa694SWarner Losh } else { 1003*b15e052eSDag-Erling Smørgrav options_set_request(OPT_BLKSIZE, "%d", size); 1004752fa694SWarner Losh } 1005752fa694SWarner Losh } 1006752fa694SWarner Losh printf("Blocksize is now %s bytes.\n", options[OPT_BLKSIZE].o_request); 1007752fa694SWarner Losh } 1008752fa694SWarner Losh 1009752fa694SWarner Losh static void 1010752fa694SWarner Losh setblocksize2(int argc, char *argv[]) 1011752fa694SWarner Losh { 1012752fa694SWarner Losh 1013752fa694SWarner Losh if (!options_rfc_enabled || !options_extra_enabled) 1014752fa694SWarner Losh printf( 1015752fa694SWarner Losh "RFC2347 style or non-RFC defined options are not enabled " 1016f471745aSWarner Losh "(but proceeding anyway)\n"); 1017752fa694SWarner Losh 1018752fa694SWarner Losh if (argc != 1) { 1019752fa694SWarner Losh int size = atoi(argv[1]); 1020752fa694SWarner Losh int i; 1021752fa694SWarner Losh size_t max; 102204ebad38SMarius Strobl u_long maxdgram; 1023752fa694SWarner Losh 1024752fa694SWarner Losh int sizes[] = { 1025752fa694SWarner Losh 8, 16, 32, 64, 128, 256, 512, 1024, 1026752fa694SWarner Losh 2048, 4096, 8192, 16384, 32768, 0 1027752fa694SWarner Losh }; 1028752fa694SWarner Losh 102904ebad38SMarius Strobl max = sizeof(maxdgram); 1030752fa694SWarner Losh if (sysctlbyname("net.inet.udp.maxdgram", 103104ebad38SMarius Strobl &maxdgram, &max, NULL, 0) < 0) { 1032752fa694SWarner Losh perror("sysctl: net.inet.udp.maxdgram"); 1033752fa694SWarner Losh return; 1034752fa694SWarner Losh } 1035752fa694SWarner Losh 1036752fa694SWarner Losh for (i = 0; sizes[i] != 0; i++) { 1037752fa694SWarner Losh if (sizes[i] == size) break; 1038752fa694SWarner Losh } 1039752fa694SWarner Losh if (sizes[i] == 0) { 1040752fa694SWarner Losh printf("Blocksize2 should be a power of two between " 1041752fa694SWarner Losh "8 and 32768.\n"); 1042752fa694SWarner Losh return; 1043752fa694SWarner Losh } 1044752fa694SWarner Losh 1045752fa694SWarner Losh if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) { 1046752fa694SWarner Losh printf("Blocksize2 should be between " 1047752fa694SWarner Losh "%d and %d bytes.\n", BLKSIZE_MIN, BLKSIZE_MAX); 1048752fa694SWarner Losh return; 104904ebad38SMarius Strobl } else if (size > (int)maxdgram - 4) { 105004ebad38SMarius Strobl printf("Blocksize2 can't be bigger than %ld bytes due " 1051752fa694SWarner Losh "to the net.inet.udp.maxdgram sysctl limitation.\n", 105204ebad38SMarius Strobl maxdgram - 4); 1053752fa694SWarner Losh for (i = 0; sizes[i+1] != 0; i++) { 105404ebad38SMarius Strobl if ((int)maxdgram < sizes[i+1]) break; 1055752fa694SWarner Losh } 1056*b15e052eSDag-Erling Smørgrav options_set_request(OPT_BLKSIZE2, "%d", sizes[i]); 1057752fa694SWarner Losh } else { 1058*b15e052eSDag-Erling Smørgrav options_set_request(OPT_BLKSIZE2, "%d", size); 1059752fa694SWarner Losh } 1060752fa694SWarner Losh } 1061752fa694SWarner Losh printf("Blocksize2 is now %s bytes.\n", 1062752fa694SWarner Losh options[OPT_BLKSIZE2].o_request); 1063752fa694SWarner Losh } 1064752fa694SWarner Losh 1065752fa694SWarner Losh static void 1066752fa694SWarner Losh setpacketdrop(int argc, char *argv[]) 1067752fa694SWarner Losh { 1068752fa694SWarner Losh 1069752fa694SWarner Losh if (argc != 1) 1070752fa694SWarner Losh packetdroppercentage = atoi(argv[1]); 1071752fa694SWarner Losh 1072752fa694SWarner Losh printf("Randomly %d in 100 packets will be dropped\n", 1073752fa694SWarner Losh packetdroppercentage); 1074752fa694SWarner Losh } 1075fdf929ffSJohn Baldwin 1076fdf929ffSJohn Baldwin static void 1077fdf929ffSJohn Baldwin setwindowsize(int argc, char *argv[]) 1078fdf929ffSJohn Baldwin { 1079fdf929ffSJohn Baldwin 1080fdf929ffSJohn Baldwin if (!options_rfc_enabled) 1081fdf929ffSJohn Baldwin printf("RFC2347 style options are not enabled " 1082fdf929ffSJohn Baldwin "(but proceeding anyway)\n"); 1083fdf929ffSJohn Baldwin 1084fdf929ffSJohn Baldwin if (argc != 1) { 1085fdf929ffSJohn Baldwin int size = atoi(argv[1]); 1086fdf929ffSJohn Baldwin 1087fdf929ffSJohn Baldwin if (size < WINDOWSIZE_MIN || size > WINDOWSIZE_MAX) { 1088fdf929ffSJohn Baldwin printf("Windowsize should be between %d and %d " 1089fdf929ffSJohn Baldwin "blocks.\n", WINDOWSIZE_MIN, WINDOWSIZE_MAX); 1090fdf929ffSJohn Baldwin return; 1091fdf929ffSJohn Baldwin } else { 1092*b15e052eSDag-Erling Smørgrav options_set_request(OPT_WINDOWSIZE, "%d", size); 1093fdf929ffSJohn Baldwin } 1094fdf929ffSJohn Baldwin } 1095fdf929ffSJohn Baldwin printf("Windowsize is now %s blocks.\n", 1096fdf929ffSJohn Baldwin options[OPT_WINDOWSIZE].o_request); 1097fdf929ffSJohn Baldwin } 1098