Annotation of qemu/cmd.c, revision 1.1.1.6

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

unix.superglobalmegacorp.com