Annotation of qemu/cmd.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
                      3:  * All Rights Reserved.
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or
                      6:  * modify it under the terms of the GNU General Public License as
                      7:  * published by the Free Software Foundation.
                      8:  *
                      9:  * This program is distributed in the hope that it would be useful,
                     10:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     12:  * GNU General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program; if not, see <http://www.gnu.org/licenses/>.
                     16:  */
                     17: 
                     18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <string.h>
                     21: #include <ctype.h>
                     22: #include <errno.h>
                     23: #include <sys/time.h>
1.1.1.2   root       24: #include <getopt.h>
1.1       root       25: 
                     26: #include "cmd.h"
1.1.1.3   root       27: #include "qemu-aio.h"
1.1       root       28: 
                     29: #define _(x)   x       /* not gettext support yet */
                     30: 
                     31: /* from libxcmd/command.c */
                     32: 
                     33: cmdinfo_t      *cmdtab;
                     34: int            ncmds;
                     35: 
                     36: static argsfunc_t      args_func;
                     37: static checkfunc_t     check_func;
                     38: static int             ncmdline;
                     39: static char            **cmdline;
                     40: 
                     41: static int
                     42: compare(const void *a, const void *b)
                     43: {
                     44:        return strcmp(((const cmdinfo_t *)a)->name,
                     45:                      ((const cmdinfo_t *)b)->name);
                     46: }
                     47: 
                     48: void
                     49: add_command(
                     50:        const cmdinfo_t *ci)
                     51: {
                     52:        cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
                     53:        cmdtab[ncmds - 1] = *ci;
                     54:        qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
                     55: }
                     56: 
                     57: static int
                     58: check_command(
                     59:        const cmdinfo_t *ci)
                     60: {
                     61:        if (check_func)
                     62:                return check_func(ci);
                     63:        return 1;
                     64: }
                     65: 
                     66: void
                     67: add_check_command(
                     68:        checkfunc_t     cf)
                     69: {
                     70:        check_func = cf;
                     71: }
                     72: 
                     73: int
                     74: command_usage(
                     75:        const cmdinfo_t *ci)
                     76: {
                     77:        printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
                     78:        return 0;
                     79: }
                     80: 
                     81: int
                     82: command(
                     83:        const cmdinfo_t *ct,
                     84:        int             argc,
                     85:        char            **argv)
                     86: {
                     87:        char            *cmd = argv[0];
                     88: 
                     89:        if (!check_command(ct))
                     90:                return 0;
                     91: 
                     92:        if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
                     93:                if (ct->argmax == -1)
                     94:                        fprintf(stderr,
                     95:        _("bad argument count %d to %s, expected at least %d arguments\n"),
                     96:                                argc-1, cmd, ct->argmin);
                     97:                else if (ct->argmin == ct->argmax)
                     98:                        fprintf(stderr,
                     99:        _("bad argument count %d to %s, expected %d arguments\n"),
                    100:                                argc-1, cmd, ct->argmin);
                    101:                else
                    102:                        fprintf(stderr,
                    103:        _("bad argument count %d to %s, expected between %d and %d arguments\n"),
                    104:                        argc-1, cmd, ct->argmin, ct->argmax);
                    105:                return 0;
                    106:        }
                    107:        optind = 0;
                    108:        return ct->cfunc(argc, argv);
                    109: }
                    110: 
                    111: const cmdinfo_t *
                    112: find_command(
                    113:        const char      *cmd)
                    114: {
                    115:        cmdinfo_t       *ct;
                    116: 
                    117:        for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
                    118:                if (strcmp(ct->name, cmd) == 0 ||
                    119:                    (ct->altname && strcmp(ct->altname, cmd) == 0))
                    120:                        return (const cmdinfo_t *)ct;
                    121:        }
                    122:        return NULL;
                    123: }
                    124: 
                    125: void
                    126: add_user_command(char *optarg)
                    127: {
                    128:        ncmdline++;
                    129:        cmdline = realloc(cmdline, sizeof(char*) * (ncmdline));
                    130:        if (!cmdline) {
                    131:                perror("realloc");
                    132:                exit(1);
                    133:        }
                    134:        cmdline[ncmdline-1] = optarg;
                    135: }
                    136: 
                    137: static int
                    138: args_command(
                    139:        int     index)
                    140: {
                    141:        if (args_func)
                    142:                return args_func(index);
                    143:        return 0;
                    144: }
                    145: 
                    146: void
                    147: add_args_command(
                    148:        argsfunc_t      af)
                    149: {
                    150:        args_func = af;
                    151: }
                    152: 
1.1.1.3   root      153: static void prep_fetchline(void *opaque)
                    154: {
                    155:     int *fetchable = opaque;
                    156: 
                    157:     qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
                    158:     *fetchable= 1;
                    159: }
                    160: 
                    161: static char *get_prompt(void);
                    162: 
1.1       root      163: void
                    164: command_loop(void)
                    165: {
1.1.1.3   root      166:        int             c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
1.1       root      167:        char            *input;
                    168:        char            **v;
                    169:        const cmdinfo_t *ct;
                    170: 
                    171:        for (i = 0; !done && i < ncmdline; i++) {
                    172:                input = strdup(cmdline[i]);
                    173:                if (!input) {
                    174:                        fprintf(stderr,
                    175:                                _("cannot strdup command '%s': %s\n"),
                    176:                                cmdline[i], strerror(errno));
                    177:                        exit(1);
                    178:                }
                    179:                v = breakline(input, &c);
                    180:                if (c) {
                    181:                        ct = find_command(v[0]);
                    182:                        if (ct) {
                    183:                                if (ct->flags & CMD_FLAG_GLOBAL)
                    184:                                        done = command(ct, c, v);
                    185:                                else {
                    186:                                        j = 0;
                    187:                                        while (!done && (j = args_command(j)))
                    188:                                                done = command(ct, c, v);
                    189:                                }
                    190:                        } else
                    191:                                fprintf(stderr, _("command \"%s\" not found\n"),
                    192:                                        v[0]);
                    193:                }
                    194:                doneline(input, v);
                    195:        }
                    196:        if (cmdline) {
                    197:                free(cmdline);
                    198:                return;
                    199:        }
1.1.1.3   root      200: 
1.1       root      201:        while (!done) {
1.1.1.3   root      202:         if (!prompted) {
                    203:             printf("%s", get_prompt());
                    204:             fflush(stdout);
                    205:             qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
                    206:                                     NULL, &fetchable);
                    207:             prompted = 1;
                    208:         }
                    209: 
                    210:         qemu_aio_wait();
                    211: 
                    212:         if (!fetchable) {
                    213:             continue;
                    214:         }
1.1       root      215:                if ((input = fetchline()) == NULL)
                    216:                        break;
                    217:                v = breakline(input, &c);
                    218:                if (c) {
                    219:                        ct = find_command(v[0]);
                    220:                        if (ct)
                    221:                                done = command(ct, c, v);
                    222:                        else
                    223:                                fprintf(stderr, _("command \"%s\" not found\n"),
                    224:                                        v[0]);
                    225:                }
                    226:                doneline(input, v);
1.1.1.3   root      227: 
                    228:         prompted = 0;
                    229:         fetchable = 0;
1.1       root      230:        }
1.1.1.3   root      231:     qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
1.1       root      232: }
                    233: 
                    234: /* from libxcmd/input.c */
                    235: 
                    236: #if defined(ENABLE_READLINE)
                    237: # include <readline/history.h>
                    238: # include <readline/readline.h>
                    239: #elif defined(ENABLE_EDITLINE)
                    240: # include <histedit.h>
                    241: #endif
                    242: 
                    243: static char *
                    244: get_prompt(void)
                    245: {
                    246:        static char     prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
                    247: 
                    248:        if (!prompt[0])
                    249:                snprintf(prompt, sizeof(prompt), "%s> ", progname);
                    250:        return prompt;
                    251: }
                    252: 
                    253: #if defined(ENABLE_READLINE)
                    254: char *
                    255: fetchline(void)
                    256: {
                    257:        char    *line;
                    258: 
                    259:        line = readline(get_prompt());
                    260:        if (line && *line)
                    261:                add_history(line);
                    262:        return line;
                    263: }
                    264: #elif defined(ENABLE_EDITLINE)
                    265: static char *el_get_prompt(EditLine *e) { return get_prompt(); }
                    266: char *
                    267: fetchline(void)
                    268: {
                    269:        static EditLine *el;
                    270:        static History  *hist;
                    271:        HistEvent       hevent;
                    272:        char            *line;
                    273:        int             count;
                    274: 
                    275:        if (!el) {
                    276:                hist = history_init();
                    277:                history(hist, &hevent, H_SETSIZE, 100);
                    278:                el = el_init(progname, stdin, stdout, stderr);
                    279:                el_source(el, NULL);
                    280:                el_set(el, EL_SIGNAL, 1);
                    281:                el_set(el, EL_PROMPT, el_get_prompt);
                    282:                el_set(el, EL_HIST, history, (const char *)hist);
                    283:        }
                    284:        line = strdup(el_gets(el, &count));
                    285:        if (line) {
                    286:                if (count > 0)
                    287:                        line[count-1] = '\0';
                    288:                if (*line)
                    289:                        history(hist, &hevent, H_ENTER, line);
                    290:        }
                    291:        return line;
                    292: }
                    293: #else
                    294: # define MAXREADLINESZ 1024
                    295: char *
                    296: fetchline(void)
                    297: {
                    298:        char    *p, *line = malloc(MAXREADLINESZ);
                    299: 
                    300:        if (!line)
                    301:                return NULL;
                    302:        if (!fgets(line, MAXREADLINESZ, stdin)) {
                    303:                free(line);
                    304:                return NULL;
                    305:        }
                    306:        p = line + strlen(line);
                    307:        if (p != line && p[-1] == '\n')
                    308:                p[-1] = '\0';
                    309:        return line;
                    310: }
                    311: #endif
                    312: 
                    313: static char *qemu_strsep(char **input, const char *delim)
                    314: {
                    315:     char *result = *input;
                    316:     if (result != NULL) {
1.1.1.3   root      317:         char *p;
                    318: 
1.1.1.2   root      319:         for (p = result; *p != '\0'; p++) {
                    320:             if (strchr(delim, *p)) {
1.1       root      321:                 break;
                    322:             }
                    323:         }
                    324:         if (*p == '\0') {
                    325:             *input = NULL;
                    326:         } else {
                    327:             *p = '\0';
                    328:             *input = p + 1;
                    329:         }
                    330:     }
                    331:     return result;
                    332: }
                    333: 
                    334: char **
                    335: breakline(
                    336:        char    *input,
                    337:        int     *count)
                    338: {
                    339:        int     c = 0;
                    340:        char    *p;
                    341:        char    **rval = calloc(sizeof(char *), 1);
                    342: 
                    343:        while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
                    344:                if (!*p)
                    345:                        continue;
                    346:                c++;
                    347:                rval = realloc(rval, sizeof(*rval) * (c + 1));
                    348:                if (!rval) {
                    349:                        c = 0;
                    350:                        break;
                    351:                }
                    352:                rval[c - 1] = p;
                    353:                rval[c] = NULL;
                    354:        }
                    355:        *count = c;
                    356:        return rval;
                    357: }
                    358: 
                    359: void
                    360: doneline(
                    361:        char    *input,
                    362:        char    **vec)
                    363: {
                    364:        free(input);
                    365:        free(vec);
                    366: }
                    367: 
                    368: #define EXABYTES(x)    ((long long)(x) << 60)
                    369: #define PETABYTES(x)   ((long long)(x) << 50)
                    370: #define TERABYTES(x)   ((long long)(x) << 40)
                    371: #define GIGABYTES(x)   ((long long)(x) << 30)
                    372: #define MEGABYTES(x)   ((long long)(x) << 20)
                    373: #define KILOBYTES(x)   ((long long)(x) << 10)
                    374: 
                    375: long long
                    376: cvtnum(
                    377:        char            *s)
                    378: {
                    379:        long long       i;
                    380:        char            *sp;
                    381:        int             c;
                    382: 
                    383:        i = strtoll(s, &sp, 0);
                    384:        if (i == 0 && sp == s)
                    385:                return -1LL;
                    386:        if (*sp == '\0')
                    387:                return i;
                    388: 
                    389:        if (sp[1] != '\0')
                    390:                return -1LL;
                    391: 
                    392:        c = tolower(*sp);
                    393:        switch (c) {
                    394:        default:
                    395:                return i;
                    396:        case 'k':
                    397:                return KILOBYTES(i);
                    398:        case 'm':
                    399:                return MEGABYTES(i);
                    400:        case 'g':
                    401:                return GIGABYTES(i);
                    402:        case 't':
                    403:                return TERABYTES(i);
                    404:        case 'p':
                    405:                return PETABYTES(i);
                    406:        case 'e':
                    407:                return  EXABYTES(i);
                    408:        }
                    409:        return -1LL;
                    410: }
                    411: 
                    412: #define TO_EXABYTES(x) ((x) / EXABYTES(1))
                    413: #define TO_PETABYTES(x)        ((x) / PETABYTES(1))
                    414: #define TO_TERABYTES(x)        ((x) / TERABYTES(1))
                    415: #define TO_GIGABYTES(x)        ((x) / GIGABYTES(1))
                    416: #define TO_MEGABYTES(x)        ((x) / MEGABYTES(1))
                    417: #define TO_KILOBYTES(x)        ((x) / KILOBYTES(1))
                    418: 
                    419: void
                    420: cvtstr(
                    421:        double          value,
                    422:        char            *str,
                    423:        size_t          size)
                    424: {
                    425:        const char      *fmt;
                    426:        int             precise;
                    427: 
                    428:        precise = ((double)value * 1000 == (double)(int)value * 1000);
                    429: 
                    430:        if (value >= EXABYTES(1)) {
                    431:                fmt = precise ? "%.f EiB" : "%.3f EiB";
                    432:                snprintf(str, size, fmt, TO_EXABYTES(value));
                    433:        } else if (value >= PETABYTES(1)) {
                    434:                fmt = precise ? "%.f PiB" : "%.3f PiB";
                    435:                snprintf(str, size, fmt, TO_PETABYTES(value));
                    436:        } else if (value >= TERABYTES(1)) {
                    437:                fmt = precise ? "%.f TiB" : "%.3f TiB";
                    438:                snprintf(str, size, fmt, TO_TERABYTES(value));
                    439:        } else if (value >= GIGABYTES(1)) {
                    440:                fmt = precise ? "%.f GiB" : "%.3f GiB";
                    441:                snprintf(str, size, fmt, TO_GIGABYTES(value));
                    442:        } else if (value >= MEGABYTES(1)) {
                    443:                fmt = precise ? "%.f MiB" : "%.3f MiB";
                    444:                snprintf(str, size, fmt, TO_MEGABYTES(value));
                    445:        } else if (value >= KILOBYTES(1)) {
                    446:                fmt = precise ? "%.f KiB" : "%.3f KiB";
                    447:                snprintf(str, size, fmt, TO_KILOBYTES(value));
                    448:        } else {
                    449:                snprintf(str, size, "%f bytes", value);
                    450:        }
                    451: }
                    452: 
                    453: struct timeval
                    454: tsub(struct timeval t1, struct timeval t2)
                    455: {
                    456:        t1.tv_usec -= t2.tv_usec;
                    457:        if (t1.tv_usec < 0) {
                    458:                t1.tv_usec += 1000000;
                    459:                t1.tv_sec--;
                    460:        }
                    461:        t1.tv_sec -= t2.tv_sec;
                    462:        return t1;
                    463: }
                    464: 
                    465: double
                    466: tdiv(double value, struct timeval tv)
                    467: {
                    468:        return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
                    469: }
                    470: 
                    471: #define HOURS(sec)     ((sec) / (60 * 60))
                    472: #define MINUTES(sec)   (((sec) % (60 * 60)) / 60)
                    473: #define SECONDS(sec)   ((sec) % 60)
                    474: 
                    475: void
                    476: timestr(
                    477:        struct timeval  *tv,
                    478:        char            *ts,
                    479:        size_t          size,
                    480:        int             format)
                    481: {
                    482:        double          usec = (double)tv->tv_usec / 1000000.0;
                    483: 
                    484:        if (format & TERSE_FIXED_TIME) {
                    485:                if (!HOURS(tv->tv_sec)) {
                    486:                        snprintf(ts, size, "%u:%02u.%02u",
                    487:                                (unsigned int) MINUTES(tv->tv_sec),
                    488:                                (unsigned int) SECONDS(tv->tv_sec),
1.1.1.4 ! root      489:                                (unsigned int) (usec * 100));
1.1       root      490:                        return;
                    491:                }
                    492:                format |= VERBOSE_FIXED_TIME;   /* fallback if hours needed */
                    493:        }
                    494: 
                    495:        if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
                    496:                snprintf(ts, size, "%u:%02u:%02u.%02u",
                    497:                        (unsigned int) HOURS(tv->tv_sec),
                    498:                        (unsigned int) MINUTES(tv->tv_sec),
                    499:                        (unsigned int) SECONDS(tv->tv_sec),
1.1.1.4 ! root      500:                        (unsigned int) (usec * 100));
1.1       root      501:        } else {
1.1.1.4 ! root      502:                snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
1.1       root      503:        }
                    504: }
                    505: 
                    506: 
                    507: /* from libxcmd/quit.c */
                    508: 
                    509: static cmdinfo_t quit_cmd;
                    510: 
                    511: /* ARGSUSED */
                    512: static int
                    513: quit_f(
                    514:        int     argc,
                    515:        char    **argv)
                    516: {
                    517:        return 1;
                    518: }
                    519: 
                    520: void
                    521: quit_init(void)
                    522: {
                    523:        quit_cmd.name = _("quit");
                    524:        quit_cmd.altname = _("q");
                    525:        quit_cmd.cfunc = quit_f;
                    526:        quit_cmd.argmin = -1;
                    527:        quit_cmd.argmax = -1;
                    528:        quit_cmd.flags = CMD_FLAG_GLOBAL;
                    529:        quit_cmd.oneline = _("exit the program");
                    530: 
                    531:        add_command(&quit_cmd);
                    532: }
                    533: 
                    534: /* from libxcmd/help.c */
                    535: 
                    536: static cmdinfo_t help_cmd;
                    537: static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
                    538: static void help_oneline(const char *cmd, const cmdinfo_t *ct);
                    539: 
                    540: static void
                    541: help_all(void)
                    542: {
                    543:        const cmdinfo_t *ct;
                    544: 
                    545:        for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++)
                    546:                help_oneline(ct->name, ct);
                    547:        printf(_("\nUse 'help commandname' for extended help.\n"));
                    548: }
                    549: 
                    550: static int
                    551: help_f(
                    552:        int             argc,
                    553:        char            **argv)
                    554: {
                    555:        const cmdinfo_t *ct;
                    556: 
                    557:        if (argc == 1) {
                    558:                help_all();
                    559:                return 0;
                    560:        }
                    561:        ct = find_command(argv[1]);
                    562:        if (ct == NULL) {
                    563:                printf(_("command %s not found\n"), argv[1]);
                    564:                return 0;
                    565:        }
                    566:        help_onecmd(argv[1], ct);
                    567:        return 0;
                    568: }
                    569: 
                    570: static void
                    571: help_onecmd(
                    572:        const char      *cmd,
                    573:        const cmdinfo_t *ct)
                    574: {
                    575:        help_oneline(cmd, ct);
                    576:        if (ct->help)
                    577:                ct->help();
                    578: }
                    579: 
                    580: static void
                    581: help_oneline(
                    582:        const char      *cmd,
                    583:        const cmdinfo_t *ct)
                    584: {
                    585:        if (cmd)
                    586:                printf("%s ", cmd);
                    587:        else {
                    588:                printf("%s ", ct->name);
                    589:                if (ct->altname)
                    590:                        printf("(or %s) ", ct->altname);
                    591:        }
                    592:        if (ct->args)
                    593:                printf("%s ", ct->args);
                    594:        printf("-- %s\n", ct->oneline);
                    595: }
                    596: 
                    597: void
                    598: help_init(void)
                    599: {
                    600:        help_cmd.name = _("help");
                    601:        help_cmd.altname = _("?");
                    602:        help_cmd.cfunc = help_f;
                    603:        help_cmd.argmin = 0;
                    604:        help_cmd.argmax = 1;
                    605:        help_cmd.flags = CMD_FLAG_GLOBAL;
                    606:        help_cmd.args = _("[command]");
                    607:        help_cmd.oneline = _("help for one or all commands");
                    608: 
                    609:        add_command(&help_cmd);
                    610: }

unix.superglobalmegacorp.com