home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / tftp / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-22  |  14.4 KB  |  739 lines

  1. /*
  2.  * Copyright (c) 1983, 1993
  3.  *    The Regents of the University of California.  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. static char copyright[] =
  36. "@(#) Copyright (c) 1983, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)main.c    8.1 (Berkeley) 6/6/93";
  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.  
  50. #ifdef HAVE_CONFIG_H
  51. #include <config.h>
  52. #endif
  53.  
  54. #include <sys/types.h>
  55. #include <sys/socket.h>
  56. #include <sys/file.h>
  57.  
  58. #include <netinet/in.h>
  59.  
  60. #include <arpa/inet.h>
  61.  
  62. #include <ctype.h>
  63. #include <errno.h>
  64. #include <netdb.h>
  65. #include <setjmp.h>
  66. #include <signal.h>
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <unistd.h>
  71.  
  72. #include "extern.h"
  73.  
  74. #define    TIMEOUT        5        /* secs between rexmt's */
  75.  
  76. struct    sockaddr_in peeraddr;
  77. int    f;
  78. short   port;
  79. int    trace;
  80. int    verbose;
  81. int    connected;
  82. char    mode[32];
  83. char    line[200];
  84. int    margc;
  85. char    *margv[20];
  86. char    *prompt = "tftp";
  87. jmp_buf    toplevel;
  88. void    intr();
  89. struct    servent *sp;
  90.  
  91. void    get __P((int, char **));
  92. void    help __P((int, char **));
  93. void    modecmd __P((int, char **));
  94. void    put __P((int, char **));
  95. void    quit __P((int, char **));
  96. void    setascii __P((int, char **));
  97. void    setbinary __P((int, char **));
  98. void    setpeer __P((int, char **));
  99. void    setrexmt __P((int, char **));
  100. void    settimeout __P((int, char **));
  101. void    settrace __P((int, char **));
  102. void    setverbose __P((int, char **));
  103. void    status __P((int, char **));
  104.  
  105. static void command __P((void));
  106.  
  107. static void getusage __P((char *));
  108. static void makeargv __P((void));
  109. static void putusage __P((char *));
  110. static void settftpmode __P((char *));
  111.  
  112. #define HELPINDENT (sizeof("connect"))
  113.  
  114. struct cmd {
  115.     char    *name;
  116.     char    *help;
  117.     void    (*handler) __P((int, char **));
  118. };
  119.  
  120. char    vhelp[] = "toggle verbose mode";
  121. char    thelp[] = "toggle packet tracing";
  122. char    chelp[] = "connect to remote tftp";
  123. char    qhelp[] = "exit tftp";
  124. char    hhelp[] = "print help information";
  125. char    shelp[] = "send file";
  126. char    rhelp[] = "receive file";
  127. char    mhelp[] = "set file transfer mode";
  128. char    sthelp[] = "show current status";
  129. char    xhelp[] = "set per-packet retransmission timeout";
  130. char    ihelp[] = "set total retransmission timeout";
  131. char    ashelp[] = "set mode to netascii";
  132. char    bnhelp[] = "set mode to octet";
  133.  
  134. struct cmd cmdtab[] = {
  135.     { "connect",    chelp,        setpeer },
  136.     { "mode",       mhelp,          modecmd },
  137.     { "put",    shelp,        put },
  138.     { "get",    rhelp,        get },
  139.     { "quit",    qhelp,        quit },
  140.     { "verbose",    vhelp,        setverbose },
  141.     { "trace",    thelp,        settrace },
  142.     { "status",    sthelp,        status },
  143.     { "binary",     bnhelp,         setbinary },
  144.     { "ascii",      ashelp,         setascii },
  145.     { "rexmt",    xhelp,        setrexmt },
  146.     { "timeout",    ihelp,        settimeout },
  147.     { "?",        hhelp,        help },
  148.     { 0 }
  149. };
  150.  
  151. struct    cmd *getcmd();
  152. char    *tail();
  153. char    *index();
  154. char    *rindex();
  155.  
  156. int
  157. main(argc, argv)
  158.     int argc;
  159.     char *argv[];
  160. {
  161.     struct sockaddr_in sin;
  162.  
  163.     sp = getservbyname("tftp", "udp");
  164.     if (sp == 0) {
  165.         fprintf(stderr, "tftp: udp/tftp: unknown service\n");
  166.         exit(1);
  167.     }
  168.     f = socket(AF_INET, SOCK_DGRAM, 0);
  169.     if (f < 0) {
  170.         perror("tftp: socket");
  171.         exit(3);
  172.     }
  173.     bzero((char *)&sin, sizeof(sin));
  174.     sin.sin_family = AF_INET;
  175.     if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  176.         perror("tftp: bind");
  177.         exit(1);
  178.     }
  179.     strcpy(mode, "netascii");
  180.     signal(SIGINT, intr);
  181.     if (argc > 1) {
  182.         if (setjmp(toplevel) != 0)
  183.             exit(0);
  184.         setpeer(argc, argv);
  185.     }
  186.     if (setjmp(toplevel) != 0)
  187.         (void)putchar('\n');
  188.     command();
  189. }
  190.  
  191. char    hostname[100];
  192.  
  193. void
  194. setpeer(argc, argv)
  195.     int argc;
  196.     char *argv[];
  197. {
  198.     struct hostent *host;
  199.  
  200.     if (argc < 2) {
  201.         strcpy(line, "Connect ");
  202.         printf("(to) ");
  203.         gets(&line[strlen(line)]);
  204.         makeargv();
  205.         argc = margc;
  206.         argv = margv;
  207.     }
  208.     if (argc > 3) {
  209.         printf("usage: %s host-name [port]\n", argv[0]);
  210.         return;
  211.     }
  212.     host = gethostbyname(argv[1]);
  213.     if (host) {
  214.         peeraddr.sin_family = host->h_addrtype;
  215.         bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
  216.         strcpy(hostname, host->h_name);
  217.     } else {
  218.         peeraddr.sin_family = AF_INET;
  219.         peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
  220.         if (peeraddr.sin_addr.s_addr == -1) {
  221.             connected = 0;
  222.             printf("%s: unknown host\n", argv[1]);
  223.             return;
  224.         }
  225.         strcpy(hostname, argv[1]);
  226.     }
  227.     port = sp->s_port;
  228.     if (argc == 3) {
  229.         port = atoi(argv[2]);
  230.         if (port < 0) {
  231.             printf("%s: bad port number\n", argv[2]);
  232.             connected = 0;
  233.             return;
  234.         }
  235.         port = htons(port);
  236.     }
  237.     connected = 1;
  238. }
  239.  
  240. struct    modes {
  241.     char *m_name;
  242.     char *m_mode;
  243. } modes[] = {
  244.     { "ascii",    "netascii" },
  245.     { "netascii",   "netascii" },
  246.     { "binary",     "octet" },
  247.     { "image",      "octet" },
  248.     { "octet",     "octet" },
  249. /*      { "mail",       "mail" },       */
  250.     { 0,        0 }
  251. };
  252.  
  253. void
  254. modecmd(argc, argv)
  255.     int argc;
  256.     char *argv[];
  257. {
  258.     register struct modes *p;
  259.     char *sep;
  260.  
  261.     if (argc < 2) {
  262.         printf("Using %s mode to transfer files.\n", mode);
  263.         return;
  264.     }
  265.     if (argc == 2) {
  266.         for (p = modes; p->m_name; p++)
  267.             if (strcmp(argv[1], p->m_name) == 0)
  268.                 break;
  269.         if (p->m_name) {
  270.             settftpmode(p->m_mode);
  271.             return;
  272.         }
  273.         printf("%s: unknown mode\n", argv[1]);
  274.         /* drop through and print usage message */
  275.     }
  276.  
  277.     printf("usage: %s [", argv[0]);
  278.     sep = " ";
  279.     for (p = modes; p->m_name; p++) {
  280.         printf("%s%s", sep, p->m_name);
  281.         if (*sep == ' ')
  282.             sep = " | ";
  283.     }
  284.     printf(" ]\n");
  285.     return;
  286. }
  287.  
  288. void
  289. setbinary(argc, argv)
  290.     int argc;
  291.     char *argv[];
  292. {      
  293.  
  294.     settftpmode("octet");
  295. }
  296.  
  297. void
  298. setascii(argc, argv)
  299.     int argc;
  300.     char *argv[];
  301. {
  302.  
  303.     settftpmode("netascii");
  304. }
  305.  
  306. static void
  307. settftpmode(newmode)
  308.     char *newmode;
  309. {
  310.     strcpy(mode, newmode);
  311.     if (verbose)
  312.         printf("mode set to %s\n", mode);
  313. }
  314.  
  315.  
  316. /*
  317.  * Send file(s).
  318.  */
  319. void
  320. put(argc, argv)
  321.     int argc;
  322.     char *argv[];
  323. {
  324.     int fd;
  325.     register int n;
  326.     register char *cp, *targ;
  327.  
  328.     if (argc < 2) {
  329.         strcpy(line, "send ");
  330.         printf("(file) ");
  331.         gets(&line[strlen(line)]);
  332.         makeargv();
  333.         argc = margc;
  334.         argv = margv;
  335.     }
  336.     if (argc < 2) {
  337.         putusage(argv[0]);
  338.         return;
  339.     }
  340.     targ = argv[argc - 1];
  341.     if (index(argv[argc - 1], ':')) {
  342.         char *cp;
  343.         struct hostent *hp;
  344.  
  345.         for (n = 1; n < argc - 1; n++)
  346.             if (index(argv[n], ':')) {
  347.                 putusage(argv[0]);
  348.                 return;
  349.             }
  350.         cp = argv[argc - 1];
  351.         targ = index(cp, ':');
  352.         *targ++ = 0;
  353.         hp = gethostbyname(cp);
  354.         if (hp == NULL) {
  355.             fprintf(stderr, "tftp: %s: ", cp);
  356.             herror((char *)NULL);
  357.             return;
  358.         }
  359.         bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
  360.         peeraddr.sin_family = hp->h_addrtype;
  361.         connected = 1;
  362.         strcpy(hostname, hp->h_name);
  363.     }
  364.     if (!connected) {
  365.         printf("No target machine specified.\n");
  366.         return;
  367.     }
  368.     if (argc < 4) {
  369.         cp = argc == 2 ? tail(targ) : argv[1];
  370.         fd = open(cp, O_RDONLY);
  371.         if (fd < 0) {
  372.             fprintf(stderr, "tftp: "); perror(cp);
  373.             return;
  374.         }
  375.         if (verbose)
  376.             printf("putting %s to %s:%s [%s]\n",
  377.                 cp, hostname, targ, mode);
  378.         peeraddr.sin_port = port;
  379.         sendfile(fd, targ, mode);
  380.         return;
  381.     }
  382.                 /* this assumes the target is a directory */
  383.                 /* on a remote unix system.  hmmmm.  */
  384.     cp = index(targ, '\0'); 
  385.     *cp++ = '/';
  386.     for (n = 1; n < argc - 1; n++) {
  387.         strcpy(cp, tail(argv[n]));
  388.         fd = open(argv[n], O_RDONLY);
  389.         if (fd < 0) {
  390.             fprintf(stderr, "tftp: "); perror(argv[n]);
  391.             continue;
  392.         }
  393.         if (verbose)
  394.             printf("putting %s to %s:%s [%s]\n",
  395.                 argv[n], hostname, targ, mode);
  396.         peeraddr.sin_port = port;
  397.         sendfile(fd, targ, mode);
  398.     }
  399. }
  400.  
  401. static void
  402. putusage(s)
  403.     char *s;
  404. {
  405.     printf("usage: %s file ... host:target, or\n", s);
  406.     printf("       %s file ... target (when already connected)\n", s);
  407. }
  408.  
  409. /*
  410.  * Receive file(s).
  411.  */
  412. void
  413. get(argc, argv)
  414.     int argc;
  415.     char *argv[];
  416. {
  417.     int fd;
  418.     register int n;
  419.     register char *cp;
  420.     char *src;
  421.  
  422.     if (argc < 2) {
  423.         strcpy(line, "get ");
  424.         printf("(files) ");
  425.         gets(&line[strlen(line)]);
  426.         makeargv();
  427.         argc = margc;
  428.         argv = margv;
  429.     }
  430.     if (argc < 2) {
  431.         getusage(argv[0]);
  432.         return;
  433.     }
  434.     if (!connected) {
  435.         for (n = 1; n < argc ; n++)
  436.             if (index(argv[n], ':') == 0) {
  437.                 getusage(argv[0]);
  438.                 return;
  439.             }
  440.     }
  441.     for (n = 1; n < argc ; n++) {
  442.         src = index(argv[n], ':');
  443.         if (src == NULL)
  444.             src = argv[n];
  445.         else {
  446.             struct hostent *hp;
  447.  
  448.             *src++ = 0;
  449.             hp = gethostbyname(argv[n]);
  450.             if (hp == NULL) {
  451.                 fprintf(stderr, "tftp: %s: ", argv[n]);
  452.                 herror((char *)NULL);
  453.                 continue;
  454.             }
  455.             bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
  456.                 hp->h_length);
  457.             peeraddr.sin_family = hp->h_addrtype;
  458.             connected = 1;
  459.             strcpy(hostname, hp->h_name);
  460.         }
  461.         if (argc < 4) {
  462.             cp = argc == 3 ? argv[2] : tail(src);
  463.             fd = creat(cp, 0644);
  464.             if (fd < 0) {
  465.                 fprintf(stderr, "tftp: "); perror(cp);
  466.                 return;
  467.             }
  468.             if (verbose)
  469.                 printf("getting from %s:%s to %s [%s]\n",
  470.                     hostname, src, cp, mode);
  471.             peeraddr.sin_port = port;
  472.             recvfile(fd, src, mode);
  473.             break;
  474.         }
  475.         cp = tail(src);         /* new .. jdg */
  476.         fd = creat(cp, 0644);
  477.         if (fd < 0) {
  478.             fprintf(stderr, "tftp: "); perror(cp);
  479.             continue;
  480.         }
  481.         if (verbose)
  482.             printf("getting from %s:%s to %s [%s]\n",
  483.                 hostname, src, cp, mode);
  484.         peeraddr.sin_port = port;
  485.         recvfile(fd, src, mode);
  486.     }
  487. }
  488.  
  489. static void
  490. getusage(s)
  491.     char *s;
  492. {
  493.     printf("usage: %s host:file host:file ... file, or\n", s);
  494.     printf("       %s file file ... file if connected\n", s);
  495. }
  496.  
  497. int    rexmtval = TIMEOUT;
  498.  
  499. void
  500. setrexmt(argc, argv)
  501.     int argc;
  502.     char *argv[];
  503. {
  504.     int t;
  505.  
  506.     if (argc < 2) {
  507.         strcpy(line, "Rexmt-timeout ");
  508.         printf("(value) ");
  509.         gets(&line[strlen(line)]);
  510.         makeargv();
  511.         argc = margc;
  512.         argv = margv;
  513.     }
  514.     if (argc != 2) {
  515.         printf("usage: %s value\n", argv[0]);
  516.         return;
  517.     }
  518.     t = atoi(argv[1]);
  519.     if (t < 0)
  520.         printf("%s: bad value\n", argv[1]);
  521.     else
  522.         rexmtval = t;
  523. }
  524.  
  525. int    maxtimeout = 5 * TIMEOUT;
  526.  
  527. void
  528. settimeout(argc, argv)
  529.     int argc;
  530.     char *argv[];
  531. {
  532.     int t;
  533.  
  534.     if (argc < 2) {
  535.         strcpy(line, "Maximum-timeout ");
  536.         printf("(value) ");
  537.         gets(&line[strlen(line)]);
  538.         makeargv();
  539.         argc = margc;
  540.         argv = margv;
  541.     }
  542.     if (argc != 2) {
  543.         printf("usage: %s value\n", argv[0]);
  544.         return;
  545.     }
  546.     t = atoi(argv[1]);
  547.     if (t < 0)
  548.         printf("%s: bad value\n", argv[1]);
  549.     else
  550.         maxtimeout = t;
  551. }
  552.  
  553. void
  554. status(argc, argv)
  555.     int argc;
  556.     char *argv[];
  557. {
  558.     if (connected)
  559.         printf("Connected to %s.\n", hostname);
  560.     else
  561.         printf("Not connected.\n");
  562.     printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
  563.         verbose ? "on" : "off", trace ? "on" : "off");
  564.     printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
  565.         rexmtval, maxtimeout);
  566. }
  567.  
  568. void
  569. intr()
  570. {
  571.  
  572.     signal(SIGALRM, SIG_IGN);
  573.     alarm(0);
  574.     longjmp(toplevel, -1);
  575. }
  576.  
  577. char *
  578. tail(filename)
  579.     char *filename;
  580. {
  581.     register char *s;
  582.     
  583.     while (*filename) {
  584.         s = rindex(filename, '/');
  585.         if (s == NULL)
  586.             break;
  587.         if (s[1])
  588.             return (s + 1);
  589.         *s = '\0';
  590.     }
  591.     return (filename);
  592. }
  593.  
  594. /*
  595.  * Command parser.
  596.  */
  597. static void
  598. command()
  599. {
  600.     register struct cmd *c;
  601.  
  602.     for (;;) {
  603.         printf("%s> ", prompt);
  604.         if (gets(line) == 0) {
  605.             if (feof(stdin)) {
  606.                 exit(0);
  607.             } else {
  608.                 continue;
  609.             }
  610.         }
  611.         if (line[0] == 0)
  612.             continue;
  613.         makeargv();
  614.         if (margc == 0)
  615.             continue;
  616.         c = getcmd(margv[0]);
  617.         if (c == (struct cmd *)-1) {
  618.             printf("?Ambiguous command\n");
  619.             continue;
  620.         }
  621.         if (c == 0) {
  622.             printf("?Invalid command\n");
  623.             continue;
  624.         }
  625.         (*c->handler)(margc, margv);
  626.     }
  627. }
  628.  
  629. struct cmd *
  630. getcmd(name)
  631.     register char *name;
  632. {
  633.     register char *p, *q;
  634.     register struct cmd *c, *found;
  635.     register int nmatches, longest;
  636.  
  637.     longest = 0;
  638.     nmatches = 0;
  639.     found = 0;
  640.     for (c = cmdtab; (p = c->name) != NULL; c++) {
  641.         for (q = name; *q == *p++; q++)
  642.             if (*q == 0)        /* exact match? */
  643.                 return (c);
  644.         if (!*q) {            /* the name was a prefix */
  645.             if (q - name > longest) {
  646.                 longest = q - name;
  647.                 nmatches = 1;
  648.                 found = c;
  649.             } else if (q - name == longest)
  650.                 nmatches++;
  651.         }
  652.     }
  653.     if (nmatches > 1)
  654.         return ((struct cmd *)-1);
  655.     return (found);
  656. }
  657.  
  658. /*
  659.  * Slice a string up into argc/argv.
  660.  */
  661. static void
  662. makeargv()
  663. {
  664.     register char *cp;
  665.     register char **argp = margv;
  666.  
  667.     margc = 0;
  668.     for (cp = line; *cp;) {
  669.         while (isspace(*cp))
  670.             cp++;
  671.         if (*cp == '\0')
  672.             break;
  673.         *argp++ = cp;
  674.         margc += 1;
  675.         while (*cp != '\0' && !isspace(*cp))
  676.             cp++;
  677.         if (*cp == '\0')
  678.             break;
  679.         *cp++ = '\0';
  680.     }
  681.     *argp++ = 0;
  682. }
  683.  
  684. void
  685. quit(argc, argv)
  686.     int argc;
  687.     char *argv[];
  688. {
  689.  
  690.     exit(0);
  691. }
  692.  
  693. /*
  694.  * Help command.
  695.  */
  696. void
  697. help(argc, argv)
  698.     int argc;
  699.     char *argv[];
  700. {
  701.     register struct cmd *c;
  702.  
  703.     if (argc == 1) {
  704.         printf("Commands may be abbreviated.  Commands are:\n\n");
  705.         for (c = cmdtab; c->name; c++)
  706.             printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
  707.         return;
  708.     }
  709.     while (--argc > 0) {
  710.         register char *arg;
  711.         arg = *++argv;
  712.         c = getcmd(arg);
  713.         if (c == (struct cmd *)-1)
  714.             printf("?Ambiguous help command %s\n", arg);
  715.         else if (c == (struct cmd *)0)
  716.             printf("?Invalid help command %s\n", arg);
  717.         else
  718.             printf("%s\n", c->help);
  719.     }
  720. }
  721.  
  722. void
  723. settrace(argc, argv)
  724.     int argc;
  725.     char **argv;
  726. {
  727.     trace = !trace;
  728.     printf("Packet tracing %s.\n", trace ? "on" : "off");
  729. }
  730.  
  731. void
  732. setverbose(argc, argv)
  733.     int argc;
  734.     char **argv;
  735. {
  736.     verbose = !verbose;
  737.     printf("Verbose mode %s.\n", verbose ? "on" : "off");
  738. }
  739.