home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / tftp / main.c next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  13.3 KB  |  674 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)main.c    5.10 (Berkeley) 3/1/91";
  42. #endif /* not lint */
  43.  
  44. /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
  45.  
  46. /*
  47.  * TFTP User Program -- Command Interface.
  48.  */
  49. #include <sys/types.h>
  50. #include <sys/socket.h>
  51. #include <sys/file.h>
  52.  
  53. #include <netinet/in.h>
  54.  
  55. #include <signal.h>
  56. #include <stdio.h>
  57. #include <errno.h>
  58. #include <setjmp.h>
  59. #include <ctype.h>
  60. #include <netdb.h>
  61.  
  62. #define    TIMEOUT        5        /* secs between rexmt's */
  63.  
  64. struct    sockaddr_in sin;
  65. int    f;
  66. short   port;
  67. int    trace;
  68. int    verbose;
  69. int    connected;
  70. char    mode[32];
  71. char    line[200];
  72. int    margc;
  73. char    *margv[20];
  74. char    *prompt = "tftp";
  75. jmp_buf    toplevel;
  76. void    intr();
  77. struct    servent *sp;
  78.  
  79. int    quit(), help(), setverbose(), settrace(), status();
  80. int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
  81. int     setbinary(), setascii();
  82.  
  83. #define HELPINDENT (sizeof("connect"))
  84.  
  85. struct cmd {
  86.     char    *name;
  87.     char    *help;
  88.     int    (*handler)();
  89. };
  90.  
  91. char    vhelp[] = "toggle verbose mode";
  92. char    thelp[] = "toggle packet tracing";
  93. char    chelp[] = "connect to remote tftp";
  94. char    qhelp[] = "exit tftp";
  95. char    hhelp[] = "print help information";
  96. char    shelp[] = "send file";
  97. char    rhelp[] = "receive file";
  98. char    mhelp[] = "set file transfer mode";
  99. char    sthelp[] = "show current status";
  100. char    xhelp[] = "set per-packet retransmission timeout";
  101. char    ihelp[] = "set total retransmission timeout";
  102. char    ashelp[] = "set mode to netascii";
  103. char    bnhelp[] = "set mode to octet";
  104.  
  105. struct cmd cmdtab[] = {
  106.     { "connect",    chelp,        setpeer },
  107.     { "mode",       mhelp,          modecmd },
  108.     { "put",    shelp,        put },
  109.     { "get",    rhelp,        get },
  110.     { "quit",    qhelp,        quit },
  111.     { "verbose",    vhelp,        setverbose },
  112.     { "trace",    thelp,        settrace },
  113.     { "status",    sthelp,        status },
  114.     { "binary",     bnhelp,         setbinary },
  115.     { "ascii",      ashelp,         setascii },
  116.     { "rexmt",    xhelp,        setrexmt },
  117.     { "timeout",    ihelp,        settimeout },
  118.     { "?",        hhelp,        help },
  119.     0
  120. };
  121.  
  122. struct    cmd *getcmd();
  123. char    *tail();
  124. char    *index();
  125. char    *rindex();
  126.  
  127. main(argc, argv)
  128.     char *argv[];
  129. {
  130.     struct sockaddr_in sin;
  131.     int top;
  132.  
  133.     sp = getservbyname("tftp", "udp");
  134.     if (sp == 0) {
  135.         fprintf(stderr, "tftp: udp/tftp: unknown service\n");
  136.         exit(1);
  137.     }
  138.     f = socket(AF_INET, SOCK_DGRAM, 0);
  139.     if (f < 0) {
  140.         perror("tftp: socket");
  141.         exit(3);
  142.     }
  143.     bzero((char *)&sin, sizeof (sin));
  144.     sin.sin_family = AF_INET;
  145.     if (bind(f, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  146.         perror("tftp: bind");
  147.         exit(1);
  148.     }
  149.     strcpy(mode, "netascii");
  150.     signal(SIGINT, intr);
  151.     if (argc > 1) {
  152.         if (setjmp(toplevel) != 0)
  153.             exit(0);
  154.         setpeer(argc, argv);
  155.     }
  156.     top = setjmp(toplevel) == 0;
  157.     for (;;)
  158.         command(top);
  159. }
  160.  
  161. char    hostname[100];
  162.  
  163. setpeer(argc, argv)
  164.     int argc;
  165.     char *argv[];
  166. {
  167.     struct hostent *host;
  168.  
  169.     if (argc < 2) {
  170.         strcpy(line, "Connect ");
  171.         printf("(to) ");
  172.         gets(&line[strlen(line)]);
  173.         makeargv();
  174.         argc = margc;
  175.         argv = margv;
  176.     }
  177.     if (argc > 3) {
  178.         printf("usage: %s host-name [port]\n", argv[0]);
  179.         return;
  180.     }
  181.     host = gethostbyname(argv[1]);
  182.     if (host) {
  183.         sin.sin_family = host->h_addrtype;
  184.         bcopy(host->h_addr, &sin.sin_addr, host->h_length);
  185.         strcpy(hostname, host->h_name);
  186.     } else {
  187.         sin.sin_family = AF_INET;
  188.         sin.sin_addr.s_addr = inet_addr(argv[1]);
  189.         if (sin.sin_addr.s_addr == -1) {
  190.             connected = 0;
  191.             printf("%s: unknown host\n", argv[1]);
  192.             return;
  193.         }
  194.         strcpy(hostname, argv[1]);
  195.     }
  196.     port = sp->s_port;
  197.     if (argc == 3) {
  198.         port = atoi(argv[2]);
  199.         if (port < 0) {
  200.             printf("%s: bad port number\n", argv[2]);
  201.             connected = 0;
  202.             return;
  203.         }
  204.         port = htons(port);
  205.     }
  206.     connected = 1;
  207. }
  208.  
  209. struct    modes {
  210.     char *m_name;
  211.     char *m_mode;
  212. } modes[] = {
  213.     { "ascii",    "netascii" },
  214.     { "netascii",   "netascii" },
  215.     { "binary",     "octet" },
  216.     { "image",      "octet" },
  217.     { "octet",     "octet" },
  218. /*      { "mail",       "mail" },       */
  219.     { 0,        0 }
  220. };
  221.  
  222. modecmd(argc, argv)
  223.     char *argv[];
  224. {
  225.     register struct modes *p;
  226.     char *sep;
  227.  
  228.     if (argc < 2) {
  229.         printf("Using %s mode to transfer files.\n", mode);
  230.         return;
  231.     }
  232.     if (argc == 2) {
  233.         for (p = modes; p->m_name; p++)
  234.             if (strcmp(argv[1], p->m_name) == 0)
  235.                 break;
  236.         if (p->m_name) {
  237.             setmode(p->m_mode);
  238.             return;
  239.         }
  240.         printf("%s: unknown mode\n", argv[1]);
  241.         /* drop through and print usage message */
  242.     }
  243.  
  244.     printf("usage: %s [", argv[0]);
  245.     sep = " ";
  246.     for (p = modes; p->m_name; p++) {
  247.         printf("%s%s", sep, p->m_name);
  248.         if (*sep == ' ')
  249.             sep = " | ";
  250.     }
  251.     printf(" ]\n");
  252.     return;
  253. }
  254.  
  255. setbinary(argc, argv)
  256. char *argv[];
  257. {       setmode("octet");
  258. }
  259.  
  260. setascii(argc, argv)
  261. char *argv[];
  262. {       setmode("netascii");
  263. }
  264.  
  265. setmode(newmode)
  266. char *newmode;
  267. {
  268.     strcpy(mode, newmode);
  269.     if (verbose)
  270.         printf("mode set to %s\n", mode);
  271. }
  272.  
  273.  
  274. /*
  275.  * Send file(s).
  276.  */
  277. put(argc, argv)
  278.     char *argv[];
  279. {
  280.     int fd;
  281.     register int n;
  282.     register char *cp, *targ;
  283.  
  284.     if (argc < 2) {
  285.         strcpy(line, "send ");
  286.         printf("(file) ");
  287.         gets(&line[strlen(line)]);
  288.         makeargv();
  289.         argc = margc;
  290.         argv = margv;
  291.     }
  292.     if (argc < 2) {
  293.         putusage(argv[0]);
  294.         return;
  295.     }
  296.     targ = argv[argc - 1];
  297.     if (index(argv[argc - 1], ':')) {
  298.         char *cp;
  299.         struct hostent *hp;
  300.  
  301.         for (n = 1; n < argc - 1; n++)
  302.             if (index(argv[n], ':')) {
  303.                 putusage(argv[0]);
  304.                 return;
  305.             }
  306.         cp = argv[argc - 1];
  307.         targ = index(cp, ':');
  308.         *targ++ = 0;
  309.         hp = gethostbyname(cp);
  310.         if (hp == NULL) {
  311.             fprintf(stderr, "tftp: %s: ", cp);
  312.             herror((char *)NULL);
  313.             return;
  314.         }
  315.         bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
  316.         sin.sin_family = hp->h_addrtype;
  317.         connected = 1;
  318.         strcpy(hostname, hp->h_name);
  319.     }
  320.     if (!connected) {
  321.         printf("No target machine specified.\n");
  322.         return;
  323.     }
  324.     if (argc < 4) {
  325.         cp = argc == 2 ? tail(targ) : argv[1];
  326.         fd = open(cp, O_RDONLY);
  327.         if (fd < 0) {
  328.             fprintf(stderr, "tftp: "); perror(cp);
  329.             return;
  330.         }
  331.         if (verbose)
  332.             printf("putting %s to %s:%s [%s]\n",
  333.                 cp, hostname, targ, mode);
  334.         sin.sin_port = port;
  335.         sendfile(fd, targ, mode);
  336.         return;
  337.     }
  338.                 /* this assumes the target is a directory */
  339.                 /* on a remote unix system.  hmmmm.  */
  340.     cp = index(targ, '\0'); 
  341.     *cp++ = '/';
  342.     for (n = 1; n < argc - 1; n++) {
  343.         strcpy(cp, tail(argv[n]));
  344.         fd = open(argv[n], O_RDONLY);
  345.         if (fd < 0) {
  346.             fprintf(stderr, "tftp: "); perror(argv[n]);
  347.             continue;
  348.         }
  349.         if (verbose)
  350.             printf("putting %s to %s:%s [%s]\n",
  351.                 argv[n], hostname, targ, mode);
  352.         sin.sin_port = port;
  353.         sendfile(fd, targ, mode);
  354.     }
  355. }
  356.  
  357. putusage(s)
  358.     char *s;
  359. {
  360.     printf("usage: %s file ... host:target, or\n", s);
  361.     printf("       %s file ... target (when already connected)\n", s);
  362. }
  363.  
  364. /*
  365.  * Receive file(s).
  366.  */
  367. get(argc, argv)
  368.     char *argv[];
  369. {
  370.     int fd;
  371.     register int n;
  372.     register char *cp;
  373.     char *src;
  374.  
  375.     if (argc < 2) {
  376.         strcpy(line, "get ");
  377.         printf("(files) ");
  378.         gets(&line[strlen(line)]);
  379.         makeargv();
  380.         argc = margc;
  381.         argv = margv;
  382.     }
  383.     if (argc < 2) {
  384.         getusage(argv[0]);
  385.         return;
  386.     }
  387.     if (!connected) {
  388.         for (n = 1; n < argc ; n++)
  389.             if (index(argv[n], ':') == 0) {
  390.                 getusage(argv[0]);
  391.                 return;
  392.             }
  393.     }
  394.     for (n = 1; n < argc ; n++) {
  395.         src = index(argv[n], ':');
  396.         if (src == NULL)
  397.             src = argv[n];
  398.         else {
  399.             struct hostent *hp;
  400.  
  401.             *src++ = 0;
  402.             hp = gethostbyname(argv[n]);
  403.             if (hp == NULL) {
  404.                 fprintf(stderr, "tftp: %s: ", argv[n]);
  405.                 herror((char *)NULL);
  406.                 continue;
  407.             }
  408.             bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
  409.             sin.sin_family = hp->h_addrtype;
  410.             connected = 1;
  411.             strcpy(hostname, hp->h_name);
  412.         }
  413.         if (argc < 4) {
  414.             cp = argc == 3 ? argv[2] : tail(src);
  415.             fd = creat(cp, 0644);
  416.             if (fd < 0) {
  417.                 fprintf(stderr, "tftp: "); perror(cp);
  418.                 return;
  419.             }
  420.             if (verbose)
  421.                 printf("getting from %s:%s to %s [%s]\n",
  422.                     hostname, src, cp, mode);
  423.             sin.sin_port = port;
  424.             recvfile(fd, src, mode);
  425.             break;
  426.         }
  427.         cp = tail(src);         /* new .. jdg */
  428.         fd = creat(cp, 0644);
  429.         if (fd < 0) {
  430.             fprintf(stderr, "tftp: "); perror(cp);
  431.             continue;
  432.         }
  433.         if (verbose)
  434.             printf("getting from %s:%s to %s [%s]\n",
  435.                 hostname, src, cp, mode);
  436.         sin.sin_port = port;
  437.         recvfile(fd, src, mode);
  438.     }
  439. }
  440.  
  441. getusage(s)
  442. char * s;
  443. {
  444.     printf("usage: %s host:file host:file ... file, or\n", s);
  445.     printf("       %s file file ... file if connected\n", s);
  446. }
  447.  
  448. int    rexmtval = TIMEOUT;
  449.  
  450. setrexmt(argc, argv)
  451.     char *argv[];
  452. {
  453.     int t;
  454.  
  455.     if (argc < 2) {
  456.         strcpy(line, "Rexmt-timeout ");
  457.         printf("(value) ");
  458.         gets(&line[strlen(line)]);
  459.         makeargv();
  460.         argc = margc;
  461.         argv = margv;
  462.     }
  463.     if (argc != 2) {
  464.         printf("usage: %s value\n", argv[0]);
  465.         return;
  466.     }
  467.     t = atoi(argv[1]);
  468.     if (t < 0)
  469.         printf("%s: bad value\n", t);
  470.     else
  471.         rexmtval = t;
  472. }
  473.  
  474. int    maxtimeout = 5 * TIMEOUT;
  475.  
  476. settimeout(argc, argv)
  477.     char *argv[];
  478. {
  479.     int t;
  480.  
  481.     if (argc < 2) {
  482.         strcpy(line, "Maximum-timeout ");
  483.         printf("(value) ");
  484.         gets(&line[strlen(line)]);
  485.         makeargv();
  486.         argc = margc;
  487.         argv = margv;
  488.     }
  489.     if (argc != 2) {
  490.         printf("usage: %s value\n", argv[0]);
  491.         return;
  492.     }
  493.     t = atoi(argv[1]);
  494.     if (t < 0)
  495.         printf("%s: bad value\n", t);
  496.     else
  497.         maxtimeout = t;
  498. }
  499.  
  500. status(argc, argv)
  501.     char *argv[];
  502. {
  503.     if (connected)
  504.         printf("Connected to %s.\n", hostname);
  505.     else
  506.         printf("Not connected.\n");
  507.     printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
  508.         verbose ? "on" : "off", trace ? "on" : "off");
  509.     printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
  510.         rexmtval, maxtimeout);
  511. }
  512.  
  513. void
  514. intr()
  515. {
  516.     signal(SIGALRM, SIG_IGN);
  517.     alarm(0);
  518.     longjmp(toplevel, -1);
  519. }
  520.  
  521. char *
  522. tail(filename)
  523.     char *filename;
  524. {
  525.     register char *s;
  526.     
  527.     while (*filename) {
  528.         s = rindex(filename, '/');
  529.         if (s == NULL)
  530.             break;
  531.         if (s[1])
  532.             return (s + 1);
  533.         *s = '\0';
  534.     }
  535.     return (filename);
  536. }
  537.  
  538. /*
  539.  * Command parser.
  540.  */
  541. command(top)
  542.     int top;
  543. {
  544.     register struct cmd *c;
  545.  
  546.     if (!top)
  547.         putchar('\n');
  548.     for (;;) {
  549.         printf("%s> ", prompt);
  550.         if (gets(line) == 0) {
  551.             if (feof(stdin)) {
  552.                 quit();
  553.             } else {
  554.                 continue;
  555.             }
  556.         }
  557.         if (line[0] == 0)
  558.             continue;
  559.         makeargv();
  560.         c = getcmd(margv[0]);
  561.         if (c == (struct cmd *)-1) {
  562.             printf("?Ambiguous command\n");
  563.             continue;
  564.         }
  565.         if (c == 0) {
  566.             printf("?Invalid command\n");
  567.             continue;
  568.         }
  569.         (*c->handler)(margc, margv);
  570.     }
  571. }
  572.  
  573. struct cmd *
  574. getcmd(name)
  575.     register char *name;
  576. {
  577.     register char *p, *q;
  578.     register struct cmd *c, *found;
  579.     register int nmatches, longest;
  580.  
  581.     longest = 0;
  582.     nmatches = 0;
  583.     found = 0;
  584.     for (c = cmdtab; p = c->name; c++) {
  585.         for (q = name; *q == *p++; q++)
  586.             if (*q == 0)        /* exact match? */
  587.                 return (c);
  588.         if (!*q) {            /* the name was a prefix */
  589.             if (q - name > longest) {
  590.                 longest = q - name;
  591.                 nmatches = 1;
  592.                 found = c;
  593.             } else if (q - name == longest)
  594.                 nmatches++;
  595.         }
  596.     }
  597.     if (nmatches > 1)
  598.         return ((struct cmd *)-1);
  599.     return (found);
  600. }
  601.  
  602. /*
  603.  * Slice a string up into argc/argv.
  604.  */
  605. makeargv()
  606. {
  607.     register char *cp;
  608.     register char **argp = margv;
  609.  
  610.     margc = 0;
  611.     for (cp = line; *cp;) {
  612.         while (isspace(*cp))
  613.             cp++;
  614.         if (*cp == '\0')
  615.             break;
  616.         *argp++ = cp;
  617.         margc += 1;
  618.         while (*cp != '\0' && !isspace(*cp))
  619.             cp++;
  620.         if (*cp == '\0')
  621.             break;
  622.         *cp++ = '\0';
  623.     }
  624.     *argp++ = 0;
  625. }
  626.  
  627. /*VARARGS*/
  628. quit()
  629. {
  630.     exit(0);
  631. }
  632.  
  633. /*
  634.  * Help command.
  635.  */
  636. help(argc, argv)
  637.     int argc;
  638.     char *argv[];
  639. {
  640.     register struct cmd *c;
  641.  
  642.     if (argc == 1) {
  643.         printf("Commands may be abbreviated.  Commands are:\n\n");
  644.         for (c = cmdtab; c->name; c++)
  645.             printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
  646.         return;
  647.     }
  648.     while (--argc > 0) {
  649.         register char *arg;
  650.         arg = *++argv;
  651.         c = getcmd(arg);
  652.         if (c == (struct cmd *)-1)
  653.             printf("?Ambiguous help command %s\n", arg);
  654.         else if (c == (struct cmd *)0)
  655.             printf("?Invalid help command %s\n", arg);
  656.         else
  657.             printf("%s\n", c->help);
  658.     }
  659. }
  660.  
  661. /*VARARGS*/
  662. settrace()
  663. {
  664.     trace = !trace;
  665.     printf("Packet tracing %s.\n", trace ? "on" : "off");
  666. }
  667.  
  668. /*VARARGS*/
  669. setverbose()
  670. {
  671.     verbose = !verbose;
  672.     printf("Verbose mode %s.\n", verbose ? "on" : "off");
  673. }
  674.