[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.35

1.35    ! deraadt     1: /*     $OpenBSD: main.c,v 1.34 2013/11/26 21:08:12 deraadt 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: #include <sys/file.h>
                     41:
                     42: #include <netinet/in.h>
                     43: #include <arpa/inet.h>
1.26      mglocker   44: #include <arpa/tftp.h>
1.1       deraadt    45:
                     46: #include <ctype.h>
1.25      mglocker   47: #include <err.h>
1.1       deraadt    48: #include <errno.h>
                     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.24      claudio   173:
                    174:        /* set default transfer mode */
                    175:        strlcpy(mode, "netascii", sizeof(mode));
                    176:
                    177:        /* set peer if given */
                    178:        if (argc > 1)
1.31      gsoares   179:                parsearg(argc, argv);
1.24      claudio   180:
                    181:        /* catch SIGINT */
1.1       deraadt   182:        signal(SIGINT, intr);
1.24      claudio   183:
1.26      mglocker  184:        /* allocate memory for packets */
                    185:        if ((ackbuf = malloc(SEGSIZE_MAX + 4)) == NULL)
                    186:                err(1, "malloc");
                    187:
1.24      claudio   188:        /* command prompt */
1.1       deraadt   189:        command();
1.24      claudio   190:
1.7       pvalchev  191:        return (0);
1.1       deraadt   192: }
                    193:
                    194: void
1.31      gsoares   195: setpeer(char *host, char *port)
1.1       deraadt   196: {
1.31      gsoares   197:        struct addrinfo hints, *res0, *res;
                    198:        int error;
                    199:        struct sockaddr_storage ss;
                    200:        char *cause = "unknown";
                    201:
                    202:        if (connected) {
                    203:                close(f);
                    204:                f = -1;
                    205:        }
                    206:        connected = 0;
                    207:
                    208:        memset(&hints, 0, sizeof(hints));
                    209:        hints.ai_family = PF_UNSPEC;
                    210:        hints.ai_socktype = SOCK_DGRAM;
                    211:        hints.ai_protocol = IPPROTO_UDP;
                    212:        hints.ai_flags = AI_CANONNAME;
                    213:        if (!port)
                    214:                port = "tftp";
                    215:        error = getaddrinfo(host, port, &hints, &res0);
                    216:        if (error) {
                    217:                warnx("%s", gai_strerror(error));
                    218:                return;
                    219:        }
                    220:
                    221:        for (res = res0; res; res = res->ai_next) {
                    222:                if (res->ai_addrlen > sizeof(peeraddr))
                    223:                        continue;
                    224:                f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
                    225:                if (f < 0) {
                    226:                        cause = "socket";
                    227:                        continue;
                    228:                }
1.1       deraadt   229:
1.31      gsoares   230:                memset(&ss, 0, sizeof(ss));
                    231:                ss.ss_family = res->ai_family;
                    232:                ss.ss_len = res->ai_addrlen;
                    233:                if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
                    234:                        cause = "bind";
                    235:                        close(f);
                    236:                        f = -1;
                    237:                        continue;
                    238:                }
                    239:
                    240:                break;
                    241:        }
                    242:
                    243:        if (f < 0)
                    244:                warn("%s", cause);
                    245:        else {
                    246:                /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
                    247:                memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
                    248:                if (res->ai_canonname) {
1.32      gsoares   249:                        (void)strlcpy(hostname, res->ai_canonname,
                    250:                            sizeof(hostname));
1.31      gsoares   251:                } else
1.32      gsoares   252:                        (void)strlcpy(hostname, host, sizeof(hostname));
1.31      gsoares   253:                        connected = 1;
                    254:        }
                    255:        freeaddrinfo(res0);
                    256: }
                    257:
                    258: void
                    259: parsearg(int argc, char *argv[])
                    260: {
1.1       deraadt   261:        if (argc < 2) {
1.25      mglocker  262:                strlcpy(line, "Connect ", sizeof(line));
1.1       deraadt   263:                printf("(to) ");
1.25      mglocker  264:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   265:                if (makeargv())
                    266:                        return;
1.1       deraadt   267:                argc = margc;
                    268:                argv = margv;
                    269:        }
                    270:        if ((argc < 2) || (argc > 3)) {
1.20      jmc       271:                printf("usage: %s [host [port]]\n", argv[0]);
1.1       deraadt   272:                return;
                    273:        }
1.31      gsoares   274:        if (argc == 2)
                    275:                setpeer(argv[1], NULL);
                    276:        else
                    277:                setpeer(argv[1], argv[2]);
1.1       deraadt   278: }
                    279:
                    280: void
1.14      deraadt   281: modecmd(int argc, char *argv[])
1.1       deraadt   282: {
1.25      mglocker  283:        struct modes    *p;
                    284:        char            *sep;
1.1       deraadt   285:
                    286:        if (argc < 2) {
                    287:                printf("Using %s mode to transfer files.\n", mode);
                    288:                return;
                    289:        }
                    290:        if (argc == 2) {
1.8       mpech     291:                for (p = modes; p->m_name != NULL; p++)
1.1       deraadt   292:                        if (strcmp(argv[1], p->m_name) == 0)
                    293:                                break;
                    294:                if (p->m_name) {
                    295:                        settftpmode(p->m_mode);
                    296:                        return;
                    297:                }
                    298:                printf("%s: unknown mode\n", argv[1]);
                    299:                /* drop through and print usage message */
                    300:        }
                    301:
                    302:        printf("usage: %s [", argv[0]);
                    303:        sep = " ";
1.8       mpech     304:        for (p = modes; p->m_name != NULL; p++) {
1.1       deraadt   305:                printf("%s%s", sep, p->m_name);
                    306:                if (*sep == ' ')
                    307:                        sep = " | ";
                    308:        }
                    309:        printf(" ]\n");
1.25      mglocker  310:
1.1       deraadt   311:        return;
                    312: }
                    313:
1.29      ray       314: /* ARGSUSED */
1.1       deraadt   315: void
1.14      deraadt   316: setbinary(int argc, char *argv[])
1.6       mickey    317: {
1.1       deraadt   318:        settftpmode("octet");
                    319: }
                    320:
1.29      ray       321: /* ARGSUSED */
1.1       deraadt   322: void
1.14      deraadt   323: setascii(int argc, char *argv[])
1.1       deraadt   324: {
                    325:        settftpmode("netascii");
                    326: }
                    327:
                    328: static void
1.14      deraadt   329: settftpmode(char *newmode)
1.1       deraadt   330: {
1.25      mglocker  331:        strlcpy(mode, newmode, sizeof(mode));
1.1       deraadt   332:        if (verbose)
                    333:                printf("mode set to %s\n", mode);
                    334: }
                    335:
                    336: /*
                    337:  * Send file(s).
                    338:  */
                    339: void
1.14      deraadt   340: put(int argc, char *argv[])
1.1       deraadt   341: {
1.25      mglocker  342:        int      fd;
                    343:        int      n;
                    344:        char    *cp, *targ;
1.1       deraadt   345:
                    346:        if (argc < 2) {
1.33      gsoares   347:                strlcpy(line, "put ", sizeof(line));
1.1       deraadt   348:                printf("(file) ");
1.24      claudio   349:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   350:                if (makeargv())
                    351:                        return;
1.1       deraadt   352:                argc = margc;
                    353:                argv = margv;
                    354:        }
                    355:        if (argc < 2) {
                    356:                putusage(argv[0]);
                    357:                return;
                    358:        }
                    359:        targ = argv[argc - 1];
1.31      gsoares   360:        if (strrchr(argv[argc - 1], ':')) {
1.1       deraadt   361:
                    362:                for (n = 1; n < argc - 1; n++)
1.4       millert   363:                        if (strchr(argv[n], ':')) {
1.1       deraadt   364:                                putusage(argv[0]);
                    365:                                return;
                    366:                        }
                    367:                cp = argv[argc - 1];
1.31      gsoares   368:                targ = strrchr(cp, ':');
1.1       deraadt   369:                *targ++ = 0;
1.31      gsoares   370:                if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
                    371:                        cp[strlen(cp) - 1] = '\0';
                    372:                        cp++;
1.1       deraadt   373:                }
1.31      gsoares   374:                setpeer(cp, NULL);
1.1       deraadt   375:        }
                    376:        if (!connected) {
                    377:                printf("No target machine specified.\n");
                    378:                return;
                    379:        }
                    380:        if (argc < 4) {
                    381:                cp = argc == 2 ? tail(targ) : argv[1];
                    382:                fd = open(cp, O_RDONLY);
                    383:                if (fd < 0) {
1.6       mickey    384:                        warn("open: %s", cp);
1.1       deraadt   385:                        return;
                    386:                }
                    387:                if (verbose)
                    388:                        printf("putting %s to %s:%s [%s]\n",
1.18      deraadt   389:                            cp, hostname, targ, mode);
1.1       deraadt   390:                sendfile(fd, targ, mode);
                    391:                return;
                    392:        }
1.18      deraadt   393:
1.24      claudio   394:        /*
                    395:         * this assumes the target is a directory on
                    396:         * on a remote unix system.  hmmmm.
                    397:         */
1.1       deraadt   398:        for (n = 1; n < argc - 1; n++) {
1.12      henning   399:                if (asprintf(&cp, "%s/%s", targ, tail(argv[n])) == -1)
                    400:                        err(1, "asprintf");
1.1       deraadt   401:                fd = open(argv[n], O_RDONLY);
                    402:                if (fd < 0) {
1.6       mickey    403:                        warn("open: %s", argv[n]);
1.22      mpech     404:                        free(cp);
1.1       deraadt   405:                        continue;
                    406:                }
                    407:                if (verbose)
                    408:                        printf("putting %s to %s:%s [%s]\n",
1.18      deraadt   409:                            argv[n], hostname, cp, mode);
1.12      henning   410:                sendfile(fd, cp, mode);
                    411:                free(cp);
1.1       deraadt   412:        }
                    413: }
                    414:
                    415: static void
1.14      deraadt   416: putusage(char *s)
1.1       deraadt   417: {
1.19      jmc       418:        printf("usage: %s file [[host:]remotename]\n", s);
1.24      claudio   419:        printf("       %s file1 file2 ... fileN [[host:]remote-directory]\n",
                    420:            s);
1.1       deraadt   421: }
                    422:
                    423: /*
                    424:  * Receive file(s).
                    425:  */
                    426: void
1.14      deraadt   427: get(int argc, char *argv[])
1.1       deraadt   428: {
1.25      mglocker  429:        int      fd;
                    430:        int      n;
                    431:        char    *cp;
                    432:        char    *src;
1.1       deraadt   433:
                    434:        if (argc < 2) {
1.25      mglocker  435:                strlcpy(line, "get ", sizeof(line));
1.1       deraadt   436:                printf("(files) ");
1.25      mglocker  437:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   438:                if (makeargv())
                    439:                        return;
1.1       deraadt   440:                argc = margc;
                    441:                argv = margv;
                    442:        }
                    443:        if (argc < 2) {
                    444:                getusage(argv[0]);
                    445:                return;
                    446:        }
                    447:        if (!connected) {
1.25      mglocker  448:                for (n = 1; n < argc; n++)
1.31      gsoares   449:                        if (strrchr(argv[n], ':') == 0) {
1.1       deraadt   450:                                getusage(argv[0]);
                    451:                                return;
                    452:                        }
                    453:        }
1.25      mglocker  454:        for (n = 1; n < argc; n++) {
1.31      gsoares   455:                src = strrchr(argv[n], ':');
1.1       deraadt   456:                if (src == NULL)
                    457:                        src = argv[n];
                    458:                else {
1.31      gsoares   459:                        char *cp;
1.1       deraadt   460:
                    461:                        *src++ = 0;
1.31      gsoares   462:                        cp = argv[n];
                    463:                        if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
                    464:                                cp[strlen(cp) - 1] = '\0';
                    465:                                cp++;
                    466:                        }
                    467:                        setpeer(cp, NULL);
                    468:                        if (!connected)
1.1       deraadt   469:                                continue;
                    470:                }
                    471:                if (argc < 4) {
                    472:                        cp = argc == 3 ? argv[2] : tail(src);
                    473:                        fd = creat(cp, 0644);
                    474:                        if (fd < 0) {
1.6       mickey    475:                                warn("create: %s", cp);
1.1       deraadt   476:                                return;
                    477:                        }
                    478:                        if (verbose)
                    479:                                printf("getting from %s:%s to %s [%s]\n",
1.18      deraadt   480:                                    hostname, src, cp, mode);
1.1       deraadt   481:                        recvfile(fd, src, mode);
                    482:                        break;
                    483:                }
1.25      mglocker  484:                cp = tail(src); /* new .. jdg */
1.1       deraadt   485:                fd = creat(cp, 0644);
                    486:                if (fd < 0) {
1.6       mickey    487:                        warn("create: %s", cp);
1.1       deraadt   488:                        continue;
                    489:                }
                    490:                if (verbose)
                    491:                        printf("getting from %s:%s to %s [%s]\n",
1.18      deraadt   492:                            hostname, src, cp, mode);
1.1       deraadt   493:                recvfile(fd, src, mode);
                    494:        }
                    495: }
                    496:
                    497: static void
1.15      deraadt   498: getusage(char *s)
1.1       deraadt   499: {
1.19      jmc       500:        printf("usage: %s [host:]file [localname]\n", s);
                    501:        printf("       %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
1.1       deraadt   502: }
                    503:
                    504: void
1.14      deraadt   505: setrexmt(int argc, char *argv[])
1.1       deraadt   506: {
1.26      mglocker  507:        int              t;
                    508:        const char      *errstr;
1.1       deraadt   509:
                    510:        if (argc < 2) {
1.25      mglocker  511:                strlcpy(line, "Rexmt-timeout ", sizeof(line));
1.1       deraadt   512:                printf("(value) ");
1.25      mglocker  513:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   514:                if (makeargv())
                    515:                        return;
1.1       deraadt   516:                argc = margc;
                    517:                argv = margv;
                    518:        }
                    519:        if (argc != 2) {
                    520:                printf("usage: %s value\n", argv[0]);
                    521:                return;
                    522:        }
1.27      mglocker  523:        t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
1.26      mglocker  524:        if (errstr)
                    525:                printf("%s: value is %s\n", argv[1], errstr);
1.1       deraadt   526:        else
                    527:                rexmtval = t;
                    528: }
                    529:
                    530: void
1.14      deraadt   531: settimeout(int argc, char *argv[])
1.1       deraadt   532: {
1.27      mglocker  533:        int              t;
                    534:        const char      *errstr;
1.1       deraadt   535:
                    536:        if (argc < 2) {
1.25      mglocker  537:                strlcpy(line, "Maximum-timeout ", sizeof(line));
1.1       deraadt   538:                printf("(value) ");
1.25      mglocker  539:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5       deraadt   540:                if (makeargv())
                    541:                        return;
1.1       deraadt   542:                argc = margc;
                    543:                argv = margv;
                    544:        }
                    545:        if (argc != 2) {
                    546:                printf("usage: %s value\n", argv[0]);
                    547:                return;
                    548:        }
1.27      mglocker  549:        t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
                    550:        if (errstr)
                    551:                printf("%s: value is %s\n", argv[1], errstr);
1.1       deraadt   552:        else
                    553:                maxtimeout = t;
                    554: }
                    555:
1.29      ray       556: /* ARGSUSED */
1.1       deraadt   557: void
1.14      deraadt   558: status(int argc, char *argv[])
1.1       deraadt   559: {
                    560:        if (connected)
                    561:                printf("Connected to %s.\n", hostname);
                    562:        else
                    563:                printf("Not connected.\n");
1.25      mglocker  564:        printf("Mode: %s Verbose: %s Tracing: %s\n",
                    565:            mode, verbose ? "on" : "off", trace ? "on" : "off");
1.1       deraadt   566:        printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
1.25      mglocker  567:            rexmtval, maxtimeout);
1.1       deraadt   568: }
                    569:
1.29      ray       570: /* ARGSUSED */
1.1       deraadt   571: void
1.16      deraadt   572: intr(int signo)
1.1       deraadt   573: {
1.24      claudio   574:        intrflag = 1;
1.1       deraadt   575: }
                    576:
                    577: char *
1.14      deraadt   578: tail(char *filename)
1.1       deraadt   579: {
1.25      mglocker  580:        char    *s;
1.6       mickey    581:
1.1       deraadt   582:        while (*filename) {
1.4       millert   583:                s = strrchr(filename, '/');
1.1       deraadt   584:                if (s == NULL)
                    585:                        break;
                    586:                if (s[1])
                    587:                        return (s + 1);
                    588:                *s = '\0';
                    589:        }
1.25      mglocker  590:
1.1       deraadt   591:        return (filename);
                    592: }
                    593:
                    594: /*
                    595:  * Command parser.
                    596:  */
                    597: static __dead void
1.14      deraadt   598: command(void)
1.1       deraadt   599: {
1.25      mglocker  600:        struct cmd      *c;
1.1       deraadt   601:
                    602:        for (;;) {
                    603:                printf("%s> ", prompt);
1.24      claudio   604:                if (readcmd(line, LBUFLEN, stdin) < 1)
                    605:                        continue;
1.1       deraadt   606:                if ((line[0] == 0) || (line[0] == '\n'))
                    607:                        continue;
1.5       deraadt   608:                if (makeargv())
                    609:                        continue;
1.1       deraadt   610:                if (margc == 0)
                    611:                        continue;
                    612:                c = getcmd(margv[0]);
1.25      mglocker  613:                if (c == (struct cmd *) - 1) {
1.1       deraadt   614:                        printf("?Ambiguous command\n");
                    615:                        continue;
                    616:                }
                    617:                if (c == 0) {
                    618:                        printf("?Invalid command\n");
                    619:                        continue;
                    620:                }
                    621:                (*c->handler)(margc, margv);
                    622:        }
                    623: }
                    624:
                    625: struct cmd *
1.14      deraadt   626: getcmd(char *name)
1.1       deraadt   627: {
1.25      mglocker  628:        char            *p, *q;
                    629:        struct cmd      *c, *found;
                    630:        int              nmatches, longest;
1.1       deraadt   631:
                    632:        longest = 0;
                    633:        nmatches = 0;
                    634:        found = 0;
1.24      claudio   635:        intrflag = 0;
1.1       deraadt   636:        for (c = cmdtab; (p = c->name) != NULL; c++) {
                    637:                for (q = name; *q == *p++; q++)
                    638:                        if (*q == 0)            /* exact match? */
                    639:                                return (c);
                    640:                if (!*q) {                      /* the name was a prefix */
                    641:                        if (q - name > longest) {
                    642:                                longest = q - name;
                    643:                                nmatches = 1;
                    644:                                found = c;
                    645:                        } else if (q - name == longest)
                    646:                                nmatches++;
                    647:                }
                    648:        }
                    649:        if (nmatches > 1)
1.25      mglocker  650:                return ((struct cmd *) - 1);
                    651:
1.1       deraadt   652:        return (found);
                    653: }
                    654:
                    655: /*
                    656:  * Slice a string up into argc/argv.
                    657:  */
1.5       deraadt   658: static int
1.14      deraadt   659: makeargv(void)
1.1       deraadt   660: {
1.25      mglocker  661:        char     *cp;
                    662:        char    **argp = margv;
                    663:        int       ret = 0;
1.1       deraadt   664:
                    665:        margc = 0;
                    666:        for (cp = line; *cp;) {
1.5       deraadt   667:                if (margc >= MAXARGV) {
                    668:                        printf("too many arguments\n");
                    669:                        ret = 1;
                    670:                        break;
                    671:                }
1.34      deraadt   672:                while (isspace((unsigned char)*cp))
1.1       deraadt   673:                        cp++;
                    674:                if (*cp == '\0')
                    675:                        break;
                    676:                *argp++ = cp;
                    677:                margc += 1;
1.34      deraadt   678:                while (*cp != '\0' && !isspace((unsigned char)*cp))
1.1       deraadt   679:                        cp++;
                    680:                if (*cp == '\0')
                    681:                        break;
                    682:                *cp++ = '\0';
                    683:        }
                    684:        *argp++ = 0;
1.25      mglocker  685:
1.5       deraadt   686:        return (ret);
1.1       deraadt   687: }
                    688:
1.29      ray       689: /* ARGSUSED */
1.1       deraadt   690: void
1.14      deraadt   691: quit(int argc, char *argv[])
1.1       deraadt   692: {
                    693:        exit(0);
                    694: }
                    695:
                    696: /*
                    697:  * Help command.
                    698:  */
                    699: void
1.14      deraadt   700: help(int argc, char *argv[])
1.1       deraadt   701: {
1.25      mglocker  702:        struct cmd      *c;
1.1       deraadt   703:
                    704:        if (argc == 1) {
                    705:                printf("Commands may be abbreviated.  Commands are:\n\n");
1.8       mpech     706:                for (c = cmdtab; c->name != NULL; c++)
1.1       deraadt   707:                        printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
                    708:                return;
                    709:        }
                    710:        while (--argc > 0) {
1.9       mpech     711:                char *arg;
1.1       deraadt   712:                arg = *++argv;
                    713:                c = getcmd(arg);
1.25      mglocker  714:                if (c == (struct cmd *) - 1)
1.1       deraadt   715:                        printf("?Ambiguous help command %s\n", arg);
                    716:                else if (c == (struct cmd *)0)
                    717:                        printf("?Invalid help command %s\n", arg);
                    718:                else
                    719:                        printf("%s\n", c->help);
                    720:        }
                    721: }
                    722:
1.29      ray       723: /* ARGSUSED */
1.1       deraadt   724: void
1.14      deraadt   725: settrace(int argc, char *argv[])
1.1       deraadt   726: {
                    727:        trace = !trace;
                    728:        printf("Packet tracing %s.\n", trace ? "on" : "off");
                    729: }
                    730:
1.29      ray       731: /* ARGSUSED */
1.1       deraadt   732: void
1.14      deraadt   733: setverbose(int argc, char *argv[])
1.1       deraadt   734: {
                    735:        verbose = !verbose;
                    736:        printf("Verbose mode %s.\n", verbose ? "on" : "off");
1.26      mglocker  737: }
                    738:
1.29      ray       739: /* ARGSUSED */
1.26      mglocker  740: void
                    741: settsize(int argc, char *argv[])
                    742: {
                    743:        opt_tsize = !opt_tsize;
                    744:        printf("Tsize option %s.\n", opt_tsize ? "on" : "off");
                    745:        if (opt_tsize)
                    746:                has_options++;
                    747:        else
                    748:                has_options--;
                    749: }
                    750:
1.29      ray       751: /* ARGSUSED */
1.26      mglocker  752: void
                    753: settout(int argc, char *argv[])
                    754: {
                    755:        opt_tout = !opt_tout;
                    756:        printf("Timeout option %s.\n", opt_tout ? "on" : "off");
                    757:        if (opt_tout)
                    758:                has_options++;
                    759:        else
                    760:                has_options--;
                    761: }
                    762:
                    763: void
                    764: setblksize(int argc, char *argv[])
                    765: {
                    766:        int              t;
                    767:        const char      *errstr;
                    768:
                    769:        if (argc < 2) {
                    770:                strlcpy(line, "Blocksize ", sizeof(line));
                    771:                printf("(value) ");
                    772:                readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
                    773:                if (makeargv())
                    774:                        return;
                    775:                argc = margc;
                    776:                argv = margv;
                    777:        }
                    778:        if (argc != 2) {
                    779:                printf("usage: %s value\n", argv[0]);
                    780:                return;
                    781:        }
                    782:        t = strtonum(argv[1], SEGSIZE_MIN, SEGSIZE_MAX, &errstr);
                    783:        if (errstr)
                    784:                printf("%s: value is %s\n", argv[1], errstr);
                    785:        else {
                    786:                if (opt_blksize == 0)
                    787:                        has_options++;
                    788:                opt_blksize = t;
                    789:        }
1.24      claudio   790: }
                    791:
                    792: int
                    793: readcmd(char *input, int len, FILE *stream)
                    794: {
                    795:        int             nfds;
                    796:        struct pollfd   pfd[1];
                    797:
                    798:        fflush(stdout);
                    799:
                    800:        pfd[0].fd = 0;
                    801:        pfd[0].events = POLLIN;
                    802:        nfds = poll(pfd, 1, INFTIM);
                    803:        if (nfds == -1) {
                    804:                if (intrflag) {
                    805:                        intrflag = 0;
                    806:                        putchar('\n');
                    807:                        return (0);
                    808:                }
                    809:                exit(1);
                    810:        }
                    811:
                    812:        if (fgets(input, len, stream) == NULL) {
                    813:                if (feof(stdin))
                    814:                        exit(0);
                    815:                else
                    816:                        return (-1);
                    817:        }
                    818:
                    819:        return (1);
1.1       deraadt   820: }