qemu/cmd.c
<<
>>
Prefs
   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>
  24#include <getopt.h>
  25
  26#include "cmd.h"
  27#include "block/aio.h"
  28#include "qemu/main-loop.h"
  29
  30#define _(x)    x       /* not gettext support yet */
  31
  32/* from libxcmd/command.c */
  33
  34cmdinfo_t       *cmdtab;
  35int             ncmds;
  36
  37static argsfunc_t       args_func;
  38static checkfunc_t      check_func;
  39static int              ncmdline;
  40static char             **cmdline;
  41
  42static int
  43compare(const void *a, const void *b)
  44{
  45        return strcmp(((const cmdinfo_t *)a)->name,
  46                      ((const cmdinfo_t *)b)->name);
  47}
  48
  49void add_command(const cmdinfo_t *ci)
  50{
  51    cmdtab = g_realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
  52    cmdtab[ncmds - 1] = *ci;
  53    qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
  54}
  55
  56static int
  57check_command(
  58        const cmdinfo_t *ci)
  59{
  60        if (check_func)
  61                return check_func(ci);
  62        return 1;
  63}
  64
  65void
  66add_check_command(
  67        checkfunc_t     cf)
  68{
  69        check_func = cf;
  70}
  71
  72int
  73command_usage(
  74        const cmdinfo_t *ci)
  75{
  76        printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
  77        return 0;
  78}
  79
  80int
  81command(
  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
 110const cmdinfo_t *
 111find_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
 124void add_user_command(char *optarg)
 125{
 126    cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *));
 127    cmdline[ncmdline-1] = optarg;
 128}
 129
 130static int
 131args_command(
 132        int     index)
 133{
 134        if (args_func)
 135                return args_func(index);
 136        return 0;
 137}
 138
 139void
 140add_args_command(
 141        argsfunc_t      af)
 142{
 143        args_func = af;
 144}
 145
 146static void prep_fetchline(void *opaque)
 147{
 148    int *fetchable = opaque;
 149
 150    qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
 151    *fetchable= 1;
 152}
 153
 154static char *get_prompt(void);
 155
 156void command_loop(void)
 157{
 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            }
 185        }
 186        doneline(input, v);
 187    }
 188    if (cmdline) {
 189        g_free(cmdline);
 190        return;
 191    }
 192
 193    while (!done) {
 194        if (!prompted) {
 195            printf("%s", get_prompt());
 196            fflush(stdout);
 197            qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
 198            prompted = 1;
 199        }
 200
 201        main_loop_wait(false);
 202
 203        if (!fetchable) {
 204            continue;
 205        }
 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);
 220
 221        prompted = 0;
 222        fetchable = 0;
 223    }
 224    qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
 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
 236static char *
 237get_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)
 247char *
 248fetchline(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)
 258static char *el_get_prompt(EditLine *e) { return get_prompt(); }
 259char *
 260fetchline(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
 288char *
 289fetchline(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
 306static char *qemu_strsep(char **input, const char *delim)
 307{
 308    char *result = *input;
 309    if (result != NULL) {
 310        char *p;
 311
 312        for (p = result; *p != '\0'; p++) {
 313            if (strchr(delim, *p)) {
 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
 327char **breakline(char *input, int *count)
 328{
 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;
 353}
 354
 355void
 356doneline(
 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
 371long long
 372cvtnum(
 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
 388        c = qemu_tolower(*sp);
 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
 415void
 416cvtstr(
 417        double          value,
 418        char            *str,
 419        size_t          size)
 420{
 421        char            *trim;
 422        const char      *suffix;
 423
 424        if (value >= EXABYTES(1)) {
 425                suffix = " EiB";
 426                snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
 427        } else if (value >= PETABYTES(1)) {
 428                suffix = " PiB";
 429                snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
 430        } else if (value >= TERABYTES(1)) {
 431                suffix = " TiB";
 432                snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
 433        } else if (value >= GIGABYTES(1)) {
 434                suffix = " GiB";
 435                snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
 436        } else if (value >= MEGABYTES(1)) {
 437                suffix = " MiB";
 438                snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
 439        } else if (value >= KILOBYTES(1)) {
 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);
 450        } else {
 451                strcat(str, suffix);
 452        }
 453}
 454
 455struct timeval
 456tsub(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
 467double
 468tdiv(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
 477void
 478timestr(
 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),
 491                                (unsigned int) (usec * 100));
 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),
 502                        (unsigned int) (usec * 100));
 503        } else {
 504                snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
 505        }
 506}
 507
 508
 509/* from libxcmd/quit.c */
 510
 511static cmdinfo_t quit_cmd;
 512
 513/* ARGSUSED */
 514static int
 515quit_f(
 516        int     argc,
 517        char    **argv)
 518{
 519        return 1;
 520}
 521
 522void
 523quit_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
 538static cmdinfo_t help_cmd;
 539static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
 540static void help_oneline(const char *cmd, const cmdinfo_t *ct);
 541
 542static void
 543help_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
 552static int
 553help_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
 572static void
 573help_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
 582static void
 583help_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
 599void
 600help_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}
 613