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