summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2010-05-06 17:37:23 +0000
committermckusick <mckusick@FreeBSD.org>2010-05-06 17:37:23 +0000
commitb25e55dcc52d6203a9ae995ca470a66b6483f71d (patch)
tree781f2c991a11a3806fdb0891b7a615cb77ebe3ab /usr.bin
parent3a0f5972a0de87aebef1af257922515700da4217 (diff)
parentf3856c6cf2fb115757967b7e32bdeb21bd27d1ee (diff)
downloadFreeBSD-src-b25e55dcc52d6203a9ae995ca470a66b6483f71d.zip
FreeBSD-src-b25e55dcc52d6203a9ae995ca470a66b6483f71d.tar.gz
Final update to current version of head in preparation for reintegration.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/chpass/Makefile2
-rw-r--r--usr.bin/find/find.c9
-rw-r--r--usr.bin/find/function.c8
-rw-r--r--usr.bin/find/ls.c8
-rw-r--r--usr.bin/find/main.c8
-rw-r--r--usr.bin/find/misc.c9
-rw-r--r--usr.bin/find/operator.c8
-rw-r--r--usr.bin/find/option.c8
-rw-r--r--usr.bin/gzip/gzip.16
-rw-r--r--usr.bin/gzip/gzip.c2
-rw-r--r--usr.bin/pathchk/pathchk.116
-rw-r--r--usr.bin/pathchk/pathchk.c18
-rw-r--r--usr.bin/script/script.c24
-rw-r--r--usr.bin/tftp/Makefile6
-rw-r--r--usr.bin/tftp/main.c656
-rw-r--r--usr.bin/tftp/tftp.160
-rw-r--r--usr.bin/tftp/tftp.c576
-rw-r--r--usr.bin/tftp/tftp.h42
18 files changed, 794 insertions, 672 deletions
diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile
index a5571d7..566173e 100644
--- a/usr.bin/chpass/Makefile
+++ b/usr.bin/chpass/Makefile
@@ -38,7 +38,9 @@ MLINKS+= chpass.1 ypchpass.1 chpass.1 ypchfn.1 chpass.1 ypchsh.1
beforeinstall:
.for i in chpass chfn chsh ypchpass ypchfn ypchsh
+.if exists(${DESTDIR}${BINDIR}/$i)
-chflags noschg ${DESTDIR}${BINDIR}/$i
+.endif
.endfor
.if !defined(NO_FSCHG)
diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c
index cc2d797..35ef5b2 100644
--- a/usr.bin/find/find.c
+++ b/usr.bin/find/find.c
@@ -32,15 +32,10 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * @(#)find.c 8.5 (Berkeley) 8/5/94
*/
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)find.c 8.5 (Berkeley) 8/5/94";
-#else
-#endif
-#endif /* not lint */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c
index 1714627..4329887 100644
--- a/usr.bin/find/function.c
+++ b/usr.bin/find/function.c
@@ -32,14 +32,10 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * @(#)function.c 8.10 (Berkeley) 5/4/95
*/
-#ifndef lint
-#if 0
-static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95";
-#endif
-#endif /* not lint */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/usr.bin/find/ls.c b/usr.bin/find/ls.c
index 88e4593..e96994b 100644
--- a/usr.bin/find/ls.c
+++ b/usr.bin/find/ls.c
@@ -29,14 +29,10 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * @(#)ls.c 8.1 (Berkeley) 6/6/93
*/
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)ls.c 8.1 (Berkeley) 6/6/93";
-#endif
-#endif /* not lint */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/usr.bin/find/main.c b/usr.bin/find/main.c
index 8e2b42c..7d4c24a 100644
--- a/usr.bin/find/main.c
+++ b/usr.bin/find/main.c
@@ -32,6 +32,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * @(#)main.c 8.4 (Berkeley) 5/4/95
*/
#ifndef lint
@@ -40,12 +42,6 @@ char copyright[] =
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95";
-#endif
-#endif /* not lint */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/usr.bin/find/misc.c b/usr.bin/find/misc.c
index 1532906..3696c13 100644
--- a/usr.bin/find/misc.c
+++ b/usr.bin/find/misc.c
@@ -32,15 +32,10 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * @(#)misc.c 8.2 (Berkeley) 4/1/94
*/
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)misc.c 8.2 (Berkeley) 4/1/94";
-#else
-#endif
-#endif /* not lint */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/usr.bin/find/operator.c b/usr.bin/find/operator.c
index c774efa..d1a7ea8 100644
--- a/usr.bin/find/operator.c
+++ b/usr.bin/find/operator.c
@@ -32,14 +32,10 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * @(#)operator.c 8.1 (Berkeley) 6/6/93
*/
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93";
-#endif
-#endif /* not lint */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/usr.bin/find/option.c b/usr.bin/find/option.c
index 7d06c91..6ae3958 100644
--- a/usr.bin/find/option.c
+++ b/usr.bin/find/option.c
@@ -32,14 +32,10 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * @(#)option.c 8.2 (Berkeley) 4/16/94
*/
-#ifndef lint
-/*
-static char sccsid[] = "@(#)option.c 8.2 (Berkeley) 4/16/94";
-*/
-#endif /* not lint */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/usr.bin/gzip/gzip.1 b/usr.bin/gzip/gzip.1
index bb1fadd..848a4b3 100644
--- a/usr.bin/gzip/gzip.1
+++ b/usr.bin/gzip/gzip.1
@@ -25,7 +25,7 @@
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
-.Dd April 7, 2010
+.Dd April 27, 2010
.Dt GZIP 1
.Os
.Sh NAME
@@ -218,8 +218,8 @@ with unpack support written by
.An Xin LI Aq delphij@FreeBSD.org .
.Sh BUGS
According to RFC 1952, the recorded file size is stored in a 32-bit
-integer and therefore it can not represent files that is bigger than
-4GB in size. This limitation also applies to
+integer, therefore, it can not represent files larger than 4GB.
+This limitation also applies to
.Fl l
option of
.Nm
diff --git a/usr.bin/gzip/gzip.c b/usr.bin/gzip/gzip.c
index 9503762..de9fe80 100644
--- a/usr.bin/gzip/gzip.c
+++ b/usr.bin/gzip/gzip.c
@@ -1178,7 +1178,7 @@ sigint_handler(int signo __unused)
if (remove_file != NULL)
unlink(remove_file);
- exit(2);
+ _exit(2);
}
#endif
diff --git a/usr.bin/pathchk/pathchk.1 b/usr.bin/pathchk/pathchk.1
index e863955..931f82f 100644
--- a/usr.bin/pathchk/pathchk.1
+++ b/usr.bin/pathchk/pathchk.1
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 21, 2002
+.Dd May 1, 2010
.Dt PATHCHK 1
.Os
.Sh NAME
@@ -35,7 +35,7 @@
.Nd check pathnames
.Sh SYNOPSIS
.Nm
-.Op Fl p
+.Op Fl pP
.Ar pathname ...
.Sh DESCRIPTION
The
@@ -95,6 +95,16 @@ No component may start with the hyphen
.Pq Ql \&-
character.
.El
+.It Fl P
+In addition to the default or
+.Fl p
+checks, write a diagnostic for each argument that:
+.Bl -bullet
+.It
+Is empty.
+.It
+Contains a component that starts with a hyphen.
+.El
.El
.Sh EXIT STATUS
.Ex -std
@@ -104,7 +114,7 @@ other
.Tn POSIX
systems:
.Pp
-.Dl "find . -print | xargs pathchk -p"
+.Dl "find . -exec pathchk -p -- {} +"
.Sh SEE ALSO
.Xr getconf 1 ,
.Xr pathconf 2 ,
diff --git a/usr.bin/pathchk/pathchk.c b/usr.bin/pathchk/pathchk.c
index dd9768a..2d8fa59 100644
--- a/usr.bin/pathchk/pathchk.c
+++ b/usr.bin/pathchk/pathchk.c
@@ -51,6 +51,7 @@ static int portable(const char *);
static void usage(void);
static int pflag; /* Perform portability checks */
+static int Pflag; /* Check for empty paths, leading '-' */
int
main(int argc, char *argv[])
@@ -58,11 +59,14 @@ main(int argc, char *argv[])
int ch, rval;
const char *arg;
- while ((ch = getopt(argc, argv, "p")) > 0) {
+ while ((ch = getopt(argc, argv, "pP")) > 0) {
switch (ch) {
case 'p':
pflag = 1;
break;
+ case 'P':
+ Pflag = 1;
+ break;
default:
usage();
/*NOTREACHED*/
@@ -102,6 +106,15 @@ check(const char *path)
p = pathd;
+ if (Pflag && *p == '\0') {
+ warnx("%s: empty pathname", path);
+ goto bad;
+ }
+ if ((Pflag || pflag) && (*p == '-' || strstr(p, "/-") != NULL)) {
+ warnx("%s: contains a component starting with '-'", path);
+ goto bad;
+ }
+
if (!pflag) {
errno = 0;
namemax = pathconf(*p == '/' ? "/" : ".", _PC_NAME_MAX);
@@ -182,9 +195,6 @@ portable(const char *path)
"0123456789._-";
long s;
- if (*path == '-')
- return (*path);
-
s = strspn(path, charset);
if (path[s] != '\0')
return (path[s]);
diff --git a/usr.bin/script/script.c b/usr.bin/script/script.c
index 6c4e0ee..a21785a 100644
--- a/usr.bin/script/script.c
+++ b/usr.bin/script/script.c
@@ -219,23 +219,17 @@ usage(void)
void
finish(void)
{
- pid_t pid;
- int die, e, status;
+ int e, status;
- die = e = 0;
- while ((pid = wait3(&status, WNOHANG, 0)) > 0)
- if (pid == child) {
- die = 1;
- if (WIFEXITED(status))
- e = WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- e = WTERMSIG(status);
- else /* can't happen */
- e = 1;
- }
-
- if (die)
+ if (waitpid(child, &status, 0) == child) {
+ if (WIFEXITED(status))
+ e = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ e = WTERMSIG(status);
+ else /* can't happen */
+ e = 1;
done(e);
+ }
}
void
diff --git a/usr.bin/tftp/Makefile b/usr.bin/tftp/Makefile
index a51afed..9be599a 100644
--- a/usr.bin/tftp/Makefile
+++ b/usr.bin/tftp/Makefile
@@ -1,9 +1,13 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
+CFLAGS=-g -Wall
+WARNS= 3
PROG= tftp
-SRCS= main.c tftp.c tftpsubs.c
+SRCS= main.c tftp.c tftp-utils.c tftp-io.c tftp-file.c tftp-transfer.c tftp-options.c
DPADD= ${LIBEDIT} ${LIBTERMCAP}
LDADD= -ledit -ltermcap
+CFLAGS+=-I${.CURDIR}/../../libexec/tftpd -I${.CURDIR}/../../usr.bin/tftp
+.PATH: ${.CURDIR}/../../libexec/tftpd
.include <bsd.prog.mk>
diff --git a/usr.bin/tftp/main.c b/usr.bin/tftp/main.c
index f01d3d8..26ca0244 100644
--- a/usr.bin/tftp/main.c
+++ b/usr.bin/tftp/main.c
@@ -54,12 +54,14 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/sysctl.h>
#include <sys/file.h>
#include <sys/param.h>
+#include <sys/stat.h>
#include <netinet/in.h>
-
#include <arpa/inet.h>
+#include <arpa/tftp.h>
#include <ctype.h>
#include <err.h>
@@ -72,119 +74,212 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
-#include "extern.h"
+#include "tftp-utils.h"
+#include "tftp-io.h"
+#include "tftp-options.h"
+#include "tftp.h"
#define MAXLINE 200
#define TIMEOUT 5 /* secs between rexmt's */
-struct sockaddr_storage peeraddr;
-int f;
-int trace;
-int verbose;
-int connected;
-char mode[32];
-char line[MAXLINE];
-int margc;
+static struct sockaddr_storage peeraddr;
+static int connected;
+static char mode[32];
+jmp_buf toplevel;
+volatile int txrx_error;
+static int peer;
+
#define MAX_MARGV 20
-char *margv[MAX_MARGV];
-jmp_buf toplevel;
-volatile int txrx_error;
-
-void get(int, char **);
-void help(int, char **);
-void intr(int);
-void modecmd(int, char **);
-void put(int, char **);
-void quit(int, char **);
-void setascii(int, char **);
-void setbinary(int, char **);
-void setpeer0(char *, const char *);
-void setpeer(int, char **);
-void setrexmt(int, char **);
-void settimeout(int, char **);
-void settrace(int, char **);
-void setverbose(int, char **);
-void status(int, char **);
+static int margc;
+static char *margv[MAX_MARGV];
+
+int verbose;
+char *port = NULL;
+
+static void get(int, char **);
+static void help(int, char **);
+static void intr(int);
+static void modecmd(int, char **);
+static void put(int, char **);
+static void quit(int, char **);
+static void setascii(int, char **);
+static void setbinary(int, char **);
+static void setpeer0(char *, const char *);
+static void setpeer(int, char **);
+static void settimeoutpacket(int, char **);
+static void settimeoutnetwork(int, char **);
+static void setdebug(int, char **);
+static void setverbose(int, char **);
+static void showstatus(int, char **);
+static void setblocksize(int, char **);
+static void setblocksize2(int, char **);
+static void setoptions(int, char **);
+static void setrollover(int, char **);
+static void setpacketdrop(int, char **);
static void command(void) __dead2;
static const char *command_prompt(void);
-static void getusage(const char *);
-static void makeargv(void);
-static void putusage(const char *);
+static void urihandling(char *URI);
+static void getusage(char *);
+static void makeargv(char *line);
+static void putusage(char *);
static void settftpmode(const char *);
-char *tail(char *);
-struct cmd *getcmd(char *);
+static char *tail(char *);
+static struct cmd *getcmd(char *);
#define HELPINDENT (sizeof("connect"))
struct cmd {
const char *name;
- char *help;
void (*handler)(int, char **);
+ const char *help;
};
-char vhelp[] = "toggle verbose mode";
-char thelp[] = "toggle packet tracing";
-char chelp[] = "connect to remote tftp";
-char qhelp[] = "exit tftp";
-char hhelp[] = "print help information";
-char shelp[] = "send file";
-char rhelp[] = "receive file";
-char mhelp[] = "set file transfer mode";
-char sthelp[] = "show current status";
-char xhelp[] = "set per-packet retransmission timeout";
-char ihelp[] = "set total retransmission timeout";
-char ashelp[] = "set mode to netascii";
-char bnhelp[] = "set mode to octet";
-
-struct cmd cmdtab[] = {
- { "connect", chelp, setpeer },
- { "mode", mhelp, modecmd },
- { "put", shelp, put },
- { "get", rhelp, get },
- { "quit", qhelp, quit },
- { "verbose", vhelp, setverbose },
- { "trace", thelp, settrace },
- { "status", sthelp, status },
- { "binary", bnhelp, setbinary },
- { "ascii", ashelp, setascii },
- { "rexmt", xhelp, setrexmt },
- { "timeout", ihelp, settimeout },
- { "?", hhelp, help },
- { NULL, NULL, NULL }
+static struct cmd cmdtab[] = {
+ { "connect", setpeer, "connect to remote tftp" },
+ { "mode", modecmd, "set file transfer mode" },
+ { "put", put, "send file" },
+ { "get", get, "receive file" },
+ { "quit", quit, "exit tftp" },
+ { "verbose", setverbose, "toggle verbose mode" },
+ { "status", showstatus, "show current status" },
+ { "binary", setbinary, "set mode to octet" },
+ { "ascii", setascii, "set mode to netascii" },
+ { "rexmt", settimeoutpacket,
+ "set per-packet retransmission timeout[-]" },
+ { "timeout", settimeoutnetwork,
+ "set total retransmission timeout" },
+ { "trace", setdebug, "enable 'debug packet'[-]" },
+ { "debug", setdebug, "enable verbose output" },
+ { "blocksize", setblocksize, "set blocksize[*]" },
+ { "blocksize2", setblocksize2, "set blocksize as a power of 2[**]" },
+ { "rollover", setrollover, "rollover after 64K packets[**]" },
+ { "options", setoptions,
+ "enable or disable RFC2347 style options" },
+ { "help", help, "print help information" },
+ { "packetdrop", setpacketdrop, "artifical packetloss feature" },
+ { "?", help, "print help information" },
+ { NULL, NULL, NULL }
+};
+
+static struct modes {
+ const char *m_name;
+ const char *m_mode;
+} modes[] = {
+ { "ascii", "netascii" },
+ { "netascii", "netascii" },
+ { "binary", "octet" },
+ { "image", "octet" },
+ { "octet", "octet" },
+ { NULL, NULL }
};
int
main(int argc, char *argv[])
{
- f = -1;
+
+ acting_as_client = 1;
+ peer = -1;
strcpy(mode, "netascii");
signal(SIGINT, intr);
if (argc > 1) {
if (setjmp(toplevel) != 0)
exit(txrx_error);
+
+ if (strncmp(argv[1], "tftp://", 7) == 0) {
+ urihandling(argv[1]);
+ exit(txrx_error);
+ }
+
setpeer(argc, argv);
}
if (setjmp(toplevel) != 0)
(void)putchar('\n');
+
+ init_options();
command();
}
-char hostname[MAXHOSTNAMELEN];
+/*
+ * RFC3617 handling of TFTP URIs:
+ *
+ * tftpURI = "tftp://" host "/" file [ mode ]
+ * mode = ";" "mode=" ( "netascii" / "octet" )
+ * file = *( unreserved / escaped )
+ * host = <as specified by RFC 2732>
+ * unreserved = <as specified in RFC 2396>
+ * escaped = <as specified in RFC 2396>
+ *
+ * We are cheating a little bit by allowing any mode as specified in the
+ * modes table defined earlier on in this file and mapping it on the real
+ * mode.
+ */
+static void
+urihandling(char *URI)
+{
+ char uri[ARG_MAX];
+ char *host = NULL;
+ char *path = NULL;
+ char *options = NULL;
+ char *mode = "octet";
+ char *s;
+ char line[MAXLINE];
+ int i;
+
+ strncpy(uri, URI, ARG_MAX);
+ host = uri + 7;
+
+ if ((s = strchr(host, '/')) == NULL) {
+ fprintf(stderr,
+ "Invalid URI: Couldn't find / after hostname\n");
+ exit(1);
+ }
+ *s = '\0';
+ path = s + 1;
+
+ if ((s = strchr(path, ';')) != NULL) {
+ *s = '\0';
+ options = s + 1;
-void
-setpeer0(char *host, const char *port)
+ if (strncmp(options, "mode=", 5) == 0) {
+ mode = options;
+ mode += 5;
+
+ for (i = 0; modes[i].m_name != NULL; i++) {
+ if (strcmp(modes[i].m_name, mode) == 0)
+ break;
+ }
+ if (modes[i].m_name == NULL) {
+ fprintf(stderr, "Invalid mode: '%s'\n", mode);
+ exit(1);
+ }
+ settftpmode(modes[i].m_mode);
+ }
+ } else {
+ settftpmode("octet");
+ }
+
+ setpeer0(host, NULL);
+
+ sprintf(line, "get %s", path);
+ makeargv(line);
+ get(margc, margv);
+}
+
+static char hostname[MAXHOSTNAMELEN];
+
+static void
+setpeer0(char *host, const char *lport)
{
struct addrinfo hints, *res0, *res;
int error;
- struct sockaddr_storage ss;
const char *cause = "unknown";
if (connected) {
- close(f);
- f = -1;
+ close(peer);
+ peer = -1;
}
connected = 0;
@@ -193,9 +288,9 @@ setpeer0(char *host, const char *port)
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_CANONNAME;
- if (!port)
- port = "tftp";
- error = getaddrinfo(host, port, &hints, &res0);
+ if (!lport)
+ lport = "tftp";
+ error = getaddrinfo(host, lport, &hints, &res0);
if (error) {
warnx("%s", gai_strerror(error));
return;
@@ -204,50 +299,53 @@ setpeer0(char *host, const char *port)
for (res = res0; res; res = res->ai_next) {
if (res->ai_addrlen > sizeof(peeraddr))
continue;
- f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (f < 0) {
+ peer = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (peer < 0) {
cause = "socket";
continue;
}
- memset(&ss, 0, sizeof(ss));
- ss.ss_family = res->ai_family;
- ss.ss_len = res->ai_addrlen;
- if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
+ memset(&peer_sock, 0, sizeof(peer_sock));
+ peer_sock.ss_family = res->ai_family;
+ peer_sock.ss_len = res->ai_addrlen;
+ if (bind(peer, (struct sockaddr *)&peer_sock, peer_sock.ss_len) < 0) {
cause = "bind";
- close(f);
- f = -1;
+ close(peer);
+ peer = -1;
continue;
}
break;
}
- if (f < 0)
+ if (peer < 0)
warn("%s", cause);
else {
/* res->ai_addr <= sizeof(peeraddr) is guaranteed */
- memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+ memcpy(&peer_sock, res->ai_addr, res->ai_addrlen);
if (res->ai_canonname) {
- (void) strlcpy(hostname, res->ai_canonname,
+ (void) strncpy(hostname, res->ai_canonname,
sizeof(hostname));
} else
- (void) strlcpy(hostname, host, sizeof(hostname));
+ (void) strncpy(hostname, host, sizeof(hostname));
+ hostname[sizeof(hostname)-1] = 0;
connected = 1;
}
freeaddrinfo(res0);
}
-void
+static void
setpeer(int argc, char *argv[])
{
+ char line[MAXLINE];
if (argc < 2) {
strcpy(line, "Connect ");
printf("(to) ");
fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
- makeargv();
+ makeargv(line);
argc = margc;
argv = margv;
}
@@ -255,26 +353,14 @@ setpeer(int argc, char *argv[])
printf("usage: %s [host [port]]\n", argv[0]);
return;
}
- if (argc == 3)
+ if (argc == 3) {
+ port = argv[2];
setpeer0(argv[1], argv[2]);
- else
+ } else
setpeer0(argv[1], NULL);
}
-struct modes {
- const char *m_name;
- const char *m_mode;
-} modes[] = {
- { "ascii", "netascii" },
- { "netascii", "netascii" },
- { "binary", "octet" },
- { "image", "octet" },
- { "octet", "octet" },
-/* { "mail", "mail" }, */
- { 0, 0 }
-};
-
-void
+static void
modecmd(int argc, char *argv[])
{
struct modes *p;
@@ -298,7 +384,7 @@ modecmd(int argc, char *argv[])
printf("usage: %s [", argv[0]);
sep = " ";
- for (p = modes; p->m_name; p++) {
+ for (p = modes; p->m_name != NULL; p++) {
printf("%s%s", sep, p->m_name);
if (*sep == ' ')
sep = " | ";
@@ -307,14 +393,14 @@ modecmd(int argc, char *argv[])
return;
}
-void
+static void
setbinary(int argc __unused, char *argv[] __unused)
{
settftpmode("octet");
}
-void
+static void
setascii(int argc __unused, char *argv[] __unused)
{
@@ -324,6 +410,7 @@ setascii(int argc __unused, char *argv[] __unused)
static void
settftpmode(const char *newmode)
{
+
strcpy(mode, newmode);
if (verbose)
printf("mode set to %s\n", mode);
@@ -333,18 +420,20 @@ settftpmode(const char *newmode)
/*
* Send file(s).
*/
-void
+static void
put(int argc, char *argv[])
{
- int fd;
- int n;
- char *cp, *targ;
+ int fd;
+ int n;
+ char *cp, *targ;
+ char line[MAXLINE];
+ struct stat sb;
if (argc < 2) {
strcpy(line, "send ");
printf("(file) ");
fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
- makeargv();
+ makeargv(line);
argc = margc;
argv = margv;
}
@@ -381,10 +470,14 @@ put(int argc, char *argv[])
warn("%s", cp);
return;
}
+
+ stat(cp, &sb);
+ asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size);
+
if (verbose)
printf("putting %s to %s:%s [%s]\n",
- cp, hostname, targ, mode);
- xmitfile(fd, targ, mode);
+ cp, hostname, targ, mode);
+ xmitfile(peer, port, fd, targ, mode);
return;
}
/* this assumes the target is a directory */
@@ -398,36 +491,43 @@ put(int argc, char *argv[])
warn("%s", argv[n]);
continue;
}
+
+ stat(cp, &sb);
+ asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size);
+
if (verbose)
printf("putting %s to %s:%s [%s]\n",
- argv[n], hostname, targ, mode);
- xmitfile(fd, targ, mode);
+ argv[n], hostname, targ, mode);
+ xmitfile(peer, port, fd, targ, mode);
}
}
static void
-putusage(const char *s)
+putusage(char *s)
{
- printf("usage: %s file [[host:]remotename]\n", s);
+
+ printf("usage: %s file [remotename]\n", s);
+ printf(" %s file host:remotename\n", s);
printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s);
}
/*
* Receive file(s).
*/
-void
+static void
get(int argc, char *argv[])
{
int fd;
int n;
char *cp;
char *src;
+ char line[MAXLINE];
if (argc < 2) {
strcpy(line, "get ");
printf("(files) ");
fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
- makeargv();
+ makeargv(line);
argc = margc;
argv = margv;
}
@@ -438,6 +538,8 @@ get(int argc, char *argv[])
if (!connected) {
for (n = 1; n < argc ; n++)
if (rindex(argv[n], ':') == 0) {
+ printf("No remote host specified and "
+ "no host given for file '%s'\n", argv[n]);
getusage(argv[0]);
return;
}
@@ -468,8 +570,8 @@ get(int argc, char *argv[])
}
if (verbose)
printf("getting from %s:%s to %s [%s]\n",
- hostname, src, cp, mode);
- recvfile(fd, src, mode);
+ hostname, src, cp, mode);
+ recvfile(peer, port, fd, src, mode);
break;
}
cp = tail(src); /* new .. jdg */
@@ -480,30 +582,31 @@ get(int argc, char *argv[])
}
if (verbose)
printf("getting from %s:%s to %s [%s]\n",
- hostname, src, cp, mode);
- recvfile(fd, src, mode);
+ hostname, src, cp, mode);
+ recvfile(peer, port, fd, src, mode);
}
}
static void
-getusage(const char *s)
+getusage(char *s)
{
- printf("usage: %s [host:]file [localname]\n", s);
+
+ printf("usage: %s file [localname]\n", s);
+ printf(" %s [host:]file [localname]\n", s);
printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
}
-int rexmtval = TIMEOUT;
-
-void
-setrexmt(int argc, char *argv[])
+static void
+settimeoutpacket(int argc, char *argv[])
{
int t;
+ char line[MAXLINE];
if (argc < 2) {
- strcpy(line, "Rexmt-timeout ");
+ strcpy(line, "Packet timeout ");
printf("(value) ");
fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
- makeargv();
+ makeargv(line);
argc = margc;
argv = margv;
}
@@ -512,24 +615,25 @@ setrexmt(int argc, char *argv[])
return;
}
t = atoi(argv[1]);
- if (t < 0)
+ if (t < 0) {
printf("%s: bad value\n", argv[1]);
- else
- rexmtval = t;
-}
+ return;
+ }
-int maxtimeout = 5 * TIMEOUT;
+ settimeouts(t, timeoutnetwork, maxtimeouts);
+}
-void
-settimeout(int argc, char *argv[])
+static void
+settimeoutnetwork(int argc, char *argv[])
{
int t;
+ char line[MAXLINE];
if (argc < 2) {
- strcpy(line, "Maximum-timeout ");
+ strcpy(line, "Network timeout ");
printf("(value) ");
fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
- makeargv();
+ makeargv(line);
argc = margc;
argv = margv;
}
@@ -538,26 +642,36 @@ settimeout(int argc, char *argv[])
return;
}
t = atoi(argv[1]);
- if (t < 0)
+ if (t < 0) {
printf("%s: bad value\n", argv[1]);
- else
- maxtimeout = t;
+ return;
+ }
+
+ settimeouts(timeoutpacket, t, maxtimeouts);
}
-void
-status(int argc __unused, char *argv[] __unused)
+static void
+showstatus(int argc __unused, char *argv[] __unused)
{
- if (connected)
- printf("Connected to %s.\n", hostname);
- else
- printf("Not connected.\n");
- printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
- verbose ? "on" : "off", trace ? "on" : "off");
- printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
- rexmtval, maxtimeout);
+
+ printf("Remote host: %s\n",
+ connected ? hostname : "none specified yet");
+ printf("RFC2347 Options support: %s\n",
+ options_rfc_enabled ? "enabled" : "disabled");
+ printf("Non-RFC defined options support: %s\n",
+ options_extra_enabled ? "enabled" : "disabled");
+ printf("Mode: %s\n", mode);
+ printf("Verbose: %s\n", verbose ? "on" : "off");
+ printf("Debug: %s\n", debug_show(debug));
+ printf("Artificial packetloss: %d in 100 packets\n",
+ packetdroppercentage);
+ printf("Segment size: %d bytes\n", segsize);
+ printf("Network timeout: %d seconds\n", timeoutpacket);
+ printf("Maximum network timeout: %d seconds\n", timeoutnetwork);
+ printf("Maximum timeouts: %d \n", maxtimeouts);
}
-void
+static void
intr(int dummy __unused)
{
@@ -566,7 +680,7 @@ intr(int dummy __unused)
longjmp(toplevel, -1);
}
-char *
+static char *
tail(char *filename)
{
char *s;
@@ -583,7 +697,7 @@ tail(char *filename)
}
static const char *
-command_prompt(void)
+command_prompt()
{
return ("tftp> ");
@@ -602,6 +716,7 @@ command(void)
const char *bp;
char *cp;
int len, num, vrbose;
+ char line[MAXLINE];
vrbose = isatty(0);
if (vrbose) {
@@ -623,6 +738,7 @@ command(void)
line[len] = '\0';
history(hist, &he, H_ENTER, bp);
} else {
+ line[0] = 0;
if (fgets(line, sizeof line , stdin) == 0) {
if (feof(stdin)) {
exit(txrx_error);
@@ -635,7 +751,7 @@ command(void)
*cp = '\0';
if (line[0] == 0)
continue;
- makeargv();
+ makeargv(line);
if (margc == 0)
continue;
c = getcmd(margv[0]);
@@ -651,7 +767,7 @@ command(void)
}
}
-struct cmd *
+static struct cmd *
getcmd(char *name)
{
const char *p, *q;
@@ -683,15 +799,15 @@ getcmd(char *name)
* Slice a string up into argc/argv.
*/
static void
-makeargv(void)
+makeargv(char *line)
{
char *cp;
char **argp = margv;
margc = 0;
- if ((cp = strchr(line, '\n')))
+ if ((cp = strchr(line, '\n')) != NULL)
*cp = '\0';
- for (cp = line; margc < MAX_MARGV - 1 && *cp;) {
+ for (cp = line; margc < MAX_MARGV - 1 && *cp != '\0';) {
while (isspace(*cp))
cp++;
if (*cp == '\0')
@@ -707,16 +823,17 @@ makeargv(void)
*argp++ = 0;
}
-void
+static void
quit(int argc __unused, char *argv[] __unused)
{
+
exit(txrx_error);
}
/*
* Help command.
*/
-void
+static void
help(int argc, char *argv[])
{
struct cmd *c;
@@ -725,6 +842,10 @@ help(int argc, char *argv[])
printf("Commands may be abbreviated. Commands are:\n\n");
for (c = cmdtab; c->name; c++)
printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
+
+ printf("\n[-] : You shouldn't use these ones anymore.\n");
+ printf("[*] : RFC2834 options support required.\n");
+ printf("[**] : Non-standard RFC2834 option.\n");
return;
}
while (--argc > 0) {
@@ -732,24 +853,211 @@ help(int argc, char *argv[])
arg = *++argv;
c = getcmd(arg);
if (c == (struct cmd *)-1)
- printf("?Ambiguous help command %s\n", arg);
+ printf("?Ambiguous help command: %s\n", arg);
else if (c == (struct cmd *)0)
- printf("?Invalid help command %s\n", arg);
+ printf("?Invalid help command: %s\n", arg);
else
printf("%s\n", c->help);
}
}
-void
-settrace(int argc __unused, char **argv __unused)
+static void
+setverbose(int argc __unused, char *argv[] __unused)
{
- trace = !trace;
- printf("Packet tracing %s.\n", trace ? "on" : "off");
-}
-void
-setverbose(int argc __unused, char **argv __unused)
-{
verbose = !verbose;
printf("Verbose mode %s.\n", verbose ? "on" : "off");
}
+
+static void
+setoptions(int argc, char *argv[])
+{
+
+ if (argc == 2) {
+ if (strcasecmp(argv[1], "enable") == 0 ||
+ strcasecmp(argv[1], "on") == 0) {
+ options_extra_enabled = 1;
+ options_rfc_enabled = 1;
+ }
+ if (strcasecmp(argv[1], "disable") == 0 ||
+ strcasecmp(argv[1], "off") == 0) {
+ options_extra_enabled = 0;
+ options_rfc_enabled = 0;
+ }
+ if (strcasecmp(argv[1], "extra") == 0)
+ options_extra_enabled = !options_extra_enabled;
+ }
+ printf("Support for RFC2347 style options are now %s.\n",
+ options_rfc_enabled ? "enabled" : "disabled");
+ printf("Support for non-RFC defined options are now %s.\n",
+ options_extra_enabled ? "enabled" : "disabled");
+
+ printf("\nThe following options are available:\n"
+ "\toptions on : enable support for RFC2347 style options\n"
+ "\toptions off : disable support for RFC2347 style options\n"
+ "\toptions extra : toggle support for non-RFC defined options\n"
+ );
+}
+
+static void
+setrollover(int argc, char *argv[])
+{
+
+ if (argc == 2) {
+ if (strcasecmp(argv[1], "never") == 0 ||
+ strcasecmp(argv[1], "none") == 0) {
+ free(options[OPT_ROLLOVER].o_request);
+ options[OPT_ROLLOVER].o_request = NULL;
+ }
+ if (strcasecmp(argv[1], "1") == 0) {
+ free(options[OPT_ROLLOVER].o_request);
+ options[OPT_ROLLOVER].o_request = strdup("1");
+ }
+ if (strcasecmp(argv[1], "0") == 0) {
+ free(options[OPT_ROLLOVER].o_request);
+ options[OPT_ROLLOVER].o_request = strdup("0");
+ }
+ }
+ printf("Support for the rollover options is %s.\n",
+ options[OPT_ROLLOVER].o_request != NULL ? "enabled" : "disabled");
+ if (options[OPT_ROLLOVER].o_request != NULL)
+ printf("Block rollover will be to block %s.\n",
+ options[OPT_ROLLOVER].o_request);
+
+
+ printf("\nThe following rollover options are available:\n"
+ "\trollover 0 : rollover to block zero (default)\n"
+ "\trollover 1 : rollover to block one\n"
+ "\trollover never : do not support the rollover option\n"
+ "\trollover none : do not support the rollover option\n"
+ );
+}
+
+static void
+setdebug(int argc, char *argv[])
+{
+ int i;
+
+ if (argc != 1) {
+ i = 1;
+ while (i < argc)
+ debug ^= debug_find(argv[i++]);
+ }
+ printf("The following debugging is enabled: %s\n", debug_show(debug));
+
+ printf("\nThe following debugs are available:\n");
+ i = 0;
+ while (debugs[i].name != NULL) {
+ printf("\t%s\t%s\n", debugs[i].name, debugs[i].desc);
+ i++;
+ }
+}
+
+static void
+setblocksize(int argc, char *argv[])
+{
+
+ if (!options_rfc_enabled)
+ printf("RFC2347 style options are not enabled "
+ "(but proceding anyway)\n");
+
+ if (argc != 1) {
+ int size = atoi(argv[1]);
+ size_t max;
+ char maxbuffer[100];
+ int *maxdgram;
+
+ max = sizeof(maxbuffer);
+ if (sysctlbyname("net.inet.udp.maxdgram",
+ maxbuffer, &max, NULL, 0) < 0) {
+ perror("sysctl: net.inet.udp.maxdgram");
+ return;
+ }
+ maxdgram = (int *)maxbuffer;
+
+ if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) {
+ printf("Blocksize should be between %d and %d bytes.\n",
+ BLKSIZE_MIN, BLKSIZE_MAX);
+ return;
+ } else if (size > *maxdgram - 4) {
+ printf("Blocksize can't be bigger than %d bytes due "
+ "to the net.inet.udp.maxdgram sysctl limitation.\n",
+ *maxdgram - 4);
+ asprintf(&options[OPT_BLKSIZE].o_request,
+ "%d", *maxdgram - 4);
+ } else {
+ asprintf(&options[OPT_BLKSIZE].o_request, "%d", size);
+ }
+ }
+ printf("Blocksize is now %s bytes.\n", options[OPT_BLKSIZE].o_request);
+}
+
+static void
+setblocksize2(int argc, char *argv[])
+{
+
+ if (!options_rfc_enabled || !options_extra_enabled)
+ printf(
+ "RFC2347 style or non-RFC defined options are not enabled "
+ "(but proceding anyway)\n");
+
+ if (argc != 1) {
+ int size = atoi(argv[1]);
+ int i;
+ size_t max;
+ char maxbuffer[100];
+ int *maxdgram;
+
+ int sizes[] = {
+ 8, 16, 32, 64, 128, 256, 512, 1024,
+ 2048, 4096, 8192, 16384, 32768, 0
+ };
+
+ max = sizeof(maxbuffer);
+ if (sysctlbyname("net.inet.udp.maxdgram",
+ maxbuffer, &max, NULL, 0) < 0) {
+ perror("sysctl: net.inet.udp.maxdgram");
+ return;
+ }
+ maxdgram = (int *)maxbuffer;
+
+ for (i = 0; sizes[i] != 0; i++) {
+ if (sizes[i] == size) break;
+ }
+ if (sizes[i] == 0) {
+ printf("Blocksize2 should be a power of two between "
+ "8 and 32768.\n");
+ return;
+ }
+
+ if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) {
+ printf("Blocksize2 should be between "
+ "%d and %d bytes.\n", BLKSIZE_MIN, BLKSIZE_MAX);
+ return;
+ } else if (size > *maxdgram - 4) {
+ printf("Blocksize2 can't be bigger than %d bytes due "
+ "to the net.inet.udp.maxdgram sysctl limitation.\n",
+ *maxdgram - 4);
+ for (i = 0; sizes[i+1] != 0; i++) {
+ if (*maxdgram < sizes[i+1]) break;
+ }
+ asprintf(&options[OPT_BLKSIZE2].o_request,
+ "%d", sizes[i]);
+ } else {
+ asprintf(&options[OPT_BLKSIZE2].o_request, "%d", size);
+ }
+ }
+ printf("Blocksize2 is now %s bytes.\n",
+ options[OPT_BLKSIZE2].o_request);
+}
+
+static void
+setpacketdrop(int argc, char *argv[])
+{
+
+ if (argc != 1)
+ packetdroppercentage = atoi(argv[1]);
+
+ printf("Randomly %d in 100 packets will be dropped\n",
+ packetdroppercentage);
+}
diff --git a/usr.bin/tftp/tftp.1 b/usr.bin/tftp/tftp.1
index 8924eb5..04daa87 100644
--- a/usr.bin/tftp/tftp.1
+++ b/usr.bin/tftp/tftp.1
@@ -37,7 +37,7 @@
.Os
.Sh NAME
.Nm tftp
-.Nd "trivial file transfer program"
+.Nd trivial file transfer program
.Sh SYNOPSIS
.Nm
.Op Ar host Op Ar port
@@ -55,28 +55,26 @@ may be specified on the command line, in which case
uses
.Ar host
as the default host for future transfers (see the
-.Ic connect
+.Cm connect
command below).
.Sh COMMANDS
Once
.Nm
is running, it issues the prompt
-.Dq Li "tftp> "
+.Dq Li tftp>
and recognizes the following commands:
.Pp
-.Bl -tag -width ".Ic verbose" -compact
-.It Ic \&? Ar command-name ...
+.Bl -tag -width verbose -compact
+.It Cm \&? Ar command-name ...
Print help information.
.Pp
-.It Ic ascii
-Shorthand for
-.Ic mode Cm ascii .
+.It Cm ascii
+Shorthand for "mode ascii"
.Pp
-.It Ic binary
-Shorthand for
-.Ic mode Cm binary .
+.It Cm binary
+Shorthand for "mode binary"
.Pp
-.It Ic connect Ar host Op Ar port
+.It Cm connect Ar host Op Ar port
Set the
.Ar host
(and optionally
@@ -88,19 +86,19 @@ protocol, unlike the
.Tn FTP
protocol,
does not maintain connections between transfers; thus, the
-.Ic connect
+.Cm connect
command does not actually create a connection,
but merely remembers what host is to be used for transfers.
You do not have to use the
-.Ic connect
+.Cm connect
command; the remote host can be specified as part of the
-.Ic get
+.Cm get
or
-.Ic put
+.Cm put
commands.
.Pp
-.It Ic get Oo Ar host : Oc Ns Ar file Op Ar localname
-.It Ic get Xo
+.It Cm get Oo Ar host : Oc Ns Ar file Op Ar localname
+.It Cm get Xo
.Oo Ar host1 : Oc Ns Ar file1
.Oo Ar host2 : Oc Ns Ar file2 ...
.Oo Ar hostN : Oc Ns Ar fileN
@@ -126,18 +124,18 @@ to disambiguate the
colons used in the IPv6 address from the colon separating the host and
the filename.
.Pp
-.It Ic mode Ar transfer-mode
+.It Cm mode Ar transfer-mode
Set the mode for transfers;
.Ar transfer-mode
may be one of
-.Cm ascii
+.Em ascii
or
-.Cm binary .
+.Em binary .
The default is
-.Cm ascii .
+.Em ascii .
.Pp
-.It Ic put Ar file Op Oo Ar host : Oc Ns Ar remotename
-.It Ic put Ar file1 file2 ... fileN Op Oo Ar host : Oc Ns Ar remote-directory
+.It Cm put Ar file Op Oo Ar host : Oc Ns Ar remotename
+.It Cm put Ar file1 file2 ... fileN Op Oo Ar host : Oc Ns Ar remote-directory
Put a file or set of files to the remote host.
When
.Ar remotename
@@ -152,27 +150,27 @@ machine.
To specify an IPv6 numeric address for a
.Ar host ,
see the example under the
-.Ic get
+.Cm get
command.
.Pp
-.It Ic quit
+.It Cm quit
Exit
.Nm .
An end of file also exits.
.Pp
-.It Ic rexmt Ar retransmission-timeout
+.It Cm rexmt Ar retransmission-timeout
Set the per-packet retransmission timeout, in seconds.
.Pp
-.It Ic status
+.It Cm status
Show current status.
.Pp
-.It Ic timeout Ar total-transmission-timeout
+.It Cm timeout Ar total-transmission-timeout
Set the total transmission timeout, in seconds.
.Pp
-.It Ic trace
+.It Cm trace
Toggle packet tracing.
.Pp
-.It Ic verbose
+.It Cm verbose
Toggle verbose mode.
.El
.Sh HISTORY
diff --git a/usr.bin/tftp/tftp.c b/usr.bin/tftp/tftp.c
index 4300902..29ba2b2 100644
--- a/usr.bin/tftp/tftp.c
+++ b/usr.bin/tftp/tftp.c
@@ -45,446 +45,230 @@ __FBSDID("$FreeBSD$");
/*
* TFTP User Program -- Protocol Machines
*/
-#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/time.h>
+#include <sys/stat.h>
#include <netinet/in.h>
-#include <arpa/inet.h>
#include <arpa/tftp.h>
#include <err.h>
-#include <errno.h>
-#include <setjmp.h>
-#include <signal.h>
+#include <netdb.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <netdb.h>
+#include <syslog.h>
-#include "extern.h"
-#include "tftpsubs.h"
-
-extern struct sockaddr_storage peeraddr; /* filled in by main */
-extern int f; /* the opened socket */
-extern int trace;
-extern int verbose;
-extern int rexmtval;
-extern int maxtimeout;
-extern volatile int txrx_error;
-
-#define PKTSIZE SEGSIZE+4
-char ackbuf[PKTSIZE];
-int timeout;
-jmp_buf toplevel;
-jmp_buf timeoutbuf;
-
-static void nak(int, const struct sockaddr *);
-static int makerequest(int, const char *, struct tftphdr *, const char *);
-static void printstats(const char *, unsigned long);
-static void startclock(void);
-static void stopclock(void);
-static void timer(int);
-static void tpacket(const char *, struct tftphdr *, int);
-static int cmpport(const struct sockaddr *, const struct sockaddr *);
+#include "tftp.h"
+#include "tftp-file.h"
+#include "tftp-utils.h"
+#include "tftp-io.h"
+#include "tftp-transfer.h"
+#include "tftp-options.h"
/*
* Send the requested file.
*/
void
-xmitfile(int fd, const char *name, const char *mode)
+xmitfile(int peer, char *port, int fd, char *name, char *mode)
{
- struct tftphdr *ap; /* data and ack packets */
- struct tftphdr *dp;
- int n;
- volatile unsigned short block;
- volatile int size, convert;
- volatile unsigned long amount;
- struct sockaddr_storage from;
- socklen_t fromlen;
- FILE *file;
- struct sockaddr_storage peer;
+ struct tftphdr *rp;
+ int n, i;
+ uint16_t block;
+ uint32_t amount;
struct sockaddr_storage serv; /* valid server port number */
+ char recvbuffer[MAXPKTSIZE];
+ struct tftp_stats tftp_stats;
+
+ stats_init(&tftp_stats);
- startclock(); /* start stat's clock */
- dp = r_init(); /* reset fillbuf/read-ahead code */
- ap = (struct tftphdr *)ackbuf;
- file = fdopen(fd, "r");
- convert = !strcmp(mode, "netascii");
- block = 0;
- amount = 0;
- memcpy(&peer, &peeraddr, peeraddr.ss_len);
memset(&serv, 0, sizeof(serv));
+ rp = (struct tftphdr *)recvbuffer;
+
+ if (port == NULL) {
+ struct servent *se;
+ se = getservbyname("tftp", "udp");
+ ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port;
+ } else
+ ((struct sockaddr_in *)&peer_sock)->sin_port =
+ htons(atoi(port));
+
+ for (i = 0; i < 12; i++) {
+ struct sockaddr_storage from;
+
+ /* Tell the other side what we want to do */
+ if (debug&DEBUG_SIMPLE)
+ printf("Sending %s\n", name);
+
+ n = send_wrq(peer, name, mode);
+ if (n > 0) {
+ printf("Cannot send WRQ packet\n");
+ return;
+ }
- signal(SIGALRM, timer);
- do {
- if (block == 0)
- size = makerequest(WRQ, name, dp, mode) - 4;
- else {
- /* size = read(fd, dp->th_data, SEGSIZE); */
- size = readit(file, &dp, convert);
- if (size < 0) {
- nak(errno + 100, (struct sockaddr *)&peer);
- break;
- }
- dp->th_opcode = htons((u_short)DATA);
- dp->th_block = htons((u_short)block);
+ /*
+ * The first packet we receive has the new destination port
+ * we have to send the next packets to.
+ */
+ n = receive_packet(peer, recvbuffer,
+ MAXPKTSIZE, &from, timeoutpacket);
+
+ /* We got some data! */
+ if (n >= 0) {
+ ((struct sockaddr_in *)&peer_sock)->sin_port =
+ ((struct sockaddr_in *)&from)->sin_port;
+ break;
}
- timeout = 0;
- (void) setjmp(timeoutbuf);
-send_data:
- if (trace)
- tpacket("sent", dp, size + 4);
- n = sendto(f, dp, size + 4, 0,
- (struct sockaddr *)&peer, peer.ss_len);
- if (n != size + 4) {
- warn("sendto");
- txrx_error = 1;
- goto abort;
+
+ /* This should be retried */
+ if (n == RP_TIMEOUT) {
+ printf("Try %d, didn't receive answer from remote.\n",
+ i + 1);
+ continue;
}
- read_ahead(file, convert);
- for ( ; ; ) {
- alarm(rexmtval);
- do {
- fromlen = sizeof(from);
- n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
- (struct sockaddr *)&from, &fromlen);
- } while (n <= 0);
- alarm(0);
- if (n < 0) {
- warn("recvfrom");
- txrx_error = 1;
- goto abort;
- }
- if (!serv.ss_family)
- serv = from;
- else if (!cmpport((struct sockaddr *)&serv,
- (struct sockaddr *)&from)) {
- warn("server port mismatch");
- txrx_error = 1;
- goto abort;
- }
- peer = from;
- if (trace)
- tpacket("received", ap, n);
- /* should verify packet came from server */
- ap->th_opcode = ntohs(ap->th_opcode);
- ap->th_block = ntohs(ap->th_block);
- if (ap->th_opcode == ERROR) {
- printf("Error code %d: %s\n", ap->th_code,
- ap->th_msg);
- txrx_error = 1;
- goto abort;
- }
- if (ap->th_opcode == ACK) {
- int j;
-
- if (ap->th_block == block) {
- break;
- }
- /* On an error, try to synchronize
- * both sides.
- */
- j = synchnet(f);
- if (j && trace) {
- printf("discarded %d packets\n",
- j);
- }
- if (ap->th_block == (block-1)) {
- goto send_data;
- }
- }
+
+ /* Everything else is fatal */
+ break;
+ }
+ if (i == 12) {
+ printf("Transfer timed out.\n");
+ return;
+ }
+ if (rp->th_opcode == ERROR) {
+ printf("Got ERROR, aborted\n");
+ return;
+ }
+
+ /*
+ * If the first packet is an OACK instead of an ACK packet,
+ * handle it different.
+ */
+ if (rp->th_opcode == OACK) {
+ if (!options_rfc_enabled) {
+ printf("Got OACK while options are not enabled!\n");
+ send_error(peer, EBADOP);
+ return;
}
- if (block > 0)
- amount += size;
- block++;
- } while (size == SEGSIZE || block == 1);
-abort:
- fclose(file);
- stopclock();
- if (amount > 0)
- printstats("Sent", amount);
-}
-/*
- * Receive a file.
- */
-void
-recvfile(int fd, const char *name, const char *mode)
-{
- struct tftphdr *ap;
- struct tftphdr *dp;
- int n;
- volatile unsigned short block;
- volatile int size, firsttrip;
- volatile unsigned long amount;
- struct sockaddr_storage from;
- socklen_t fromlen;
- FILE *file;
- volatile int convert; /* true if converting crlf -> lf */
- struct sockaddr_storage peer;
- struct sockaddr_storage serv; /* valid server port number */
+ parse_options(peer, rp->th_stuff, n + 2);
+ }
+
+ if (read_init(fd, NULL, mode) < 0) {
+ warn("read_init()");
+ return;
+ }
- startclock();
- dp = w_init();
- ap = (struct tftphdr *)ackbuf;
- file = fdopen(fd, "w");
- convert = !strcmp(mode, "netascii");
block = 1;
- firsttrip = 1;
- amount = 0;
- memcpy(&peer, &peeraddr, peeraddr.ss_len);
- memset(&serv, 0, sizeof(serv));
+ tftp_send(peer, &block, &tftp_stats);
- signal(SIGALRM, timer);
- do {
- if (firsttrip) {
- size = makerequest(RRQ, name, ap, mode);
- firsttrip = 0;
- } else {
- ap->th_opcode = htons((u_short)ACK);
- ap->th_block = htons((u_short)(block));
- size = 4;
- block++;
- }
- timeout = 0;
- (void) setjmp(timeoutbuf);
-send_ack:
- if (trace)
- tpacket("sent", ap, size);
- if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer,
- peer.ss_len) != size) {
- alarm(0);
- warn("sendto");
- txrx_error = 1;
- goto abort;
- }
- write_behind(file, convert);
- for ( ; ; ) {
- alarm(rexmtval);
- do {
- fromlen = sizeof(from);
- n = recvfrom(f, dp, PKTSIZE, 0,
- (struct sockaddr *)&from, &fromlen);
- } while (n <= 0);
- alarm(0);
- if (n < 0) {
- warn("recvfrom");
- txrx_error = 1;
- goto abort;
- }
- if (!serv.ss_family)
- serv = from;
- else if (!cmpport((struct sockaddr *)&serv,
- (struct sockaddr *)&from)) {
- warn("server port mismatch");
- txrx_error = 1;
- goto abort;
- }
- peer = from;
- if (trace)
- tpacket("received", dp, n);
- /* should verify client address */
- dp->th_opcode = ntohs(dp->th_opcode);
- dp->th_block = ntohs(dp->th_block);
- if (dp->th_opcode == ERROR) {
- printf("Error code %d: %s\n", dp->th_code,
- dp->th_msg);
- txrx_error = 1;
- goto abort;
- }
- if (dp->th_opcode == DATA) {
- int j;
-
- if (dp->th_block == block) {
- break; /* have next packet */
- }
- /* On an error, try to synchronize
- * both sides.
- */
- j = synchnet(f);
- if (j && trace) {
- printf("discarded %d packets\n", j);
- }
- if (dp->th_block == (block-1)) {
- goto send_ack; /* resend ack */
- }
- }
- }
- /* size = write(fd, dp->th_data, n - 4); */
- size = writeit(file, &dp, n - 4, convert);
- if (size < 0) {
- nak(errno + 100, (struct sockaddr *)&peer);
- break;
- }
- amount += size;
- } while (size == SEGSIZE);
-abort: /* ok to ack, since user */
- ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
- ap->th_block = htons((u_short)block);
- (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
- peer.ss_len);
- write_behind(file, convert); /* flush last buffer */
- fclose(file);
- stopclock();
+ read_close();
if (amount > 0)
- printstats("Received", amount);
-}
+ printstats("Sent", verbose, &tftp_stats);
-static int
-makerequest(int request, const char *name, struct tftphdr *tp, const char *mode)
-{
- char *cp;
-
- tp->th_opcode = htons((u_short)request);
- cp = tp->th_stuff;
- strcpy(cp, name);
- cp += strlen(name);
- *cp++ = '\0';
- strcpy(cp, mode);
- cp += strlen(mode);
- *cp++ = '\0';
- return (cp - (char *)tp);
+ txrx_error = 1;
}
-struct errmsg {
- int e_code;
- const char *e_msg;
-} errmsgs[] = {
- { EUNDEF, "Undefined error code" },
- { ENOTFOUND, "File not found" },
- { EACCESS, "Access violation" },
- { ENOSPACE, "Disk full or allocation exceeded" },
- { EBADOP, "Illegal TFTP operation" },
- { EBADID, "Unknown transfer ID" },
- { EEXISTS, "File already exists" },
- { ENOUSER, "No such user" },
- { -1, 0 }
-};
-
/*
- * Send a nak packet (error message).
- * Error code passed in is one of the
- * standard TFTP codes, or a UNIX errno
- * offset by 100.
+ * Receive a file.
*/
-static void
-nak(int error, const struct sockaddr *peer)
-{
- struct errmsg *pe;
- struct tftphdr *tp;
- int length;
-
- tp = (struct tftphdr *)ackbuf;
- tp->th_opcode = htons((u_short)ERROR);
- tp->th_code = htons((u_short)error);
- for (pe = errmsgs; pe->e_code >= 0; pe++)
- if (pe->e_code == error)
- break;
- if (pe->e_code < 0) {
- pe->e_msg = strerror(error - 100);
- tp->th_code = EUNDEF;
- }
- strcpy(tp->th_msg, pe->e_msg);
- length = strlen(pe->e_msg) + 4;
- if (trace)
- tpacket("sent", tp, length);
- if (sendto(f, ackbuf, length, 0, peer, peer->sa_len) != length)
- warn("nak");
-}
-
-static void
-tpacket(const char *s, struct tftphdr *tp, int n)
+void
+recvfile(int peer, char *port, int fd, char *name, char *mode)
{
- static const char *opcodes[] =
- { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
- char *cp, *file;
- u_short op = ntohs(tp->th_opcode);
-
- if (op < RRQ || op > ERROR)
- printf("%s opcode=%x ", s, op);
- else
- printf("%s %s ", s, opcodes[op]);
- switch (op) {
-
- case RRQ:
- case WRQ:
- n -= 2;
- file = cp = tp->th_stuff;
- cp = index(cp, '\0');
- printf("<file=%s, mode=%s>\n", file, cp + 1);
- break;
+ struct tftphdr *rp;
+ uint16_t block;
+ char recvbuffer[MAXPKTSIZE];
+ int n, i;
+ struct tftp_stats tftp_stats;
+
+ stats_init(&tftp_stats);
+
+ rp = (struct tftphdr *)recvbuffer;
+
+ if (port == NULL) {
+ struct servent *se;
+ se = getservbyname("tftp", "udp");
+ ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port;
+ } else
+ ((struct sockaddr_in *)&peer_sock)->sin_port =
+ htons(atoi(port));
+
+ for (i = 0; i < 12; i++) {
+ struct sockaddr_storage from;
+
+ /* Tell the other side what we want to do */
+ if (debug&DEBUG_SIMPLE)
+ printf("Requesting %s\n", name);
+
+ n = send_rrq(peer, name, mode);
+ if (n > 0) {
+ printf("Cannot send RRQ packet\n");
+ return;
+ }
- case DATA:
- printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
- break;
+ /*
+ * The first packet we receive has the new destination port
+ * we have to send the next packets to.
+ */
+ n = receive_packet(peer, recvbuffer,
+ MAXPKTSIZE, &from, timeoutpacket);
+
+ /* We got something useful! */
+ if (n >= 0) {
+ ((struct sockaddr_in *)&peer_sock)->sin_port =
+ ((struct sockaddr_in *)&from)->sin_port;
+ break;
+ }
- case ACK:
- printf("<block=%d>\n", ntohs(tp->th_block));
- break;
+ /* We should retry if this happens */
+ if (n == RP_TIMEOUT) {
+ printf("Try %d, didn't receive answer from remote.\n",
+ i + 1);
+ continue;
+ }
- case ERROR:
- printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
+ /* Otherwise it is a fatal error */
break;
}
-}
-
-struct timeval tstart;
-struct timeval tstop;
-
-static void
-startclock(void)
-{
- (void)gettimeofday(&tstart, NULL);
-}
-
-static void
-stopclock(void)
-{
+ if (rp->th_opcode == ERROR) {
+ tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg);
+ return;
+ }
- (void)gettimeofday(&tstop, NULL);
-}
+ if (write_init(fd, NULL, mode) < 0) {
+ warn("write_init");
+ return;
+ }
-static void
-printstats(const char *direction, unsigned long amount)
-{
- double delta;
- /* compute delta in 1/10's second units */
- delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
- ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
- delta = delta/10.; /* back to seconds */
- printf("%s %ld bytes in %.1f seconds", direction, amount, delta);
- if (verbose)
- printf(" [%.0f bits/sec]", (amount*8.)/delta);
- putchar('\n');
-}
+ stats_init(&tftp_stats);
+
+ /*
+ * If the first packet is an OACK packet instead of an DATA packet,
+ * handle it different.
+ */
+ if (rp->th_opcode == OACK) {
+ if (!options_rfc_enabled) {
+ printf("Got OACK while options are not enabled!\n");
+ send_error(peer, EBADOP);
+ return;
+ }
-static void
-timer(int sig __unused)
-{
+ parse_options(peer, rp->th_stuff, n + 2);
- timeout += rexmtval;
- if (timeout >= maxtimeout) {
- printf("Transfer timed out.\n");
- longjmp(toplevel, -1);
+ n = send_ack(peer, 0);
+ if (n > 0) {
+ printf("Cannot send ACK on OACK.\n");
+ return;
+ }
+ block = 0;
+ tftp_receive(peer, &block, &tftp_stats, NULL, 0);
+ } else {
+ block = 1;
+ tftp_receive(peer, &block, &tftp_stats, rp, n);
}
- txrx_error = 1;
- longjmp(timeoutbuf, 1);
-}
-
-static int
-cmpport(const struct sockaddr *sa, const struct sockaddr *sb)
-{
- char a[NI_MAXSERV], b[NI_MAXSERV];
-
- if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV))
- return 0;
- if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV))
- return 0;
- if (strcmp(a, b) != 0)
- return 0;
- return 1;
+ write_close();
+ if (tftp_stats.amount > 0)
+ printstats("Received", verbose, &tftp_stats);
+ return;
}
diff --git a/usr.bin/tftp/tftp.h b/usr.bin/tftp/tftp.h
new file mode 100644
index 0000000..5928dea
--- /dev/null
+++ b/usr.bin/tftp/tftp.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD$
+ */
+
+void recvfile(int peer, char *port, int fd, char *name, char *mode);
+void xmitfile(int peer, char *port, int fd, char *name, char *mode);
+
+extern int verbose;
+extern int maxtimeout;
+extern volatile int txrx_error;
OpenPOWER on IntegriCloud