virsh.c 52.3 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
 * Karel Zak <kzak@redhat.com>
K
Karel Zak 已提交
10 11
 * Daniel P. Berrange <berrange@redhat.com>
 *
K
Karel Zak 已提交
12 13
 *
 * $Id$
14 15
 */

16
#define _GNU_SOURCE             /* isblank() */
K
Karel Zak 已提交
17

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

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

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

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)

52 53 54 55
/*
 * The error handler for virtsh
 */
static void
56 57
virshErrorHandler(void *unused, virErrorPtr error)
{
58 59 60 61 62 63 64 65 66 67
    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 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81
/*
 * 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>
 *        
82 83 84
 *    keyword         =     [a-zA-Z]
 *    number          =     [0-9]+
 *    string          =     [^[:blank:]] | "[[:alnum:]]"$
K
Karel Zak 已提交
85 86 87 88 89
 *
 */

/*
 * vshCmdOptType - command option type 
90
 */
K
Karel Zak 已提交
91
typedef enum {
92 93 94 95 96
    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 已提交
97 98 99 100 101
} vshCmdOptType;

/*
 * Command Option Flags
 */
102 103
#define VSH_OFLAG_NONE    0     /* without flags */
#define VSH_OFLAG_REQ    (1 << 1)       /* option required */
K
Karel Zak 已提交
104 105 106 107 108 109 110 111

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

/*
 * vshCmdInfo -- information about command
 */
112 113 114
typedef struct {
    const char *name;           /* name of information */
    const char *data;           /* information */
K
Karel Zak 已提交
115 116 117 118 119
} vshCmdInfo;

/*
 * vshCmdOptDef - command option definition
 */
120 121 122 123 124
typedef struct {
    const char *name;           /* the name of option */
    vshCmdOptType type;         /* option type */
    int flag;                   /* flags */
    const char *help;           /* help string */
K
Karel Zak 已提交
125 126 127 128 129 130
} vshCmdOptDef;

/*
 * vshCmdOpt - command options
 */
typedef struct vshCmdOpt {
131 132 133
    vshCmdOptDef *def;          /* pointer to relevant option */
    char *data;                 /* allocated data */
    struct vshCmdOpt *next;
K
Karel Zak 已提交
134 135 136 137 138
} vshCmdOpt;

/*
 * vshCmdDef - command definition
 */
139 140 141 142 143
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 已提交
144 145 146 147 148 149
} vshCmdDef;

/*
 * vshCmd - parsed command
 */
typedef struct __vshCmd {
150 151 152
    vshCmdDef *def;             /* command definition */
    vshCmdOpt *opts;            /* list of command arguments */
    struct __vshCmd *next;      /* next command */
K
Karel Zak 已提交
153 154 155 156 157 158
} __vshCmd;

/*
 * vshControl
 */
typedef struct __vshControl {
K
Karel Zak 已提交
159
    char *name;                 /* connection name */
160 161 162 163 164 165 166 167
    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 已提交
168
} __vshControl;
169

170

K
Karel Zak 已提交
171 172
static vshCmdDef commands[];

173 174 175 176 177
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 已提交
178

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

181
static const char *vshCmddefGetInfo(vshCmdDef * cmd, const char *info);
K
Karel Zak 已提交
182
static vshCmdDef *vshCmddefSearch(const char *cmdname);
183
static int vshCmddefHelp(vshControl * ctl, const char *name, int withprog);
K
Karel Zak 已提交
184

185 186 187 188 189
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);
K
Karel Zak 已提交
190 191 192 193 194 195 196 197 198 199 200 201

#define VSH_DOMBYID     (1 << 1)
#define VSH_DOMBYUUID   (1 << 2)
#define VSH_DOMBYNAME   (1 << 3)

static virDomainPtr vshCommandOptDomainBy(vshControl * ctl, vshCmd * cmd,
                            const char *optname, char **name, int flag);

/* default is lookup by Id, Name and UUID */
#define vshCommandOptDomain(_ctl, _cmd, _optname, _name) \
                            vshCommandOptDomainBy(_ctl, _cmd, _optname, _name,\
                                        VSH_DOMBYID|VSH_DOMBYUUID|VSH_DOMBYNAME)
K
Karel Zak 已提交
202

K
Karel Zak 已提交
203 204
static void vshPrintExtra(vshControl * ctl, const char *format, ...);
static void vshDebug(vshControl * ctl, int level, const char *format, ...);
K
Karel Zak 已提交
205 206

/* XXX: add batch support */
K
Karel Zak 已提交
207
#define vshPrint(_ctl, ...)   fprintf(stdout, __VA_ARGS__)
K
Karel Zak 已提交
208

K
Karel Zak 已提交
209
static const char *vshDomainStateToString(int state);
210 211
static int vshConnectionUsability(vshControl * ctl, virConnectPtr conn,
                                  int showerror);
K
Karel Zak 已提交
212

213 214 215 216 217 218 219 220 221
static void *_vshMalloc(vshControl * ctl, size_t sz, const char *filename, int line);
#define vshMalloc(_ctl, _sz)    _vshMalloc(_ctl, _sz, __FILE__, __LINE__)

static void *_vshCalloc(vshControl * ctl, size_t nmemb, size_t sz, const char *filename, int line);
#define vshCalloc(_ctl, _nmemb, _sz)    _vshCalloc(_ctl, _nmemb, _sz, __FILE__, __LINE__)

static char *_vshStrdup(vshControl * ctl, const char *s, const char *filename, int line);
#define vshStrdup(_ctl, _s)    _vshStrdup(_ctl, _s, __FILE__, __LINE__)

K
Karel Zak 已提交
222 223 224 225 226 227 228 229 230
/* ---------------
 * Commands
 * ---------------
 */

/*
 * "help" command 
 */
static vshCmdInfo info_help[] = {
231 232 233
    {"syntax", "help [<command>]"},
    {"help", "print help"},
    {"desc", "Prints global help or command specific help."},
234
    {"version", "Prints version information."},
235
    {NULL, NULL}
K
Karel Zak 已提交
236 237 238
};

static vshCmdOptDef opts_help[] = {
239 240
    {"command", VSH_OT_DATA, 0, "name of command"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
241 242 243
};

static int
244 245
cmdHelp(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
246
    const char *cmdname = vshCommandOptString(cmd, "command", NULL);
K
Karel Zak 已提交
247 248 249

    if (!cmdname) {
        vshCmdDef *def;
250

K
Karel Zak 已提交
251
        vshPrint(ctl, "Commands:\n\n");
252
        for (def = commands; def->name; def++)
K
Karel Zak 已提交
253
            vshPrint(ctl, "    %-15s %s\n", def->name,
254
                     vshCmddefGetInfo(def, "help"));
K
Karel Zak 已提交
255 256 257 258 259 260 261 262 263
        return TRUE;
    }
    return vshCmddefHelp(ctl, cmdname, FALSE);
}

/*
 * "connect" command 
 */
static vshCmdInfo info_connect[] = {
K
Karel Zak 已提交
264
    {"syntax", "connect [name] [--readonly]"},
265 266 267 268
    {"help", "(re)connect to hypervisor"},
    {"desc",
     "Connect to local hypervisor. This is build-in command after shell start up."},
    {NULL, NULL}
K
Karel Zak 已提交
269 270 271
};

static vshCmdOptDef opts_connect[] = {
K
Karel Zak 已提交
272
    {"name",     VSH_OT_DATA, 0, "optional argument currently unused (or used for tests only)"},
273 274
    {"readonly", VSH_OT_BOOL, 0, "read-only connection"},
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
275 276 277
};

static int
278 279
cmdConnect(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
280
    int ro = vshCommandOptBool(cmd, "readonly");
K
Karel Zak 已提交
281
    
K
Karel Zak 已提交
282
    if (ctl->conn) {
283 284 285
        if (virConnectClose(ctl->conn) != 0) {
            vshError(ctl, FALSE,
                     "failed to disconnect from the hypervisor");
K
Karel Zak 已提交
286 287 288 289
            return FALSE;
        }
        ctl->conn = NULL;
    }
K
Karel Zak 已提交
290 291 292 293 294
    
    if (ctl->name)
        free(ctl->name);
    ctl->name = vshCommandOptString(cmd, "name", NULL);

K
Karel Zak 已提交
295
    if (!ro)
K
Karel Zak 已提交
296
        ctl->conn = virConnectOpen(ctl->name);
K
Karel Zak 已提交
297
    else
K
Karel Zak 已提交
298
        ctl->conn = virConnectOpenReadOnly(ctl->name);
K
Karel Zak 已提交
299 300 301

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

K
Karel Zak 已提交
303 304 305 306 307 308 309
    return ctl->conn ? TRUE : FALSE;
}

/*
 * "list" command
 */
static vshCmdInfo info_list[] = {
310 311 312 313
    {"syntax", "list"},
    {"help", "list domains"},
    {"desc", "Returns list of domains."},
    {NULL, NULL}
K
Karel Zak 已提交
314 315 316 317 318
};



static int
319 320
cmdList(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
321 322 323 324
    int *ids, maxid, i;

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

K
Karel Zak 已提交
326 327 328 329 330 331
    maxid = virConnectNumOfDomains(ctl->conn);
    if (maxid <= 0) {
        /* strange, there should be at least dom0... */
        vshError(ctl, FALSE, "failed to list active domains.");
        return FALSE;
    }
332 333
    ids = vshMalloc(ctl, sizeof(int) * maxid);

K
Karel Zak 已提交
334
    virConnectListDomains(ctl->conn, &ids[0], maxid);
335

K
Karel Zak 已提交
336 337
    vshPrintExtra(ctl, "%3s %-20s %s\n", "Id", "Name", "State");
    vshPrintExtra(ctl, "----------------------------------\n");
338 339

    for (i = 0; i < maxid; i++) {
K
Karel Zak 已提交
340 341 342
        int ret;
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
343 344

        /* this kind of work with domains is not atomic operation */
K
Karel Zak 已提交
345 346 347
        if (!dom)
            continue;
        ret = virDomainGetInfo(dom, &info);
348

K
Karel Zak 已提交
349
        vshPrint(ctl, "%3d %-20s %s\n",
350 351 352 353
                 virDomainGetID(dom),
                 virDomainGetName(dom),
                 ret <
                 0 ? "no state" : vshDomainStateToString(info.state));
354
        virDomainFree(dom);
K
Karel Zak 已提交
355 356 357 358 359 360
    }
    free(ids);
    return TRUE;
}

/*
K
Karel Zak 已提交
361
 * "domstate" command
K
Karel Zak 已提交
362
 */
K
Karel Zak 已提交
363 364
static vshCmdInfo info_domstate[] = {
    {"syntax", "domstate <domain>"},
365 366 367
    {"help", "domain state"},
    {"desc", "Returns state about a running domain."},
    {NULL, NULL}
K
Karel Zak 已提交
368 369
};

K
Karel Zak 已提交
370
static vshCmdOptDef opts_domstate[] = {
K
Karel Zak 已提交
371
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
372
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
373 374 375
};

static int
K
Karel Zak 已提交
376
cmdDomstate(vshControl * ctl, vshCmd * cmd)
377
{
378
    virDomainInfo info;
K
Karel Zak 已提交
379
    virDomainPtr dom;
K
Karel Zak 已提交
380
    int ret = TRUE;
381

K
Karel Zak 已提交
382 383
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
384

K
Karel Zak 已提交
385
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
K
Karel Zak 已提交
386
        return FALSE;
387 388

    if (virDomainGetInfo(dom, &info) == 0)
K
Karel Zak 已提交
389
        vshPrint(ctl, "%s\n",
390
                 vshDomainStateToString(info.state));
K
Karel Zak 已提交
391 392
    else
        ret = FALSE;
393

394 395 396 397 398 399 400 401
    virDomainFree(dom);
    return ret;
}

/*
 * "suspend" command
 */
static vshCmdInfo info_suspend[] = {
402 403 404 405
    {"syntax", "suspend <domain>"},
    {"help", "suspend a domain"},
    {"desc", "Suspend a running domain."},
    {NULL, NULL}
406 407 408
};

static vshCmdOptDef opts_suspend[] = {
K
Karel Zak 已提交
409
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
410
    {NULL, 0, 0, NULL}
411 412 413
};

static int
414 415
cmdSuspend(vshControl * ctl, vshCmd * cmd)
{
416
    virDomainPtr dom;
K
Karel Zak 已提交
417 418
    char *name;
    int ret = TRUE;
419

420 421 422
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
423
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
424
        return FALSE;
425 426

    if (virDomainSuspend(dom) == 0) {
K
Karel Zak 已提交
427
        vshPrint(ctl, "Domain %s suspended\n", name);
428 429 430 431
    } else {
        vshError(ctl, FALSE, "Failed to suspend domain\n");
        ret = FALSE;
    }
432

433 434 435 436
    virDomainFree(dom);
    return ret;
}

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
/*
 * "create" command
 */
static vshCmdInfo info_create[] = {
    {"syntax", "create a domain from an XML <file>"},
    {"help", "create a domain from an XML file"},
    {"desc", "Create a domain."},
    {NULL, NULL}
};

static vshCmdOptDef opts_create[] = {
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, "file conatining an XML domain description"},
    {NULL, 0, 0, NULL}
};

static int
cmdCreate(vshControl * ctl, vshCmd * cmd)
{
    virDomainPtr dom;
    char *from;
    int found;
    int ret = TRUE;
    char buffer[4096];
    int fd, l;

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

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

    fd = open(from, O_RDONLY);
    if (fd < 0) {
        vshError(ctl, FALSE, "Failed to read description file %s\n", from);
        return(FALSE);
    }
    l = read(fd, &buffer[0], sizeof(buffer));
    if ((l <= 0) || (l >= (int) sizeof(buffer))) {
        vshError(ctl, FALSE, "Failed to read description file %s\n", from);
        close(fd);
        return(FALSE);
    }
    buffer[l] = 0;
    dom = virDomainCreateLinux(ctl->conn, &buffer[0], 0);
    if (dom != NULL) {
K
Karel Zak 已提交
483
        vshPrint(ctl, "Domain %s created from %s\n", 
484 485 486 487 488 489 490 491
                 virDomainGetName(dom), from);
    } else {
        vshError(ctl, FALSE, "Failed to create domain\n");
        ret = FALSE;
    }
    return ret;
}

492 493 494 495
/*
 * "save" command
 */
static vshCmdInfo info_save[] = {
496 497 498 499
    {"syntax", "save <domain> <file>"},
    {"help", "save a domain state to a file"},
    {"desc", "Save a running domain."},
    {NULL, NULL}
500 501 502
};

static vshCmdOptDef opts_save[] = {
K
Karel Zak 已提交
503
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
504 505
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, "where to save the data"},
    {NULL, 0, 0, NULL}
506 507 508
};

static int
509 510
cmdSave(vshControl * ctl, vshCmd * cmd)
{
511 512 513 514
    virDomainPtr dom;
    char *name;
    char *to;
    int ret = TRUE;
515

516 517 518
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

519
    if (!(to = vshCommandOptString(cmd, "file", NULL)))
520
        return FALSE;
521

522 523
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
        return FALSE;
524 525

    if (virDomainSave(dom, to) == 0) {
K
Karel Zak 已提交
526
        vshPrint(ctl, "Domain %s saved\n", name);
527 528 529 530
    } else {
        vshError(ctl, FALSE, "Failed to save domain\n");
        ret = FALSE;
    }
531

532 533 534 535 536 537 538 539
    virDomainFree(dom);
    return ret;
}

/*
 * "restore" command
 */
static vshCmdInfo info_restore[] = {
540 541 542 543
    {"syntax", "restore a domain from <file>"},
    {"help", "restore a domain from a saved state in a file"},
    {"desc", "Restore a domain."},
    {NULL, NULL}
544 545 546
};

static vshCmdOptDef opts_restore[] = {
547 548
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, "the state to restore"},
    {NULL, 0, 0, NULL}
549 550 551
};

static int
552 553
cmdRestore(vshControl * ctl, vshCmd * cmd)
{
554 555 556
    char *from;
    int found;
    int ret = TRUE;
557

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

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

    if (virDomainRestore(ctl->conn, from) == 0) {
K
Karel Zak 已提交
566
        vshPrint(ctl, "Domain restored from %s\n", from);
567 568 569 570 571 572 573
    } else {
        vshError(ctl, FALSE, "Failed to restore domain\n");
        ret = FALSE;
    }
    return ret;
}

574 575 576 577
/*
 * "resume" command
 */
static vshCmdInfo info_resume[] = {
578 579 580 581
    {"syntax", "resume <domain>"},
    {"help", "resume a domain"},
    {"desc", "Resume a previously suspended domain."},
    {NULL, NULL}
582 583 584
};

static vshCmdOptDef opts_resume[] = {
K
Karel Zak 已提交
585
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
586
    {NULL, 0, 0, NULL}
587 588 589
};

static int
590 591
cmdResume(vshControl * ctl, vshCmd * cmd)
{
592
    virDomainPtr dom;
K
Karel Zak 已提交
593 594
    int ret = TRUE;
    char *name;
595

596 597 598
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

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

    if (virDomainResume(dom) == 0) {
K
Karel Zak 已提交
603
        vshPrint(ctl, "Domain %s resumed\n", name);
604 605 606 607
    } else {
        vshError(ctl, FALSE, "Failed to resume domain\n");
        ret = FALSE;
    }
608

609 610 611 612
    virDomainFree(dom);
    return ret;
}

613 614 615 616
/*
 * "shutdown" command
 */
static vshCmdInfo info_shutdown[] = {
617 618 619 620
    {"syntax", "shutdown <domain>"},
    {"help", "gracefully shutdown a domain"},
    {"desc", "Run shutdown in the targetted domain"},
    {NULL, NULL}
621 622 623
};

static vshCmdOptDef opts_shutdown[] = {
K
Karel Zak 已提交
624
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
625
    {NULL, 0, 0, NULL}
626 627 628
};

static int
629 630
cmdShutdown(vshControl * ctl, vshCmd * cmd)
{
631 632 633
    virDomainPtr dom;
    int ret = TRUE;
    char *name;
634

635 636 637 638 639
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

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

    if (virDomainShutdown(dom) == 0) {
K
Karel Zak 已提交
642
        vshPrint(ctl, "Domain %s is being shutdown\n", name);
643 644 645 646
    } else {
        vshError(ctl, FALSE, "Failed to shutdown domain\n");
        ret = FALSE;
    }
647

648 649 650 651
    virDomainFree(dom);
    return ret;
}

652 653 654 655 656 657 658 659 660 661 662
/*
 * "reboot" command
 */
static vshCmdInfo info_reboot[] = {
    {"syntax", "reboot <domain>"},
    {"help", "reboot a domain"},
    {"desc", "Run a reboot command in the targetted domain"},
    {NULL, NULL}
};

static vshCmdOptDef opts_reboot[] = {
K
Karel Zak 已提交
663
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
    {NULL, 0, 0, NULL}
};

static int
cmdReboot(vshControl * ctl, vshCmd * cmd)
{
    virDomainPtr dom;
    int ret = TRUE;
    char *name;

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

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

    if (virDomainReboot(dom, 0) == 0) {
K
Karel Zak 已提交
681
        vshPrint(ctl, "Domain %s is being rebooted\n", name);
682 683 684 685 686 687 688 689 690
    } else {
        vshError(ctl, FALSE, "Failed to reboot domain\n");
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

691 692 693 694
/*
 * "destroy" command
 */
static vshCmdInfo info_destroy[] = {
695 696 697 698
    {"syntax", "destroy <domain>"},
    {"help", "destroy a domain"},
    {"desc", "Destroy a given domain."},
    {NULL, NULL}
699 700 701
};

static vshCmdOptDef opts_destroy[] = {
K
Karel Zak 已提交
702
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
703
    {NULL, 0, 0, NULL}
704 705 706
};

static int
707 708
cmdDestroy(vshControl * ctl, vshCmd * cmd)
{
709
    virDomainPtr dom;
K
Karel Zak 已提交
710 711
    int ret = TRUE;
    char *name;
712

713 714 715
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
716
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
717
        return FALSE;
718 719

    if (virDomainDestroy(dom) == 0) {
K
Karel Zak 已提交
720
        vshPrint(ctl, "Domain %s destroyed\n", name);
721 722 723 724 725
    } else {
        vshError(ctl, FALSE, "Failed to destroy domain\n");
        ret = FALSE;
        virDomainFree(dom);
    }
726

K
Karel Zak 已提交
727 728 729 730
    return ret;
}

/*
731
 * "dominfo" command
K
Karel Zak 已提交
732
 */
733 734
static vshCmdInfo info_dominfo[] = {
    {"syntax", "dominfo <domain>"},
735 736 737
    {"help", "domain information"},
    {"desc", "Returns basic information about the domain."},
    {NULL, NULL}
K
Karel Zak 已提交
738 739
};

740
static vshCmdOptDef opts_dominfo[] = {
K
Karel Zak 已提交
741
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
742
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
743 744 745
};

static int
746
cmdDominfo(vshControl * ctl, vshCmd * cmd)
747
{
K
Karel Zak 已提交
748 749
    virDomainInfo info;
    virDomainPtr dom;
K
Karel Zak 已提交
750
    int ret = TRUE;
K
Karel Zak 已提交
751
    char *str, uuid[37];
752

K
Karel Zak 已提交
753 754 755
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
756
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
K
Karel Zak 已提交
757
        return FALSE;
758

K
Karel Zak 已提交
759 760 761 762
    vshPrint(ctl, "%-15s %d\n", "Id:", virDomainGetID(dom));
    vshPrint(ctl, "%-15s %s\n", "Name:", virDomainGetName(dom));
    if (virDomainGetUUIDString(dom, &uuid[0])==0)
        vshPrint(ctl, "%-15s %s\n", "UUID:", uuid);
763 764

    if ((str = virDomainGetOSType(dom))) {
K
Karel Zak 已提交
765
        vshPrint(ctl, "%-15s %s\n", "OS Type:", str);
766 767 768 769
        free(str);
    }

    if (virDomainGetInfo(dom, &info) == 0) {
K
Karel Zak 已提交
770
        vshPrint(ctl, "%-15s %s\n", "State:",
771 772
                 vshDomainStateToString(info.state));

K
Karel Zak 已提交
773
        vshPrint(ctl, "%-15s %d\n", "CPU(s):", info.nrVirtCpu);
774 775

        if (info.cpuTime != 0) {
776
	    double cpuUsed = info.cpuTime;
777

778
            cpuUsed /= 1000000000.0;
779

780
            vshPrint(ctl, "%-15s %.1lfs\n", "CPU time:", cpuUsed);
K
Karel Zak 已提交
781
        }
782

K
Karel Zak 已提交
783
        vshPrint(ctl, "%-15s %lu kB\n", "Max memory:",
784
                 info.maxMem);
K
Karel Zak 已提交
785
        vshPrint(ctl, "%-15s %lu kB\n", "Used memory:",
786 787
                 info.memory);

K
Karel Zak 已提交
788 789 790
    } else {
        ret = FALSE;
    }
791

792
    virDomainFree(dom);
K
Karel Zak 已提交
793 794 795
    return ret;
}

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
/*
 * "nodeinfo" command
 */
static vshCmdInfo info_nodeinfo[] = {
    {"syntax", "nodeinfo"},
    {"help", "node information"},
    {"desc", "Returns basic information about the node."},
    {NULL, NULL}
};

static int
cmdNodeinfo(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
    virNodeInfo info;
        
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

    if (virNodeGetInfo(ctl->conn, &info) < 0) {
        vshError(ctl, FALSE, "failed to get node information");
        return FALSE;
    }    
K
Karel Zak 已提交
818 819 820 821 822 823 824 825
    vshPrint(ctl, "%-20s %s\n", "CPU model:", info.model);
    vshPrint(ctl, "%-20s %d\n", "CPU(s):", info.cpus);
    vshPrint(ctl, "%-20s %d MHz\n", "CPU frequency:", info.mhz);
    vshPrint(ctl, "%-20s %d\n", "CPU socket(s):", info.sockets);
    vshPrint(ctl, "%-20s %d\n", "Core(s) per socket:", info.cores);
    vshPrint(ctl, "%-20s %d\n", "Thread(s) per core:", info.threads);
    vshPrint(ctl, "%-20s %d\n", "NUMA cell(s):", info.nodes);
    vshPrint(ctl, "%-20s %lu kB\n", "Memory size:", info.memory);
826 827 828 829
        
    return TRUE;
}

830 831 832 833
/*
 * "dumpxml" command
 */
static vshCmdInfo info_dumpxml[] = {
834 835
    {"syntax", "dumpxml <name>"},
    {"help", "domain information in XML"},
836
    {"desc", "Ouput the domain information as an XML dump to stdout"},
837
    {NULL, NULL}
838 839 840
};

static vshCmdOptDef opts_dumpxml[] = {
K
Karel Zak 已提交
841
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id, uuid"},
842
    {NULL, 0, 0, NULL}
843 844 845
};

static int
846 847
cmdDumpXML(vshControl * ctl, vshCmd * cmd)
{
848
    virDomainPtr dom;
K
Karel Zak 已提交
849
    int ret = TRUE;
850
    char *dump;
851

852 853 854
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
855
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
856
        return FALSE;
857

858 859 860 861 862 863 864
    dump = virDomainGetXMLDesc(dom, 0);
    if (dump != NULL) {
        printf("%s", dump);
        free(dump);
    } else {
        ret = FALSE;
    }
865

866 867 868 869
    virDomainFree(dom);
    return ret;
}

K
Karel Zak 已提交
870
/*
K
Karel Zak 已提交
871
 * "domname" command
K
Karel Zak 已提交
872
 */
K
Karel Zak 已提交
873
static vshCmdInfo info_domname[] = {
K
Karel Zak 已提交
874 875
    {"syntax", "domname <domain>"},
    {"help", "convert a domain Id or UUID to domain name"},
876
    {NULL, NULL}
K
Karel Zak 已提交
877 878
};

K
Karel Zak 已提交
879
static vshCmdOptDef opts_domname[] = {
K
Karel Zak 已提交
880
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain id or uuid"},
881
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
882 883 884
};

static int
K
Karel Zak 已提交
885
cmdDomname(vshControl * ctl, vshCmd * cmd)
886
{
K
Karel Zak 已提交
887 888 889 890
    virDomainPtr dom;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
K
Karel Zak 已提交
891 892
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, 
                                    VSH_DOMBYID|VSH_DOMBYUUID)))
K
Karel Zak 已提交
893
        return FALSE;
894

K
Karel Zak 已提交
895 896
    vshPrint(ctl, "%s\n", virDomainGetName(dom));
    virDomainFree(dom);
K
Karel Zak 已提交
897 898 899 900
    return TRUE;
}

/*
K
Karel Zak 已提交
901
 * "domid" command
K
Karel Zak 已提交
902
 */
K
Karel Zak 已提交
903
static vshCmdInfo info_domid[] = {
K
Karel Zak 已提交
904 905
    {"syntax", "domid <domain>"},
    {"help", "convert a domain name or UUID to domain Id"},
906
    {NULL, NULL}
K
Karel Zak 已提交
907 908
};

K
Karel Zak 已提交
909
static vshCmdOptDef opts_domid[] = {
K
Karel Zak 已提交
910
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or uuid"},
911
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
912 913 914
};

static int
K
Karel Zak 已提交
915
cmdDomid(vshControl * ctl, vshCmd * cmd)
916
{
917
    virDomainPtr dom;
K
Karel Zak 已提交
918 919 920

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
K
Karel Zak 已提交
921 922
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, 
                                    VSH_DOMBYNAME|VSH_DOMBYUUID)))
K
Karel Zak 已提交
923
        return FALSE;
K
Karel Zak 已提交
924 925 926 927 928
    
    vshPrint(ctl, "%d\n", virDomainGetID(dom));
    virDomainFree(dom);
    return TRUE;
}
929

K
Karel Zak 已提交
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
/*
 * "domuuid" command
 */
static vshCmdInfo info_domuuid[] = {
    {"syntax", "domuuid <domain>"},
    {"help", "convert a domain name or id to domain UUID"},
    {NULL, NULL}
};

static vshCmdOptDef opts_domuuid[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain id or name"},
    {NULL, 0, 0, NULL}
};

static int
cmdDomuuid(vshControl * ctl, vshCmd * cmd)
{
    virDomainPtr dom;
    char uuid[37];

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
K
Karel Zak 已提交
951
        return FALSE;
K
Karel Zak 已提交
952 953 954 955 956 957 958 959 960
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, 
                                    VSH_DOMBYNAME|VSH_DOMBYID)))
        return FALSE;
    
    if (virDomainGetUUIDString(dom, uuid) != -1)
        vshPrint(ctl, "%s\n", uuid);
    else
        vshError(ctl, FALSE, "failed to get domain UUID");
    
K
Karel Zak 已提交
961 962 963
    return TRUE;
}

K
Karel Zak 已提交
964

965 966 967 968
/*
 * "version" command
 */
static vshCmdInfo info_version[] = {
969 970
    {"syntax", "version"},
    {"help", "show versions"},
971
    {"desc", "Display the version information available"},
972
    {NULL, NULL}
973 974 975 976
};


static int
977 978
cmdVersion(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
979 980
    unsigned long hvVersion;
    const char *hvType;
981 982 983 984 985 986 987
    unsigned long libVersion;
    unsigned long includeVersion;
    unsigned long apiVersion;
    int ret;
    unsigned int major;
    unsigned int minor;
    unsigned int rel;
988 989 990

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

992 993
    hvType = virConnectGetType(ctl->conn);
    if (hvType == NULL) {
K
Karel Zak 已提交
994
        vshError(ctl, FALSE, "failed to get hypervisor type\n");
995 996 997
        return FALSE;
    }

998 999 1000 1001 1002
    includeVersion = LIBVIR_VERSION_NUMBER;
    major = includeVersion / 1000000;
    includeVersion %= 1000000;
    minor = includeVersion / 1000;
    rel = includeVersion % 1000;
K
Karel Zak 已提交
1003
    vshPrint(ctl, "Compiled against library: libvir %d.%d.%d\n",
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
             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;
K
Karel Zak 已提交
1015
    vshPrint(ctl, "Using library: libvir %d.%d.%d\n",
1016
             major, minor, rel);
1017

1018 1019 1020 1021
    major = apiVersion / 1000000;
    apiVersion %= 1000000;
    minor = apiVersion / 1000;
    rel = apiVersion % 1000;
K
Karel Zak 已提交
1022
    vshPrint(ctl, "Using API: %s %d.%d.%d\n", hvType,
1023 1024
             major, minor, rel);

1025
    ret = virConnectGetVersion(ctl->conn, &hvVersion);
1026 1027
    if (ret < 0) {
        vshError(ctl, FALSE, "failed to get the hypervisor version");
1028 1029 1030
        return FALSE;
    }
    if (hvVersion == 0) {
K
Karel Zak 已提交
1031
        vshPrint(ctl,
1032
                 "cannot extract running %s hypervisor version\n", hvType);
1033
    } else {
1034
        major = hvVersion / 1000000;
1035
        hvVersion %= 1000000;
1036 1037
        minor = hvVersion / 1000;
        rel = hvVersion % 1000;
1038

K
Karel Zak 已提交
1039
        vshPrint(ctl, "Running hypervisor: %s %d.%d.%d\n",
1040
                 hvType, major, minor, rel);
1041 1042 1043 1044
    }
    return TRUE;
}

K
Karel Zak 已提交
1045 1046 1047 1048
/*
 * "quit" command
 */
static vshCmdInfo info_quit[] = {
1049 1050 1051
    {"syntax", "quit"},
    {"help", "quit this interactive terminal"},
    {NULL, NULL}
K
Karel Zak 已提交
1052 1053 1054
};

static int
1055 1056
cmdQuit(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
1057 1058 1059 1060 1061 1062 1063 1064
    ctl->imode = FALSE;
    return TRUE;
}

/*
 * Commands
 */
static vshCmdDef commands[] = {
1065
    {"connect", cmdConnect, opts_connect, info_connect},
1066
    {"create", cmdCreate, opts_create, info_create},
K
Karel Zak 已提交
1067 1068
    {"destroy", cmdDestroy, opts_destroy, info_destroy},
    {"domid", cmdDomid, opts_domid, info_domid},
K
Karel Zak 已提交
1069
    {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
1070
    {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
K
Karel Zak 已提交
1071 1072
    {"domname", cmdDomname, opts_domname, info_domname},
    {"domstate", cmdDomstate, opts_domstate, info_domstate},
1073
    {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
K
Karel Zak 已提交
1074 1075 1076 1077 1078 1079
    {"help", cmdHelp, opts_help, info_help},
    {"list", cmdList, NULL, info_list},
    {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
    {"quit", cmdQuit, NULL, info_quit},
    {"reboot", cmdReboot, opts_reboot, info_reboot},
    {"restore", cmdRestore, opts_restore, info_restore},
1080 1081 1082
    {"resume", cmdResume, opts_resume, info_resume},
    {"save", cmdSave, opts_save, info_save},
    {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
K
Karel Zak 已提交
1083
    {"suspend", cmdSuspend, opts_suspend, info_suspend},
1084 1085
    {"version", cmdVersion, NULL, info_version},
    {NULL, NULL, NULL, NULL}
K
Karel Zak 已提交
1086 1087 1088 1089 1090 1091
};

/* ---------------
 * Utils for work with command definition
 * ---------------
 */
K
Karel Zak 已提交
1092
static const char *
1093 1094
vshCmddefGetInfo(vshCmdDef * cmd, const char *name)
{
K
Karel Zak 已提交
1095
    vshCmdInfo *info;
1096

K
Karel Zak 已提交
1097
    for (info = cmd->info; info && info->name; info++) {
1098
        if (strcmp(info->name, name) == 0)
K
Karel Zak 已提交
1099 1100 1101 1102 1103 1104
            return info->data;
    }
    return NULL;
}

static vshCmdOptDef *
1105 1106
vshCmddefGetOption(vshCmdDef * cmd, const char *name)
{
K
Karel Zak 已提交
1107
    vshCmdOptDef *opt;
1108

K
Karel Zak 已提交
1109
    for (opt = cmd->opts; opt && opt->name; opt++)
1110
        if (strcmp(opt->name, name) == 0)
K
Karel Zak 已提交
1111 1112 1113 1114 1115
            return opt;
    return NULL;
}

static vshCmdOptDef *
1116 1117
vshCmddefGetData(vshCmdDef * cmd, int data_ct)
{
K
Karel Zak 已提交
1118 1119
    vshCmdOptDef *opt;

1120
    for (opt = cmd->opts; opt && opt->name; opt++) {
1121 1122
        if (opt->type == VSH_OT_DATA) {
            if (data_ct == 0)
1123 1124 1125 1126 1127
                return opt;
            else
                data_ct--;
        }
    }
K
Karel Zak 已提交
1128 1129 1130
    return NULL;
}

1131 1132 1133
/*
 * Checks for required options
 */
1134 1135
static int
vshCommandCheckOpts(vshControl * ctl, vshCmd * cmd)
1136 1137 1138
{
    vshCmdDef *def = cmd->def;
    vshCmdOptDef *d;
1139
    int err = 0;
1140 1141 1142 1143

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

            while (o && ok == 0) {
1147
                if (o->def == d)
1148
                    ok = 1;
1149 1150 1151
                o = o->next;
            }
            if (!ok) {
1152 1153 1154 1155 1156
                vshError(ctl, FALSE,
                         d->type == VSH_OT_DATA ?
                         "command '%s' requires <%s> option" :
                         "command '%s' requires --%s option",
                         def->name, d->name);
1157 1158
                err = 1;
            }
1159

1160 1161 1162 1163 1164
        }
    }
    return !err;
}

K
Karel Zak 已提交
1165
static vshCmdDef *
1166 1167
vshCmddefSearch(const char *cmdname)
{
K
Karel Zak 已提交
1168
    vshCmdDef *c;
1169

K
Karel Zak 已提交
1170
    for (c = commands; c->name; c++)
1171
        if (strcmp(c->name, cmdname) == 0)
K
Karel Zak 已提交
1172 1173 1174 1175 1176
            return c;
    return NULL;
}

static int
1177 1178
vshCmddefHelp(vshControl * ctl, const char *cmdname, int withprog)
{
K
Karel Zak 已提交
1179
    vshCmdDef *def = vshCmddefSearch(cmdname);
1180

K
Karel Zak 已提交
1181
    if (!def) {
1182 1183 1184
        vshError(ctl, FALSE, "command '%s' doesn't exist", cmdname);
        return FALSE;
    } else {
K
Karel Zak 已提交
1185
        vshCmdOptDef *opt;
K
Karel Zak 已提交
1186 1187 1188
        const char *desc = vshCmddefGetInfo(def, "desc");
        const char *help = vshCmddefGetInfo(def, "help");
        const char *syntax = vshCmddefGetInfo(def, "syntax");
K
Karel Zak 已提交
1189 1190

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

K
Karel Zak 已提交
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
        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);
1206
            for (opt = def->opts; opt->name; opt++) {
K
Karel Zak 已提交
1207
                char buf[256];
1208 1209

                if (opt->type == VSH_OT_BOOL)
K
Karel Zak 已提交
1210
                    snprintf(buf, sizeof(buf), "--%s", opt->name);
1211
                else if (opt->type == VSH_OT_INT)
K
Karel Zak 已提交
1212
                    snprintf(buf, sizeof(buf), "--%s <number>", opt->name);
1213
                else if (opt->type == VSH_OT_STRING)
K
Karel Zak 已提交
1214
                    snprintf(buf, sizeof(buf), "--%s <string>", opt->name);
1215
                else if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
1216
                    snprintf(buf, sizeof(buf), "<%s>", opt->name);
1217

K
Karel Zak 已提交
1218
                fprintf(stdout, "    %-15s  %s\n", buf, opt->help);
1219
            }
K
Karel Zak 已提交
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
        }
        fputc('\n', stdout);
    }
    return TRUE;
}

/* ---------------
 * Utils for work with runtime commands data
 * ---------------
 */
1230 1231 1232
static void
vshCommandOptFree(vshCmdOpt * arg)
{
K
Karel Zak 已提交
1233 1234
    vshCmdOpt *a = arg;

1235
    while (a) {
K
Karel Zak 已提交
1236
        vshCmdOpt *tmp = a;
1237

K
Karel Zak 已提交
1238 1239 1240 1241 1242 1243 1244 1245 1246
        a = a->next;

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

static void
1247 1248
vshCommandFree(vshCmd * cmd)
{
K
Karel Zak 已提交
1249 1250
    vshCmd *c = cmd;

1251
    while (c) {
K
Karel Zak 已提交
1252
        vshCmd *tmp = c;
1253

K
Karel Zak 已提交
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
        c = c->next;

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

/*
 * Returns option by name
 */
static vshCmdOpt *
1266 1267
vshCommandOpt(vshCmd * cmd, const char *name)
{
K
Karel Zak 已提交
1268
    vshCmdOpt *opt = cmd->opts;
1269 1270 1271

    while (opt) {
        if (opt->def && strcmp(opt->def->name, name) == 0)
K
Karel Zak 已提交
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
            return opt;
        opt = opt->next;
    }
    return NULL;
}

/*
 * Returns option as INT
 */
static int
1282 1283
vshCommandOptInt(vshCmd * cmd, const char *name, int *found)
{
K
Karel Zak 已提交
1284 1285
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
    int res = 0;
1286

K
Karel Zak 已提交
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
    if (arg)
        res = atoi(arg->data);
    if (found)
        *found = arg ? TRUE : FALSE;
    return res;
}

/*
 * Returns option as STRING
 */
static char *
1298 1299
vshCommandOptString(vshCmd * cmd, const char *name, int *found)
{
K
Karel Zak 已提交
1300
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
1301

K
Karel Zak 已提交
1302 1303
    if (found)
        *found = arg ? TRUE : FALSE;
1304 1305

    return arg && arg->data && *arg->data ? arg->data : NULL;
K
Karel Zak 已提交
1306 1307 1308 1309 1310 1311
}

/*
 * Returns TRUE/FALSE if the option exists
 */
static int
1312 1313
vshCommandOptBool(vshCmd * cmd, const char *name)
{
K
Karel Zak 已提交
1314 1315 1316
    return vshCommandOpt(cmd, name) ? TRUE : FALSE;
}

1317

K
Karel Zak 已提交
1318
static virDomainPtr
K
Karel Zak 已提交
1319 1320
vshCommandOptDomainBy(vshControl * ctl, vshCmd * cmd, const char *optname,
                    char **name, int flag)
1321
{
K
Karel Zak 已提交
1322 1323 1324
    virDomainPtr dom = NULL;
    char *n, *end = NULL;
    int id;
1325

K
Karel Zak 已提交
1326 1327
    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
        vshError(ctl, FALSE, "undefined domain name or id");
1328
        return NULL;
K
Karel Zak 已提交
1329
    }
1330

K
Karel Zak 已提交
1331
    vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
1332 1333
             cmd->def->name, optname, n);

K
Karel Zak 已提交
1334 1335
    if (name)
        *name = n;
1336

K
Karel Zak 已提交
1337
    /* try it by ID */
K
Karel Zak 已提交
1338 1339 1340 1341 1342 1343 1344
    if (flag & VSH_DOMBYID) {
        id = (int) strtol(n, &end, 10);
        if (id >= 0 && end && *end == '\0') {
            vshDebug(ctl, 5, "%s: <%s> seems like domain ID\n",
                     cmd->def->name, optname);
            dom = virDomainLookupByID(ctl->conn, id);
        }
1345
    }
K
Karel Zak 已提交
1346
    /* try it by UUID */
K
Karel Zak 已提交
1347
    if (dom==NULL && (flag & VSH_DOMBYUUID) && strlen(n)==36) {
K
Karel Zak 已提交
1348 1349
        vshDebug(ctl, 5, "%s: <%s> tring as domain UUID\n",
                cmd->def->name, optname);
K
Karel Zak 已提交
1350
        dom = virDomainLookupByUUIDString(ctl->conn, n);
K
Karel Zak 已提交
1351
    }
K
Karel Zak 已提交
1352
    /* try it by NAME */
K
Karel Zak 已提交
1353
    if (dom==NULL && (flag & VSH_DOMBYNAME)) {
K
Karel Zak 已提交
1354
        vshDebug(ctl, 5, "%s: <%s> tring as domain NAME\n",
1355
                 cmd->def->name, optname);
K
Karel Zak 已提交
1356
        dom = virDomainLookupByName(ctl->conn, n);
1357
    }
K
Karel Zak 已提交
1358

1359
    if (!dom)
K
Karel Zak 已提交
1360
        vshError(ctl, FALSE, "failed to get domain '%s'", n);
1361

K
Karel Zak 已提交
1362 1363 1364
    return dom;
}

K
Karel Zak 已提交
1365 1366 1367 1368
/*
 * Executes command(s) and returns return code from last command
 */
static int
1369 1370
vshCommandRun(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
1371
    int ret = TRUE;
1372 1373

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

K
Karel Zak 已提交
1376 1377
        if (ctl->timing)
            GETTIMEOFDAY(&before);
1378

K
Karel Zak 已提交
1379 1380 1381 1382
        ret = cmd->def->handler(ctl, cmd);

        if (ctl->timing)
            GETTIMEOFDAY(&after);
1383 1384

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

        if (ctl->timing)
K
Karel Zak 已提交
1388
            vshPrint(ctl, "\n(Time: %.3f ms)\n\n",
1389 1390
                     DIFF_MSEC(&after, &before));
        else
K
Karel Zak 已提交
1391
            vshPrintExtra(ctl, "\n");
K
Karel Zak 已提交
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406
        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

1407 1408 1409
static int
vshCommandGetToken(vshControl * ctl, char *str, char **end, char **res)
{
K
Karel Zak 已提交
1410 1411 1412 1413 1414
    int tk = VSH_TK_NONE;
    int quote = FALSE;
    int sz = 0;
    char *p = str;
    char *tkstr = NULL;
1415

K
Karel Zak 已提交
1416
    *end = NULL;
1417 1418

    while (p && *p && isblank((unsigned char) *p))
K
Karel Zak 已提交
1419
        p++;
1420 1421

    if (p == NULL || *p == '\0')
K
Karel Zak 已提交
1422
        return VSH_TK_END;
1423 1424
    if (*p == ';') {
        *end = ++p;             /* = \0 or begi of next command */
K
Karel Zak 已提交
1425 1426
        return VSH_TK_END;
    }
1427
    while (*p) {
K
Karel Zak 已提交
1428
        /* end of token is blank space or ';' */
1429
        if ((quote == FALSE && isblank((unsigned char) *p)) || *p == ';')
K
Karel Zak 已提交
1430
            break;
1431

1432
        /* end of option name could be '=' */
1433 1434
        if (tk == VSH_TK_OPTION && *p == '=') {
            p++;                /* skip '=' */
1435 1436
            break;
        }
1437 1438 1439 1440

        if (tk == VSH_TK_NONE) {
            if (*p == '-' && *(p + 1) == '-' && *(p + 2)
                && isalnum((unsigned char) *(p + 2))) {
K
Karel Zak 已提交
1441
                tk = VSH_TK_OPTION;
1442
                p += 2;
K
Karel Zak 已提交
1443 1444
            } else {
                tk = VSH_TK_DATA;
1445 1446
                if (*p == '"') {
                    quote = TRUE;
K
Karel Zak 已提交
1447 1448 1449 1450 1451
                    p++;
                } else {
                    quote = FALSE;
                }
            }
1452 1453
            tkstr = p;          /* begin of token */
        } else if (quote && *p == '"') {
K
Karel Zak 已提交
1454 1455
            quote = FALSE;
            p++;
1456
            break;              /* end of "..." token */
K
Karel Zak 已提交
1457 1458 1459 1460 1461 1462 1463 1464
        }
        p++;
        sz++;
    }
    if (quote) {
        vshError(ctl, FALSE, "missing \"");
        return VSH_TK_ERROR;
    }
1465
    if (tkstr == NULL || *tkstr == '\0' || p == NULL)
K
Karel Zak 已提交
1466
        return VSH_TK_END;
1467
    if (sz == 0)
K
Karel Zak 已提交
1468
        return VSH_TK_END;
1469

1470
    *res = vshMalloc(ctl, sz + 1);
K
Karel Zak 已提交
1471
    memcpy(*res, tkstr, sz);
1472
    *(*res + sz) = '\0';
K
Karel Zak 已提交
1473 1474 1475 1476 1477 1478

    *end = p;
    return tk;
}

static int
1479 1480
vshCommandParse(vshControl * ctl, char *cmdstr)
{
K
Karel Zak 已提交
1481 1482 1483 1484
    char *str;
    char *tkdata = NULL;
    vshCmd *clast = NULL;
    vshCmdOpt *first = NULL;
1485

K
Karel Zak 已提交
1486 1487 1488 1489
    if (ctl->cmd) {
        vshCommandFree(ctl->cmd);
        ctl->cmd = NULL;
    }
1490 1491

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

K
Karel Zak 已提交
1494
    str = cmdstr;
1495
    while (str && *str) {
K
Karel Zak 已提交
1496 1497 1498
        vshCmdOpt *last = NULL;
        vshCmdDef *cmd = NULL;
        int tk = VSH_TK_NONE;
1499
        int data_ct = 0;
1500

K
Karel Zak 已提交
1501
        first = NULL;
1502 1503

        while (tk != VSH_TK_END) {
K
Karel Zak 已提交
1504 1505
            char *end = NULL;
            vshCmdOptDef *opt = NULL;
1506

K
Karel Zak 已提交
1507
            tkdata = NULL;
1508

K
Karel Zak 已提交
1509 1510
            /* get token */
            tk = vshCommandGetToken(ctl, str, &end, &tkdata);
1511

K
Karel Zak 已提交
1512
            str = end;
1513 1514

            if (tk == VSH_TK_END)
K
Karel Zak 已提交
1515
                break;
1516
            if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
1517
                goto syntaxError;
1518 1519

            if (cmd == NULL) {
K
Karel Zak 已提交
1520
                /* first token must be command name */
1521 1522 1523 1524
                if (tk != VSH_TK_DATA) {
                    vshError(ctl, FALSE,
                             "unexpected token (command name): '%s'",
                             tkdata);
K
Karel Zak 已提交
1525 1526 1527
                    goto syntaxError;
                }
                if (!(cmd = vshCmddefSearch(tkdata))) {
1528 1529
                    vshError(ctl, FALSE, "unknown command: '%s'", tkdata);
                    goto syntaxError;   /* ... or ignore this command only? */
K
Karel Zak 已提交
1530 1531
                }
                free(tkdata);
1532
            } else if (tk == VSH_TK_OPTION) {
K
Karel Zak 已提交
1533 1534
                if (!(opt = vshCmddefGetOption(cmd, tkdata))) {
                    vshError(ctl, FALSE,
1535 1536
                             "command '%s' doesn't support option --%s",
                             cmd->name, tkdata);
K
Karel Zak 已提交
1537 1538
                    goto syntaxError;
                }
1539
                free(tkdata);   /* option name */
K
Karel Zak 已提交
1540 1541 1542 1543 1544
                tkdata = NULL;

                if (opt->type != VSH_OT_BOOL) {
                    /* option data */
                    tk = vshCommandGetToken(ctl, str, &end, &tkdata);
1545 1546
                    str = end;
                    if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
1547
                        goto syntaxError;
1548
                    if (tk != VSH_TK_DATA) {
K
Karel Zak 已提交
1549
                        vshError(ctl, FALSE,
1550 1551 1552 1553
                                 "expected syntax: --%s <%s>",
                                 opt->name,
                                 opt->type ==
                                 VSH_OT_INT ? "number" : "string");
K
Karel Zak 已提交
1554 1555 1556
                        goto syntaxError;
                    }
                }
1557
            } else if (tk == VSH_TK_DATA) {
1558
                if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
1559
                    vshError(ctl, FALSE, "unexpected data '%s'", tkdata);
K
Karel Zak 已提交
1560 1561 1562 1563 1564
                    goto syntaxError;
                }
            }
            if (opt) {
                /* save option */
1565
                vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
1566

K
Karel Zak 已提交
1567 1568 1569 1570
                arg->def = opt;
                arg->data = tkdata;
                arg->next = NULL;
                tkdata = NULL;
1571

K
Karel Zak 已提交
1572 1573 1574 1575 1576
                if (!first)
                    first = arg;
                if (last)
                    last->next = arg;
                last = arg;
1577

K
Karel Zak 已提交
1578
                vshDebug(ctl, 4, "%s: %s(%s): %s\n",
1579 1580 1581 1582
                         cmd->name,
                         opt->name,
                         tk == VSH_TK_OPTION ? "OPTION" : "DATA",
                         arg->data);
K
Karel Zak 已提交
1583 1584 1585 1586
            }
            if (!str)
                break;
        }
1587

K
Karel Zak 已提交
1588 1589
        /* commad parsed -- allocate new struct for the command */
        if (cmd) {
1590
            vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
1591

K
Karel Zak 已提交
1592 1593 1594 1595
            c->opts = first;
            c->def = cmd;
            c->next = NULL;

1596 1597
            if (!vshCommandCheckOpts(ctl, c))
                goto syntaxError;
1598

K
Karel Zak 已提交
1599 1600 1601 1602 1603 1604 1605
            if (!ctl->cmd)
                ctl->cmd = c;
            if (clast)
                clast->next = c;
            clast = c;
        }
    }
1606

K
Karel Zak 已提交
1607 1608
    return TRUE;

1609
  syntaxError:
K
Karel Zak 已提交
1610 1611 1612 1613 1614 1615
    if (ctl->cmd)
        vshCommandFree(ctl->cmd);
    if (first)
        vshCommandOptFree(first);
    if (tkdata)
        free(tkdata);
1616
    return FALSE;
K
Karel Zak 已提交
1617 1618 1619 1620 1621 1622 1623
}


/* ---------------
 * Misc utils  
 * ---------------
 */
K
Karel Zak 已提交
1624
static const char *
1625 1626
vshDomainStateToString(int state)
{
K
Karel Zak 已提交
1627 1628
    switch (state) {
        case VIR_DOMAIN_RUNNING:
1629
            return "running ";
K
Karel Zak 已提交
1630 1631 1632 1633 1634 1635 1636 1637
        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";
K
Karel Zak 已提交
1638 1639
        case VIR_DOMAIN_CRASHED:
            return "crashed";
K
Karel Zak 已提交
1640
        default:
1641
            return "no state";  /* = dom0 state */
K
Karel Zak 已提交
1642 1643 1644 1645 1646
    }
    return NULL;
}

static int
1647 1648
vshConnectionUsability(vshControl * ctl, virConnectPtr conn, int showerror)
{
K
Karel Zak 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
    /* 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;
}

K
Karel Zak 已提交
1660 1661
static void
vshDebug(vshControl * ctl, int level, const char *format, ...)
1662
{
K
Karel Zak 已提交
1663 1664 1665 1666 1667 1668 1669 1670
    va_list ap;

    if (level > ctl->debug)
        return;

    va_start(ap, format);
    vfprintf(stdout, format, ap);
    va_end(ap);
K
Karel Zak 已提交
1671 1672 1673
}

static void
K
Karel Zak 已提交
1674
vshPrintExtra(vshControl * ctl, const char *format, ...)
1675
{
K
Karel Zak 已提交
1676
    va_list ap;
1677

K
Karel Zak 已提交
1678
    if (ctl->quiet == TRUE)
K
Karel Zak 已提交
1679
        return;
1680

K
Karel Zak 已提交
1681
    va_start(ap, format);
1682
    vfprintf(stdout, format, ap);
K
Karel Zak 已提交
1683 1684 1685
    va_end(ap);
}

K
Karel Zak 已提交
1686

K
Karel Zak 已提交
1687
static void
1688 1689
vshError(vshControl * ctl, int doexit, const char *format, ...)
{
K
Karel Zak 已提交
1690
    va_list ap;
1691

K
Karel Zak 已提交
1692 1693 1694 1695
    if (doexit)
        fprintf(stderr, "%s: error: ", progname);
    else
        fputs("error: ", stderr);
1696

K
Karel Zak 已提交
1697 1698 1699 1700 1701
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);

    fputc('\n', stderr);
1702

K
Karel Zak 已提交
1703
    if (doexit) {
1704 1705
        if (ctl)
            vshDeinit(ctl);
K
Karel Zak 已提交
1706 1707 1708 1709
        exit(EXIT_FAILURE);
    }
}

1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745
static void *
_vshMalloc(vshControl * ctl, size_t size, const char *filename, int line)
{
    void *x;

    if ((x = malloc(size)))
        return x;
    vshError(ctl, TRUE, "%s: %d: failed to allocate %d bytes\n", 
                filename, line, (int) size);
    return NULL;
}

static void *
_vshCalloc(vshControl * ctl, size_t nmemb, size_t size, const char *filename, int line)
{
    void *x;

    if ((x = calloc(nmemb, size)))
        return x;
    vshError(ctl, TRUE, "%s: %d: failed to allocate %d bytes\n", 
                filename, line, (int) (size*nmemb));
    return NULL;
}

static char *
_vshStrdup(vshControl * ctl, const char *s, const char *filename, int line)
{
    char *x;

    if ((x = strdup(s)))
        return x;
    vshError(ctl, TRUE, "%s: %d: failed to allocate %d bytes\n", 
                filename, line, strlen(s));
    return NULL;
}

K
Karel Zak 已提交
1746 1747 1748 1749
/*
 * Initialize vistsh
 */
static int
1750 1751
vshInit(vshControl * ctl)
{
K
Karel Zak 已提交
1752 1753 1754 1755
    if (ctl->conn)
        return FALSE;

    ctl->uid = getuid();
1756

1757 1758
    /* set up the library error handler */
    virSetErrorFunc(NULL, virshErrorHandler);
1759

K
Karel Zak 已提交
1760 1761
    /* basic connection to hypervisor */
    if (ctl->uid == 0)
K
Karel Zak 已提交
1762
        ctl->conn = virConnectOpen(ctl->name);
K
Karel Zak 已提交
1763
    else
K
Karel Zak 已提交
1764
        ctl->conn = virConnectOpenReadOnly(ctl->name);
1765

K
Karel Zak 已提交
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
    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 *
1783 1784
vshReadlineCommandGenerator(const char *text, int state)
{
K
Karel Zak 已提交
1785
    static int list_index, len;
K
Karel Zak 已提交
1786
    const char *name;
K
Karel Zak 已提交
1787 1788 1789 1790 1791 1792 1793

    /* 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;
1794
        len = strlen(text);
K
Karel Zak 已提交
1795 1796 1797 1798 1799
    }

    /* Return the next name which partially matches from the
     * command list. 
     */
K
Karel Zak 已提交
1800
    while ((name = commands[list_index].name)) {
K
Karel Zak 已提交
1801
        list_index++;
1802
        if (strncmp(name, text, len) == 0)
1803
            return vshStrdup(NULL, name);
K
Karel Zak 已提交
1804 1805 1806 1807 1808 1809 1810
    }

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

static char *
1811 1812
vshReadlineOptionsGenerator(const char *text, int state)
{
K
Karel Zak 已提交
1813 1814
    static int list_index, len;
    static vshCmdDef *cmd = NULL;
K
Karel Zak 已提交
1815
    const char *name;
K
Karel Zak 已提交
1816 1817 1818 1819 1820 1821 1822 1823 1824

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

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

1825
        cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
1826
        memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
K
Karel Zak 已提交
1827 1828 1829

        cmd = vshCmddefSearch(cmdname);
        list_index = 0;
1830
        len = strlen(text);
K
Karel Zak 已提交
1831 1832 1833 1834 1835
        free(cmdname);
    }

    if (!cmd)
        return NULL;
1836

K
Karel Zak 已提交
1837
    while ((name = cmd->opts[list_index].name)) {
K
Karel Zak 已提交
1838 1839
        vshCmdOptDef *opt = &cmd->opts[list_index];
        char *res;
1840

K
Karel Zak 已提交
1841
        list_index++;
1842

K
Karel Zak 已提交
1843
        if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
1844 1845
            /* ignore non --option */
            continue;
1846

K
Karel Zak 已提交
1847
        if (len > 2) {
1848
            if (strncmp(name, text + 2, len - 2))
K
Karel Zak 已提交
1849 1850
                continue;
        }
1851
        res = vshMalloc(NULL, strlen(name) + 3);
K
Karel Zak 已提交
1852 1853 1854 1855 1856 1857 1858 1859 1860
        sprintf(res, "--%s", name);
        return res;
    }

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

static char **
1861 1862 1863
vshReadlineCompletion(const char *text, int start,
                      int end ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
1864 1865
    char **matches = (char **) NULL;

1866
    if (start == 0)
K
Karel Zak 已提交
1867
        /* command name generator */
1868
        matches = rl_completion_matches(text, vshReadlineCommandGenerator);
K
Karel Zak 已提交
1869 1870
    else
        /* commands options */
1871
        matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
K
Karel Zak 已提交
1872 1873 1874 1875 1876
    return matches;
}


static void
1877 1878
vshReadlineInit(void)
{
K
Karel Zak 已提交
1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889
    /* 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
1890 1891
vshDeinit(vshControl * ctl)
{
K
Karel Zak 已提交
1892
    if (ctl->conn) {
1893 1894 1895 1896
        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 已提交
1897 1898 1899 1900
        }
    }
    return TRUE;
}
1901

K
Karel Zak 已提交
1902 1903 1904 1905
/*
 * Print usage
 */
static void
1906 1907
vshUsage(vshControl * ctl, const char *cmdname)
{
K
Karel Zak 已提交
1908
    vshCmdDef *cmd;
1909

K
Karel Zak 已提交
1910 1911 1912 1913
    /* global help */
    if (!cmdname) {
        fprintf(stdout, "\n%s [options] [commands]\n\n"
                "  options:\n"
K
Karel Zak 已提交
1914
                "    -c | --connect <name>   optional argument currently unused (or used for tests only)\n"
K
Karel Zak 已提交
1915 1916 1917 1918 1919 1920
                "    -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);
1921 1922 1923 1924 1925 1926 1927 1928

        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 已提交
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
        return;
    }
    if (!vshCmddefHelp(ctl, cmdname, TRUE))
        exit(EXIT_FAILURE);
}

/*
 * argv[]:  virsh [options] [command]
 *
 */
static int
1940 1941
vshParseArgv(vshControl * ctl, int argc, char **argv)
{
K
Karel Zak 已提交
1942 1943
    char *last = NULL;
    int i, end = 0, help = 0;
1944
    int arg, idx = 0;
K
Karel Zak 已提交
1945
    struct option opt[] = {
1946 1947 1948 1949 1950
        {"debug", 1, 0, 'd'},
        {"help", 0, 0, 'h'},
        {"quiet", 0, 0, 'q'},
        {"timing", 0, 0, 't'},
        {"version", 0, 0, 'v'},
K
Karel Zak 已提交
1951
        {"connect", 1, 0, 'c'},
K
Karel Zak 已提交
1952
        {0, 0, 0, 0}
1953 1954
    };

K
Karel Zak 已提交
1955 1956

    if (argc < 2)
K
Karel Zak 已提交
1957
        return TRUE;
1958

1959
    /* look for begin of the command, for example:
K
Karel Zak 已提交
1960 1961 1962 1963
     *   ./virsh --debug 5 -q command --cmdoption
     *                  <--- ^ --->
     *        getopt() stuff | command suff
     */
1964
    for (i = 1; i < argc; i++) {
K
Karel Zak 已提交
1965 1966
        if (*argv[i] != '-') {
            int valid = FALSE;
1967

K
Karel Zak 已提交
1968 1969 1970 1971
            /* non "--option" argv, is it command? */
            if (last) {
                struct option *o;
                int sz = strlen(last);
1972 1973 1974

                for (o = opt; o->name; o++) {
                    if (sz == 2 && *(last + 1) == o->val)
K
Karel Zak 已提交
1975 1976
                        /* valid virsh short option */
                        valid = TRUE;
1977
                    else if (sz > 2 && strcmp(o->name, last + 2) == 0)
K
Karel Zak 已提交
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989
                        /* valid virsh long option */
                        valid = TRUE;
                }
            }
            if (!valid) {
                end = i;
                break;
            }
        }
        last = argv[i];
    }
    end = end ? : argc;
1990

K
Karel Zak 已提交
1991
    /* standard (non-command) options */
1992 1993
    while ((arg = getopt_long(end, argv, "d:hqtv", opt, &idx)) != -1) {
        switch (arg) {
K
Karel Zak 已提交
1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005
            case 'd':
                ctl->debug = atoi(optarg);
                break;
            case 'h':
                help = 1;
                break;
            case 'q':
                ctl->quiet = TRUE;
                break;
            case 't':
                ctl->timing = TRUE;
                break;
K
Karel Zak 已提交
2006 2007 2008
            case 'c':
                ctl->name = vshStrdup(ctl, optarg);
                break;
K
Karel Zak 已提交
2009 2010 2011 2012
            case 'v':
                fprintf(stdout, "%s\n", VERSION);
                exit(EXIT_SUCCESS);
            default:
2013 2014
                vshError(ctl, TRUE,
                  "unsupported option '-%c'. See --help.", arg);
K
Karel Zak 已提交
2015 2016 2017 2018 2019 2020 2021 2022
                break;
        }
    }

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

K
Karel Zak 已提交
2025 2026 2027
    if (argc > end) {
        /* parse command */
        char *cmdstr;
2028 2029
        int sz = 0, ret;

K
Karel Zak 已提交
2030 2031
        ctl->imode = FALSE;

2032 2033 2034
        for (i = end; i < argc; i++)
            sz += strlen(argv[i]) + 1;  /* +1 is for blank space between items */

2035
        cmdstr = vshCalloc(ctl, sz + 1, 1);
2036 2037

        for (i = end; i < argc; i++) {
K
Karel Zak 已提交
2038 2039 2040 2041
            strncat(cmdstr, argv[i], sz);
            sz -= strlen(argv[i]);
            strncat(cmdstr, " ", sz--);
        }
K
Karel Zak 已提交
2042
        vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
K
Karel Zak 已提交
2043
        ret = vshCommandParse(ctl, cmdstr);
2044

K
Karel Zak 已提交
2045 2046 2047 2048 2049 2050
        free(cmdstr);
        return ret;
    }
    return TRUE;
}

2051 2052 2053 2054
int
main(int argc, char **argv)
{
    vshControl _ctl, *ctl = &_ctl;
K
Karel Zak 已提交
2055 2056
    int ret = TRUE;

2057
    if (!(progname = strrchr(argv[0], '/')))
K
Karel Zak 已提交
2058 2059 2060
        progname = argv[0];
    else
        progname++;
2061

K
Karel Zak 已提交
2062
    memset(ctl, 0, sizeof(vshControl));
2063
    ctl->imode = TRUE;          /* default is interactive mode */
K
Karel Zak 已提交
2064 2065 2066

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

K
Karel Zak 已提交
2068 2069
    if (!vshInit(ctl))
        exit(EXIT_FAILURE);
2070

K
Karel Zak 已提交
2071
    if (!ctl->imode) {
2072
        ret = vshCommandRun(ctl, ctl->cmd);
2073
    } else {
K
Karel Zak 已提交
2074 2075
        /* interactive mode */
        if (!ctl->quiet) {
K
Karel Zak 已提交
2076
            vshPrint(ctl,
2077 2078
                     "Welcome to %s, the virtualization interactive terminal.\n\n",
                     progname);
K
Karel Zak 已提交
2079
            vshPrint(ctl,
2080 2081
                     "Type:  'help' for help with commands\n"
                     "       'quit' to quit\n\n");
K
Karel Zak 已提交
2082
        }
K
Karel Zak 已提交
2083
        vshReadlineInit();
K
Karel Zak 已提交
2084
        do {
2085 2086 2087 2088
            ctl->cmdstr =
                readline(ctl->uid == 0 ? VSH_PROMPT_RW : VSH_PROMPT_RO);
            if (ctl->cmdstr == NULL)
                break;          /* EOF */
K
Karel Zak 已提交
2089 2090 2091 2092 2093 2094 2095
            if (*ctl->cmdstr) {
                add_history(ctl->cmdstr);
                if (vshCommandParse(ctl, ctl->cmdstr))
                    vshCommandRun(ctl, ctl->cmd);
            }
            free(ctl->cmdstr);
            ctl->cmdstr = NULL;
2096
        } while (ctl->imode);
K
Karel Zak 已提交
2097

2098 2099
        if (ctl->cmdstr == NULL)
            fputc('\n', stdout);        /* line break after alone prompt */
K
Karel Zak 已提交
2100
    }
2101

K
Karel Zak 已提交
2102 2103
    vshDeinit(ctl);
    exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
2104
}
K
Karel Zak 已提交
2105 2106 2107 2108 2109 2110

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