Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: tftp/main.c
===================================================================
--- tftp/main.c	(nonexistent)
+++ tftp/main.c	(revision 5)
@@ -0,0 +1,945 @@
+/*
+ * Copyright (c) 1983, 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.
+ */
+
+#include "common/tftpsubs.h"
+
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
+/*
+ * TFTP User Program -- Command Interface.
+ */
+#include <sys/file.h>
+#include <ctype.h>
+#ifdef WITH_READLINE
+#include <readline/readline.h>
+#ifdef HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif
+#endif
+
+#include "extern.h"
+
+#define	TIMEOUT		5       /* secs between rexmt's */
+#define	LBUFLEN		200     /* size of input buffer */
+
+struct modes {
+    const char *m_name;
+    const char *m_mode;
+    int m_openflags;
+};
+
+static const struct modes modes[] = {
+    {"netascii", "netascii", O_TEXT},
+    {"ascii", "netascii", O_TEXT},
+    {"octet", "octet", O_BINARY},
+    {"binary", "octet", O_BINARY},
+    {"image", "octet", O_BINARY},
+    {0, 0, 0}
+};
+
+#define MODE_OCTET    (&modes[2])
+#define MODE_NETASCII (&modes[0])
+#define MODE_DEFAULT  MODE_NETASCII
+
+#ifdef HAVE_IPV6
+int ai_fam = AF_UNSPEC;
+int ai_fam_sock = AF_UNSPEC;
+#else
+int ai_fam = AF_INET;
+int ai_fam_sock = AF_INET;
+#endif
+
+union sock_addr peeraddr;
+int f = -1;
+u_short port;
+int trace;
+int verbose;
+int literal;
+int connected;
+const struct modes *mode;
+#ifdef WITH_READLINE
+char *line = NULL;
+#else
+char line[LBUFLEN];
+#endif
+int margc;
+char *margv[20];
+const char *prompt = "tftp> ";
+sigjmp_buf toplevel;
+void intr(int);
+struct servent *sp;
+int portrange = 0;
+unsigned int portrange_from = 0;
+unsigned int portrange_to = 0;
+
+void get(int, char **);
+void help(int, char **);
+void modecmd(int, char **);
+void put(int, char **);
+void quit(int, char **);
+void setascii(int, char **);
+void setbinary(int, 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 **);
+void setliteral(int, char **);
+
+static void command(void);
+
+static void getusage(char *);
+static void makeargv(void);
+static void putusage(char *);
+static void settftpmode(const struct modes *);
+
+#define HELPINDENT (sizeof("connect"))
+
+struct cmd {
+    const char *name;
+    const char *help;
+    void (*handler) (int, char **);
+};
+
+struct cmd cmdtab[] = {
+    {"connect",
+     "connect to remote tftp",
+     setpeer},
+    {"mode",
+     "set file transfer mode",
+     modecmd},
+    {"put",
+     "send file",
+     put},
+    {"get",
+     "receive file",
+     get},
+    {"quit",
+     "exit tftp",
+     quit},
+    {"verbose",
+     "toggle verbose mode",
+     setverbose},
+    {"trace",
+     "toggle packet tracing",
+     settrace},
+    {"literal",
+     "toggle literal mode, ignore ':' in file name",
+     setliteral},
+    {"status",
+     "show current status",
+     status},
+    {"binary",
+     "set mode to octet",
+     setbinary},
+    {"ascii",
+     "set mode to netascii",
+     setascii},
+    {"rexmt",
+     "set per-packet transmission timeout",
+     setrexmt},
+    {"timeout",
+     "set total retransmission timeout",
+     settimeout},
+    {"?",
+     "print help information",
+     help},
+    {"help",
+     "print help information",
+     help},
+    {0, 0, 0}
+};
+
+struct cmd *getcmd(char *);
+char *tail(char *);
+
+char *xstrdup(const char *);
+
+const char *program;
+
+static void usage(int errcode)
+{
+    fprintf(stderr,
+#ifdef HAVE_IPV6
+            "Usage: %s [-4][-6][-v][-l][-m mode] [host [port]] [-c command]\n",
+#else
+            "Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n",
+#endif
+            program);
+    exit(errcode);
+}
+
+int main(int argc, char *argv[])
+{
+    union sock_addr sa;
+    int arg;
+    static int pargc, peerargc;
+    static int iscmd = 0;
+    char **pargv;
+    const char *optx;
+    char *peerargv[3];
+
+    program = argv[0];
+
+    mode = MODE_DEFAULT;
+
+    peerargv[0] = argv[0];
+    peerargc = 1;
+
+    for (arg = 1; !iscmd && arg < argc; arg++) {
+        if (argv[arg][0] == '-') {
+            for (optx = &argv[arg][1]; *optx; optx++) {
+                switch (*optx) {
+                case '4':
+                    ai_fam = AF_INET;
+                    break;
+#ifdef HAVE_IPV6
+                case '6':
+                    ai_fam = AF_INET6;
+                    break;
+#endif
+                case 'v':
+                    verbose = 1;
+                    break;
+                case 'V':
+                    /* Print version and configuration to stdout and exit */
+                    printf("%s\n", TFTP_CONFIG_STR);
+                    exit(0);
+                case 'l':
+                    literal = 1;
+                    break;
+                case 'm':
+                    if (++arg >= argc)
+                        usage(EX_USAGE);
+                    {
+                        const struct modes *p;
+
+                        for (p = modes; p->m_name; p++) {
+                            if (!strcmp(argv[arg], p->m_name))
+                                break;
+                        }
+                        if (p->m_name) {
+                            settftpmode(p);
+                        } else {
+                            fprintf(stderr, "%s: invalid mode: %s\n",
+                                    argv[0], argv[arg]);
+                            exit(EX_USAGE);
+                        }
+                    }
+                    break;
+                case 'c':
+                    iscmd = 1;
+                    break;
+                case 'R':
+                    if (++arg >= argc)
+                        usage(EX_USAGE);
+                    if (sscanf
+                        (argv[arg], "%u:%u", &portrange_from,
+                         &portrange_to) != 2
+                        || portrange_from > portrange_to
+                        || portrange_to > 65535) {
+                        fprintf(stderr, "Bad port range: %s\n", argv[arg]);
+                        exit(EX_USAGE);
+                    }
+                    portrange = 1;
+                    break;
+                case 'h':
+                default:
+                    usage(*optx == 'h' ? 0 : EX_USAGE);
+                }
+            }
+        } else {
+            if (peerargc >= 3)
+                usage(EX_USAGE);
+
+            peerargv[peerargc++] = argv[arg];
+        }
+    }
+
+    ai_fam_sock = ai_fam;
+
+    pargv = argv + arg;
+    pargc = argc - arg;
+
+    sp = getservbyname("tftp", "udp");
+    if (sp == 0) {
+        /* Use canned values */
+        if (verbose)
+            fprintf(stderr,
+                    "tftp: tftp/udp: unknown service, faking it...\n");
+        sp = xmalloc(sizeof(struct servent));
+        sp->s_name = (char *)"tftp";
+        sp->s_aliases = NULL;
+        sp->s_port = htons(IPPORT_TFTP);
+        sp->s_proto = (char *)"udp";
+    }
+
+    bsd_signal(SIGINT, intr);
+
+    if (peerargc) {
+        /* Set peer */
+        if (sigsetjmp(toplevel, 1) != 0)
+            exit(EX_NOHOST);
+        setpeer(peerargc, peerargv);
+    }
+
+    if (ai_fam_sock == AF_UNSPEC)
+        ai_fam_sock = AF_INET;
+
+    f = socket(ai_fam_sock, SOCK_DGRAM, 0);
+    if (f < 0) {
+        perror("tftp: socket");
+        exit(EX_OSERR);
+    }
+    bzero(&sa, sizeof(sa));
+    sa.sa.sa_family = ai_fam_sock;
+    if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
+        perror("tftp: bind");
+        exit(EX_OSERR);
+    }
+
+    if (iscmd && pargc) {
+        /* -c specified; execute command and exit */
+        struct cmd *c;
+
+        if (sigsetjmp(toplevel, 1) != 0)
+            exit(EX_UNAVAILABLE);
+
+        c = getcmd(pargv[0]);
+        if (c == (struct cmd *)-1 || c == (struct cmd *)0) {
+            fprintf(stderr, "%s: invalid command: %s\n", argv[0],
+                    pargv[1]);
+            exit(EX_USAGE);
+        }
+        (*c->handler) (pargc, pargv);
+        exit(0);
+    }
+#ifdef WITH_READLINE
+#ifdef HAVE_READLINE_HISTORY_H
+    using_history();
+#endif
+#endif
+
+    if (sigsetjmp(toplevel, 1) != 0)
+        (void)putchar('\n');
+    command();
+
+    return 0;                   /* Never reached */
+}
+
+char *hostname;
+
+/* Called when a command is incomplete; modifies
+   the global variable "line" */
+static void getmoreargs(const char *partial, const char *mprompt)
+{
+#ifdef WITH_READLINE
+    char *eline;
+    int len, elen;
+
+    len = strlen(partial);
+    eline = readline(mprompt);
+    if (!eline)
+        exit(0);                /* EOF */
+
+    elen = strlen(eline);
+
+    if (line) {
+        free(line);
+        line = NULL;
+    }
+    line = xmalloc(len + elen + 1);
+    strcpy(line, partial);
+    strcpy(line + len, eline);
+    free(eline);
+
+#ifdef HAVE_READLINE_HISTORY_H
+    add_history(line);
+#endif
+#else
+    int len = strlen(partial);
+
+    strcpy(line, partial);
+    fputs(mprompt, stdout);
+    if (fgets(line + len, LBUFLEN - len, stdin) == 0)
+        if (feof(stdin))
+            exit(0);            /* EOF */
+#endif
+}
+
+void setpeer(int argc, char *argv[])
+{
+    int err;
+
+    if (argc < 2) {
+        getmoreargs("connect ", "(to) ");
+        makeargv();
+        argc = margc;
+        argv = margv;
+    }
+    if ((argc < 2) || (argc > 3)) {
+        printf("usage: %s host-name [port]\n", argv[0]);
+        return;
+    }
+
+    peeraddr.sa.sa_family = ai_fam;
+    err = set_sock_addr(argv[1], &peeraddr, &hostname);
+    if (err) {
+        printf("Error: %s\n", gai_strerror(err));
+        printf("%s: unknown host\n", argv[1]);
+        connected = 0;
+        return;
+    }
+    ai_fam = peeraddr.sa.sa_family;
+    if (f == -1) { /* socket not open */
+        ai_fam_sock = ai_fam;
+    } else { /* socket was already open */
+        if (ai_fam_sock != ai_fam) { /* need reopen socken for new family */
+            union sock_addr sa;
+
+            close(f);
+            ai_fam_sock = ai_fam;
+            f = socket(ai_fam_sock, SOCK_DGRAM, 0);
+            if (f < 0) {
+                perror("tftp: socket");
+                exit(EX_OSERR);
+            }
+            bzero((char *)&sa, sizeof (sa));
+            sa.sa.sa_family = ai_fam_sock;
+            if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
+                perror("tftp: bind");
+                exit(EX_OSERR);
+            }
+        }
+    }
+    port = sp->s_port;
+    if (argc == 3) {
+        struct servent *usp;
+        usp = getservbyname(argv[2], "udp");
+        if (usp) {
+            port = usp->s_port;
+        } else {
+            unsigned long myport;
+            char *ep;
+            myport = strtoul(argv[2], &ep, 10);
+            if (*ep || myport > 65535UL) {
+                printf("%s: bad port number\n", argv[2]);
+                connected = 0;
+                return;
+            }
+            port = htons((u_short) myport);
+        }
+    }
+
+    if (verbose) {
+        char tmp[INET6_ADDRSTRLEN], *tp;
+        tp = (char *)inet_ntop(peeraddr.sa.sa_family, SOCKADDR_P(&peeraddr),
+                               tmp, INET6_ADDRSTRLEN);
+        if (!tp)
+            tp = (char *)"???";
+        printf("Connected to %s (%s), port %u\n",
+               hostname, tp, (unsigned int)ntohs(port));
+    }
+    connected = 1;
+}
+
+void modecmd(int argc, char *argv[])
+{
+    const struct modes *p;
+    const char *sep;
+
+    if (argc < 2) {
+        printf("Using %s mode to transfer files.\n", mode->m_mode);
+        return;
+    }
+    if (argc == 2) {
+        for (p = modes; p->m_name; p++)
+            if (strcmp(argv[1], p->m_name) == 0)
+                break;
+        if (p->m_name) {
+            settftpmode(p);
+            return;
+        }
+        printf("%s: unknown mode\n", argv[1]);
+        /* drop through and print usage message */
+    }
+
+    printf("usage: %s [", argv[0]);
+    sep = " ";
+    for (p = modes; p->m_name; p++) {
+        printf("%s%s", sep, p->m_name);
+        if (*sep == ' ')
+            sep = " | ";
+    }
+    printf(" ]\n");
+    return;
+}
+
+void setbinary(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;                 /* Quiet unused warning */
+    settftpmode(MODE_OCTET);
+}
+
+void setascii(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;                 /* Quiet unused warning */
+    settftpmode(MODE_NETASCII);
+}
+
+static void settftpmode(const struct modes *newmode)
+{
+    mode = newmode;
+    if (verbose)
+        printf("mode set to %s\n", mode->m_mode);
+}
+
+/*
+ * Send file(s).
+ */
+void put(int argc, char *argv[])
+{
+    int fd;
+    int n, err;
+    char *cp, *targ;
+
+    if (argc < 2) {
+        getmoreargs("send ", "(file) ");
+        makeargv();
+        argc = margc;
+        argv = margv;
+    }
+    if (argc < 2) {
+        putusage(argv[0]);
+        return;
+    }
+    targ = argv[argc - 1];
+    if (!literal && strchr(argv[argc - 1], ':')) {
+        for (n = 1; n < argc - 1; n++)
+            if (strchr(argv[n], ':')) {
+                putusage(argv[0]);
+                return;
+            }
+        cp = argv[argc - 1];
+        targ = strchr(cp, ':');
+        *targ++ = 0;
+        peeraddr.sa.sa_family = ai_fam;
+        err = set_sock_addr(cp, &peeraddr,&hostname);
+        if (err) {
+            printf("Error: %s\n", gai_strerror(err));
+            printf("%s: unknown host\n", argv[1]);
+            connected = 0;
+            return;
+        }
+        ai_fam = peeraddr.sa.sa_family;
+        connected = 1;
+    }
+    if (!connected) {
+        printf("No target machine specified.\n");
+        return;
+    }
+    if (argc < 4) {
+        cp = argc == 2 ? tail(targ) : argv[1];
+        fd = open(cp, O_RDONLY | mode->m_openflags);
+        if (fd < 0) {
+            fprintf(stderr, "tftp: ");
+            perror(cp);
+            return;
+        }
+        if (verbose)
+            printf("putting %s to %s:%s [%s]\n",
+                   cp, hostname, targ, mode->m_mode);
+        sa_set_port(&peeraddr, port);
+        tftp_sendfile(fd, targ, mode->m_mode);
+        return;
+    }
+    /* this assumes the target is a directory */
+    /* on a remote unix system.  hmmmm.  */
+    cp = strchr(targ, '\0');
+    *cp++ = '/';
+    for (n = 1; n < argc - 1; n++) {
+        strcpy(cp, tail(argv[n]));
+        fd = open(argv[n], O_RDONLY | mode->m_openflags);
+        if (fd < 0) {
+            fprintf(stderr, "tftp: ");
+            perror(argv[n]);
+            continue;
+        }
+        if (verbose)
+            printf("putting %s to %s:%s [%s]\n",
+                   argv[n], hostname, targ, mode->m_mode);
+        sa_set_port(&peeraddr, port);
+        tftp_sendfile(fd, targ, mode->m_mode);
+    }
+}
+
+static void putusage(char *s)
+{
+    printf("usage: %s file ... host:target, or\n", s);
+    printf("       %s file ... target (when already connected)\n", s);
+}
+
+/*
+ * Receive file(s).
+ */
+void get(int argc, char *argv[])
+{
+    int fd;
+    int n;
+    char *cp;
+    char *src;
+
+    if (argc < 2) {
+        getmoreargs("get ", "(files) ");
+        makeargv();
+        argc = margc;
+        argv = margv;
+    }
+    if (argc < 2) {
+        getusage(argv[0]);
+        return;
+    }
+    if (!connected) {
+        for (n = 1; n < argc; n++)
+            if (literal || strchr(argv[n], ':') == 0) {
+                getusage(argv[0]);
+                return;
+            }
+    }
+    for (n = 1; n < argc; n++) {
+        src = strchr(argv[n], ':');
+        if (literal || src == NULL)
+            src = argv[n];
+        else {
+            int err;
+
+            *src++ = 0;
+            peeraddr.sa.sa_family = ai_fam;
+            err = set_sock_addr(argv[n], &peeraddr, &hostname);
+            if (err) {
+                printf("Warning: %s\n", gai_strerror(err));
+                printf("%s: unknown host\n", argv[1]);
+                continue;
+            }
+            ai_fam = peeraddr.sa.sa_family;
+            connected = 1;
+        }
+        if (argc < 4) {
+            cp = argc == 3 ? argv[2] : tail(src);
+            fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags,
+                      0666);
+            if (fd < 0) {
+                fprintf(stderr, "tftp: ");
+                perror(cp);
+                return;
+            }
+            if (verbose)
+                printf("getting from %s:%s to %s [%s]\n",
+                       hostname, src, cp, mode->m_mode);
+            sa_set_port(&peeraddr, port);
+            tftp_recvfile(fd, src, mode->m_mode);
+            break;
+        }
+        cp = tail(src);         /* new .. jdg */
+        fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags,
+                  0666);
+        if (fd < 0) {
+            fprintf(stderr, "tftp: ");
+            perror(cp);
+            continue;
+        }
+        if (verbose)
+            printf("getting from %s:%s to %s [%s]\n",
+                   hostname, src, cp, mode->m_mode);
+        sa_set_port(&peeraddr, port);
+        tftp_recvfile(fd, src, mode->m_mode);
+    }
+}
+
+static void getusage(char *s)
+{
+    printf("usage: %s host:file host:file ... file, or\n", s);
+    printf("       %s file file ... file if connected\n", s);
+}
+
+int rexmtval = TIMEOUT;
+
+void setrexmt(int argc, char *argv[])
+{
+    int t;
+
+    if (argc < 2) {
+        getmoreargs("rexmt-timeout ", "(value) ");
+        makeargv();
+        argc = margc;
+        argv = margv;
+    }
+    if (argc != 2) {
+        printf("usage: %s value\n", argv[0]);
+        return;
+    }
+    t = atoi(argv[1]);
+    if (t < 0)
+        printf("%s: bad value\n", argv[1]);
+    else
+        rexmtval = t;
+}
+
+int maxtimeout = 5 * TIMEOUT;
+
+void settimeout(int argc, char *argv[])
+{
+    int t;
+
+    if (argc < 2) {
+        getmoreargs("maximum-timeout ", "(value) ");
+        makeargv();
+        argc = margc;
+        argv = margv;
+    }
+    if (argc != 2) {
+        printf("usage: %s value\n", argv[0]);
+        return;
+    }
+    t = atoi(argv[1]);
+    if (t < 0)
+        printf("%s: bad value\n", argv[1]);
+    else
+        maxtimeout = t;
+}
+
+void setliteral(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;                 /* Quiet unused warning */
+    literal = !literal;
+    printf("Literal mode %s.\n", literal ? "on" : "off");
+}
+
+void status(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;                 /* Quiet unused warning */
+    if (connected)
+        printf("Connected to %s.\n", hostname);
+    else
+        printf("Not connected.\n");
+    printf("Mode: %s Verbose: %s Tracing: %s Literal: %s\n", mode->m_mode,
+           verbose ? "on" : "off", trace ? "on" : "off",
+           literal ? "on" : "off");
+    printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
+           rexmtval, maxtimeout);
+}
+
+void intr(int sig)
+{
+    (void)sig;                  /* Quiet unused warning */
+
+    bsd_signal(SIGALRM, SIG_IGN);
+    alarm(0);
+    siglongjmp(toplevel, -1);
+}
+
+char *tail(char *filename)
+{
+    char *s;
+
+    while (*filename) {
+        s = strrchr(filename, '/');
+        if (s == NULL)
+            break;
+        if (s[1])
+            return (s + 1);
+        *s = '\0';
+    }
+    return (filename);
+}
+
+/*
+ * Command parser.
+ */
+static void command(void)
+{
+    struct cmd *c;
+
+    for (;;) {
+#ifdef WITH_READLINE
+        if (line) {
+            free(line);
+            line = NULL;
+        }
+        line = readline(prompt);
+        if (!line)
+            exit(0);            /* EOF */
+#else
+        fputs(prompt, stdout);
+        if (fgets(line, LBUFLEN, stdin) == 0) {
+            if (feof(stdin)) {
+                exit(0);
+            } else {
+                continue;
+            }
+        }
+#endif
+        if ((line[0] == 0) || (line[0] == '\n'))
+            continue;
+#ifdef WITH_READLINE
+#ifdef HAVE_READLINE_HISTORY_H
+        add_history(line);
+#endif
+#endif
+        makeargv();
+        if (margc == 0)
+            continue;
+
+        c = getcmd(margv[0]);
+        if (c == (struct cmd *)-1) {
+            printf("?Ambiguous command\n");
+            continue;
+        }
+        if (c == 0) {
+            printf("?Invalid command\n");
+            continue;
+        }
+        (*c->handler) (margc, margv);
+    }
+}
+
+struct cmd *getcmd(char *name)
+{
+    const char *p;
+    char *q;
+    struct cmd *c, *found;
+    int nmatches, longest;
+
+    longest = 0;
+    nmatches = 0;
+    found = 0;
+    for (c = cmdtab; (p = c->name) != NULL; c++) {
+        for (q = name; *q == *p++; q++)
+            if (*q == 0)        /* exact match? */
+                return (c);
+        if (!*q) {              /* the name was a prefix */
+            if (q - name > longest) {
+                longest = q - name;
+                nmatches = 1;
+                found = c;
+            } else if (q - name == longest)
+                nmatches++;
+        }
+    }
+    if (nmatches > 1)
+        return ((struct cmd *)-1);
+    return (found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+static void makeargv(void)
+{
+    char *cp;
+    char **argp = margv;
+
+    margc = 0;
+    for (cp = line; *cp;) {
+        while (isspace(*cp))
+            cp++;
+        if (*cp == '\0')
+            break;
+        *argp++ = cp;
+        margc += 1;
+        while (*cp != '\0' && !isspace(*cp))
+            cp++;
+        if (*cp == '\0')
+            break;
+        *cp++ = '\0';
+    }
+    *argp++ = 0;
+}
+
+void quit(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;                 /* Quiet unused warning */
+    exit(0);
+}
+
+/*
+ * Help command.
+ */
+void help(int argc, char *argv[])
+{
+    struct cmd *c;
+
+    printf("%s\n", VERSION);
+
+    if (argc == 1) {
+        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);
+        return;
+    }
+    while (--argc > 0) {
+        char *arg;
+        arg = *++argv;
+        c = getcmd(arg);
+        if (c == (struct cmd *)-1)
+            printf("?Ambiguous help command %s\n", arg);
+        else if (c == (struct cmd *)0)
+            printf("?Invalid help command %s\n", arg);
+        else
+            printf("%s\n", c->help);
+    }
+}
+
+void settrace(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;                 /* Quiet unused warning */
+
+    trace = !trace;
+    printf("Packet tracing %s.\n", trace ? "on" : "off");
+}
+
+void setverbose(int argc, char *argv[])
+{
+    (void)argc;
+    (void)argv;                 /* Quiet unused warning */
+
+    verbose = !verbose;
+    printf("Verbose mode %s.\n", verbose ? "on" : "off");
+}
Index: tftp/tftp.c
===================================================================
--- tftp/tftp.c	(nonexistent)
+++ tftp/tftp.c	(revision 5)
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1983, 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.
+ */
+
+#include "common/tftpsubs.h"
+
+/*
+ * TFTP User Program -- Protocol Machines
+ */
+#include "extern.h"
+
+extern union sock_addr peeraddr; /* filled in by main */
+extern int f;                    /* the opened socket */
+extern int trace;
+extern int verbose;
+extern int rexmtval;
+extern int maxtimeout;
+
+#define PKTSIZE    SEGSIZE+4
+char ackbuf[PKTSIZE];
+int timeout;
+extern sigjmp_buf toplevel;
+sigjmp_buf timeoutbuf;
+
+static void nak(int, const char *);
+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);
+
+/*
+ * Send the requested file.
+ */
+void tftp_sendfile(int fd, const char *name, const char *mode)
+{
+    struct tftphdr *ap;         /* data and ack packets */
+    struct tftphdr *dp;
+    int n;
+    volatile int is_request;
+    volatile u_short block;
+    volatile int size, convert;
+    volatile off_t amount;
+    union sock_addr from;
+    socklen_t fromlen;
+    FILE *file;
+    u_short ap_opcode, ap_block;
+
+    startclock();               /* start stat's clock */
+    dp = r_init();              /* reset fillbuf/read-ahead code */
+    ap = (struct tftphdr *)ackbuf;
+    convert = !strcmp(mode, "netascii");
+    file = fdopen(fd, convert ? "rt" : "rb");
+    block = 0;
+    is_request = 1;             /* First packet is the actual WRQ */
+    amount = 0;
+
+    bsd_signal(SIGALRM, timer);
+    do {
+        if (is_request) {
+            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, NULL);
+                break;
+            }
+            dp->th_opcode = htons((u_short) DATA);
+            dp->th_block = htons((u_short) block);
+        }
+        timeout = 0;
+        (void)sigsetjmp(timeoutbuf, 1);
+
+        if (trace)
+            tpacket("sent", dp, size + 4);
+        n = sendto(f, dp, size + 4, 0,
+                   &peeraddr.sa, SOCKLEN(&peeraddr));
+        if (n != size + 4) {
+            perror("tftp: sendto");
+            goto abort;
+        }
+        read_ahead(file, convert);
+        for (;;) {
+            alarm(rexmtval);
+            do {
+                fromlen = sizeof(from);
+                n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
+                             &from.sa, &fromlen);
+            } while (n <= 0);
+            alarm(0);
+            if (n < 0) {
+                perror("tftp: recvfrom");
+                goto abort;
+            }
+            sa_set_port(&peeraddr, SOCKPORT(&from));  /* added */
+            if (trace)
+                tpacket("received", ap, n);
+            /* should verify packet came from server */
+            ap_opcode = ntohs((u_short) ap->th_opcode);
+            ap_block = ntohs((u_short) ap->th_block);
+            if (ap_opcode == ERROR) {
+                printf("Error code %d: %s\n", ap_block, ap->th_msg);
+                goto abort;
+            }
+            if (ap_opcode == ACK) {
+                int j;
+
+                if (ap_block == block) {
+                    break;
+                }
+                /* On an error, try to synchronize
+                 * both sides.
+                 */
+                j = synchnet(f);
+                if (j && trace) {
+                    printf("discarded %d packets\n", j);
+                }
+                /*
+                 * RFC1129/RFC1350: We MUST NOT re-send the DATA
+                 * packet in response to an invalid ACK.  Doing so
+                 * would cause the Sorcerer's Apprentice bug.
+                 */
+            }
+        }
+        if (!is_request)
+            amount += size;
+        is_request = 0;
+        block++;
+    } while (size == SEGSIZE || block == 1);
+  abort:
+    fclose(file);
+    stopclock();
+    if (amount > 0)
+        printstats("Sent", amount);
+}
+
+/*
+ * Receive a file.
+ */
+void tftp_recvfile(int fd, const char *name, const char *mode)
+{
+    struct tftphdr *ap;
+    struct tftphdr *dp;
+    int n;
+    volatile u_short block;
+    volatile int size, firsttrip;
+    volatile unsigned long amount;
+    union sock_addr from;
+    socklen_t fromlen;
+    FILE *file;
+    volatile int convert;       /* true if converting crlf -> lf */
+    u_short dp_opcode, dp_block;
+
+    startclock();
+    dp = w_init();
+    ap = (struct tftphdr *)ackbuf;
+    convert = !strcmp(mode, "netascii");
+    file = fdopen(fd, convert ? "wt" : "wb");
+    block = 1;
+    firsttrip = 1;
+    amount = 0;
+
+    bsd_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)sigsetjmp(timeoutbuf, 1);
+      send_ack:
+        if (trace)
+            tpacket("sent", ap, size);
+        if (sendto(f, ackbuf, size, 0, &peeraddr.sa,
+                   SOCKLEN(&peeraddr)) != size) {
+            alarm(0);
+            perror("tftp: sendto");
+            goto abort;
+        }
+        write_behind(file, convert);
+        for (;;) {
+            alarm(rexmtval);
+            do {
+                fromlen = sizeof(from);
+                n = recvfrom(f, dp, PKTSIZE, 0,
+                             &from.sa, &fromlen);
+            } while (n <= 0);
+            alarm(0);
+            if (n < 0) {
+                perror("tftp: recvfrom");
+                goto abort;
+            }
+            sa_set_port(&peeraddr, SOCKPORT(&from));  /* added */
+            if (trace)
+                tpacket("received", dp, n);
+            /* should verify client address */
+            dp_opcode = ntohs((u_short) dp->th_opcode);
+            dp_block = ntohs((u_short) dp->th_block);
+            if (dp_opcode == ERROR) {
+                printf("Error code %d: %s\n", dp_block, dp->th_msg);
+                goto abort;
+            }
+            if (dp_opcode == DATA) {
+                int j;
+
+                if (dp_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_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, NULL);
+            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 *)&peeraddr,
+                 SOCKLEN(&peeraddr));
+    write_behind(file, convert);        /* flush last buffer */
+    fclose(file);
+    stopclock();
+    if (amount > 0)
+        printstats("Received", amount);
+}
+
+static int
+makerequest(int request, const char *name,
+            struct tftphdr *tp, const char *mode)
+{
+    char *cp;
+    size_t len = 0;
+
+    tp->th_opcode = htons((u_short) request);
+    cp = (char *)&(tp->th_stuff);
+    len = strlen(name) + 1;
+    memcpy(cp, name, len);
+    cp += len;
+    len = strlen(mode) + 1;
+    memcpy(cp, mode, len);
+    cp += len;
+    return (cp - (char *)tp);
+}
+
+static const char *const errmsgs[] = {
+    "Undefined error code",     /* 0 - EUNDEF */
+    "File not found",           /* 1 - ENOTFOUND */
+    "Access denied",            /* 2 - EACCESS */
+    "Disk full or allocation exceeded", /* 3 - ENOSPACE */
+    "Illegal TFTP operation",   /* 4 - EBADOP */
+    "Unknown transfer ID",      /* 5 - EBADID */
+    "File already exists",      /* 6 - EEXISTS */
+    "No such user",             /* 7 - ENOUSER */
+    "Failure to negotiate RFC2347 options"      /* 8 - EOPTNEG */
+};
+
+#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+static void nak(int error, const char *msg)
+{
+    struct tftphdr *tp;
+    int length;
+
+    tp = (struct tftphdr *)ackbuf;
+    tp->th_opcode = htons((u_short) ERROR);
+    tp->th_code = htons((u_short) error);
+
+    if (error >= 100) {
+        /* This is a Unix errno+100 */
+        if (!msg)
+            msg = strerror(error - 100);
+        error = EUNDEF;
+    } else {
+        if ((unsigned)error >= ERR_CNT)
+            error = EUNDEF;
+
+        if (!msg)
+            msg = errmsgs[error];
+    }
+
+    tp->th_code = htons((u_short) error);
+
+    length = strlen(msg) + 1;
+    memcpy(tp->th_msg, msg, length);
+    length += 4;                /* Add space for header */
+
+    if (trace)
+        tpacket("sent", tp, length);
+    if (sendto(f, ackbuf, length, 0, &peeraddr.sa,
+               SOCKLEN(&peeraddr)) != length)
+        perror("nak");
+}
+
+static void tpacket(const char *s, struct tftphdr *tp, int n)
+{
+    static const char *opcodes[] =
+        { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
+    char *cp, *file;
+    u_short op = ntohs((u_short) 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 = (char *)&(tp->th_stuff);
+        cp = strchr(cp, '\0');
+        printf("<file=%s, mode=%s>\n", file, cp + 1);
+        break;
+
+    case DATA:
+        printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
+        break;
+
+    case ACK:
+        printf("<block=%d>\n", ntohs(tp->th_block));
+        break;
+
+    case ERROR:
+        printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
+        break;
+    }
+}
+
+struct timeval tstart;
+struct timeval tstop;
+
+static void startclock(void)
+{
+    (void)gettimeofday(&tstart, NULL);
+}
+
+static void stopclock(void)
+{
+
+    (void)gettimeofday(&tstop, NULL);
+}
+
+static void printstats(const char *direction, unsigned long amount)
+{
+    double delta;
+
+    delta = (tstop.tv_sec + (tstop.tv_usec / 100000.0)) -
+        (tstart.tv_sec + (tstart.tv_usec / 100000.0));
+    if (verbose) {
+        printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
+        printf(" [%.0f bit/s]", (amount * 8.) / delta);
+        putchar('\n');
+    }
+}
+
+static void timer(int sig)
+{
+    int save_errno = errno;
+
+    (void)sig;                  /* Shut up unused warning */
+
+    timeout += rexmtval;
+    if (timeout >= maxtimeout) {
+        printf("Transfer timed out.\n");
+        errno = save_errno;
+        siglongjmp(toplevel, -1);
+    }
+    errno = save_errno;
+    siglongjmp(timeoutbuf, 1);
+}
Index: tftp
===================================================================
--- tftp	(nonexistent)
+++ tftp	(revision 5)

Property changes on: tftp
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- .	(nonexistent)
+++ .	(revision 5)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~