virsh.c 46.4 KB
Newer Older
1
/*
2
 * virsh.c: a Xen shell used to exercise the libvir API
3 4 5 6 7 8
 *
 * Copyright (C) 2005 Red Hat, Inc.
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
K
Karel Zak 已提交
9 10 11
 * Karel Zak <kzak@redhat.com>
 *
 * $Id$
12 13
 */

14
#define _GNU_SOURCE             /* isblank() */
K
Karel Zak 已提交
15

16
#include "libvirt.h"
17
#include "virterror.h"
18
#include <stdio.h>
K
Karel Zak 已提交
19 20 21
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
22
#include <unistd.h>
K
Karel Zak 已提交
23
#include <getopt.h>
24
#include <sys/types.h>
K
Karel Zak 已提交
25
#include <sys/time.h>
K
Karel Zak 已提交
26 27 28 29 30 31
#include <ctype.h>

#include <readline/readline.h>
#include <readline/history.h>

#include "config.h"
32
#include "internal.h"
K
Karel Zak 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

static char *progname;

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

#define VSH_PROMPT_RW    "virsh # "
#define VSH_PROMPT_RO    "virsh > "

#define GETTIMEOFDAY(T) gettimeofday(T, NULL)
#define DIFF_MSEC(T, U) \
        ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
          ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)

typedef enum {
50 51 52 53
    VSH_MESG,                   /* standard output */
    VSH_HEADER,                 /* header for standard output */
    VSH_FOOTER,                 /* timing, last command state, or whatever */
    VSH_DEBUG1,                 /* debugN where 'N' = level */
K
Karel Zak 已提交
54 55 56 57 58 59
    VSH_DEBUG2,
    VSH_DEBUG3,
    VSH_DEBUG4,
    VSH_DEBUG5
} vshOutType;

60 61 62 63
/*
 * The error handler for virtsh
 */
static void
64 65
virshErrorHandler(void *unused, virErrorPtr error)
{
66 67 68 69 70 71 72 73 74 75
    if ((unused != NULL) || (error == NULL))
        return;

    /* Suppress the VIR_ERR_NO_XEN error which fails as non-root */
    if ((error->code == VIR_ERR_NO_XEN) || (error->code == VIR_ERR_OK))
        return;

    virDefaultErrorFunc(error);
}

K
Karel Zak 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89
/*
 * virsh command line grammar:
 *
 *    command_line    =     <command>\n | <command>; <command>; ...
 *
 *    command         =    <keyword> <option> <data>
 *
 *    option          =     <bool_option> | <int_option> | <string_option>
 *    data            =     <string>
 *
 *    bool_option     =     --optionname
 *    int_option      =     --optionname <number>
 *    string_option   =     --optionname <string>
 *        
90 91 92
 *    keyword         =     [a-zA-Z]
 *    number          =     [0-9]+
 *    string          =     [^[:blank:]] | "[[:alnum:]]"$
K
Karel Zak 已提交
93 94 95 96 97
 *
 */

/*
 * vshCmdOptType - command option type 
98
 */
K
Karel Zak 已提交
99
typedef enum {
100 101 102 103 104
    VSH_OT_NONE = 0,            /* none */
    VSH_OT_BOOL,                /* boolean option */
    VSH_OT_STRING,              /* string option */
    VSH_OT_INT,                 /* int option */
    VSH_OT_DATA                 /* string data (as non-option) */
K
Karel Zak 已提交
105 106 107 108 109
} vshCmdOptType;

/*
 * Command Option Flags
 */
110 111
#define VSH_OFLAG_NONE    0     /* without flags */
#define VSH_OFLAG_REQ    (1 << 1)       /* option required */
K
Karel Zak 已提交
112 113 114 115 116 117 118 119

/* dummy */
typedef struct __vshControl vshControl;
typedef struct __vshCmd vshCmd;

/*
 * vshCmdInfo -- information about command
 */
120 121 122
typedef struct {
    const char *name;           /* name of information */
    const char *data;           /* information */
K
Karel Zak 已提交
123 124 125 126 127
} vshCmdInfo;

/*
 * vshCmdOptDef - command option definition
 */
128 129 130 131 132
typedef struct {
    const char *name;           /* the name of option */
    vshCmdOptType type;         /* option type */
    int flag;                   /* flags */
    const char *help;           /* help string */
K
Karel Zak 已提交
133 134 135 136 137 138
} vshCmdOptDef;

/*
 * vshCmdOpt - command options
 */
typedef struct vshCmdOpt {
139 140 141
    vshCmdOptDef *def;          /* pointer to relevant option */
    char *data;                 /* allocated data */
    struct vshCmdOpt *next;
K
Karel Zak 已提交
142 143 144 145 146
} vshCmdOpt;

/*
 * vshCmdDef - command definition
 */
147 148 149 150 151
typedef struct {
    const char *name;
    int (*handler) (vshControl *, vshCmd *);    /* command handler */
    vshCmdOptDef *opts;         /* definition of command options */
    vshCmdInfo *info;           /* details about command */
K
Karel Zak 已提交
152 153 154 155 156 157
} vshCmdDef;

/*
 * vshCmd - parsed command
 */
typedef struct __vshCmd {
158 159 160
    vshCmdDef *def;             /* command definition */
    vshCmdOpt *opts;            /* list of command arguments */
    struct __vshCmd *next;      /* next command */
K
Karel Zak 已提交
161 162 163 164 165 166
} __vshCmd;

/*
 * vshControl
 */
typedef struct __vshControl {
167 168 169 170 171 172 173 174
    virConnectPtr conn;         /* connection to hypervisor */
    vshCmd *cmd;                /* the current command */
    char *cmdstr;               /* string with command */
    uid_t uid;                  /* process owner */
    int imode;                  /* interactive mode? */
    int quiet;                  /* quiet mode */
    int debug;                  /* print debug messages? */
    int timing;                 /* print timing info? */
K
Karel Zak 已提交
175
} __vshControl;
176

177

K
Karel Zak 已提交
178 179
static vshCmdDef commands[];

180 181 182 183 184
static void vshError(vshControl * ctl, int doexit, const char *format,
                     ...);
static int vshInit(vshControl * ctl);
static int vshDeinit(vshControl * ctl);
static void vshUsage(vshControl * ctl, const char *cmdname);
K
Karel Zak 已提交
185

186
static int vshParseArgv(vshControl * ctl, int argc, char **argv);
K
Karel Zak 已提交
187

188
static const char *vshCmddefGetInfo(vshCmdDef * cmd, const char *info);
K
Karel Zak 已提交
189
static vshCmdDef *vshCmddefSearch(const char *cmdname);
190
static int vshCmddefHelp(vshControl * ctl, const char *name, int withprog);
K
Karel Zak 已提交
191

192 193 194 195 196 197 198
static vshCmdOpt *vshCommandOpt(vshCmd * cmd, const char *name);
static int vshCommandOptInt(vshCmd * cmd, const char *name, int *found);
static char *vshCommandOptString(vshCmd * cmd, const char *name,
                                 int *found);
static int vshCommandOptBool(vshCmd * cmd, const char *name);
static virDomainPtr vshCommandOptDomain(vshControl * ctl, vshCmd * cmd,
                                        const char *optname, char **name);
K
Karel Zak 已提交
199

K
Karel Zak 已提交
200

201 202
static void vshPrint(vshControl * ctl, vshOutType out, const char *format,
                     ...);
K
Karel Zak 已提交
203

K
Karel Zak 已提交
204

K
Karel Zak 已提交
205
static const char *vshDomainStateToString(int state);
206 207
static int vshConnectionUsability(vshControl * ctl, virConnectPtr conn,
                                  int showerror);
K
Karel Zak 已提交
208 209 210 211 212 213 214 215 216 217

/* ---------------
 * Commands
 * ---------------
 */

/*
 * "help" command 
 */
static vshCmdInfo info_help[] = {
218 219 220 221 222
    {"syntax", "help [<command>]"},
    {"help", "print help"},
    {"desc", "Prints global help or command specific help."},
    {"version", "Prints versionning informations."},
    {NULL, NULL}
K
Karel Zak 已提交
223 224 225
};

static vshCmdOptDef opts_help[] = {
226 227
    {"command", VSH_OT_DATA, 0, "name of command"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
228 229 230
};

static int
231 232
cmdHelp(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
233
    const char *cmdname = vshCommandOptString(cmd, "command", NULL);
K
Karel Zak 已提交
234 235 236

    if (!cmdname) {
        vshCmdDef *def;
237

K
Karel Zak 已提交
238
        vshPrint(ctl, VSH_HEADER, "Commands:\n\n");
239 240 241
        for (def = commands; def->name; def++)
            vshPrint(ctl, VSH_MESG, "    %-15s %s\n", def->name,
                     vshCmddefGetInfo(def, "help"));
K
Karel Zak 已提交
242 243 244 245 246 247 248 249 250
        return TRUE;
    }
    return vshCmddefHelp(ctl, cmdname, FALSE);
}

/*
 * "connect" command 
 */
static vshCmdInfo info_connect[] = {
251 252 253 254 255
    {"syntax", "connect [--readonly]"},
    {"help", "(re)connect to hypervisor"},
    {"desc",
     "Connect to local hypervisor. This is build-in command after shell start up."},
    {NULL, NULL}
K
Karel Zak 已提交
256 257 258
};

static vshCmdOptDef opts_connect[] = {
259 260
    {"readonly", VSH_OT_BOOL, 0, "read-only connection"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
261 262 263
};

static int
264 265
cmdConnect(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
266
    int ro = vshCommandOptBool(cmd, "readonly");
267

K
Karel Zak 已提交
268
    if (ctl->conn) {
269 270 271
        if (virConnectClose(ctl->conn) != 0) {
            vshError(ctl, FALSE,
                     "failed to disconnect from the hypervisor");
K
Karel Zak 已提交
272 273 274 275 276 277 278 279 280 281 282
            return FALSE;
        }
        ctl->conn = NULL;
    }
    if (!ro)
        ctl->conn = virConnectOpen(NULL);
    else
        ctl->conn = virConnectOpenReadOnly(NULL);

    if (!ctl->conn)
        vshError(ctl, FALSE, "failed to connect to the hypervisor");
283

K
Karel Zak 已提交
284 285 286 287 288 289 290
    return ctl->conn ? TRUE : FALSE;
}

/*
 * "list" command
 */
static vshCmdInfo info_list[] = {
291 292 293 294
    {"syntax", "list"},
    {"help", "list domains"},
    {"desc", "Returns list of domains."},
    {NULL, NULL}
K
Karel Zak 已提交
295 296 297 298 299
};



static int
300 301
cmdList(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
302 303 304 305
    int *ids, maxid, i;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
306

K
Karel Zak 已提交
307 308 309 310 311 312 313 314
    maxid = virConnectNumOfDomains(ctl->conn);
    if (maxid <= 0) {
        /* strange, there should be at least dom0... */
        vshError(ctl, FALSE, "failed to list active domains.");
        return FALSE;
    }
    ids = malloc(sizeof(int) * maxid);
    virConnectListDomains(ctl->conn, &ids[0], maxid);
315

K
Karel Zak 已提交
316 317
    vshPrint(ctl, VSH_HEADER, "%3s %-20s %s\n", "Id", "Name", "State");
    vshPrint(ctl, VSH_HEADER, "----------------------------------\n");
318 319

    for (i = 0; i < maxid; i++) {
K
Karel Zak 已提交
320 321 322
        int ret;
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
323 324

        /* this kind of work with domains is not atomic operation */
K
Karel Zak 已提交
325 326 327
        if (!dom)
            continue;
        ret = virDomainGetInfo(dom, &info);
328 329 330 331 332 333

        vshPrint(ctl, VSH_MESG, "%3d %-20s %s\n",
                 virDomainGetID(dom),
                 virDomainGetName(dom),
                 ret <
                 0 ? "no state" : vshDomainStateToString(info.state));
334
        virDomainFree(dom);
K
Karel Zak 已提交
335 336 337 338 339 340 341 342 343
    }
    free(ids);
    return TRUE;
}

/*
 * "dstate" command
 */
static vshCmdInfo info_dstate[] = {
344 345 346 347
    {"syntax", "dstate <domain>"},
    {"help", "domain state"},
    {"desc", "Returns state about a running domain."},
    {NULL, NULL}
K
Karel Zak 已提交
348 349 350
};

static vshCmdOptDef opts_dstate[] = {
351 352
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
353 354 355
};

static int
356 357
cmdDstate(vshControl * ctl, vshCmd * cmd)
{
358
    virDomainInfo info;
K
Karel Zak 已提交
359
    virDomainPtr dom;
K
Karel Zak 已提交
360
    int ret = TRUE;
361

K
Karel Zak 已提交
362 363
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
364

K
Karel Zak 已提交
365
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
K
Karel Zak 已提交
366
        return FALSE;
367 368 369 370

    if (virDomainGetInfo(dom, &info) == 0)
        vshPrint(ctl, VSH_MESG, "%s\n",
                 vshDomainStateToString(info.state));
K
Karel Zak 已提交
371 372
    else
        ret = FALSE;
373

374 375 376 377 378 379 380 381
    virDomainFree(dom);
    return ret;
}

/*
 * "suspend" command
 */
static vshCmdInfo info_suspend[] = {
382 383 384 385
    {"syntax", "suspend <domain>"},
    {"help", "suspend a domain"},
    {"desc", "Suspend a running domain."},
    {NULL, NULL}
386 387 388
};

static vshCmdOptDef opts_suspend[] = {
389 390
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {NULL, 0, 0, NULL}
391 392 393
};

static int
394 395
cmdSuspend(vshControl * ctl, vshCmd * cmd)
{
396
    virDomainPtr dom;
K
Karel Zak 已提交
397 398
    char *name;
    int ret = TRUE;
399

400 401 402
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
403
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
404
        return FALSE;
405 406

    if (virDomainSuspend(dom) == 0) {
K
Karel Zak 已提交
407
        vshPrint(ctl, VSH_MESG, "Domain %s suspended\n", name);
408 409 410 411
    } else {
        vshError(ctl, FALSE, "Failed to suspend domain\n");
        ret = FALSE;
    }
412

413 414 415 416
    virDomainFree(dom);
    return ret;
}

417 418 419 420
/*
 * "save" command
 */
static vshCmdInfo info_save[] = {
421 422 423 424
    {"syntax", "save <domain> <file>"},
    {"help", "save a domain state to a file"},
    {"desc", "Save a running domain."},
    {NULL, NULL}
425 426 427
};

static vshCmdOptDef opts_save[] = {
428 429 430
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, "where to save the data"},
    {NULL, 0, 0, NULL}
431 432 433
};

static int
434 435
cmdSave(vshControl * ctl, vshCmd * cmd)
{
436 437 438 439
    virDomainPtr dom;
    char *name;
    char *to;
    int ret = TRUE;
440

441 442 443
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

444
    if (!(to = vshCommandOptString(cmd, "file", NULL)))
445
        return FALSE;
446

447 448
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
        return FALSE;
449 450

    if (virDomainSave(dom, to) == 0) {
451 452 453 454 455
        vshPrint(ctl, VSH_MESG, "Domain %s saved\n", name);
    } else {
        vshError(ctl, FALSE, "Failed to save domain\n");
        ret = FALSE;
    }
456

457 458 459 460 461 462 463 464
    virDomainFree(dom);
    return ret;
}

/*
 * "restore" command
 */
static vshCmdInfo info_restore[] = {
465 466 467 468
    {"syntax", "restore a domain from <file>"},
    {"help", "restore a domain from a saved state in a file"},
    {"desc", "Restore a domain."},
    {NULL, NULL}
469 470 471
};

static vshCmdOptDef opts_restore[] = {
472 473
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, "the state to restore"},
    {NULL, 0, 0, NULL}
474 475 476
};

static int
477 478
cmdRestore(vshControl * ctl, vshCmd * cmd)
{
479 480 481
    char *from;
    int found;
    int ret = TRUE;
482

483 484 485 486 487 488
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

    from = vshCommandOptString(cmd, "file", &found);
    if (!found)
        return FALSE;
489 490

    if (virDomainRestore(ctl->conn, from) == 0) {
491 492 493 494 495 496 497 498
        vshPrint(ctl, VSH_MESG, "Domain restored from %s\n", from);
    } else {
        vshError(ctl, FALSE, "Failed to restore domain\n");
        ret = FALSE;
    }
    return ret;
}

499 500 501 502
/*
 * "resume" command
 */
static vshCmdInfo info_resume[] = {
503 504 505 506
    {"syntax", "resume <domain>"},
    {"help", "resume a domain"},
    {"desc", "Resume a previously suspended domain."},
    {NULL, NULL}
507 508 509
};

static vshCmdOptDef opts_resume[] = {
510 511
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {NULL, 0, 0, NULL}
512 513 514
};

static int
515 516
cmdResume(vshControl * ctl, vshCmd * cmd)
{
517
    virDomainPtr dom;
K
Karel Zak 已提交
518 519
    int ret = TRUE;
    char *name;
520

521 522 523
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
524
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
525
        return FALSE;
526 527

    if (virDomainResume(dom) == 0) {
K
Karel Zak 已提交
528
        vshPrint(ctl, VSH_MESG, "Domain %s resumed\n", name);
529 530 531 532
    } else {
        vshError(ctl, FALSE, "Failed to resume domain\n");
        ret = FALSE;
    }
533

534 535 536 537
    virDomainFree(dom);
    return ret;
}

538 539 540 541
/*
 * "shutdown" command
 */
static vshCmdInfo info_shutdown[] = {
542 543 544 545
    {"syntax", "shutdown <domain>"},
    {"help", "gracefully shutdown a domain"},
    {"desc", "Run shutdown in the targetted domain"},
    {NULL, NULL}
546 547 548
};

static vshCmdOptDef opts_shutdown[] = {
549 550
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {NULL, 0, 0, NULL}
551 552 553
};

static int
554 555
cmdShutdown(vshControl * ctl, vshCmd * cmd)
{
556 557 558
    virDomainPtr dom;
    int ret = TRUE;
    char *name;
559

560 561 562 563 564
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
        return FALSE;
565 566

    if (virDomainShutdown(dom) == 0) {
567 568 569 570 571
        vshPrint(ctl, VSH_MESG, "Domain %s is being shutdown\n", name);
    } else {
        vshError(ctl, FALSE, "Failed to shutdown domain\n");
        ret = FALSE;
    }
572

573 574 575 576
    virDomainFree(dom);
    return ret;
}

577 578 579 580
/*
 * "destroy" command
 */
static vshCmdInfo info_destroy[] = {
581 582 583 584
    {"syntax", "destroy <domain>"},
    {"help", "destroy a domain"},
    {"desc", "Destroy a given domain."},
    {NULL, NULL}
585 586 587
};

static vshCmdOptDef opts_destroy[] = {
588 589
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {NULL, 0, 0, NULL}
590 591 592
};

static int
593 594
cmdDestroy(vshControl * ctl, vshCmd * cmd)
{
595
    virDomainPtr dom;
K
Karel Zak 已提交
596 597
    int ret = TRUE;
    char *name;
598

599 600 601
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
602
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
603
        return FALSE;
604 605

    if (virDomainDestroy(dom) == 0) {
K
Karel Zak 已提交
606
        vshPrint(ctl, VSH_MESG, "Domain %s destroyed\n", name);
607 608 609 610 611
    } else {
        vshError(ctl, FALSE, "Failed to destroy domain\n");
        ret = FALSE;
        virDomainFree(dom);
    }
612

K
Karel Zak 已提交
613 614 615 616 617 618 619
    return ret;
}

/*
 * "dinfo" command
 */
static vshCmdInfo info_dinfo[] = {
620 621 622 623
    {"syntax", "dinfo <domain>"},
    {"help", "domain information"},
    {"desc", "Returns basic information about the domain."},
    {NULL, NULL}
K
Karel Zak 已提交
624 625 626
};

static vshCmdOptDef opts_dinfo[] = {
627 628
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
629 630 631
};

static int
632 633
cmdDinfo(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
634 635
    virDomainInfo info;
    virDomainPtr dom;
K
Karel Zak 已提交
636
    int ret = TRUE;
637
    char *str;
638

K
Karel Zak 已提交
639 640 641
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
642
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
K
Karel Zak 已提交
643
        return FALSE;
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659

    vshPrint(ctl, VSH_MESG, "%-15s %d\n", "Id:", virDomainGetID(dom));
    vshPrint(ctl, VSH_MESG, "%-15s %s\n", "Name:", virDomainGetName(dom));

    if ((str = virDomainGetOSType(dom))) {
        vshPrint(ctl, VSH_MESG, "%-15s %s\n", "OS Type:", str);
        free(str);
    }

    if (virDomainGetInfo(dom, &info) == 0) {
        vshPrint(ctl, VSH_MESG, "%-15s %s\n", "State:",
                 vshDomainStateToString(info.state));

        vshPrint(ctl, VSH_MESG, "%-15s %d\n", "CPU(s):", info.nrVirtCpu);

        if (info.cpuTime != 0) {
K
Karel Zak 已提交
660
            float cpuUsed = info.cpuTime;
661

K
Karel Zak 已提交
662
            cpuUsed /= 1000000000;
663

K
Karel Zak 已提交
664
            vshPrint(ctl, VSH_MESG, "%-15s %.1fs\n", "CPU time:", cpuUsed);
K
Karel Zak 已提交
665
        }
666

K
Karel Zak 已提交
667
        vshPrint(ctl, VSH_MESG, "%-15s %lu kB\n", "Max memory:",
668
                 info.maxMem);
K
Karel Zak 已提交
669
        vshPrint(ctl, VSH_MESG, "%-15s %lu kB\n", "Used memory:",
670 671
                 info.memory);

K
Karel Zak 已提交
672 673 674
    } else {
        ret = FALSE;
    }
675

676
    virDomainFree(dom);
K
Karel Zak 已提交
677 678 679
    return ret;
}

680 681 682 683
/*
 * "dumpxml" command
 */
static vshCmdInfo info_dumpxml[] = {
684 685 686 687
    {"syntax", "dumpxml <name>"},
    {"help", "domain information in XML"},
    {"desc", "Ouput the domain informations as an XML dump to stdout"},
    {NULL, NULL}
688 689 690
};

static vshCmdOptDef opts_dumpxml[] = {
691 692
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or id"},
    {NULL, 0, 0, NULL}
693 694 695
};

static int
696 697
cmdDumpXML(vshControl * ctl, vshCmd * cmd)
{
698
    virDomainPtr dom;
K
Karel Zak 已提交
699
    int ret = TRUE;
700
    char *dump;
701

702 703 704
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
705
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
706
        return FALSE;
707

708 709 710 711 712 713 714
    dump = virDomainGetXMLDesc(dom, 0);
    if (dump != NULL) {
        printf("%s", dump);
        free(dump);
    } else {
        ret = FALSE;
    }
715

716 717 718 719
    virDomainFree(dom);
    return ret;
}

K
Karel Zak 已提交
720 721 722 723
/*
 * "nameof" command
 */
static vshCmdInfo info_nameof[] = {
724 725 726
    {"syntax", "nameof <id>"},
    {"help", "convert a domain Id to domain name"},
    {NULL, NULL}
K
Karel Zak 已提交
727 728 729
};

static vshCmdOptDef opts_nameof[] = {
730 731
    {"id", VSH_OT_DATA, VSH_OFLAG_REQ, "domain Id"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
732 733 734
};

static int
735 736
cmdNameof(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
737 738 739 740 741 742 743 744
    int found;
    int id = vshCommandOptInt(cmd, "id", &found);
    virDomainPtr dom;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!found)
        return FALSE;
745

K
Karel Zak 已提交
746 747 748
    dom = virDomainLookupByID(ctl->conn, id);
    if (dom) {
        vshPrint(ctl, VSH_MESG, "%s\n", virDomainGetName(dom));
749
        virDomainFree(dom);
K
Karel Zak 已提交
750 751 752 753 754 755 756 757 758 759 760
    } else {
        vshError(ctl, FALSE, "failed to get domain '%d'", id);
        return FALSE;
    }
    return TRUE;
}

/*
 * "idof" command
 */
static vshCmdInfo info_idof[] = {
761 762 763
    {"syntax", "idof <name>"},
    {"help", "convert a domain name to domain Id"},
    {NULL, NULL}
K
Karel Zak 已提交
764 765 766
};

static vshCmdOptDef opts_idof[] = {
767 768
    {"name", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
769 770 771
};

static int
772 773
cmdIdof(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
774
    char *name = vshCommandOptString(cmd, "name", NULL);
775
    virDomainPtr dom;
K
Karel Zak 已提交
776 777 778 779 780

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!name)
        return FALSE;
781

K
Karel Zak 已提交
782 783
    dom = virDomainLookupByName(ctl->conn, name);
    if (dom) {
784
        vshPrint(ctl, VSH_MESG, "%d\n", virDomainGetID(dom));
785
        virDomainFree(dom);
K
Karel Zak 已提交
786 787 788 789 790 791 792
    } else {
        vshError(ctl, FALSE, "failed to get domain '%s'", name);
        return FALSE;
    }
    return TRUE;
}

793 794 795 796
/*
 * "version" command
 */
static vshCmdInfo info_version[] = {
797 798 799 800
    {"syntax", "version"},
    {"help", "show versions"},
    {"desc", "Display the version informations available"},
    {NULL, NULL}
801 802 803 804
};


static int
805 806
cmdVersion(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
807 808
    unsigned long hvVersion;
    const char *hvType;
809 810 811 812 813 814 815
    unsigned long libVersion;
    unsigned long includeVersion;
    unsigned long apiVersion;
    int ret;
    unsigned int major;
    unsigned int minor;
    unsigned int rel;
816 817 818

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
819

820 821
    hvType = virConnectGetType(ctl->conn);
    if (hvType == NULL) {
K
Karel Zak 已提交
822
        vshError(ctl, FALSE, "failed to get hypervisor type\n");
823 824 825
        return FALSE;
    }

826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
    includeVersion = LIBVIR_VERSION_NUMBER;
    major = includeVersion / 1000000;
    includeVersion %= 1000000;
    minor = includeVersion / 1000;
    rel = includeVersion % 1000;
    vshPrint(ctl, VSH_MESG, "Compiled against library: libvir %d.%d.%d\n",
             major, minor, rel);

    ret = virGetVersion(&libVersion, hvType, &apiVersion);
    if (ret < 0) {
        vshError(ctl, FALSE, "failed to get the library version");
        return FALSE;
    }
    major = libVersion / 1000000;
    libVersion %= 1000000;
    minor = libVersion / 1000;
    rel = libVersion % 1000;
    vshPrint(ctl, VSH_MESG, "Using library: libvir %d.%d.%d\n",
             major, minor, rel);
845

846 847 848 849 850 851 852
    major = apiVersion / 1000000;
    apiVersion %= 1000000;
    minor = apiVersion / 1000;
    rel = apiVersion % 1000;
    vshPrint(ctl, VSH_MESG, "Using API: %s %d.%d.%d\n", hvType,
             major, minor, rel);

853
    ret = virConnectGetVersion(ctl->conn, &hvVersion);
854 855
    if (ret < 0) {
        vshError(ctl, FALSE, "failed to get the hypervisor version");
856 857 858 859
        return FALSE;
    }
    if (hvVersion == 0) {
        vshPrint(ctl, VSH_MESG,
860
                 "cannot extract running %s hypervisor version\n", hvType);
861
    } else {
862
        major = hvVersion / 1000000;
863
        hvVersion %= 1000000;
864 865
        minor = hvVersion / 1000;
        rel = hvVersion % 1000;
866

867 868
        vshPrint(ctl, VSH_MESG, "Running hypervisor: %s %d.%d.%d\n",
                 hvType, major, minor, rel);
869 870 871 872
    }
    return TRUE;
}

K
Karel Zak 已提交
873 874 875 876
/*
 * "quit" command
 */
static vshCmdInfo info_quit[] = {
877 878 879
    {"syntax", "quit"},
    {"help", "quit this interactive terminal"},
    {NULL, NULL}
K
Karel Zak 已提交
880 881 882
};

static int
883 884
cmdQuit(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
885 886 887 888 889 890 891 892
    ctl->imode = FALSE;
    return TRUE;
}

/*
 * Commands
 */
static vshCmdDef commands[] = {
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
    {"connect", cmdConnect, opts_connect, info_connect},
    {"dinfo", cmdDinfo, opts_dinfo, info_dinfo},
    {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
    {"dstate", cmdDstate, opts_dstate, info_dstate},
    {"suspend", cmdSuspend, opts_suspend, info_suspend},
    {"resume", cmdResume, opts_resume, info_resume},
    {"save", cmdSave, opts_save, info_save},
    {"restore", cmdRestore, opts_restore, info_restore},
    {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
    {"destroy", cmdDestroy, opts_destroy, info_destroy},
    {"help", cmdHelp, opts_help, info_help},
    {"idof", cmdIdof, opts_idof, info_idof},
    {"list", cmdList, NULL, info_list},
    {"nameof", cmdNameof, opts_nameof, info_nameof},
    {"version", cmdVersion, NULL, info_version},
    {"quit", cmdQuit, NULL, info_quit},
    {NULL, NULL, NULL, NULL}
K
Karel Zak 已提交
910 911 912 913 914 915
};

/* ---------------
 * Utils for work with command definition
 * ---------------
 */
K
Karel Zak 已提交
916
static const char *
917 918
vshCmddefGetInfo(vshCmdDef * cmd, const char *name)
{
K
Karel Zak 已提交
919
    vshCmdInfo *info;
920

K
Karel Zak 已提交
921
    for (info = cmd->info; info && info->name; info++) {
922
        if (strcmp(info->name, name) == 0)
K
Karel Zak 已提交
923 924 925 926 927 928
            return info->data;
    }
    return NULL;
}

static vshCmdOptDef *
929 930
vshCmddefGetOption(vshCmdDef * cmd, const char *name)
{
K
Karel Zak 已提交
931
    vshCmdOptDef *opt;
932

K
Karel Zak 已提交
933
    for (opt = cmd->opts; opt && opt->name; opt++)
934
        if (strcmp(opt->name, name) == 0)
K
Karel Zak 已提交
935 936 937 938 939
            return opt;
    return NULL;
}

static vshCmdOptDef *
940 941
vshCmddefGetData(vshCmdDef * cmd, int data_ct)
{
K
Karel Zak 已提交
942 943
    vshCmdOptDef *opt;

944
    for (opt = cmd->opts; opt && opt->name; opt++) {
945 946
        if (opt->type == VSH_OT_DATA) {
            if (data_ct == 0)
947 948 949 950 951
                return opt;
            else
                data_ct--;
        }
    }
K
Karel Zak 已提交
952 953 954
    return NULL;
}

955 956 957
/*
 * Checks for required options
 */
958 959
static int
vshCommandCheckOpts(vshControl * ctl, vshCmd * cmd)
960 961 962
{
    vshCmdDef *def = cmd->def;
    vshCmdOptDef *d;
963
    int err = 0;
964 965 966 967

    for (d = def->opts; d && d->name; d++) {
        if (d->flag & VSH_OFLAG_REQ) {
            vshCmdOpt *o = cmd->opts;
968 969 970
            int ok = 0;

            while (o && ok == 0) {
971
                if (o->def == d)
972
                    ok = 1;
973 974 975
                o = o->next;
            }
            if (!ok) {
976 977 978 979 980
                vshError(ctl, FALSE,
                         d->type == VSH_OT_DATA ?
                         "command '%s' requires <%s> option" :
                         "command '%s' requires --%s option",
                         def->name, d->name);
981 982
                err = 1;
            }
983

984 985 986 987 988
        }
    }
    return !err;
}

K
Karel Zak 已提交
989
static vshCmdDef *
990 991
vshCmddefSearch(const char *cmdname)
{
K
Karel Zak 已提交
992
    vshCmdDef *c;
993

K
Karel Zak 已提交
994
    for (c = commands; c->name; c++)
995
        if (strcmp(c->name, cmdname) == 0)
K
Karel Zak 已提交
996 997 998 999 1000
            return c;
    return NULL;
}

static int
1001 1002
vshCmddefHelp(vshControl * ctl, const char *cmdname, int withprog)
{
K
Karel Zak 已提交
1003
    vshCmdDef *def = vshCmddefSearch(cmdname);
1004

K
Karel Zak 已提交
1005
    if (!def) {
1006 1007 1008
        vshError(ctl, FALSE, "command '%s' doesn't exist", cmdname);
        return FALSE;
    } else {
K
Karel Zak 已提交
1009
        vshCmdOptDef *opt;
K
Karel Zak 已提交
1010 1011 1012
        const char *desc = vshCmddefGetInfo(def, "desc");
        const char *help = vshCmddefGetInfo(def, "help");
        const char *syntax = vshCmddefGetInfo(def, "syntax");
K
Karel Zak 已提交
1013 1014

        fputs("  NAME\n", stdout);
1015 1016
        fprintf(stdout, "    %s - %s\n", def->name, help);

K
Karel Zak 已提交
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
        if (syntax) {
            fputs("\n  SYNOPSIS\n", stdout);
            if (!withprog)
                fprintf(stdout, "    %s\n", syntax);
            else
                fprintf(stdout, "    %s %s\n", progname, syntax);
        }
        if (desc) {
            fputs("\n  DESCRIPTION\n", stdout);
            fprintf(stdout, "    %s\n", desc);
        }
        if (def->opts) {
            fputs("\n  OPTIONS\n", stdout);
1030
            for (opt = def->opts; opt->name; opt++) {
K
Karel Zak 已提交
1031
                char buf[256];
1032 1033

                if (opt->type == VSH_OT_BOOL)
K
Karel Zak 已提交
1034
                    snprintf(buf, sizeof(buf), "--%s", opt->name);
1035
                else if (opt->type == VSH_OT_INT)
K
Karel Zak 已提交
1036
                    snprintf(buf, sizeof(buf), "--%s <number>", opt->name);
1037
                else if (opt->type == VSH_OT_STRING)
K
Karel Zak 已提交
1038
                    snprintf(buf, sizeof(buf), "--%s <string>", opt->name);
1039
                else if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
1040
                    snprintf(buf, sizeof(buf), "<%s>", opt->name);
1041

K
Karel Zak 已提交
1042
                fprintf(stdout, "    %-15s  %s\n", buf, opt->help);
1043
            }
K
Karel Zak 已提交
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
        }
        fputc('\n', stdout);
    }
    return TRUE;
}

/* ---------------
 * Utils for work with runtime commands data
 * ---------------
 */
1054 1055 1056
static void
vshCommandOptFree(vshCmdOpt * arg)
{
K
Karel Zak 已提交
1057 1058
    vshCmdOpt *a = arg;

1059
    while (a) {
K
Karel Zak 已提交
1060
        vshCmdOpt *tmp = a;
1061

K
Karel Zak 已提交
1062 1063 1064 1065 1066 1067 1068 1069 1070
        a = a->next;

        if (tmp->data)
            free(tmp->data);
        free(tmp);
    }
}

static void
1071 1072
vshCommandFree(vshCmd * cmd)
{
K
Karel Zak 已提交
1073 1074
    vshCmd *c = cmd;

1075
    while (c) {
K
Karel Zak 已提交
1076
        vshCmd *tmp = c;
1077

K
Karel Zak 已提交
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
        c = c->next;

        if (tmp->opts)
            vshCommandOptFree(tmp->opts);
        free(tmp);
    }
}

/*
 * Returns option by name
 */
static vshCmdOpt *
1090 1091
vshCommandOpt(vshCmd * cmd, const char *name)
{
K
Karel Zak 已提交
1092
    vshCmdOpt *opt = cmd->opts;
1093 1094 1095

    while (opt) {
        if (opt->def && strcmp(opt->def->name, name) == 0)
K
Karel Zak 已提交
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
            return opt;
        opt = opt->next;
    }
    return NULL;
}

/*
 * Returns option as INT
 */
static int
1106 1107
vshCommandOptInt(vshCmd * cmd, const char *name, int *found)
{
K
Karel Zak 已提交
1108 1109
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
    int res = 0;
1110

K
Karel Zak 已提交
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
    if (arg)
        res = atoi(arg->data);
    if (found)
        *found = arg ? TRUE : FALSE;
    return res;
}

/*
 * Returns option as STRING
 */
static char *
1122 1123
vshCommandOptString(vshCmd * cmd, const char *name, int *found)
{
K
Karel Zak 已提交
1124
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
1125

K
Karel Zak 已提交
1126 1127
    if (found)
        *found = arg ? TRUE : FALSE;
1128 1129

    return arg && arg->data && *arg->data ? arg->data : NULL;
K
Karel Zak 已提交
1130 1131 1132 1133 1134 1135
}

/*
 * Returns TRUE/FALSE if the option exists
 */
static int
1136 1137
vshCommandOptBool(vshCmd * cmd, const char *name)
{
K
Karel Zak 已提交
1138 1139 1140
    return vshCommandOpt(cmd, name) ? TRUE : FALSE;
}

1141

K
Karel Zak 已提交
1142
static virDomainPtr
1143 1144 1145
vshCommandOptDomain(vshControl * ctl, vshCmd * cmd, const char *optname,
                    char **name)
{
K
Karel Zak 已提交
1146 1147 1148
    virDomainPtr dom = NULL;
    char *n, *end = NULL;
    int id;
1149

K
Karel Zak 已提交
1150 1151
    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
        vshError(ctl, FALSE, "undefined domain name or id");
1152
        return NULL;
K
Karel Zak 已提交
1153
    }
1154 1155 1156 1157

    vshPrint(ctl, VSH_DEBUG5, "%s: found option <%s>: %s\n",
             cmd->def->name, optname, n);

K
Karel Zak 已提交
1158 1159
    if (name)
        *name = n;
1160

K
Karel Zak 已提交
1161 1162
    /* try it by ID */
    id = (int) strtol(n, &end, 10);
1163 1164 1165
    if (id >= 0 && end && *end == '\0') {
        vshPrint(ctl, VSH_DEBUG5, "%s: <%s> seems like domain ID\n",
                 cmd->def->name, optname);
K
Karel Zak 已提交
1166
        dom = virDomainLookupByID(ctl->conn, id);
1167
    }
1168

K
Karel Zak 已提交
1169
    /* try it by NAME */
1170
    if (!dom) {
1171 1172
        vshPrint(ctl, VSH_DEBUG5, "%s: <%s> tring as domain NAME\n",
                 cmd->def->name, optname);
K
Karel Zak 已提交
1173
        dom = virDomainLookupByName(ctl->conn, n);
1174
    }
1175
    if (!dom)
K
Karel Zak 已提交
1176
        vshError(ctl, FALSE, "failed to get domain '%s'", n);
1177

K
Karel Zak 已提交
1178 1179 1180
    return dom;
}

K
Karel Zak 已提交
1181 1182 1183 1184
/*
 * Executes command(s) and returns return code from last command
 */
static int
1185 1186
vshCommandRun(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
1187
    int ret = TRUE;
1188 1189

    while (cmd) {
K
Karel Zak 已提交
1190
        struct timeval before, after;
1191

K
Karel Zak 已提交
1192 1193
        if (ctl->timing)
            GETTIMEOFDAY(&before);
1194

K
Karel Zak 已提交
1195 1196 1197 1198
        ret = cmd->def->handler(ctl, cmd);

        if (ctl->timing)
            GETTIMEOFDAY(&after);
1199 1200

        if (strcmp(cmd->def->name, "quit") == 0)        /* hack ... */
K
Karel Zak 已提交
1201 1202 1203
            return ret;

        if (ctl->timing)
1204 1205 1206
            vshPrint(ctl, VSH_MESG, "\n(Time: %.3f ms)\n\n",
                     DIFF_MSEC(&after, &before));
        else
K
Karel Zak 已提交
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
            vshPrint(ctl, VSH_FOOTER, "\n");
        cmd = cmd->next;
    }
    return ret;
}

/* ---------------
 * Command string parsing
 * ---------------
 */
#define VSH_TK_ERROR    -1
#define VSH_TK_NONE    0
#define VSH_TK_OPTION    1
#define VSH_TK_DATA    2
#define VSH_TK_END    3

1223 1224 1225
static int
vshCommandGetToken(vshControl * ctl, char *str, char **end, char **res)
{
K
Karel Zak 已提交
1226 1227 1228 1229 1230
    int tk = VSH_TK_NONE;
    int quote = FALSE;
    int sz = 0;
    char *p = str;
    char *tkstr = NULL;
1231

K
Karel Zak 已提交
1232
    *end = NULL;
1233 1234

    while (p && *p && isblank((unsigned char) *p))
K
Karel Zak 已提交
1235
        p++;
1236 1237

    if (p == NULL || *p == '\0')
K
Karel Zak 已提交
1238
        return VSH_TK_END;
1239 1240
    if (*p == ';') {
        *end = ++p;             /* = \0 or begi of next command */
K
Karel Zak 已提交
1241 1242
        return VSH_TK_END;
    }
1243
    while (*p) {
K
Karel Zak 已提交
1244
        /* end of token is blank space or ';' */
1245
        if ((quote == FALSE && isblank((unsigned char) *p)) || *p == ';')
K
Karel Zak 已提交
1246
            break;
1247

1248
        /* end of option name could be '=' */
1249 1250
        if (tk == VSH_TK_OPTION && *p == '=') {
            p++;                /* skip '=' */
1251 1252
            break;
        }
1253 1254 1255 1256

        if (tk == VSH_TK_NONE) {
            if (*p == '-' && *(p + 1) == '-' && *(p + 2)
                && isalnum((unsigned char) *(p + 2))) {
K
Karel Zak 已提交
1257
                tk = VSH_TK_OPTION;
1258
                p += 2;
K
Karel Zak 已提交
1259 1260
            } else {
                tk = VSH_TK_DATA;
1261 1262
                if (*p == '"') {
                    quote = TRUE;
K
Karel Zak 已提交
1263 1264 1265 1266 1267
                    p++;
                } else {
                    quote = FALSE;
                }
            }
1268 1269
            tkstr = p;          /* begin of token */
        } else if (quote && *p == '"') {
K
Karel Zak 已提交
1270 1271
            quote = FALSE;
            p++;
1272
            break;              /* end of "..." token */
K
Karel Zak 已提交
1273 1274 1275 1276 1277 1278 1279 1280
        }
        p++;
        sz++;
    }
    if (quote) {
        vshError(ctl, FALSE, "missing \"");
        return VSH_TK_ERROR;
    }
1281
    if (tkstr == NULL || *tkstr == '\0' || p == NULL)
K
Karel Zak 已提交
1282
        return VSH_TK_END;
1283
    if (sz == 0)
K
Karel Zak 已提交
1284
        return VSH_TK_END;
1285 1286

    *res = malloc(sz + 1);
K
Karel Zak 已提交
1287
    memcpy(*res, tkstr, sz);
1288
    *(*res + sz) = '\0';
K
Karel Zak 已提交
1289 1290 1291 1292 1293 1294

    *end = p;
    return tk;
}

static int
1295 1296
vshCommandParse(vshControl * ctl, char *cmdstr)
{
K
Karel Zak 已提交
1297 1298 1299 1300
    char *str;
    char *tkdata = NULL;
    vshCmd *clast = NULL;
    vshCmdOpt *first = NULL;
1301

K
Karel Zak 已提交
1302 1303 1304 1305
    if (ctl->cmd) {
        vshCommandFree(ctl->cmd);
        ctl->cmd = NULL;
    }
1306 1307

    if (cmdstr == NULL || *cmdstr == '\0')
K
Karel Zak 已提交
1308
        return FALSE;
1309

K
Karel Zak 已提交
1310
    str = cmdstr;
1311
    while (str && *str) {
K
Karel Zak 已提交
1312 1313 1314
        vshCmdOpt *last = NULL;
        vshCmdDef *cmd = NULL;
        int tk = VSH_TK_NONE;
1315
        int data_ct = 0;
1316

K
Karel Zak 已提交
1317
        first = NULL;
1318 1319

        while (tk != VSH_TK_END) {
K
Karel Zak 已提交
1320 1321
            char *end = NULL;
            vshCmdOptDef *opt = NULL;
1322

K
Karel Zak 已提交
1323
            tkdata = NULL;
1324

K
Karel Zak 已提交
1325 1326
            /* get token */
            tk = vshCommandGetToken(ctl, str, &end, &tkdata);
1327

K
Karel Zak 已提交
1328
            str = end;
1329 1330

            if (tk == VSH_TK_END)
K
Karel Zak 已提交
1331
                break;
1332
            if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
1333
                goto syntaxError;
1334 1335

            if (cmd == NULL) {
K
Karel Zak 已提交
1336
                /* first token must be command name */
1337 1338 1339 1340
                if (tk != VSH_TK_DATA) {
                    vshError(ctl, FALSE,
                             "unexpected token (command name): '%s'",
                             tkdata);
K
Karel Zak 已提交
1341 1342 1343
                    goto syntaxError;
                }
                if (!(cmd = vshCmddefSearch(tkdata))) {
1344 1345
                    vshError(ctl, FALSE, "unknown command: '%s'", tkdata);
                    goto syntaxError;   /* ... or ignore this command only? */
K
Karel Zak 已提交
1346 1347
                }
                free(tkdata);
1348
            } else if (tk == VSH_TK_OPTION) {
K
Karel Zak 已提交
1349 1350
                if (!(opt = vshCmddefGetOption(cmd, tkdata))) {
                    vshError(ctl, FALSE,
1351 1352
                             "command '%s' doesn't support option --%s",
                             cmd->name, tkdata);
K
Karel Zak 已提交
1353 1354
                    goto syntaxError;
                }
1355
                free(tkdata);   /* option name */
K
Karel Zak 已提交
1356 1357 1358 1359 1360
                tkdata = NULL;

                if (opt->type != VSH_OT_BOOL) {
                    /* option data */
                    tk = vshCommandGetToken(ctl, str, &end, &tkdata);
1361 1362
                    str = end;
                    if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
1363
                        goto syntaxError;
1364
                    if (tk != VSH_TK_DATA) {
K
Karel Zak 已提交
1365
                        vshError(ctl, FALSE,
1366 1367 1368 1369
                                 "expected syntax: --%s <%s>",
                                 opt->name,
                                 opt->type ==
                                 VSH_OT_INT ? "number" : "string");
K
Karel Zak 已提交
1370 1371 1372
                        goto syntaxError;
                    }
                }
1373
            } else if (tk == VSH_TK_DATA) {
1374
                if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
1375
                    vshError(ctl, FALSE, "unexpected data '%s'", tkdata);
K
Karel Zak 已提交
1376 1377 1378 1379 1380 1381
                    goto syntaxError;
                }
            }
            if (opt) {
                /* save option */
                vshCmdOpt *arg = malloc(sizeof(vshCmdOpt));
1382

K
Karel Zak 已提交
1383 1384 1385 1386
                arg->def = opt;
                arg->data = tkdata;
                arg->next = NULL;
                tkdata = NULL;
1387

K
Karel Zak 已提交
1388 1389 1390 1391 1392
                if (!first)
                    first = arg;
                if (last)
                    last->next = arg;
                last = arg;
1393

K
Karel Zak 已提交
1394
                vshPrint(ctl, VSH_DEBUG4, "%s: %s(%s): %s\n",
1395 1396 1397 1398
                         cmd->name,
                         opt->name,
                         tk == VSH_TK_OPTION ? "OPTION" : "DATA",
                         arg->data);
K
Karel Zak 已提交
1399 1400 1401 1402
            }
            if (!str)
                break;
        }
1403

K
Karel Zak 已提交
1404 1405
        /* commad parsed -- allocate new struct for the command */
        if (cmd) {
1406 1407
            vshCmd *c = malloc(sizeof(vshCmd));

K
Karel Zak 已提交
1408 1409 1410 1411
            c->opts = first;
            c->def = cmd;
            c->next = NULL;

1412 1413
            if (!vshCommandCheckOpts(ctl, c))
                goto syntaxError;
1414

K
Karel Zak 已提交
1415 1416 1417 1418 1419 1420 1421
            if (!ctl->cmd)
                ctl->cmd = c;
            if (clast)
                clast->next = c;
            clast = c;
        }
    }
1422

K
Karel Zak 已提交
1423 1424
    return TRUE;

1425
  syntaxError:
K
Karel Zak 已提交
1426 1427 1428 1429 1430 1431
    if (ctl->cmd)
        vshCommandFree(ctl->cmd);
    if (first)
        vshCommandOptFree(first);
    if (tkdata)
        free(tkdata);
1432
    return FALSE;
K
Karel Zak 已提交
1433 1434 1435 1436 1437 1438 1439
}


/* ---------------
 * Misc utils  
 * ---------------
 */
K
Karel Zak 已提交
1440
static const char *
1441 1442
vshDomainStateToString(int state)
{
K
Karel Zak 已提交
1443 1444
    switch (state) {
        case VIR_DOMAIN_RUNNING:
1445
            return "running ";
K
Karel Zak 已提交
1446 1447 1448 1449 1450 1451 1452 1453 1454
        case VIR_DOMAIN_BLOCKED:
            return "blocked ";
        case VIR_DOMAIN_PAUSED:
            return "paused ";
        case VIR_DOMAIN_SHUTDOWN:
            return "in shutdown";
        case VIR_DOMAIN_SHUTOFF:
            return "shut off";
        default:
1455
            return "no state";  /* = dom0 state */
K
Karel Zak 已提交
1456 1457 1458 1459 1460
    }
    return NULL;
}

static int
1461 1462
vshConnectionUsability(vshControl * ctl, virConnectPtr conn, int showerror)
{
K
Karel Zak 已提交
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
    /* TODO: use something like virConnectionState() to 
     *       check usability of the connection 
     */
    if (!conn) {
        if (showerror)
            vshError(ctl, FALSE, "no valid connection.");
        return FALSE;
    }
    return TRUE;
}

static int
1475 1476 1477
vshWantedDebug(vshOutType type, int mode)
{
    switch (type) {
K
Karel Zak 已提交
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
        case VSH_DEBUG5:
            if (mode < 5)
                return FALSE;
            return TRUE;
        case VSH_DEBUG4:
            if (mode < 4)
                return FALSE;
            return TRUE;
        case VSH_DEBUG3:
            if (mode < 3)
                return FALSE;
            return TRUE;
        case VSH_DEBUG2:
            if (mode < 2)
                return FALSE;
            return TRUE;
        case VSH_DEBUG1:
            if (mode < 1)
                return FALSE;
            return TRUE;
        default:
            /* it's right, all others types have to pass */
            return TRUE;
    }
    return FALSE;
}

static void
1506 1507
vshPrint(vshControl * ctl, vshOutType type, const char *format, ...)
{
K
Karel Zak 已提交
1508
    va_list ap;
1509 1510

    if (ctl->quiet == TRUE && (type == VSH_HEADER || type == VSH_FOOTER))
K
Karel Zak 已提交
1511 1512 1513 1514
        return;

    if (!vshWantedDebug(type, ctl->debug))
        return;
1515

K
Karel Zak 已提交
1516 1517 1518 1519 1520 1521
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
}

static void
1522 1523
vshError(vshControl * ctl, int doexit, const char *format, ...)
{
K
Karel Zak 已提交
1524
    va_list ap;
1525

K
Karel Zak 已提交
1526 1527 1528 1529
    if (doexit)
        fprintf(stderr, "%s: error: ", progname);
    else
        fputs("error: ", stderr);
1530

K
Karel Zak 已提交
1531 1532 1533 1534 1535
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);

    fputc('\n', stderr);
1536

K
Karel Zak 已提交
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546
    if (doexit) {
        vshDeinit(ctl);
        exit(EXIT_FAILURE);
    }
}

/*
 * Initialize vistsh
 */
static int
1547 1548
vshInit(vshControl * ctl)
{
K
Karel Zak 已提交
1549 1550 1551 1552
    if (ctl->conn)
        return FALSE;

    ctl->uid = getuid();
1553

1554 1555
    /* set up the library error handler */
    virSetErrorFunc(NULL, virshErrorHandler);
1556

K
Karel Zak 已提交
1557 1558 1559 1560 1561
    /* basic connection to hypervisor */
    if (ctl->uid == 0)
        ctl->conn = virConnectOpen(NULL);
    else
        ctl->conn = virConnectOpenReadOnly(NULL);
1562

K
Karel Zak 已提交
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
    if (!ctl->conn)
        vshError(ctl, TRUE, "failed to connect to the hypervisor");

    return TRUE;
}

/* -----------------
 * Readline stuff
 * -----------------
 */

/* 
 * Generator function for command completion.  STATE lets us
 * know whether to start from scratch; without any state
 * (i.e. STATE == 0), then we start at the top of the list. 
 */
static char *
1580 1581
vshReadlineCommandGenerator(const char *text, int state)
{
K
Karel Zak 已提交
1582
    static int list_index, len;
K
Karel Zak 已提交
1583
    const char *name;
K
Karel Zak 已提交
1584 1585 1586 1587 1588 1589 1590

    /* If this is a new word to complete, initialize now.  This
     * includes saving the length of TEXT for efficiency, and
     * initializing the index variable to 0. 
     */
    if (!state) {
        list_index = 0;
1591
        len = strlen(text);
K
Karel Zak 已提交
1592 1593 1594 1595 1596
    }

    /* Return the next name which partially matches from the
     * command list. 
     */
K
Karel Zak 已提交
1597
    while ((name = commands[list_index].name)) {
K
Karel Zak 已提交
1598
        list_index++;
1599
        if (strncmp(name, text, len) == 0)
K
Karel Zak 已提交
1600 1601 1602 1603 1604 1605 1606 1607
            return strdup(name);
    }

    /* If no names matched, then return NULL. */
    return NULL;
}

static char *
1608 1609
vshReadlineOptionsGenerator(const char *text, int state)
{
K
Karel Zak 已提交
1610 1611
    static int list_index, len;
    static vshCmdDef *cmd = NULL;
K
Karel Zak 已提交
1612
    const char *name;
K
Karel Zak 已提交
1613 1614 1615 1616 1617 1618 1619 1620 1621

    if (!state) {
        /* determine command name */
        char *p;
        char *cmdname;

        if (!(p = strchr(rl_line_buffer, ' ')))
            return NULL;

1622 1623
        cmdname = calloc((p - rl_line_buffer) + 1, 1);
        memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
K
Karel Zak 已提交
1624 1625 1626

        cmd = vshCmddefSearch(cmdname);
        list_index = 0;
1627
        len = strlen(text);
K
Karel Zak 已提交
1628 1629 1630 1631 1632
        free(cmdname);
    }

    if (!cmd)
        return NULL;
1633

K
Karel Zak 已提交
1634
    while ((name = cmd->opts[list_index].name)) {
K
Karel Zak 已提交
1635 1636
        vshCmdOptDef *opt = &cmd->opts[list_index];
        char *res;
1637

K
Karel Zak 已提交
1638
        list_index++;
1639

K
Karel Zak 已提交
1640
        if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
1641 1642
            /* ignore non --option */
            continue;
1643

K
Karel Zak 已提交
1644
        if (len > 2) {
1645
            if (strncmp(name, text + 2, len - 2))
K
Karel Zak 已提交
1646 1647
                continue;
        }
1648
        res = malloc(strlen(name) + 3);
K
Karel Zak 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657
        sprintf(res, "--%s", name);
        return res;
    }

    /* If no names matched, then return NULL. */
    return NULL;
}

static char **
1658 1659 1660
vshReadlineCompletion(const char *text, int start,
                      int end ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
1661 1662
    char **matches = (char **) NULL;

1663
    if (start == 0)
K
Karel Zak 已提交
1664
        /* command name generator */
1665
        matches = rl_completion_matches(text, vshReadlineCommandGenerator);
K
Karel Zak 已提交
1666 1667
    else
        /* commands options */
1668
        matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
K
Karel Zak 已提交
1669 1670 1671 1672 1673
    return matches;
}


static void
1674 1675
vshReadlineInit(void)
{
K
Karel Zak 已提交
1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
    /* Allow conditional parsing of the ~/.inputrc file. */
    rl_readline_name = "virsh";

    /* Tell the completer that we want a crack first. */
    rl_attempted_completion_function = vshReadlineCompletion;
}

/*
 * Deinitliaze virsh
 */
static int
1687 1688
vshDeinit(vshControl * ctl)
{
K
Karel Zak 已提交
1689
    if (ctl->conn) {
1690 1691 1692 1693
        if (virConnectClose(ctl->conn) != 0) {
            ctl->conn = NULL;   /* prevent recursive call from vshError() */
            vshError(ctl, TRUE,
                     "failed to disconnect from the hypervisor");
K
Karel Zak 已提交
1694 1695 1696 1697
        }
    }
    return TRUE;
}
1698

K
Karel Zak 已提交
1699 1700 1701 1702
/*
 * Print usage
 */
static void
1703 1704
vshUsage(vshControl * ctl, const char *cmdname)
{
K
Karel Zak 已提交
1705
    vshCmdDef *cmd;
1706

K
Karel Zak 已提交
1707 1708 1709 1710 1711 1712 1713 1714 1715 1716
    /* global help */
    if (!cmdname) {
        fprintf(stdout, "\n%s [options] [commands]\n\n"
                "  options:\n"
                "    -d | --debug <num>      debug level [0-5]\n"
                "    -h | --help             this help\n"
                "    -q | --quiet            quiet mode\n"
                "    -t | --timing           print timing information\n"
                "    -v | --version          program version\n\n"
                "  commands (non interactive mode):\n", progname);
1717 1718 1719 1720 1721 1722 1723 1724

        for (cmd = commands; cmd->name; cmd++)
            fprintf(stdout,
                    "    %-15s %s\n", cmd->name, vshCmddefGetInfo(cmd,
                                                                  "help"));

        fprintf(stdout,
                "\n  (specify --help <command> for details about the command)\n\n");
K
Karel Zak 已提交
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735
        return;
    }
    if (!vshCmddefHelp(ctl, cmdname, TRUE))
        exit(EXIT_FAILURE);
}

/*
 * argv[]:  virsh [options] [command]
 *
 */
static int
1736 1737
vshParseArgv(vshControl * ctl, int argc, char **argv)
{
K
Karel Zak 已提交
1738 1739
    char *last = NULL;
    int i, end = 0, help = 0;
1740
    int arg, idx = 0;
K
Karel Zak 已提交
1741
    struct option opt[] = {
1742 1743 1744 1745 1746
        {"debug", 1, 0, 'd'},
        {"help", 0, 0, 'h'},
        {"quiet", 0, 0, 'q'},
        {"timing", 0, 0, 't'},
        {"version", 0, 0, 'v'},
K
Karel Zak 已提交
1747
        {0, 0, 0, 0}
1748 1749
    };

K
Karel Zak 已提交
1750 1751

    if (argc < 2)
K
Karel Zak 已提交
1752
        return TRUE;
1753

1754
    /* look for begin of the command, for example:
K
Karel Zak 已提交
1755 1756 1757 1758
     *   ./virsh --debug 5 -q command --cmdoption
     *                  <--- ^ --->
     *        getopt() stuff | command suff
     */
1759
    for (i = 1; i < argc; i++) {
K
Karel Zak 已提交
1760 1761
        if (*argv[i] != '-') {
            int valid = FALSE;
1762

K
Karel Zak 已提交
1763 1764 1765 1766
            /* non "--option" argv, is it command? */
            if (last) {
                struct option *o;
                int sz = strlen(last);
1767 1768 1769

                for (o = opt; o->name; o++) {
                    if (sz == 2 && *(last + 1) == o->val)
K
Karel Zak 已提交
1770 1771
                        /* valid virsh short option */
                        valid = TRUE;
1772
                    else if (sz > 2 && strcmp(o->name, last + 2) == 0)
K
Karel Zak 已提交
1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784
                        /* valid virsh long option */
                        valid = TRUE;
                }
            }
            if (!valid) {
                end = i;
                break;
            }
        }
        last = argv[i];
    }
    end = end ? : argc;
1785

K
Karel Zak 已提交
1786
    /* standard (non-command) options */
1787 1788
    while ((arg = getopt_long(end, argv, "d:hqtv", opt, &idx)) != -1) {
        switch (arg) {
K
Karel Zak 已提交
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804
            case 'd':
                ctl->debug = atoi(optarg);
                break;
            case 'h':
                help = 1;
                break;
            case 'q':
                ctl->quiet = TRUE;
                break;
            case 't':
                ctl->timing = TRUE;
                break;
            case 'v':
                fprintf(stdout, "%s\n", VERSION);
                exit(EXIT_SUCCESS);
            default:
1805 1806
                vshError(ctl, TRUE,
                  "unsupported option '-%c'. See --help.", arg);
K
Karel Zak 已提交
1807 1808 1809 1810 1811 1812 1813 1814
                break;
        }
    }

    if (help) {
        /* global or command specific help */
        vshUsage(ctl, argc > end ? argv[end] : NULL);
        exit(EXIT_SUCCESS);
1815 1816
    }

K
Karel Zak 已提交
1817 1818 1819
    if (argc > end) {
        /* parse command */
        char *cmdstr;
1820 1821
        int sz = 0, ret;

K
Karel Zak 已提交
1822 1823
        ctl->imode = FALSE;

1824 1825 1826 1827 1828 1829
        for (i = end; i < argc; i++)
            sz += strlen(argv[i]) + 1;  /* +1 is for blank space between items */

        cmdstr = calloc(sz + 1, 1);

        for (i = end; i < argc; i++) {
K
Karel Zak 已提交
1830 1831 1832 1833 1834 1835
            strncat(cmdstr, argv[i], sz);
            sz -= strlen(argv[i]);
            strncat(cmdstr, " ", sz--);
        }
        vshPrint(ctl, VSH_DEBUG2, "command: \"%s\"\n", cmdstr);
        ret = vshCommandParse(ctl, cmdstr);
1836

K
Karel Zak 已提交
1837 1838 1839 1840 1841 1842
        free(cmdstr);
        return ret;
    }
    return TRUE;
}

1843 1844 1845 1846
int
main(int argc, char **argv)
{
    vshControl _ctl, *ctl = &_ctl;
K
Karel Zak 已提交
1847 1848
    int ret = TRUE;

1849
    if (!(progname = strrchr(argv[0], '/')))
K
Karel Zak 已提交
1850 1851 1852
        progname = argv[0];
    else
        progname++;
1853

K
Karel Zak 已提交
1854
    memset(ctl, 0, sizeof(vshControl));
1855
    ctl->imode = TRUE;          /* default is interactive mode */
K
Karel Zak 已提交
1856 1857 1858

    if (!vshParseArgv(ctl, argc, argv))
        exit(EXIT_FAILURE);
1859

K
Karel Zak 已提交
1860 1861
    if (!vshInit(ctl))
        exit(EXIT_FAILURE);
1862

K
Karel Zak 已提交
1863
    if (!ctl->imode) {
1864
        ret = vshCommandRun(ctl, ctl->cmd);
1865
    } else {
K
Karel Zak 已提交
1866 1867
        /* interactive mode */
        if (!ctl->quiet) {
1868 1869 1870 1871 1872 1873
            vshPrint(ctl, VSH_MESG,
                     "Welcome to %s, the virtualization interactive terminal.\n\n",
                     progname);
            vshPrint(ctl, VSH_MESG,
                     "Type:  'help' for help with commands\n"
                     "       'quit' to quit\n\n");
K
Karel Zak 已提交
1874
        }
K
Karel Zak 已提交
1875
        vshReadlineInit();
K
Karel Zak 已提交
1876
        do {
1877 1878 1879 1880
            ctl->cmdstr =
                readline(ctl->uid == 0 ? VSH_PROMPT_RW : VSH_PROMPT_RO);
            if (ctl->cmdstr == NULL)
                break;          /* EOF */
K
Karel Zak 已提交
1881 1882 1883 1884 1885 1886 1887
            if (*ctl->cmdstr) {
                add_history(ctl->cmdstr);
                if (vshCommandParse(ctl, ctl->cmdstr))
                    vshCommandRun(ctl, ctl->cmd);
            }
            free(ctl->cmdstr);
            ctl->cmdstr = NULL;
1888
        } while (ctl->imode);
K
Karel Zak 已提交
1889

1890 1891
        if (ctl->cmdstr == NULL)
            fputc('\n', stdout);        /* line break after alone prompt */
K
Karel Zak 已提交
1892
    }
1893

K
Karel Zak 已提交
1894 1895
    vshDeinit(ctl);
    exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
1896
}
K
Karel Zak 已提交
1897 1898 1899 1900 1901 1902

/*
 * vim: set tabstop=4:
 * vim: set shiftwidth=4:
 * vim: set expandtab:
 */