[BACK]Return to main.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tftp

Annotation of src/usr.bin/tftp/main.c, Revision 1.44

1.44    ! kn          1: /*     $OpenBSD: main.c,v 1.43 2018/09/20 11:42:42 jsg Exp $   */
1.1       deraadt     2: /*     $NetBSD: main.c,v 1.6 1995/05/21 16:54:10 mycroft Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1983, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
1.13      millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
1.25      mglocker   34:  * TFTP User Program -- Command Interface
                     35:  *
                     36:  * This version includes many modifications by Jim Guyton <guyton@rand-unix>
1.1       deraadt    37:  */
1.24      claudio    38:
1.1       deraadt    39: #include <sys/socket.h>
                     40:
                     41: #include <netinet/in.h>
                     42: #include <arpa/inet.h>
1.26      mglocker   43: #include <arpa/tftp.h>
1.1       deraadt    44:
                     45: #include <ctype.h>
1.25      mglocker   46: #include <err.h>
1.1       deraadt    47: #include <errno.h>
1.42      guenther   48: #include <fcntl.h>
1.1       deraadt    49: #include <netdb.h>
1.25      mglocker   50: #include <poll.h>
1.1       deraadt    51: #include <signal.h>
                     52: #include <stdio.h>
                     53: #include <stdlib.h>
                     54: #include <string.h>
                     55: #include <unistd.h>
1.35      deraadt    56: #include <limits.h>
1.1       deraadt    57:
                     58: #include "extern.h"
                     59:
                     60: #define        LBUFLEN         200             /* size of input buffer */
1.5       deraadt    61: #define        MAXARGV         20
1.24      claudio    62: #define HELPINDENT     (sizeof("connect"))
1.1       deraadt    63:
1.25      mglocker   64: void                    get(int, char **);
                     65: void                    help(int, char **);
                     66: void                    modecmd(int, char **);
                     67: void                    put(int, char **);
                     68: void                    quit(int, char **);
                     69: void                    setascii(int, char **);
                     70: void                    setbinary(int, char **);
1.31      gsoares    71: void                    setpeer(char *, char *);
                     72: void                    parsearg(int, char **);
1.25      mglocker   73: void                    setrexmt(int, char **);
                     74: void                    settimeout(int, char **);
                     75: void                    settrace(int, char **);
                     76: void                    setverbose(int, char **);
1.26      mglocker   77: void                    settsize(int, char **);
                     78: void                    settout(int, char **);
                     79: void                    setblksize(int, char **);
1.25      mglocker   80: void                    status(int, char **);
                     81: int                     readcmd(char *, int, FILE *);
                     82: static void             getusage(char *);
                     83: static int              makeargv(void);
                     84: static void             putusage(char *);
                     85: static void             settftpmode(char *);
                     86: static __dead void      command(void);
                     87: struct cmd             *getcmd(char *);
                     88: char                   *tail(char *);
                     89:
1.31      gsoares    90: struct sockaddr_storage         peeraddr;
1.25      mglocker   91: int                     f;
                     92: int                     trace;
                     93: int                     verbose;
                     94: int                     connected;
                     95: char                    mode[32];
                     96: char                    line[LBUFLEN];
                     97: int                     margc;
                     98: char                   *margv[MAXARGV+1];
                     99: char                   *prompt = "tftp";
                    100: void                    intr(int);
                    101: int                     rexmtval = TIMEOUT;
                    102: int                     maxtimeout = 5 * TIMEOUT;
1.35      deraadt   103: char                    hostname[HOST_NAME_MAX+1];
1.25      mglocker  104: FILE                   *file = NULL;
                    105: volatile sig_atomic_t   intrflag = 0;
1.26      mglocker  106: char                   *ackbuf;
                    107: int                     has_options = 0;
                    108: int                     opt_tsize = 0;
                    109: int                     opt_tout = 0;
                    110: int                     opt_blksize = 0;
1.1       deraadt   111:
                    112: char   vhelp[] = "toggle verbose mode";
                    113: char   thelp[] = "toggle packet tracing";
                    114: char   chelp[] = "connect to remote tftp";
                    115: char   qhelp[] = "exit tftp";
                    116: char   hhelp[] = "print help information";
                    117: char   shelp[] = "send file";
                    118: char   rhelp[] = "receive file";
                    119: char   mhelp[] = "set file transfer mode";
                    120: char   sthelp[] = "show current status";
                    121: char   xhelp[] = "set per-packet retransmission timeout";
                    122: char   ihelp[] = "set total retransmission timeout";
1.24      claudio   123: char   ashelp[] = "set mode to netascii";
                    124: char   bnhelp[] = "set mode to octet";
1.26      mglocker  125: char   oshelp[] = "toggle tsize option";
                    126: char   othelp[] = "toggle timeout option";
                    127: char   obhelp[] = "set alternative blksize option";
1.1       deraadt   128:
1.25      mglocker  129: struct cmd {
                    130:        char    *name;
                    131:        char    *help;
                    132:        void     (*handler)(int, char **);
                    133: };
                    134:
1.1       deraadt   135: struct cmd cmdtab[] = {
1.31      gsoares   136:        { "connect",    chelp,  parsearg },
1.25      mglocker  137:        { "mode",       mhelp,  modecmd },
                    138:        { "put",        shelp,  put },
                    139:        { "get",        rhelp,  get },
                    140:        { "quit",       qhelp,  quit },
                    141:        { "verbose",    vhelp,  setverbose },
                    142:        { "trace",      thelp,  settrace },
                    143:        { "status",     sthelp, status },
                    144:        { "binary",     bnhelp, setbinary },
                    145:        { "ascii",      ashelp, setascii },
                    146:        { "rexmt",      xhelp,  setrexmt },
                    147:        { "timeout",    ihelp,  settimeout },
1.26      mglocker  148:        { "tsize",      oshelp, settsize },
                    149:        { "tout",       othelp, settout },
                    150:        { "blksize",    obhelp, setblksize },
1.25      mglocker  151:        { "help",       hhelp,  help },
                    152:        { "?",          hhelp,  help },
                    153:        { NULL,         NULL,   NULL }
1.1       deraadt   154: };
                    155:
1.24      claudio   156: struct modes {
1.25      mglocker  157:        char    *m_name;
                    158:        char    *m_mode;
1.24      claudio   159: } modes[] = {
                    160:        { "ascii",      "netascii" },
                    161:        { "netascii",   "netascii" },
                    162:        { "binary",     "octet" },
                    163:        { "image",      "octet" },
                    164:        { "octet",      "octet" },
                    165: /*     { "mail",       "mail" }, */
                    166:        { NULL,         NULL }
                    167: };
                    168:
1.1       deraadt   169: int
1.14      deraadt   170: main(int argc, char *argv[])
1.1       deraadt   171: {
1.31      gsoares   172:        f = -1;
1.36      deraadt   173:
1.38      deraadt   174:        if (pledge("stdio rpath wpath cpath dns inet", NULL) == -1)
1.37      deraadt   175:                err(1, "pledge");
1.24      claudio   176:
                    177:        /* set default transfer mode */
                    178:        strlcpy(mode, "netascii", sizeof(mode));
                    179:
                    180:        /* set peer if given */
                    181:        if (argc > 1)
1.31      gsoares   182:                parsearg(argc, argv);
1.24      claudio   183:
                    184:        /* catch SIGINT */
1.1       deraadt   185:        signal(SIGINT, intr);
1.24      claudio   186:
1.26      mglocker  187:        /* allocate memory for packets */
                    188:        if ((ackbuf = malloc(SEGSIZE_MAX + 4)) == NULL)
                    189:                err(1, "malloc");
                    190:
1.24      claudio   191:        /* command prompt */
1.1       deraadt   192:        command();
1.24      claudio   193:
1.7       pvalchev  194:        return (0);
1.1       deraadt   195: }
                    196:
                    197: void
1.31      gsoares   198: setpeer(char *host, char *port)
1.1       deraadt   199: {
1.31      gsoares   200:        struct addrinfo hints, *res0, *res;
                    201:        int error;
                    202:        struct sockaddr_storage ss;
                    203:        char *cause = "unknown";
                    204:
                    205:        if (connected) {
                    206:                close(f);
                    207:                f = -1;
                    208:        }
                    209:        connected = 0;
                    210:
                    211:        memset(&hints, 0, sizeof(hints));
                    212:        hints.ai_family = PF_UNSPEC;
                    213:        hints.ai_socktype = SOCK_DGRAM;
                    214:        hints.ai_protocol = IPPROTO_UDP;
                    215:        hints.ai_flags = AI_CANONNAME;
                    216:        if (!port)
                    217:                port = "tftp";
                    218:        error = getaddrinfo(host, port, &hints, &res0);
                    219:        if (error) {
                    220:                warnx("%s", gai_strerror(error));
                    221:                return;
                    222:        }
                    223:
                    224:        for (res = res0; res; res = res->ai_next) {
                    225:                if (res->ai_addrlen > sizeof(peeraddr))
                    226:                        continue;
                    227:                f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
                    228:                if (f < 0) {
                    229:                        cause = "socket";
                    230:                        continue;
                    231:                }
1.1       deraadt   232:
1.31      gsoares   233:                memset(&ss, 0, sizeof(ss));
                    234:                ss.ss_family = res->ai_family;
1.41      guenther  235:                if (bind(f, (struct sockaddr *)&ss, res->ai_addrlen) < 0) {
1.31      gsoares   236:                        cause = "bind";
                    237:                        close(f);
                    238:                        f = -1;
                    239:                        continue;
                    240:                }
                    241:
                    242:                break;
                    243:        }
                    244:
                    245:        if (f < 0)
                    246:                warn("%s", cause);
                    247:        else {
                    248:                /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
                    249:                memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
                    250:                if (res->ai_canonname) {
1.32      gsoares   251:                        (void)strlcpy(hostname, res->ai_canonname,
                    252:                            sizeof(hostname));
1.31      gsoares   253:                } else
1.32      gsoares   254:                        (void)strlcpy(hostname, host, sizeof(hostname));
1.43      jsg       255:                connected = 1;
1.31      gsoares   256:        }
                    257:        freeaddrinfo(res0);
                    258: }
                    259:
                    260: void
                    261: parsearg(int argc, char *argv[])
                    262: {
1.1       deraadt   263:        if (argc < 2) {
1.25      mglocker  264:                strlcpy(line, "Connect ", sizeof(line));
1.1       deraadt   265:                printf("(to) ");
1.25      mglocker  266:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   267:                if (makeargv())
                    268:                        return;
1.1       deraadt   269:                argc = margc;
                    270:                argv = margv;
                    271:        }
                    272:        if ((argc < 2) || (argc > 3)) {
1.20      jmc       273:                printf("usage: %s [host [port]]\n", argv[0]);
1.1       deraadt   274:                return;
                    275:        }
1.31      gsoares   276:        if (argc == 2)
                    277:                setpeer(argv[1], NULL);
                    278:        else
                    279:                setpeer(argv[1], argv[2]);
1.1       deraadt   280: }
                    281:
                    282: void
1.14      deraadt   283: modecmd(int argc, char *argv[])
1.1       deraadt   284: {
1.25      mglocker  285:        struct modes    *p;
                    286:        char            *sep;
1.1       deraadt   287:
                    288:        if (argc < 2) {
                    289:                printf("Using %s mode to transfer files.\n", mode);
                    290:                return;
                    291:        }
                    292:        if (argc == 2) {
1.8       mpech     293:                for (p = modes; p->m_name != NULL; p++)
1.1       deraadt   294:                        if (strcmp(argv[1], p->m_name) == 0)
                    295:                                break;
                    296:                if (p->m_name) {
                    297:                        settftpmode(p->m_mode);
                    298:                        return;
                    299:                }
                    300:                printf("%s: unknown mode\n", argv[1]);
                    301:                /* drop through and print usage message */
                    302:        }
                    303:
                    304:        printf("usage: %s [", argv[0]);
                    305:        sep = " ";
1.8       mpech     306:        for (p = modes; p->m_name != NULL; p++) {
1.1       deraadt   307:                printf("%s%s", sep, p->m_name);
                    308:                if (*sep == ' ')
                    309:                        sep = " | ";
                    310:        }
                    311:        printf(" ]\n");
1.25      mglocker  312:
1.1       deraadt   313:        return;
                    314: }
                    315:
1.29      ray       316: /* ARGSUSED */
1.1       deraadt   317: void
1.14      deraadt   318: setbinary(int argc, char *argv[])
1.6       mickey    319: {
1.1       deraadt   320:        settftpmode("octet");
                    321: }
                    322:
1.29      ray       323: /* ARGSUSED */
1.1       deraadt   324: void
1.14      deraadt   325: setascii(int argc, char *argv[])
1.1       deraadt   326: {
                    327:        settftpmode("netascii");
                    328: }
                    329:
                    330: static void
1.14      deraadt   331: settftpmode(char *newmode)
1.1       deraadt   332: {
1.25      mglocker  333:        strlcpy(mode, newmode, sizeof(mode));
1.1       deraadt   334:        if (verbose)
                    335:                printf("mode set to %s\n", mode);
                    336: }
                    337:
                    338: /*
                    339:  * Send file(s).
                    340:  */
                    341: void
1.14      deraadt   342: put(int argc, char *argv[])
1.1       deraadt   343: {
1.25      mglocker  344:        int      fd;
                    345:        int      n;
                    346:        char    *cp, *targ;
1.1       deraadt   347:
                    348:        if (argc < 2) {
1.33      gsoares   349:                strlcpy(line, "put ", sizeof(line));
1.1       deraadt   350:                printf("(file) ");
1.24      claudio   351:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   352:                if (makeargv())
                    353:                        return;
1.1       deraadt   354:                argc = margc;
                    355:                argv = margv;
                    356:        }
                    357:        if (argc < 2) {
                    358:                putusage(argv[0]);
                    359:                return;
                    360:        }
                    361:        targ = argv[argc - 1];
1.31      gsoares   362:        if (strrchr(argv[argc - 1], ':')) {
1.1       deraadt   363:
                    364:                for (n = 1; n < argc - 1; n++)
1.4       millert   365:                        if (strchr(argv[n], ':')) {
1.1       deraadt   366:                                putusage(argv[0]);
                    367:                                return;
                    368:                        }
                    369:                cp = argv[argc - 1];
1.31      gsoares   370:                targ = strrchr(cp, ':');
1.1       deraadt   371:                *targ++ = 0;
1.31      gsoares   372:                if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
                    373:                        cp[strlen(cp) - 1] = '\0';
                    374:                        cp++;
1.1       deraadt   375:                }
1.31      gsoares   376:                setpeer(cp, NULL);
1.1       deraadt   377:        }
                    378:        if (!connected) {
                    379:                printf("No target machine specified.\n");
                    380:                return;
                    381:        }
                    382:        if (argc < 4) {
                    383:                cp = argc == 2 ? tail(targ) : argv[1];
                    384:                fd = open(cp, O_RDONLY);
                    385:                if (fd < 0) {
1.6       mickey    386:                        warn("open: %s", cp);
1.1       deraadt   387:                        return;
                    388:                }
                    389:                if (verbose)
                    390:                        printf("putting %s to %s:%s [%s]\n",
1.18      deraadt   391:                            cp, hostname, targ, mode);
1.1       deraadt   392:                sendfile(fd, targ, mode);
                    393:                return;
                    394:        }
1.18      deraadt   395:
1.24      claudio   396:        /*
                    397:         * this assumes the target is a directory on
                    398:         * on a remote unix system.  hmmmm.
                    399:         */
1.1       deraadt   400:        for (n = 1; n < argc - 1; n++) {
1.12      henning   401:                if (asprintf(&cp, "%s/%s", targ, tail(argv[n])) == -1)
                    402:                        err(1, "asprintf");
1.1       deraadt   403:                fd = open(argv[n], O_RDONLY);
                    404:                if (fd < 0) {
1.6       mickey    405:                        warn("open: %s", argv[n]);
1.22      mpech     406:                        free(cp);
1.1       deraadt   407:                        continue;
                    408:                }
                    409:                if (verbose)
                    410:                        printf("putting %s to %s:%s [%s]\n",
1.18      deraadt   411:                            argv[n], hostname, cp, mode);
1.12      henning   412:                sendfile(fd, cp, mode);
                    413:                free(cp);
1.1       deraadt   414:        }
                    415: }
                    416:
                    417: static void
1.14      deraadt   418: putusage(char *s)
1.1       deraadt   419: {
1.19      jmc       420:        printf("usage: %s file [[host:]remotename]\n", s);
1.24      claudio   421:        printf("       %s file1 file2 ... fileN [[host:]remote-directory]\n",
                    422:            s);
1.1       deraadt   423: }
                    424:
                    425: /*
                    426:  * Receive file(s).
                    427:  */
                    428: void
1.14      deraadt   429: get(int argc, char *argv[])
1.1       deraadt   430: {
1.25      mglocker  431:        int      fd;
                    432:        int      n;
                    433:        char    *cp;
                    434:        char    *src;
1.1       deraadt   435:
                    436:        if (argc < 2) {
1.25      mglocker  437:                strlcpy(line, "get ", sizeof(line));
1.1       deraadt   438:                printf("(files) ");
1.25      mglocker  439:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   440:                if (makeargv())
                    441:                        return;
1.1       deraadt   442:                argc = margc;
                    443:                argv = margv;
                    444:        }
                    445:        if (argc < 2) {
                    446:                getusage(argv[0]);
                    447:                return;
                    448:        }
                    449:        if (!connected) {
1.25      mglocker  450:                for (n = 1; n < argc; n++)
1.31      gsoares   451:                        if (strrchr(argv[n], ':') == 0) {
1.1       deraadt   452:                                getusage(argv[0]);
                    453:                                return;
                    454:                        }
                    455:        }
1.25      mglocker  456:        for (n = 1; n < argc; n++) {
1.31      gsoares   457:                src = strrchr(argv[n], ':');
1.1       deraadt   458:                if (src == NULL)
                    459:                        src = argv[n];
                    460:                else {
1.31      gsoares   461:                        char *cp;
1.1       deraadt   462:
                    463:                        *src++ = 0;
1.31      gsoares   464:                        cp = argv[n];
                    465:                        if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
                    466:                                cp[strlen(cp) - 1] = '\0';
                    467:                                cp++;
                    468:                        }
                    469:                        setpeer(cp, NULL);
                    470:                        if (!connected)
1.1       deraadt   471:                                continue;
                    472:                }
                    473:                if (argc < 4) {
                    474:                        cp = argc == 3 ? argv[2] : tail(src);
1.39      deraadt   475:                        fd = open(cp, O_CREAT | O_TRUNC | O_WRONLY, 0644);
1.1       deraadt   476:                        if (fd < 0) {
1.6       mickey    477:                                warn("create: %s", cp);
1.1       deraadt   478:                                return;
                    479:                        }
                    480:                        if (verbose)
                    481:                                printf("getting from %s:%s to %s [%s]\n",
1.18      deraadt   482:                                    hostname, src, cp, mode);
1.1       deraadt   483:                        recvfile(fd, src, mode);
                    484:                        break;
                    485:                }
1.25      mglocker  486:                cp = tail(src); /* new .. jdg */
1.39      deraadt   487:                fd = open(cp, O_CREAT | O_TRUNC | O_WRONLY, 0644);
1.1       deraadt   488:                if (fd < 0) {
1.6       mickey    489:                        warn("create: %s", cp);
1.1       deraadt   490:                        continue;
                    491:                }
                    492:                if (verbose)
                    493:                        printf("getting from %s:%s to %s [%s]\n",
1.18      deraadt   494:                            hostname, src, cp, mode);
1.1       deraadt   495:                recvfile(fd, src, mode);
                    496:        }
                    497: }
                    498:
                    499: static void
1.15      deraadt   500: getusage(char *s)
1.1       deraadt   501: {
1.19      jmc       502:        printf("usage: %s [host:]file [localname]\n", s);
                    503:        printf("       %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
1.1       deraadt   504: }
                    505:
                    506: void
1.14      deraadt   507: setrexmt(int argc, char *argv[])
1.1       deraadt   508: {
1.26      mglocker  509:        int              t;
                    510:        const char      *errstr;
1.1       deraadt   511:
                    512:        if (argc < 2) {
1.25      mglocker  513:                strlcpy(line, "Rexmt-timeout ", sizeof(line));
1.1       deraadt   514:                printf("(value) ");
1.25      mglocker  515:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   516:                if (makeargv())
                    517:                        return;
1.1       deraadt   518:                argc = margc;
                    519:                argv = margv;
                    520:        }
                    521:        if (argc != 2) {
                    522:                printf("usage: %s value\n", argv[0]);
                    523:                return;
                    524:        }
1.27      mglocker  525:        t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
1.26      mglocker  526:        if (errstr)
                    527:                printf("%s: value is %s\n", argv[1], errstr);
1.1       deraadt   528:        else
                    529:                rexmtval = t;
                    530: }
                    531:
                    532: void
1.14      deraadt   533: settimeout(int argc, char *argv[])
1.1       deraadt   534: {
1.27      mglocker  535:        int              t;
                    536:        const char      *errstr;
1.1       deraadt   537:
                    538:        if (argc < 2) {
1.25      mglocker  539:                strlcpy(line, "Maximum-timeout ", sizeof(line));
1.1       deraadt   540:                printf("(value) ");
1.25      mglocker  541:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   542:                if (makeargv())
                    543:                        return;
1.1       deraadt   544:                argc = margc;
                    545:                argv = margv;
                    546:        }
                    547:        if (argc != 2) {
                    548:                printf("usage: %s value\n", argv[0]);
                    549:                return;
                    550:        }
1.27      mglocker  551:        t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
                    552:        if (errstr)
                    553:                printf("%s: value is %s\n", argv[1], errstr);
1.1       deraadt   554:        else
                    555:                maxtimeout = t;
                    556: }
                    557:
1.29      ray       558: /* ARGSUSED */
1.1       deraadt   559: void
1.14      deraadt   560: status(int argc, char *argv[])
1.1       deraadt   561: {
                    562:        if (connected)
                    563:                printf("Connected to %s.\n", hostname);
                    564:        else
                    565:                printf("Not connected.\n");
1.25      mglocker  566:        printf("Mode: %s Verbose: %s Tracing: %s\n",
                    567:            mode, verbose ? "on" : "off", trace ? "on" : "off");
1.1       deraadt   568:        printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
1.25      mglocker  569:            rexmtval, maxtimeout);
1.1       deraadt   570: }
                    571:
1.29      ray       572: /* ARGSUSED */
1.1       deraadt   573: void
1.16      deraadt   574: intr(int signo)
1.1       deraadt   575: {
1.24      claudio   576:        intrflag = 1;
1.1       deraadt   577: }
                    578:
                    579: char *
1.14      deraadt   580: tail(char *filename)
1.1       deraadt   581: {
1.25      mglocker  582:        char    *s;
1.6       mickey    583:
1.1       deraadt   584:        while (*filename) {
1.4       millert   585:                s = strrchr(filename, '/');
1.1       deraadt   586:                if (s == NULL)
                    587:                        break;
                    588:                if (s[1])
                    589:                        return (s + 1);
                    590:                *s = '\0';
                    591:        }
1.25      mglocker  592:
1.1       deraadt   593:        return (filename);
                    594: }
                    595:
                    596: /*
                    597:  * Command parser.
                    598:  */
                    599: static __dead void
1.14      deraadt   600: command(void)
1.1       deraadt   601: {
1.25      mglocker  602:        struct cmd      *c;
1.1       deraadt   603:
                    604:        for (;;) {
1.44    ! kn        605:                if (isatty(STDIN_FILENO))
        !           606:                        printf("%s> ", prompt);
1.24      claudio   607:                if (readcmd(line, LBUFLEN, stdin) < 1)
                    608:                        continue;
1.1       deraadt   609:                if ((line[0] == 0) || (line[0] == '\n'))
                    610:                        continue;
1.5       deraadt   611:                if (makeargv())
                    612:                        continue;
1.1       deraadt   613:                if (margc == 0)
                    614:                        continue;
                    615:                c = getcmd(margv[0]);
1.25      mglocker  616:                if (c == (struct cmd *) - 1) {
1.1       deraadt   617:                        printf("?Ambiguous command\n");
                    618:                        continue;
                    619:                }
                    620:                if (c == 0) {
                    621:                        printf("?Invalid command\n");
                    622:                        continue;
                    623:                }
                    624:                (*c->handler)(margc, margv);
                    625:        }
                    626: }
                    627:
                    628: struct cmd *
1.14      deraadt   629: getcmd(char *name)
1.1       deraadt   630: {
1.25      mglocker  631:        char            *p, *q;
                    632:        struct cmd      *c, *found;
                    633:        int              nmatches, longest;
1.1       deraadt   634:
                    635:        longest = 0;
                    636:        nmatches = 0;
                    637:        found = 0;
1.24      claudio   638:        intrflag = 0;
1.1       deraadt   639:        for (c = cmdtab; (p = c->name) != NULL; c++) {
                    640:                for (q = name; *q == *p++; q++)
                    641:                        if (*q == 0)            /* exact match? */
                    642:                                return (c);
                    643:                if (!*q) {                      /* the name was a prefix */
                    644:                        if (q - name > longest) {
                    645:                                longest = q - name;
                    646:                                nmatches = 1;
                    647:                                found = c;
                    648:                        } else if (q - name == longest)
                    649:                                nmatches++;
                    650:                }
                    651:        }
                    652:        if (nmatches > 1)
1.25      mglocker  653:                return ((struct cmd *) - 1);
                    654:
1.1       deraadt   655:        return (found);
                    656: }
                    657:
                    658: /*
                    659:  * Slice a string up into argc/argv.
                    660:  */
1.5       deraadt   661: static int
1.14      deraadt   662: makeargv(void)
1.1       deraadt   663: {
1.25      mglocker  664:        char     *cp;
                    665:        char    **argp = margv;
                    666:        int       ret = 0;
1.1       deraadt   667:
                    668:        margc = 0;
                    669:        for (cp = line; *cp;) {
1.5       deraadt   670:                if (margc >= MAXARGV) {
                    671:                        printf("too many arguments\n");
                    672:                        ret = 1;
                    673:                        break;
                    674:                }
1.34      deraadt   675:                while (isspace((unsigned char)*cp))
1.1       deraadt   676:                        cp++;
                    677:                if (*cp == '\0')
                    678:                        break;
                    679:                *argp++ = cp;
                    680:                margc += 1;
1.34      deraadt   681:                while (*cp != '\0' && !isspace((unsigned char)*cp))
1.1       deraadt   682:                        cp++;
                    683:                if (*cp == '\0')
                    684:                        break;
                    685:                *cp++ = '\0';
                    686:        }
                    687:        *argp++ = 0;
1.25      mglocker  688:
1.5       deraadt   689:        return (ret);
1.1       deraadt   690: }
                    691:
1.29      ray       692: /* ARGSUSED */
1.1       deraadt   693: void
1.14      deraadt   694: quit(int argc, char *argv[])
1.1       deraadt   695: {
                    696:        exit(0);
                    697: }
                    698:
                    699: /*
                    700:  * Help command.
                    701:  */
                    702: void
1.14      deraadt   703: help(int argc, char *argv[])
1.1       deraadt   704: {
1.25      mglocker  705:        struct cmd      *c;
1.1       deraadt   706:
                    707:        if (argc == 1) {
                    708:                printf("Commands may be abbreviated.  Commands are:\n\n");
1.8       mpech     709:                for (c = cmdtab; c->name != NULL; c++)
1.1       deraadt   710:                        printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
                    711:                return;
                    712:        }
                    713:        while (--argc > 0) {
1.9       mpech     714:                char *arg;
1.1       deraadt   715:                arg = *++argv;
                    716:                c = getcmd(arg);
1.25      mglocker  717:                if (c == (struct cmd *) - 1)
1.1       deraadt   718:                        printf("?Ambiguous help command %s\n", arg);
1.40      krw       719:                else if (c == NULL)
1.1       deraadt   720:                        printf("?Invalid help command %s\n", arg);
                    721:                else
                    722:                        printf("%s\n", c->help);
                    723:        }
                    724: }
                    725:
1.29      ray       726: /* ARGSUSED */
1.1       deraadt   727: void
1.14      deraadt   728: settrace(int argc, char *argv[])
1.1       deraadt   729: {
                    730:        trace = !trace;
                    731:        printf("Packet tracing %s.\n", trace ? "on" : "off");
                    732: }
                    733:
1.29      ray       734: /* ARGSUSED */
1.1       deraadt   735: void
1.14      deraadt   736: setverbose(int argc, char *argv[])
1.1       deraadt   737: {
                    738:        verbose = !verbose;
                    739:        printf("Verbose mode %s.\n", verbose ? "on" : "off");
1.26      mglocker  740: }
                    741:
1.29      ray       742: /* ARGSUSED */
1.26      mglocker  743: void
                    744: settsize(int argc, char *argv[])
                    745: {
                    746:        opt_tsize = !opt_tsize;
                    747:        printf("Tsize option %s.\n", opt_tsize ? "on" : "off");
                    748:        if (opt_tsize)
                    749:                has_options++;
                    750:        else
                    751:                has_options--;
                    752: }
                    753:
1.29      ray       754: /* ARGSUSED */
1.26      mglocker  755: void
                    756: settout(int argc, char *argv[])
                    757: {
                    758:        opt_tout = !opt_tout;
                    759:        printf("Timeout option %s.\n", opt_tout ? "on" : "off");
                    760:        if (opt_tout)
                    761:                has_options++;
                    762:        else
                    763:                has_options--;
                    764: }
                    765:
                    766: void
                    767: setblksize(int argc, char *argv[])
                    768: {
                    769:        int              t;
                    770:        const char      *errstr;
                    771:
                    772:        if (argc < 2) {
                    773:                strlcpy(line, "Blocksize ", sizeof(line));
                    774:                printf("(value) ");
                    775:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
                    776:                if (makeargv())
                    777:                        return;
                    778:                argc = margc;
                    779:                argv = margv;
                    780:        }
                    781:        if (argc != 2) {
                    782:                printf("usage: %s value\n", argv[0]);
                    783:                return;
                    784:        }
                    785:        t = strtonum(argv[1], SEGSIZE_MIN, SEGSIZE_MAX, &errstr);
                    786:        if (errstr)
                    787:                printf("%s: value is %s\n", argv[1], errstr);
                    788:        else {
                    789:                if (opt_blksize == 0)
                    790:                        has_options++;
                    791:                opt_blksize = t;
                    792:        }
1.24      claudio   793: }
                    794:
                    795: int
                    796: readcmd(char *input, int len, FILE *stream)
                    797: {
                    798:        int             nfds;
                    799:        struct pollfd   pfd[1];
                    800:
                    801:        fflush(stdout);
                    802:
                    803:        pfd[0].fd = 0;
                    804:        pfd[0].events = POLLIN;
                    805:        nfds = poll(pfd, 1, INFTIM);
                    806:        if (nfds == -1) {
                    807:                if (intrflag) {
                    808:                        intrflag = 0;
                    809:                        putchar('\n');
                    810:                        return (0);
                    811:                }
                    812:                exit(1);
                    813:        }
                    814:
                    815:        if (fgets(input, len, stream) == NULL) {
                    816:                if (feof(stdin))
                    817:                        exit(0);
                    818:                else
                    819:                        return (-1);
                    820:        }
                    821:
                    822:        return (1);
1.1       deraadt   823: }