123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684 |
- /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #ifndef lint
- char copyright[] =
- "@(#) Copyright (c) 1983 Regents of the University of California.\n\
- All rights reserved.\n";
- #endif /* not lint */
-
- #ifndef lint
- static char sccsid[] = "@(#)main.c 5.8 (Berkeley) 10/11/88";
- #endif /* not lint */
-
- /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
-
- /*
- * TFTP User Program -- Command Interface.
- */
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/file.h>
-
- #include <netinet/in.h>
-
- #include <signal.h>
- #include <stdio.h>
- #include <errno.h>
- #include <setjmp.h>
- #include <ctype.h>
- #include <netdb.h>
-
- #define TIMEOUT 5 /* secs between rexmt's */
-
- struct sockaddr_in sin;
- int f;
- short port;
- int trace;
- int verbose;
- int connected;
- char mode[32];
- char line[200];
- int margc;
- char *margv[20];
- char *prompt = "tftp";
- jmp_buf toplevel;
- void intr(int);
- struct servent *sp;
-
- int segsize = 512;
-
- int quit(), help(), setverbose(), settrace(), status();
- int get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
- int setbinary(), setascii(), setblocksize();
-
- #define HELPINDENT (sizeof("connect"))
-
- struct cmd {
- char *name;
- char *help;
- int (*handler)();
- };
-
- 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";
- char bshelp[] = "set blocksize for next transfer";
-
- 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 },
- { "blocksize", bshelp, setblocksize },
- { "?", hhelp, help },
- 0
- };
-
- struct cmd *getcmd();
- char *tail();
- char *index();
- char *rindex();
-
- main(argc, argv)
- char *argv[];
- {
- struct sockaddr_in sin;
- int top;
-
- sp = getservbyname("tftp", "udp");
- if (sp == 0) {
- fprintf(stderr, "tftp: udp/tftp: unknown service\n");
- exit(1);
- }
- f = socket(AF_INET, SOCK_DGRAM, 0);
- if (f < 0) {
- perror("tftp: socket");
- exit(3);
- }
- bzero((char *)&sin, sizeof (sin));
- sin.sin_family = AF_INET;
- if (bind(f, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
- perror("tftp: bind");
- exit(1);
- }
- strcpy(mode, "netascii");
- signal(SIGINT, intr);
- if (argc > 1) {
- if (setjmp(toplevel) != 0)
- exit(0);
- setpeer(argc, argv);
- }
- top = setjmp(toplevel) == 0;
- for (;;)
- command(top);
- }
-
- char hostname[100];
-
- setpeer(argc, argv)
- int argc;
- char *argv[];
- {
- struct hostent *host;
-
- if (argc < 2) {
- strcpy(line, "Connect ");
- printf("(to) ");
- fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
- makeargv();
- argc = margc;
- argv = margv;
- }
- if (argc > 3) {
- printf("usage: %s host-name [port]\n", argv[0]);
- return;
- }
- host = gethostbyname(argv[1]);
- if (host) {
- sin.sin_family = host->h_addrtype;
- bcopy(host->h_addr, &sin.sin_addr, host->h_length);
- strcpy(hostname, host->h_name);
- } else {
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = inet_addr(argv[1]);
- if (sin.sin_addr.s_addr == -1) {
- connected = 0;
- printf("%s: unknown host\n", argv[1]);
- return;
- }
- strcpy(hostname, argv[1]);
- }
- port = sp->s_port;
- if (argc == 3) {
- port = atoi(argv[2]);
- if (port < 0) {
- printf("%s: bad port number\n", argv[2]);
- connected = 0;
- return;
- }
- port = htons(port);
- }
- connected = 1;
- }
-
- struct modes {
- char *m_name;
- char *m_mode;
- } modes[] = {
- { "ascii", "netascii" },
- { "netascii", "netascii" },
- { "binary", "octet" },
- { "image", "octet" },
- { "octet", "octet" },
- /* { "mail", "mail" }, */
- { 0, 0 }
- };
-
- modecmd(argc, argv)
- char *argv[];
- {
- register struct modes *p;
- char *sep;
-
- if (argc < 2) {
- printf("Using %s mode to transfer files.\n", 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) {
- setmode(p->m_mode);
- 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;
- }
-
- setbinary(argc, argv)
- char *argv[];
- { setmode("octet");
- }
-
- setascii(argc, argv)
- char *argv[];
- { setmode("netascii");
- }
-
- setmode(newmode)
- char *newmode;
- {
- strcpy(mode, newmode);
- if (verbose)
- printf("mode set to %s\n", mode);
- }
-
-
- /*
- * Send file(s).
- */
- put(argc, argv)
- char *argv[];
- {
- int fd;
- register int n;
- register char *cp, *targ;
-
- if (argc < 2) {
- strcpy(line, "send ");
- printf("(file) ");
- fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
- makeargv();
- argc = margc;
- argv = margv;
- }
- if (argc < 2) {
- putusage(argv[0]);
- return;
- }
- targ = argv[argc - 1];
- if (index(argv[argc - 1], ':')) {
- char *cp;
- struct hostent *hp;
-
- for (n = 1; n < argc - 1; n++)
- if (index(argv[n], ':')) {
- putusage(argv[0]);
- return;
- }
- cp = argv[argc - 1];
- targ = index(cp, ':');
- *targ++ = 0;
- hp = gethostbyname(cp);
- if (hp == NULL) {
- fprintf(stderr, "tftp: %s: ", cp);
- herror((char *)NULL);
- return;
- }
- bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
- sin.sin_family = hp->h_addrtype;
- connected = 1;
- strcpy(hostname, hp->h_name);
- }
- if (!connected) {
- printf("No target machine specified.\n");
- return;
- }
- if (argc < 4) {
- cp = argc == 2 ? tail(targ) : argv[1];
- fd = open(cp, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "tftp: "); perror(cp);
- return;
- }
- if (verbose)
- printf("putting %s to %s:%s [%s]\n",
- cp, hostname, targ, mode);
- sin.sin_port = port;
- sendfile(fd, targ, mode);
- return;
- }
- /* this assumes the target is a directory */
- /* on a remote unix system. hmmmm. */
- cp = index(targ, '\0');
- *cp++ = '/';
- for (n = 1; n < argc - 1; n++) {
- strcpy(cp, tail(argv[n]));
- fd = open(argv[n], O_RDONLY);
- 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);
- sin.sin_port = port;
- sendfile(fd, targ, mode);
- }
- }
-
- putusage(s)
- char *s;
- {
- printf("usage: %s file ... host:target, or\n", s);
- printf(" %s file ... target (when already connected)\n", s);
- }
-
- /*
- * Receive file(s).
- */
- get(argc, argv)
- char *argv[];
- {
- int fd;
- register int n;
- register char *cp;
- char *src;
-
- if (argc < 2) {
- strcpy(line, "get ");
- printf("(files) ");
- fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
- makeargv();
- argc = margc;
- argv = margv;
- }
- if (argc < 2) {
- getusage(argv[0]);
- return;
- }
- if (!connected) {
- for (n = 1; n < argc ; n++)
- if (index(argv[n], ':') == 0) {
- getusage(argv[0]);
- return;
- }
- }
- for (n = 1; n < argc ; n++) {
- src = index(argv[n], ':');
- if (src == NULL)
- src = argv[n];
- else {
- struct hostent *hp;
-
- *src++ = 0;
- hp = gethostbyname(argv[n]);
- if (hp == NULL) {
- fprintf(stderr, "tftp: %s: ", argv[n]);
- herror((char *)NULL);
- continue;
- }
- bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
- sin.sin_family = hp->h_addrtype;
- connected = 1;
- strcpy(hostname, hp->h_name);
- }
- if (argc < 4) {
- cp = argc == 3 ? argv[2] : tail(src);
- fd = creat(cp, 0644);
- if (fd < 0) {
- fprintf(stderr, "tftp: "); perror(cp);
- return;
- }
- if (verbose)
- printf("getting from %s:%s to %s [%s]\n",
- hostname, src, cp, mode);
- sin.sin_port = port;
- recvfile(fd, src, mode);
- break;
- }
- cp = tail(src); /* new .. jdg */
- fd = creat(cp, 0644);
- if (fd < 0) {
- fprintf(stderr, "tftp: "); perror(cp);
- continue;
- }
- if (verbose)
- printf("getting from %s:%s to %s [%s]\n",
- hostname, src, cp, mode);
- sin.sin_port = port;
- recvfile(fd, src, mode);
- }
- }
-
- getusage(s)
- 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;
-
- setrexmt(argc, argv)
- char *argv[];
- {
- int t;
-
- if (argc < 2) {
- strcpy(line, "Rexmt-timeout ");
- printf("(value) ");
- fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
- makeargv();
- argc = margc;
- argv = margv;
- }
- if (argc != 2) {
- printf("usage: %s value\n", argv[0]);
- return;
- }
- t = atoi(argv[1]);
- if (t < 0)
- printf("%d: bad value\n", t);
- else
- rexmtval = t;
- }
-
- int maxtimeout = 5 * TIMEOUT;
-
- settimeout(argc, argv)
- char *argv[];
- {
- int t;
-
- if (argc < 2) {
- strcpy(line, "Maximum-timeout ");
- printf("(value) ");
- fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
- makeargv();
- argc = margc;
- argv = margv;
- }
- if (argc != 2) {
- printf("usage: %s value\n", argv[0]);
- return;
- }
- t = atoi(argv[1]);
- if (t < 0)
- printf("%d: bad value\n", t);
- else
- maxtimeout = t;
- }
-
- status(argc, argv)
- char *argv[];
- {
- 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);
- }
-
- void intr(int sig)
- {
- signal(SIGALRM, SIG_IGN);
- alarm(0);
- longjmp(toplevel, -1);
- }
-
- char *
- tail(filename)
- char *filename;
- {
- register char *s;
-
- while (*filename) {
- s = rindex(filename, '/');
- if (s == NULL)
- break;
- if (s[1])
- return (s + 1);
- *s = '\0';
- }
- return (filename);
- }
-
- /*
- * Command parser.
- */
- command(top)
- int top;
- {
- register struct cmd *c;
-
- if (!top)
- putchar('\n');
- for (;;) {
- printf("%s> ", prompt);
- if (fgets(line, sizeof(line), stdin) == 0) {
- if (feof(stdin)) {
- quit();
- } else {
- continue;
- }
- }
- if (line[0] == 0)
- continue;
- makeargv();
- 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(name)
- register char *name;
- {
- register char *p, *q;
- register struct cmd *c, *found;
- register int nmatches, longest;
-
- longest = 0;
- nmatches = 0;
- found = 0;
- for (c = cmdtab; p = c->name; 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.
- */
- makeargv()
- {
- register char *cp;
- register 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;
- }
-
- /*VARARGS*/
- quit()
- {
- exit(0);
- }
-
- /*
- * Help command.
- */
- help(argc, argv)
- int argc;
- char *argv[];
- {
- register struct cmd *c;
-
- if (argc == 1) {
- printf("Commands may be abbreviated. Commands are:\n\n");
- for (c = cmdtab; c->name; c++)
- printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
- return;
- }
- while (--argc > 0) {
- register 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);
- }
- }
-
- /*VARARGS*/
- settrace()
- {
- trace = !trace;
- printf("Packet tracing %s.\n", trace ? "on" : "off");
- }
-
- /*VARARGS*/
- setverbose()
- {
- verbose = !verbose;
- printf("Verbose mode %s.\n", verbose ? "on" : "off");
- }
-
- setblocksize(argc, argv)
- char *argv[];
- {
- int t;
-
- if (argc < 2) {
- strcpy(line, "blocksize ");
- printf("(value) ");
- fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
- makeargv();
- argc = margc;
- argv = margv;
- }
- if (argc != 2) {
- printf("usage: %s value\n", argv[0]);
- return;
- }
- t = atoi(argv[1]);
- if (t < 8 || t > 1432)
- printf("%d: bad value\n", t);
- else
- segsize = t;
- }
|