virsh.c 65.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
static const char *vshDomainVcpuStateToString(int state);
211 212
static int vshConnectionUsability(vshControl * ctl, virConnectPtr conn,
                                  int showerror);
K
Karel Zak 已提交
213

214 215 216 217 218 219 220 221 222
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 已提交
223 224 225 226 227 228 229 230 231
/* ---------------
 * Commands
 * ---------------
 */

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

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

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

    if (!cmdname) {
        vshCmdDef *def;
251

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

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

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

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

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

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

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

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

317 318 319 320 321 322
static vshCmdOptDef opts_list[] = {
    {"inactive", VSH_OT_BOOL, 0, "list inactive domains"},
    {"all", VSH_OT_BOOL, 0, "list inactive & active domains"},
    {NULL, 0, 0, NULL}
};

K
Karel Zak 已提交
323 324 325


static int
326 327
cmdList(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
328 329 330 331 332 333 334
    int inactive = vshCommandOptBool(cmd, "inactive");
    int all = vshCommandOptBool(cmd, "all");
    int active = !inactive || all ? 1 : 0;
    int *ids = NULL, maxid = 0, i;
    const char **names = NULL;
    int maxname = 0;
    inactive |= all;
K
Karel Zak 已提交
335 336 337

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
338 339 340 341
    
    if (active) {
      maxid = virConnectNumOfDomains(ctl->conn);
      if (maxid < 0) {
K
Karel Zak 已提交
342 343
        vshError(ctl, FALSE, "failed to list active domains.");
        return FALSE;
344 345
      }
      if (maxid) {
346
        ids = vshMalloc(ctl, sizeof(int) * maxid);
347
	
348
        if (virConnectListDomains(ctl->conn, &ids[0], maxid) < 0) {
349 350 351
	  vshError(ctl, FALSE, "failed to list active domains.");
	  free(ids);
	  return FALSE;
352
        }
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
      }
    }
    if (inactive) {
      maxname = virConnectNumOfDefinedDomains(ctl->conn);
      if (maxname < 0) {
        vshError(ctl, FALSE, "failed to list inactive domains.");
	if (ids)
	  free(ids);
        return FALSE;
      }
      if (maxname) {
        names = vshMalloc(ctl, sizeof(int) * maxname);
	
        if (virConnectListDefinedDomains(ctl->conn, names, maxname) < 0) {
	  vshError(ctl, FALSE, "failed to list inactive domains.");
	  if (ids)
	    free(ids);
	  free(names);
	  return FALSE;
        }
      }
374
    }
K
Karel Zak 已提交
375 376
    vshPrintExtra(ctl, "%3s %-20s %s\n", "Id", "Name", "State");
    vshPrintExtra(ctl, "----------------------------------\n");
377 378

    for (i = 0; i < maxid; i++) {
K
Karel Zak 已提交
379 380 381
        int ret;
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
382 383

        /* this kind of work with domains is not atomic operation */
K
Karel Zak 已提交
384 385 386
        if (!dom)
            continue;
        ret = virDomainGetInfo(dom, &info);
387

K
Karel Zak 已提交
388
        vshPrint(ctl, "%3d %-20s %s\n",
389 390 391 392
                 virDomainGetID(dom),
                 virDomainGetName(dom),
                 ret <
                 0 ? "no state" : vshDomainStateToString(info.state));
393
        virDomainFree(dom);
K
Karel Zak 已提交
394
    }
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
    for (i = 0; i < maxname; i++) {
        int ret;
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);

        /* this kind of work with domains is not atomic operation */
        if (!dom)
            continue;
        ret = virDomainGetInfo(dom, &info);

        vshPrint(ctl, "%3d %-20s %s\n",
                 virDomainGetID(dom),
		 names[i],
                 ret <
                 0 ? "no state" : vshDomainStateToString(info.state));
        virDomainFree(dom);
    }
412 413
    if (ids)
        free(ids);
414 415
    if (names)
        free(names);
K
Karel Zak 已提交
416 417 418 419
    return TRUE;
}

/*
K
Karel Zak 已提交
420
 * "domstate" command
K
Karel Zak 已提交
421
 */
K
Karel Zak 已提交
422 423
static vshCmdInfo info_domstate[] = {
    {"syntax", "domstate <domain>"},
424 425 426
    {"help", "domain state"},
    {"desc", "Returns state about a running domain."},
    {NULL, NULL}
K
Karel Zak 已提交
427 428
};

K
Karel Zak 已提交
429
static vshCmdOptDef opts_domstate[] = {
K
Karel Zak 已提交
430
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
431
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
432 433 434
};

static int
K
Karel Zak 已提交
435
cmdDomstate(vshControl * ctl, vshCmd * cmd)
436
{
437
    virDomainInfo info;
K
Karel Zak 已提交
438
    virDomainPtr dom;
K
Karel Zak 已提交
439
    int ret = TRUE;
440

K
Karel Zak 已提交
441 442
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
443

K
Karel Zak 已提交
444
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
K
Karel Zak 已提交
445
        return FALSE;
446 447

    if (virDomainGetInfo(dom, &info) == 0)
K
Karel Zak 已提交
448
        vshPrint(ctl, "%s\n",
449
                 vshDomainStateToString(info.state));
K
Karel Zak 已提交
450 451
    else
        ret = FALSE;
452

453 454 455 456 457 458 459 460
    virDomainFree(dom);
    return ret;
}

/*
 * "suspend" command
 */
static vshCmdInfo info_suspend[] = {
461 462 463 464
    {"syntax", "suspend <domain>"},
    {"help", "suspend a domain"},
    {"desc", "Suspend a running domain."},
    {NULL, NULL}
465 466 467
};

static vshCmdOptDef opts_suspend[] = {
K
Karel Zak 已提交
468
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
469
    {NULL, 0, 0, NULL}
470 471 472
};

static int
473 474
cmdSuspend(vshControl * ctl, vshCmd * cmd)
{
475
    virDomainPtr dom;
K
Karel Zak 已提交
476 477
    char *name;
    int ret = TRUE;
478

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

K
Karel Zak 已提交
482
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
483
        return FALSE;
484 485

    if (virDomainSuspend(dom) == 0) {
K
Karel Zak 已提交
486
        vshPrint(ctl, "Domain %s suspended\n", name);
487 488 489 490
    } else {
        vshError(ctl, FALSE, "Failed to suspend domain\n");
        ret = FALSE;
    }
491

492 493 494 495
    virDomainFree(dom);
    return ret;
}

496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
/*
 * "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 已提交
542
        vshPrint(ctl, "Domain %s created from %s\n", 
543 544 545 546 547 548 549 550
                 virDomainGetName(dom), from);
    } else {
        vshError(ctl, FALSE, "Failed to create domain\n");
        ret = FALSE;
    }
    return ret;
}

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
/*
 * "define" command
 */
static vshCmdInfo info_define[] = {
    {"syntax", "define a domain from an XML <file>"},
    {"help", "define (but don't start) a domain from an XML file"},
    {"desc", "Define a domain."},
    {NULL, NULL}
};

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

static int
cmdDefine(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 = virDomainDefineXML(ctl->conn, &buffer[0]);
    if (dom != NULL) {
        vshPrint(ctl, "Domain %s defined from %s\n",
                 virDomainGetName(dom), from);
    } else {
        vshError(ctl, FALSE, "Failed to define domain\n");
        ret = FALSE;
    }
    return ret;
}

/*
 * "undefine" command
 */
static vshCmdInfo info_undefine[] = {
    {"syntax", "undefine <domain>"},
    {"help", "Undefine an inactive domain"},
    {"desc", "Undefine the configuration for an inactive domain"},
    {NULL, NULL}
};

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

static int
cmdUndefine(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 (virDomainUndefine(dom) == 0) {
        vshPrint(ctl, "Domain %s has been undefined\n", name);
    } else {
        vshError(ctl, FALSE, "Failed to undefine domain\n");
        ret = FALSE;
    }

    return ret;
}


/*
 * "start" command
 */
static vshCmdInfo info_start[] = {
    {"syntax", "start a domain "},
    {"help", "start a (previously defined) inactive domain"},
    {"desc", "Start a domain."},
    {NULL, NULL}
};

static vshCmdOptDef opts_start[] = {
    {"name", VSH_OT_DATA, VSH_OFLAG_REQ, "name of the inactive domain" },
    {NULL, 0, 0, NULL}
};

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

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

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

    dom = virDomainLookupByName(ctl->conn, name);
    if (!dom)
        return FALSE;

    if (virDomainGetID(dom) != (unsigned int)-1) {
        vshError(ctl, FALSE, "Domain is already active\n");
        return FALSE;
    }

    if (virDomainCreate(dom) == 0) {
        vshPrint(ctl, "Domain %s started\n",
                 name);
    } else {
        vshError(ctl, FALSE, "Failed to start domain\n");
        ret = FALSE;
    }
    return ret;
}

694 695 696 697
/*
 * "save" command
 */
static vshCmdInfo info_save[] = {
698 699 700 701
    {"syntax", "save <domain> <file>"},
    {"help", "save a domain state to a file"},
    {"desc", "Save a running domain."},
    {NULL, NULL}
702 703 704
};

static vshCmdOptDef opts_save[] = {
K
Karel Zak 已提交
705
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
706 707
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, "where to save the data"},
    {NULL, 0, 0, NULL}
708 709 710
};

static int
711 712
cmdSave(vshControl * ctl, vshCmd * cmd)
{
713 714 715 716
    virDomainPtr dom;
    char *name;
    char *to;
    int ret = TRUE;
717

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

721
    if (!(to = vshCommandOptString(cmd, "file", NULL)))
722
        return FALSE;
723

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

    if (virDomainSave(dom, to) == 0) {
K
Karel Zak 已提交
728
        vshPrint(ctl, "Domain %s saved\n", name);
729 730 731 732
    } else {
        vshError(ctl, FALSE, "Failed to save domain\n");
        ret = FALSE;
    }
733

734 735 736 737 738 739 740 741
    virDomainFree(dom);
    return ret;
}

/*
 * "restore" command
 */
static vshCmdInfo info_restore[] = {
742 743 744 745
    {"syntax", "restore a domain from <file>"},
    {"help", "restore a domain from a saved state in a file"},
    {"desc", "Restore a domain."},
    {NULL, NULL}
746 747 748
};

static vshCmdOptDef opts_restore[] = {
749 750
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, "the state to restore"},
    {NULL, 0, 0, NULL}
751 752 753
};

static int
754 755
cmdRestore(vshControl * ctl, vshCmd * cmd)
{
756 757 758
    char *from;
    int found;
    int ret = TRUE;
759

760 761 762 763 764 765
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

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

    if (virDomainRestore(ctl->conn, from) == 0) {
K
Karel Zak 已提交
768
        vshPrint(ctl, "Domain restored from %s\n", from);
769 770 771 772 773 774 775
    } else {
        vshError(ctl, FALSE, "Failed to restore domain\n");
        ret = FALSE;
    }
    return ret;
}

776 777 778 779
/*
 * "resume" command
 */
static vshCmdInfo info_resume[] = {
780 781 782 783
    {"syntax", "resume <domain>"},
    {"help", "resume a domain"},
    {"desc", "Resume a previously suspended domain."},
    {NULL, NULL}
784 785 786
};

static vshCmdOptDef opts_resume[] = {
K
Karel Zak 已提交
787
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
788
    {NULL, 0, 0, NULL}
789 790 791
};

static int
792 793
cmdResume(vshControl * ctl, vshCmd * cmd)
{
794
    virDomainPtr dom;
K
Karel Zak 已提交
795 796
    int ret = TRUE;
    char *name;
797

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

K
Karel Zak 已提交
801
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
802
        return FALSE;
803 804

    if (virDomainResume(dom) == 0) {
K
Karel Zak 已提交
805
        vshPrint(ctl, "Domain %s resumed\n", name);
806 807 808 809
    } else {
        vshError(ctl, FALSE, "Failed to resume domain\n");
        ret = FALSE;
    }
810

811 812 813 814
    virDomainFree(dom);
    return ret;
}

815 816 817 818
/*
 * "shutdown" command
 */
static vshCmdInfo info_shutdown[] = {
819 820 821 822
    {"syntax", "shutdown <domain>"},
    {"help", "gracefully shutdown a domain"},
    {"desc", "Run shutdown in the targetted domain"},
    {NULL, NULL}
823 824 825
};

static vshCmdOptDef opts_shutdown[] = {
K
Karel Zak 已提交
826
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
827
    {NULL, 0, 0, NULL}
828 829 830
};

static int
831 832
cmdShutdown(vshControl * ctl, vshCmd * cmd)
{
833 834 835
    virDomainPtr dom;
    int ret = TRUE;
    char *name;
836

837 838 839 840 841
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

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

    if (virDomainShutdown(dom) == 0) {
K
Karel Zak 已提交
844
        vshPrint(ctl, "Domain %s is being shutdown\n", name);
845 846 847 848
    } else {
        vshError(ctl, FALSE, "Failed to shutdown domain\n");
        ret = FALSE;
    }
849

850 851 852 853
    virDomainFree(dom);
    return ret;
}

854 855 856 857 858 859 860 861 862 863 864
/*
 * "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 已提交
865
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882
    {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 已提交
883
        vshPrint(ctl, "Domain %s is being rebooted\n", name);
884 885 886 887 888 889 890 891 892
    } else {
        vshError(ctl, FALSE, "Failed to reboot domain\n");
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

893 894 895 896
/*
 * "destroy" command
 */
static vshCmdInfo info_destroy[] = {
897 898 899 900
    {"syntax", "destroy <domain>"},
    {"help", "destroy a domain"},
    {"desc", "Destroy a given domain."},
    {NULL, NULL}
901 902 903
};

static vshCmdOptDef opts_destroy[] = {
K
Karel Zak 已提交
904
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
905
    {NULL, 0, 0, NULL}
906 907 908
};

static int
909 910
cmdDestroy(vshControl * ctl, vshCmd * cmd)
{
911
    virDomainPtr dom;
K
Karel Zak 已提交
912 913
    int ret = TRUE;
    char *name;
914

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

K
Karel Zak 已提交
918
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
919
        return FALSE;
920 921

    if (virDomainDestroy(dom) == 0) {
K
Karel Zak 已提交
922
        vshPrint(ctl, "Domain %s destroyed\n", name);
923 924 925 926 927
    } else {
        vshError(ctl, FALSE, "Failed to destroy domain\n");
        ret = FALSE;
        virDomainFree(dom);
    }
928

K
Karel Zak 已提交
929 930 931 932
    return ret;
}

/*
933
 * "dominfo" command
K
Karel Zak 已提交
934
 */
935 936
static vshCmdInfo info_dominfo[] = {
    {"syntax", "dominfo <domain>"},
937 938 939
    {"help", "domain information"},
    {"desc", "Returns basic information about the domain."},
    {NULL, NULL}
K
Karel Zak 已提交
940 941
};

942
static vshCmdOptDef opts_dominfo[] = {
K
Karel Zak 已提交
943
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
944
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
945 946 947
};

static int
948
cmdDominfo(vshControl * ctl, vshCmd * cmd)
949
{
K
Karel Zak 已提交
950 951
    virDomainInfo info;
    virDomainPtr dom;
K
Karel Zak 已提交
952
    int ret = TRUE;
K
Karel Zak 已提交
953
    char *str, uuid[37];
954

K
Karel Zak 已提交
955 956 957
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

K
Karel Zak 已提交
958
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
K
Karel Zak 已提交
959
        return FALSE;
960

K
Karel Zak 已提交
961 962 963 964
    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);
965 966

    if ((str = virDomainGetOSType(dom))) {
K
Karel Zak 已提交
967
        vshPrint(ctl, "%-15s %s\n", "OS Type:", str);
968 969 970 971
        free(str);
    }

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

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

        if (info.cpuTime != 0) {
978
	    double cpuUsed = info.cpuTime;
979

980
            cpuUsed /= 1000000000.0;
981

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

K
Karel Zak 已提交
985
        vshPrint(ctl, "%-15s %lu kB\n", "Max memory:",
986
                 info.maxMem);
K
Karel Zak 已提交
987
        vshPrint(ctl, "%-15s %lu kB\n", "Used memory:",
988 989
                 info.memory);

K
Karel Zak 已提交
990 991 992
    } else {
        ret = FALSE;
    }
993

994
    virDomainFree(dom);
K
Karel Zak 已提交
995 996 997
    return ret;
}

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
/*
 * "vcpuinfo" command
 */
static vshCmdInfo info_vcpuinfo[] = {
    {"syntax", "vcpuinfo <domain>"},
    {"help", "domain vcpu information"},
    {"desc", "Returns basic information about the domain virtual CPUs."},
    {NULL, NULL}
};

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

static int
cmdVcpuinfo(vshControl * ctl, vshCmd * cmd)
{
    virDomainInfo info;
    virDomainPtr dom;
    virNodeInfo nodeinfo;
    virVcpuInfoPtr cpuinfo;
    unsigned char *cpumap;
    int ncpus;
    size_t cpumaplen;
    int ret = TRUE;

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

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

    if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
        virDomainFree(dom);
	return FALSE;
    }

    if (virDomainGetInfo(dom, &info) != 0) {
        virDomainFree(dom);
        return FALSE;
    }

    cpuinfo = malloc(sizeof(virVcpuInfo)*info.nrVirtCpu);
    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
    cpumap = malloc(info.nrVirtCpu * cpumaplen);

    if ((ncpus = virDomainGetVcpus(dom, 
				   cpuinfo, info.nrVirtCpu,
				   cpumap, cpumaplen)) >= 0) {
        int n;
	for (n = 0 ; n < ncpus ; n++) {
	    unsigned int m;
	    vshPrint(ctl, "%-15s %d\n", "VCPU:", n);
	    vshPrint(ctl, "%-15s %d\n", "CPU:", cpuinfo[n].cpu);
	    vshPrint(ctl, "%-15s %s\n", "State:",
		     vshDomainVcpuStateToString(cpuinfo[n].state));
	    if (cpuinfo[n].cpuTime != 0) {
	        double cpuUsed = cpuinfo[n].cpuTime;
		
		cpuUsed /= 1000000000.0;
		
		vshPrint(ctl, "%-15s %.1lfs\n", "CPU time:", cpuUsed);
	    }
	    vshPrint(ctl, "%-15s ", "CPU Affinity:");
	    for (m = 0 ; m < VIR_NODEINFO_MAXCPUS(nodeinfo) ; m++) {
	        vshPrint(ctl, "%c", VIR_CPU_USABLE(cpumap, cpumaplen, n, m) ? 'y' : '-');
	    }
	    vshPrint(ctl, "\n");
	    if (n < (ncpus - 1)) {
	        vshPrint(ctl, "\n");
	    }
	}
    } else {
        ret = FALSE;
    }

    free(cpumap);
    free(cpuinfo);
    virDomainFree(dom);
    return ret;
}

/*
 * "vcpupin" command
 */
static vshCmdInfo info_vcpupin[] = {
    {"syntax", "vcpupin <domain>"},
    {"help", "control domain vcpu affinity"},
    {"desc", "Pin domain VCPUs to host physical CPUs"},
    {NULL, NULL}
};

static vshCmdOptDef opts_vcpupin[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
    {"vcpu", VSH_OT_DATA, VSH_OFLAG_REQ, "vcpu number"},
    {"cpulist", VSH_OT_DATA, VSH_OFLAG_REQ, "host cpu number(s) (comma separated)"},
    {NULL, 0, 0, NULL}
};

static int
cmdVcpupin(vshControl * ctl, vshCmd * cmd)
{
    virDomainInfo info;
    virDomainPtr dom;
    virNodeInfo nodeinfo;
    int vcpu;
    char *cpulist;
    int ret = TRUE;
    int vcpufound = 0;
    unsigned char *cpumap;
    int cpumaplen;

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

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

    vcpu = vshCommandOptInt(cmd, "vcpu", &vcpufound);
    if (!vcpufound) {
        virDomainFree(dom);
        return FALSE;
    }

    if (!(cpulist = vshCommandOptString(cmd, "cpulist", NULL))) {
        virDomainFree(dom);
        return FALSE;
    }
      
    if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
        virDomainFree(dom);
        return FALSE;
    }

    if (virDomainGetInfo(dom, &info) != 0) {
        virDomainFree(dom);
        return FALSE;
    }

    if (vcpu >= info.nrVirtCpu) {
        virDomainFree(dom);
        return FALSE;
    }

    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
    cpumap = malloc(cpumaplen);
    memset(cpumap, 0, cpumaplen);

    do {
        unsigned int cpu = atoi(cpulist);

        if (cpu < VIR_NODEINFO_MAXCPUS(nodeinfo)) {
            VIR_USE_CPU(cpumap, cpu);
        }
        cpulist = index(cpulist, ',');
        if (cpulist)
            cpulist++;
    } while (cpulist);

    if (virDomainPinVcpu(dom, vcpu, cpumap, cpumaplen) != 0) {
        ret = FALSE;
    }

    free(cpumap);
    virDomainFree(dom);
    return ret;
}

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
/*
 * "setvcpus" command
 */
static vshCmdInfo info_setvcpus[] = {
    {"syntax", "setvcpus <domain> <count>"},
    {"help", "change number of virtual CPUs"},
    {"desc", "Change the number of virtual CPUs active in the guest domain"},
    {NULL, NULL}
};

static vshCmdOptDef opts_setvcpus[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
    {"count", VSH_OT_DATA, VSH_OFLAG_REQ, "number of virtual CPUs"},
    {NULL, 0, 0, NULL}
};

static int
cmdSetvcpus(vshControl * ctl, vshCmd * cmd)
{
    virDomainPtr dom;
    int count;
    int ret = TRUE;

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

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

    count = vshCommandOptInt(cmd, "count", &count);
    if (!count) {
        virDomainFree(dom);
        return FALSE;
    }

    if (virDomainSetVcpus(dom, count) != 0) {
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

/*
 * "setmemory" command
 */
static vshCmdInfo info_setmem[] = {
    {"syntax", "setmem <domain> <bytes>"},
    {"help", "change memory allocation"},
    {"desc", "Change the current memory allocation in the guest domain"},
    {NULL, NULL}
};

static vshCmdOptDef opts_setmem[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
    {"bytes", VSH_OT_DATA, VSH_OFLAG_REQ, "number of bytes of memory"},
    {NULL, 0, 0, NULL}
};

static int
cmdSetmem(vshControl * ctl, vshCmd * cmd)
{
    virDomainPtr dom;
    int bytes;
    int ret = TRUE;

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

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

    bytes = vshCommandOptInt(cmd, "bytes", &bytes);
    if (!bytes) {
        virDomainFree(dom);
        return FALSE;
    }

    if (virDomainSetMemory(dom, bytes) != 0) {
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

/*
 * "setmaxmem" command
 */
static vshCmdInfo info_setmaxmem[] = {
    {"syntax", "setmaxmem <domain> <bytes>"},
    {"help", "change maximum memory limit"},
    {"desc", "Change the maximum memory allocation limit in the guest domain"},
    {NULL, NULL}
};

static vshCmdOptDef opts_setmaxmem[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"},
    {"bytes", VSH_OT_DATA, VSH_OFLAG_REQ, "maxmimum memory limit in bytes"},
    {NULL, 0, 0, NULL}
};

static int
cmdSetmaxmem(vshControl * ctl, vshCmd * cmd)
{
    virDomainPtr dom;
    int bytes;
    int ret = TRUE;

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

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

    bytes = vshCommandOptInt(cmd, "bytes", &bytes);
    if (!bytes) {
        virDomainFree(dom);
        return FALSE;
    }

    if (virDomainSetMaxMemory(dom, bytes) != 0) {
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
/*
 * "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 已提交
1318 1319 1320 1321 1322 1323 1324 1325
    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);
1326 1327 1328 1329
        
    return TRUE;
}

1330 1331 1332 1333
/*
 * "dumpxml" command
 */
static vshCmdInfo info_dumpxml[] = {
1334 1335
    {"syntax", "dumpxml <name>"},
    {"help", "domain information in XML"},
1336
    {"desc", "Ouput the domain information as an XML dump to stdout"},
1337
    {NULL, NULL}
1338 1339 1340
};

static vshCmdOptDef opts_dumpxml[] = {
K
Karel Zak 已提交
1341
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id, uuid"},
1342
    {NULL, 0, 0, NULL}
1343 1344 1345
};

static int
1346 1347
cmdDumpXML(vshControl * ctl, vshCmd * cmd)
{
1348
    virDomainPtr dom;
K
Karel Zak 已提交
1349
    int ret = TRUE;
1350
    char *dump;
1351

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

K
Karel Zak 已提交
1355
    if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
1356
        return FALSE;
1357

1358 1359 1360 1361 1362 1363 1364
    dump = virDomainGetXMLDesc(dom, 0);
    if (dump != NULL) {
        printf("%s", dump);
        free(dump);
    } else {
        ret = FALSE;
    }
1365

1366 1367 1368 1369
    virDomainFree(dom);
    return ret;
}

K
Karel Zak 已提交
1370
/*
K
Karel Zak 已提交
1371
 * "domname" command
K
Karel Zak 已提交
1372
 */
K
Karel Zak 已提交
1373
static vshCmdInfo info_domname[] = {
K
Karel Zak 已提交
1374 1375
    {"syntax", "domname <domain>"},
    {"help", "convert a domain Id or UUID to domain name"},
1376
    {NULL, NULL}
K
Karel Zak 已提交
1377 1378
};

K
Karel Zak 已提交
1379
static vshCmdOptDef opts_domname[] = {
K
Karel Zak 已提交
1380
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain id or uuid"},
1381
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
1382 1383 1384
};

static int
K
Karel Zak 已提交
1385
cmdDomname(vshControl * ctl, vshCmd * cmd)
1386
{
K
Karel Zak 已提交
1387 1388 1389 1390
    virDomainPtr dom;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
K
Karel Zak 已提交
1391 1392
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, 
                                    VSH_DOMBYID|VSH_DOMBYUUID)))
K
Karel Zak 已提交
1393
        return FALSE;
1394

K
Karel Zak 已提交
1395 1396
    vshPrint(ctl, "%s\n", virDomainGetName(dom));
    virDomainFree(dom);
K
Karel Zak 已提交
1397 1398 1399 1400
    return TRUE;
}

/*
K
Karel Zak 已提交
1401
 * "domid" command
K
Karel Zak 已提交
1402
 */
K
Karel Zak 已提交
1403
static vshCmdInfo info_domid[] = {
K
Karel Zak 已提交
1404 1405
    {"syntax", "domid <domain>"},
    {"help", "convert a domain name or UUID to domain Id"},
1406
    {NULL, NULL}
K
Karel Zak 已提交
1407 1408
};

K
Karel Zak 已提交
1409
static vshCmdOptDef opts_domid[] = {
K
Karel Zak 已提交
1410
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name or uuid"},
1411
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
1412 1413 1414
};

static int
K
Karel Zak 已提交
1415
cmdDomid(vshControl * ctl, vshCmd * cmd)
1416
{
1417
    virDomainPtr dom;
K
Karel Zak 已提交
1418 1419 1420

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
K
Karel Zak 已提交
1421 1422
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, 
                                    VSH_DOMBYNAME|VSH_DOMBYUUID)))
K
Karel Zak 已提交
1423
        return FALSE;
K
Karel Zak 已提交
1424 1425 1426 1427 1428
    
    vshPrint(ctl, "%d\n", virDomainGetID(dom));
    virDomainFree(dom);
    return TRUE;
}
1429

K
Karel Zak 已提交
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
/*
 * "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 已提交
1451
        return FALSE;
K
Karel Zak 已提交
1452 1453 1454 1455 1456 1457 1458 1459 1460
    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 已提交
1461 1462 1463
    return TRUE;
}

K
Karel Zak 已提交
1464

1465 1466 1467 1468
/*
 * "version" command
 */
static vshCmdInfo info_version[] = {
1469 1470
    {"syntax", "version"},
    {"help", "show versions"},
1471
    {"desc", "Display the version information available"},
1472
    {NULL, NULL}
1473 1474 1475 1476
};


static int
1477 1478
cmdVersion(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
1479 1480
    unsigned long hvVersion;
    const char *hvType;
1481 1482 1483 1484 1485 1486 1487
    unsigned long libVersion;
    unsigned long includeVersion;
    unsigned long apiVersion;
    int ret;
    unsigned int major;
    unsigned int minor;
    unsigned int rel;
1488 1489 1490

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

1492 1493
    hvType = virConnectGetType(ctl->conn);
    if (hvType == NULL) {
K
Karel Zak 已提交
1494
        vshError(ctl, FALSE, "failed to get hypervisor type\n");
1495 1496 1497
        return FALSE;
    }

1498 1499 1500 1501 1502
    includeVersion = LIBVIR_VERSION_NUMBER;
    major = includeVersion / 1000000;
    includeVersion %= 1000000;
    minor = includeVersion / 1000;
    rel = includeVersion % 1000;
K
Karel Zak 已提交
1503
    vshPrint(ctl, "Compiled against library: libvir %d.%d.%d\n",
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
             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 已提交
1515
    vshPrint(ctl, "Using library: libvir %d.%d.%d\n",
1516
             major, minor, rel);
1517

1518 1519 1520 1521
    major = apiVersion / 1000000;
    apiVersion %= 1000000;
    minor = apiVersion / 1000;
    rel = apiVersion % 1000;
K
Karel Zak 已提交
1522
    vshPrint(ctl, "Using API: %s %d.%d.%d\n", hvType,
1523 1524
             major, minor, rel);

1525
    ret = virConnectGetVersion(ctl->conn, &hvVersion);
1526 1527
    if (ret < 0) {
        vshError(ctl, FALSE, "failed to get the hypervisor version");
1528 1529 1530
        return FALSE;
    }
    if (hvVersion == 0) {
K
Karel Zak 已提交
1531
        vshPrint(ctl,
1532
                 "cannot extract running %s hypervisor version\n", hvType);
1533
    } else {
1534
        major = hvVersion / 1000000;
1535
        hvVersion %= 1000000;
1536 1537
        minor = hvVersion / 1000;
        rel = hvVersion % 1000;
1538

K
Karel Zak 已提交
1539
        vshPrint(ctl, "Running hypervisor: %s %d.%d.%d\n",
1540
                 hvType, major, minor, rel);
1541 1542 1543 1544
    }
    return TRUE;
}

K
Karel Zak 已提交
1545 1546 1547 1548
/*
 * "quit" command
 */
static vshCmdInfo info_quit[] = {
1549 1550 1551
    {"syntax", "quit"},
    {"help", "quit this interactive terminal"},
    {NULL, NULL}
K
Karel Zak 已提交
1552 1553 1554
};

static int
1555 1556
cmdQuit(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
1557 1558 1559 1560 1561 1562 1563 1564
    ctl->imode = FALSE;
    return TRUE;
}

/*
 * Commands
 */
static vshCmdDef commands[] = {
1565
    {"connect", cmdConnect, opts_connect, info_connect},
1566
    {"create", cmdCreate, opts_create, info_create},
1567
    {"start", cmdStart, opts_start, info_start},
K
Karel Zak 已提交
1568
    {"destroy", cmdDestroy, opts_destroy, info_destroy},
1569
    {"define", cmdDefine, opts_define, info_define},
K
Karel Zak 已提交
1570
    {"domid", cmdDomid, opts_domid, info_domid},
K
Karel Zak 已提交
1571
    {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
1572
    {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
K
Karel Zak 已提交
1573 1574
    {"domname", cmdDomname, opts_domname, info_domname},
    {"domstate", cmdDomstate, opts_domstate, info_domstate},
1575
    {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
K
Karel Zak 已提交
1576
    {"help", cmdHelp, opts_help, info_help},
1577
    {"list", cmdList, opts_list, info_list},
K
Karel Zak 已提交
1578 1579 1580 1581
    {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
    {"quit", cmdQuit, NULL, info_quit},
    {"reboot", cmdReboot, opts_reboot, info_reboot},
    {"restore", cmdRestore, opts_restore, info_restore},
1582 1583 1584
    {"resume", cmdResume, opts_resume, info_resume},
    {"save", cmdSave, opts_save, info_save},
    {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
1585 1586 1587
    {"setmem", cmdSetmem, opts_setmem, info_setmem},
    {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
    {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
K
Karel Zak 已提交
1588
    {"suspend", cmdSuspend, opts_suspend, info_suspend},
1589
    {"undefine", cmdUndefine, opts_undefine, info_undefine},
1590 1591
    {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
    {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
1592 1593
    {"version", cmdVersion, NULL, info_version},
    {NULL, NULL, NULL, NULL}
K
Karel Zak 已提交
1594 1595 1596 1597 1598 1599
};

/* ---------------
 * Utils for work with command definition
 * ---------------
 */
K
Karel Zak 已提交
1600
static const char *
1601 1602
vshCmddefGetInfo(vshCmdDef * cmd, const char *name)
{
K
Karel Zak 已提交
1603
    vshCmdInfo *info;
1604

K
Karel Zak 已提交
1605
    for (info = cmd->info; info && info->name; info++) {
1606
        if (strcmp(info->name, name) == 0)
K
Karel Zak 已提交
1607 1608 1609 1610 1611 1612
            return info->data;
    }
    return NULL;
}

static vshCmdOptDef *
1613 1614
vshCmddefGetOption(vshCmdDef * cmd, const char *name)
{
K
Karel Zak 已提交
1615
    vshCmdOptDef *opt;
1616

K
Karel Zak 已提交
1617
    for (opt = cmd->opts; opt && opt->name; opt++)
1618
        if (strcmp(opt->name, name) == 0)
K
Karel Zak 已提交
1619 1620 1621 1622 1623
            return opt;
    return NULL;
}

static vshCmdOptDef *
1624 1625
vshCmddefGetData(vshCmdDef * cmd, int data_ct)
{
K
Karel Zak 已提交
1626 1627
    vshCmdOptDef *opt;

1628
    for (opt = cmd->opts; opt && opt->name; opt++) {
1629 1630
        if (opt->type == VSH_OT_DATA) {
            if (data_ct == 0)
1631 1632 1633 1634 1635
                return opt;
            else
                data_ct--;
        }
    }
K
Karel Zak 已提交
1636 1637 1638
    return NULL;
}

1639 1640 1641
/*
 * Checks for required options
 */
1642 1643
static int
vshCommandCheckOpts(vshControl * ctl, vshCmd * cmd)
1644 1645 1646
{
    vshCmdDef *def = cmd->def;
    vshCmdOptDef *d;
1647
    int err = 0;
1648 1649 1650 1651

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

            while (o && ok == 0) {
1655
                if (o->def == d)
1656
                    ok = 1;
1657 1658 1659
                o = o->next;
            }
            if (!ok) {
1660 1661 1662 1663 1664
                vshError(ctl, FALSE,
                         d->type == VSH_OT_DATA ?
                         "command '%s' requires <%s> option" :
                         "command '%s' requires --%s option",
                         def->name, d->name);
1665 1666
                err = 1;
            }
1667

1668 1669 1670 1671 1672
        }
    }
    return !err;
}

K
Karel Zak 已提交
1673
static vshCmdDef *
1674 1675
vshCmddefSearch(const char *cmdname)
{
K
Karel Zak 已提交
1676
    vshCmdDef *c;
1677

K
Karel Zak 已提交
1678
    for (c = commands; c->name; c++)
1679
        if (strcmp(c->name, cmdname) == 0)
K
Karel Zak 已提交
1680 1681 1682 1683 1684
            return c;
    return NULL;
}

static int
1685 1686
vshCmddefHelp(vshControl * ctl, const char *cmdname, int withprog)
{
K
Karel Zak 已提交
1687
    vshCmdDef *def = vshCmddefSearch(cmdname);
1688

K
Karel Zak 已提交
1689
    if (!def) {
1690 1691 1692
        vshError(ctl, FALSE, "command '%s' doesn't exist", cmdname);
        return FALSE;
    } else {
K
Karel Zak 已提交
1693
        vshCmdOptDef *opt;
K
Karel Zak 已提交
1694 1695 1696
        const char *desc = vshCmddefGetInfo(def, "desc");
        const char *help = vshCmddefGetInfo(def, "help");
        const char *syntax = vshCmddefGetInfo(def, "syntax");
K
Karel Zak 已提交
1697 1698

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

K
Karel Zak 已提交
1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
        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);
1714
            for (opt = def->opts; opt->name; opt++) {
K
Karel Zak 已提交
1715
                char buf[256];
1716 1717

                if (opt->type == VSH_OT_BOOL)
K
Karel Zak 已提交
1718
                    snprintf(buf, sizeof(buf), "--%s", opt->name);
1719
                else if (opt->type == VSH_OT_INT)
K
Karel Zak 已提交
1720
                    snprintf(buf, sizeof(buf), "--%s <number>", opt->name);
1721
                else if (opt->type == VSH_OT_STRING)
K
Karel Zak 已提交
1722
                    snprintf(buf, sizeof(buf), "--%s <string>", opt->name);
1723
                else if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
1724
                    snprintf(buf, sizeof(buf), "<%s>", opt->name);
1725

K
Karel Zak 已提交
1726
                fprintf(stdout, "    %-15s  %s\n", buf, opt->help);
1727
            }
K
Karel Zak 已提交
1728 1729 1730 1731 1732 1733 1734 1735 1736 1737
        }
        fputc('\n', stdout);
    }
    return TRUE;
}

/* ---------------
 * Utils for work with runtime commands data
 * ---------------
 */
1738 1739 1740
static void
vshCommandOptFree(vshCmdOpt * arg)
{
K
Karel Zak 已提交
1741 1742
    vshCmdOpt *a = arg;

1743
    while (a) {
K
Karel Zak 已提交
1744
        vshCmdOpt *tmp = a;
1745

K
Karel Zak 已提交
1746 1747 1748 1749 1750 1751 1752 1753 1754
        a = a->next;

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

static void
1755 1756
vshCommandFree(vshCmd * cmd)
{
K
Karel Zak 已提交
1757 1758
    vshCmd *c = cmd;

1759
    while (c) {
K
Karel Zak 已提交
1760
        vshCmd *tmp = c;
1761

K
Karel Zak 已提交
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
        c = c->next;

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

/*
 * Returns option by name
 */
static vshCmdOpt *
1774 1775
vshCommandOpt(vshCmd * cmd, const char *name)
{
K
Karel Zak 已提交
1776
    vshCmdOpt *opt = cmd->opts;
1777 1778 1779

    while (opt) {
        if (opt->def && strcmp(opt->def->name, name) == 0)
K
Karel Zak 已提交
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789
            return opt;
        opt = opt->next;
    }
    return NULL;
}

/*
 * Returns option as INT
 */
static int
1790 1791
vshCommandOptInt(vshCmd * cmd, const char *name, int *found)
{
K
Karel Zak 已提交
1792 1793
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
    int res = 0;
1794

K
Karel Zak 已提交
1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805
    if (arg)
        res = atoi(arg->data);
    if (found)
        *found = arg ? TRUE : FALSE;
    return res;
}

/*
 * Returns option as STRING
 */
static char *
1806 1807
vshCommandOptString(vshCmd * cmd, const char *name, int *found)
{
K
Karel Zak 已提交
1808
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
1809

K
Karel Zak 已提交
1810 1811
    if (found)
        *found = arg ? TRUE : FALSE;
1812 1813

    return arg && arg->data && *arg->data ? arg->data : NULL;
K
Karel Zak 已提交
1814 1815 1816 1817 1818 1819
}

/*
 * Returns TRUE/FALSE if the option exists
 */
static int
1820 1821
vshCommandOptBool(vshCmd * cmd, const char *name)
{
K
Karel Zak 已提交
1822 1823 1824
    return vshCommandOpt(cmd, name) ? TRUE : FALSE;
}

1825

K
Karel Zak 已提交
1826
static virDomainPtr
K
Karel Zak 已提交
1827 1828
vshCommandOptDomainBy(vshControl * ctl, vshCmd * cmd, const char *optname,
                    char **name, int flag)
1829
{
K
Karel Zak 已提交
1830 1831 1832
    virDomainPtr dom = NULL;
    char *n, *end = NULL;
    int id;
1833

K
Karel Zak 已提交
1834 1835
    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
        vshError(ctl, FALSE, "undefined domain name or id");
1836
        return NULL;
K
Karel Zak 已提交
1837
    }
1838

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

K
Karel Zak 已提交
1842 1843
    if (name)
        *name = n;
1844

K
Karel Zak 已提交
1845
    /* try it by ID */
K
Karel Zak 已提交
1846 1847 1848 1849 1850 1851 1852
    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);
        }
1853
    }
K
Karel Zak 已提交
1854
    /* try it by UUID */
K
Karel Zak 已提交
1855
    if (dom==NULL && (flag & VSH_DOMBYUUID) && strlen(n)==36) {
K
Karel Zak 已提交
1856 1857
        vshDebug(ctl, 5, "%s: <%s> tring as domain UUID\n",
                cmd->def->name, optname);
K
Karel Zak 已提交
1858
        dom = virDomainLookupByUUIDString(ctl->conn, n);
K
Karel Zak 已提交
1859
    }
K
Karel Zak 已提交
1860
    /* try it by NAME */
K
Karel Zak 已提交
1861
    if (dom==NULL && (flag & VSH_DOMBYNAME)) {
K
Karel Zak 已提交
1862
        vshDebug(ctl, 5, "%s: <%s> tring as domain NAME\n",
1863
                 cmd->def->name, optname);
K
Karel Zak 已提交
1864
        dom = virDomainLookupByName(ctl->conn, n);
1865
    }
K
Karel Zak 已提交
1866

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

K
Karel Zak 已提交
1870 1871 1872
    return dom;
}

K
Karel Zak 已提交
1873 1874 1875 1876
/*
 * Executes command(s) and returns return code from last command
 */
static int
1877 1878
vshCommandRun(vshControl * ctl, vshCmd * cmd)
{
K
Karel Zak 已提交
1879
    int ret = TRUE;
1880 1881

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

K
Karel Zak 已提交
1884 1885
        if (ctl->timing)
            GETTIMEOFDAY(&before);
1886

K
Karel Zak 已提交
1887 1888 1889 1890
        ret = cmd->def->handler(ctl, cmd);

        if (ctl->timing)
            GETTIMEOFDAY(&after);
1891 1892

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

        if (ctl->timing)
K
Karel Zak 已提交
1896
            vshPrint(ctl, "\n(Time: %.3f ms)\n\n",
1897 1898
                     DIFF_MSEC(&after, &before));
        else
K
Karel Zak 已提交
1899
            vshPrintExtra(ctl, "\n");
K
Karel Zak 已提交
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914
        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

1915 1916 1917
static int
vshCommandGetToken(vshControl * ctl, char *str, char **end, char **res)
{
K
Karel Zak 已提交
1918 1919 1920 1921 1922
    int tk = VSH_TK_NONE;
    int quote = FALSE;
    int sz = 0;
    char *p = str;
    char *tkstr = NULL;
1923

K
Karel Zak 已提交
1924
    *end = NULL;
1925 1926

    while (p && *p && isblank((unsigned char) *p))
K
Karel Zak 已提交
1927
        p++;
1928 1929

    if (p == NULL || *p == '\0')
K
Karel Zak 已提交
1930
        return VSH_TK_END;
1931 1932
    if (*p == ';') {
        *end = ++p;             /* = \0 or begi of next command */
K
Karel Zak 已提交
1933 1934
        return VSH_TK_END;
    }
1935
    while (*p) {
K
Karel Zak 已提交
1936
        /* end of token is blank space or ';' */
1937
        if ((quote == FALSE && isblank((unsigned char) *p)) || *p == ';')
K
Karel Zak 已提交
1938
            break;
1939

1940
        /* end of option name could be '=' */
1941 1942
        if (tk == VSH_TK_OPTION && *p == '=') {
            p++;                /* skip '=' */
1943 1944
            break;
        }
1945 1946 1947 1948

        if (tk == VSH_TK_NONE) {
            if (*p == '-' && *(p + 1) == '-' && *(p + 2)
                && isalnum((unsigned char) *(p + 2))) {
K
Karel Zak 已提交
1949
                tk = VSH_TK_OPTION;
1950
                p += 2;
K
Karel Zak 已提交
1951 1952
            } else {
                tk = VSH_TK_DATA;
1953 1954
                if (*p == '"') {
                    quote = TRUE;
K
Karel Zak 已提交
1955 1956 1957 1958 1959
                    p++;
                } else {
                    quote = FALSE;
                }
            }
1960 1961
            tkstr = p;          /* begin of token */
        } else if (quote && *p == '"') {
K
Karel Zak 已提交
1962 1963
            quote = FALSE;
            p++;
1964
            break;              /* end of "..." token */
K
Karel Zak 已提交
1965 1966 1967 1968 1969 1970 1971 1972
        }
        p++;
        sz++;
    }
    if (quote) {
        vshError(ctl, FALSE, "missing \"");
        return VSH_TK_ERROR;
    }
1973
    if (tkstr == NULL || *tkstr == '\0' || p == NULL)
K
Karel Zak 已提交
1974
        return VSH_TK_END;
1975
    if (sz == 0)
K
Karel Zak 已提交
1976
        return VSH_TK_END;
1977

1978
    *res = vshMalloc(ctl, sz + 1);
K
Karel Zak 已提交
1979
    memcpy(*res, tkstr, sz);
1980
    *(*res + sz) = '\0';
K
Karel Zak 已提交
1981 1982 1983 1984 1985 1986

    *end = p;
    return tk;
}

static int
1987 1988
vshCommandParse(vshControl * ctl, char *cmdstr)
{
K
Karel Zak 已提交
1989 1990 1991 1992
    char *str;
    char *tkdata = NULL;
    vshCmd *clast = NULL;
    vshCmdOpt *first = NULL;
1993

K
Karel Zak 已提交
1994 1995 1996 1997
    if (ctl->cmd) {
        vshCommandFree(ctl->cmd);
        ctl->cmd = NULL;
    }
1998 1999

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

K
Karel Zak 已提交
2002
    str = cmdstr;
2003
    while (str && *str) {
K
Karel Zak 已提交
2004 2005 2006
        vshCmdOpt *last = NULL;
        vshCmdDef *cmd = NULL;
        int tk = VSH_TK_NONE;
2007
        int data_ct = 0;
2008

K
Karel Zak 已提交
2009
        first = NULL;
2010 2011

        while (tk != VSH_TK_END) {
K
Karel Zak 已提交
2012 2013
            char *end = NULL;
            vshCmdOptDef *opt = NULL;
2014

K
Karel Zak 已提交
2015
            tkdata = NULL;
2016

K
Karel Zak 已提交
2017 2018
            /* get token */
            tk = vshCommandGetToken(ctl, str, &end, &tkdata);
2019

K
Karel Zak 已提交
2020
            str = end;
2021 2022

            if (tk == VSH_TK_END)
K
Karel Zak 已提交
2023
                break;
2024
            if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
2025
                goto syntaxError;
2026 2027

            if (cmd == NULL) {
K
Karel Zak 已提交
2028
                /* first token must be command name */
2029 2030 2031 2032
                if (tk != VSH_TK_DATA) {
                    vshError(ctl, FALSE,
                             "unexpected token (command name): '%s'",
                             tkdata);
K
Karel Zak 已提交
2033 2034 2035
                    goto syntaxError;
                }
                if (!(cmd = vshCmddefSearch(tkdata))) {
2036 2037
                    vshError(ctl, FALSE, "unknown command: '%s'", tkdata);
                    goto syntaxError;   /* ... or ignore this command only? */
K
Karel Zak 已提交
2038 2039
                }
                free(tkdata);
2040
            } else if (tk == VSH_TK_OPTION) {
K
Karel Zak 已提交
2041 2042
                if (!(opt = vshCmddefGetOption(cmd, tkdata))) {
                    vshError(ctl, FALSE,
2043 2044
                             "command '%s' doesn't support option --%s",
                             cmd->name, tkdata);
K
Karel Zak 已提交
2045 2046
                    goto syntaxError;
                }
2047
                free(tkdata);   /* option name */
K
Karel Zak 已提交
2048 2049 2050 2051 2052
                tkdata = NULL;

                if (opt->type != VSH_OT_BOOL) {
                    /* option data */
                    tk = vshCommandGetToken(ctl, str, &end, &tkdata);
2053 2054
                    str = end;
                    if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
2055
                        goto syntaxError;
2056
                    if (tk != VSH_TK_DATA) {
K
Karel Zak 已提交
2057
                        vshError(ctl, FALSE,
2058 2059 2060 2061
                                 "expected syntax: --%s <%s>",
                                 opt->name,
                                 opt->type ==
                                 VSH_OT_INT ? "number" : "string");
K
Karel Zak 已提交
2062 2063 2064
                        goto syntaxError;
                    }
                }
2065
            } else if (tk == VSH_TK_DATA) {
2066
                if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
2067
                    vshError(ctl, FALSE, "unexpected data '%s'", tkdata);
K
Karel Zak 已提交
2068 2069 2070 2071 2072
                    goto syntaxError;
                }
            }
            if (opt) {
                /* save option */
2073
                vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
2074

K
Karel Zak 已提交
2075 2076 2077 2078
                arg->def = opt;
                arg->data = tkdata;
                arg->next = NULL;
                tkdata = NULL;
2079

K
Karel Zak 已提交
2080 2081 2082 2083 2084
                if (!first)
                    first = arg;
                if (last)
                    last->next = arg;
                last = arg;
2085

K
Karel Zak 已提交
2086
                vshDebug(ctl, 4, "%s: %s(%s): %s\n",
2087 2088 2089 2090
                         cmd->name,
                         opt->name,
                         tk == VSH_TK_OPTION ? "OPTION" : "DATA",
                         arg->data);
K
Karel Zak 已提交
2091 2092 2093 2094
            }
            if (!str)
                break;
        }
2095

K
Karel Zak 已提交
2096 2097
        /* commad parsed -- allocate new struct for the command */
        if (cmd) {
2098
            vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
2099

K
Karel Zak 已提交
2100 2101 2102 2103
            c->opts = first;
            c->def = cmd;
            c->next = NULL;

2104 2105
            if (!vshCommandCheckOpts(ctl, c))
                goto syntaxError;
2106

K
Karel Zak 已提交
2107 2108 2109 2110 2111 2112 2113
            if (!ctl->cmd)
                ctl->cmd = c;
            if (clast)
                clast->next = c;
            clast = c;
        }
    }
2114

K
Karel Zak 已提交
2115 2116
    return TRUE;

2117
  syntaxError:
K
Karel Zak 已提交
2118 2119 2120 2121 2122 2123
    if (ctl->cmd)
        vshCommandFree(ctl->cmd);
    if (first)
        vshCommandOptFree(first);
    if (tkdata)
        free(tkdata);
2124
    return FALSE;
K
Karel Zak 已提交
2125 2126 2127 2128 2129 2130 2131
}


/* ---------------
 * Misc utils  
 * ---------------
 */
K
Karel Zak 已提交
2132
static const char *
2133 2134
vshDomainStateToString(int state)
{
K
Karel Zak 已提交
2135 2136
    switch (state) {
        case VIR_DOMAIN_RUNNING:
2137
            return "running ";
K
Karel Zak 已提交
2138 2139 2140 2141 2142 2143 2144 2145
        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 已提交
2146 2147
        case VIR_DOMAIN_CRASHED:
            return "crashed";
K
Karel Zak 已提交
2148
        default:
2149
            return "no state";  /* = dom0 state */
K
Karel Zak 已提交
2150 2151 2152 2153
    }
    return NULL;
}

2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169
static const char *
vshDomainVcpuStateToString(int state)
{
    switch (state) {
        case VIR_VCPU_OFFLINE:
            return "offline";
        case VIR_VCPU_BLOCKED:
            return "blocked";
        case VIR_VCPU_RUNNING:
            return "running";
        default:
            return "no state";
    }
    return NULL;
}

K
Karel Zak 已提交
2170
static int
2171 2172
vshConnectionUsability(vshControl * ctl, virConnectPtr conn, int showerror)
{
K
Karel Zak 已提交
2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183
    /* 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 已提交
2184 2185
static void
vshDebug(vshControl * ctl, int level, const char *format, ...)
2186
{
K
Karel Zak 已提交
2187 2188 2189 2190 2191 2192 2193 2194
    va_list ap;

    if (level > ctl->debug)
        return;

    va_start(ap, format);
    vfprintf(stdout, format, ap);
    va_end(ap);
K
Karel Zak 已提交
2195 2196 2197
}

static void
K
Karel Zak 已提交
2198
vshPrintExtra(vshControl * ctl, const char *format, ...)
2199
{
K
Karel Zak 已提交
2200
    va_list ap;
2201

K
Karel Zak 已提交
2202
    if (ctl->quiet == TRUE)
K
Karel Zak 已提交
2203
        return;
2204

K
Karel Zak 已提交
2205
    va_start(ap, format);
2206
    vfprintf(stdout, format, ap);
K
Karel Zak 已提交
2207 2208 2209
    va_end(ap);
}

K
Karel Zak 已提交
2210

K
Karel Zak 已提交
2211
static void
2212 2213
vshError(vshControl * ctl, int doexit, const char *format, ...)
{
K
Karel Zak 已提交
2214
    va_list ap;
2215

K
Karel Zak 已提交
2216 2217 2218 2219
    if (doexit)
        fprintf(stderr, "%s: error: ", progname);
    else
        fputs("error: ", stderr);
2220

K
Karel Zak 已提交
2221 2222 2223 2224 2225
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);

    fputc('\n', stderr);
2226

K
Karel Zak 已提交
2227
    if (doexit) {
2228 2229
        if (ctl)
            vshDeinit(ctl);
K
Karel Zak 已提交
2230 2231 2232 2233
        exit(EXIT_FAILURE);
    }
}

2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269
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 已提交
2270 2271 2272 2273
/*
 * Initialize vistsh
 */
static int
2274 2275
vshInit(vshControl * ctl)
{
K
Karel Zak 已提交
2276 2277 2278 2279
    if (ctl->conn)
        return FALSE;

    ctl->uid = getuid();
2280

2281 2282
    /* set up the library error handler */
    virSetErrorFunc(NULL, virshErrorHandler);
2283

2284 2285 2286 2287
    /* basic connection to hypervisor, for Xen connections unless
       we're root open a read only connections. Allow 'test' HV
       to be RW all the time though */
    if (ctl->uid == 0 || (ctl->name && !strncmp(ctl->name, "test", 4)))
K
Karel Zak 已提交
2288
        ctl->conn = virConnectOpen(ctl->name);
K
Karel Zak 已提交
2289
    else
K
Karel Zak 已提交
2290
        ctl->conn = virConnectOpenReadOnly(ctl->name);
2291

K
Karel Zak 已提交
2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308
    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 *
2309 2310
vshReadlineCommandGenerator(const char *text, int state)
{
K
Karel Zak 已提交
2311
    static int list_index, len;
K
Karel Zak 已提交
2312
    const char *name;
K
Karel Zak 已提交
2313 2314 2315 2316 2317 2318 2319

    /* 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;
2320
        len = strlen(text);
K
Karel Zak 已提交
2321 2322 2323 2324 2325
    }

    /* Return the next name which partially matches from the
     * command list. 
     */
K
Karel Zak 已提交
2326
    while ((name = commands[list_index].name)) {
K
Karel Zak 已提交
2327
        list_index++;
2328
        if (strncmp(name, text, len) == 0)
2329
            return vshStrdup(NULL, name);
K
Karel Zak 已提交
2330 2331 2332 2333 2334 2335 2336
    }

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

static char *
2337 2338
vshReadlineOptionsGenerator(const char *text, int state)
{
K
Karel Zak 已提交
2339 2340
    static int list_index, len;
    static vshCmdDef *cmd = NULL;
K
Karel Zak 已提交
2341
    const char *name;
K
Karel Zak 已提交
2342 2343 2344 2345 2346 2347 2348 2349 2350

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

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

2351
        cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
2352
        memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
K
Karel Zak 已提交
2353 2354 2355

        cmd = vshCmddefSearch(cmdname);
        list_index = 0;
2356
        len = strlen(text);
K
Karel Zak 已提交
2357 2358 2359 2360 2361
        free(cmdname);
    }

    if (!cmd)
        return NULL;
2362

K
Karel Zak 已提交
2363
    while ((name = cmd->opts[list_index].name)) {
K
Karel Zak 已提交
2364 2365
        vshCmdOptDef *opt = &cmd->opts[list_index];
        char *res;
2366

K
Karel Zak 已提交
2367
        list_index++;
2368

K
Karel Zak 已提交
2369
        if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
2370 2371
            /* ignore non --option */
            continue;
2372

K
Karel Zak 已提交
2373
        if (len > 2) {
2374
            if (strncmp(name, text + 2, len - 2))
K
Karel Zak 已提交
2375 2376
                continue;
        }
2377
        res = vshMalloc(NULL, strlen(name) + 3);
K
Karel Zak 已提交
2378 2379 2380 2381 2382 2383 2384 2385 2386
        sprintf(res, "--%s", name);
        return res;
    }

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

static char **
2387 2388 2389
vshReadlineCompletion(const char *text, int start,
                      int end ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
2390 2391
    char **matches = (char **) NULL;

2392
    if (start == 0)
K
Karel Zak 已提交
2393
        /* command name generator */
2394
        matches = rl_completion_matches(text, vshReadlineCommandGenerator);
K
Karel Zak 已提交
2395 2396
    else
        /* commands options */
2397
        matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
K
Karel Zak 已提交
2398 2399 2400 2401 2402
    return matches;
}


static void
2403 2404
vshReadlineInit(void)
{
K
Karel Zak 已提交
2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
    /* 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
2416 2417
vshDeinit(vshControl * ctl)
{
K
Karel Zak 已提交
2418
    if (ctl->conn) {
2419 2420 2421 2422
        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 已提交
2423 2424 2425 2426
        }
    }
    return TRUE;
}
2427

K
Karel Zak 已提交
2428 2429 2430 2431
/*
 * Print usage
 */
static void
2432 2433
vshUsage(vshControl * ctl, const char *cmdname)
{
K
Karel Zak 已提交
2434
    vshCmdDef *cmd;
2435

K
Karel Zak 已提交
2436 2437 2438 2439
    /* global help */
    if (!cmdname) {
        fprintf(stdout, "\n%s [options] [commands]\n\n"
                "  options:\n"
K
Karel Zak 已提交
2440
                "    -c | --connect <name>   optional argument currently unused (or used for tests only)\n"
K
Karel Zak 已提交
2441 2442 2443 2444 2445 2446
                "    -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);
2447 2448 2449 2450 2451 2452 2453 2454

        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 已提交
2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465
        return;
    }
    if (!vshCmddefHelp(ctl, cmdname, TRUE))
        exit(EXIT_FAILURE);
}

/*
 * argv[]:  virsh [options] [command]
 *
 */
static int
2466 2467
vshParseArgv(vshControl * ctl, int argc, char **argv)
{
K
Karel Zak 已提交
2468 2469
    char *last = NULL;
    int i, end = 0, help = 0;
2470
    int arg, idx = 0;
K
Karel Zak 已提交
2471
    struct option opt[] = {
2472 2473 2474 2475 2476
        {"debug", 1, 0, 'd'},
        {"help", 0, 0, 'h'},
        {"quiet", 0, 0, 'q'},
        {"timing", 0, 0, 't'},
        {"version", 0, 0, 'v'},
K
Karel Zak 已提交
2477
        {"connect", 1, 0, 'c'},
K
Karel Zak 已提交
2478
        {0, 0, 0, 0}
2479 2480
    };

K
Karel Zak 已提交
2481 2482

    if (argc < 2)
K
Karel Zak 已提交
2483
        return TRUE;
2484

2485
    /* look for begin of the command, for example:
K
Karel Zak 已提交
2486 2487 2488 2489
     *   ./virsh --debug 5 -q command --cmdoption
     *                  <--- ^ --->
     *        getopt() stuff | command suff
     */
2490
    for (i = 1; i < argc; i++) {
K
Karel Zak 已提交
2491 2492
        if (*argv[i] != '-') {
            int valid = FALSE;
2493

K
Karel Zak 已提交
2494 2495 2496 2497
            /* non "--option" argv, is it command? */
            if (last) {
                struct option *o;
                int sz = strlen(last);
2498 2499 2500

                for (o = opt; o->name; o++) {
                    if (sz == 2 && *(last + 1) == o->val)
K
Karel Zak 已提交
2501 2502
                        /* valid virsh short option */
                        valid = TRUE;
2503
                    else if (sz > 2 && strcmp(o->name, last + 2) == 0)
K
Karel Zak 已提交
2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515
                        /* valid virsh long option */
                        valid = TRUE;
                }
            }
            if (!valid) {
                end = i;
                break;
            }
        }
        last = argv[i];
    }
    end = end ? : argc;
2516

K
Karel Zak 已提交
2517
    /* standard (non-command) options */
2518 2519
    while ((arg = getopt_long(end, argv, "d:hqtv", opt, &idx)) != -1) {
        switch (arg) {
K
Karel Zak 已提交
2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
            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 已提交
2532 2533 2534
            case 'c':
                ctl->name = vshStrdup(ctl, optarg);
                break;
K
Karel Zak 已提交
2535 2536 2537 2538
            case 'v':
                fprintf(stdout, "%s\n", VERSION);
                exit(EXIT_SUCCESS);
            default:
2539 2540
                vshError(ctl, TRUE,
                  "unsupported option '-%c'. See --help.", arg);
K
Karel Zak 已提交
2541 2542 2543 2544 2545 2546 2547 2548
                break;
        }
    }

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

K
Karel Zak 已提交
2551 2552 2553
    if (argc > end) {
        /* parse command */
        char *cmdstr;
2554 2555
        int sz = 0, ret;

K
Karel Zak 已提交
2556 2557
        ctl->imode = FALSE;

2558 2559 2560
        for (i = end; i < argc; i++)
            sz += strlen(argv[i]) + 1;  /* +1 is for blank space between items */

2561
        cmdstr = vshCalloc(ctl, sz + 1, 1);
2562 2563

        for (i = end; i < argc; i++) {
K
Karel Zak 已提交
2564 2565 2566 2567
            strncat(cmdstr, argv[i], sz);
            sz -= strlen(argv[i]);
            strncat(cmdstr, " ", sz--);
        }
K
Karel Zak 已提交
2568
        vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
K
Karel Zak 已提交
2569
        ret = vshCommandParse(ctl, cmdstr);
2570

K
Karel Zak 已提交
2571 2572 2573 2574 2575 2576
        free(cmdstr);
        return ret;
    }
    return TRUE;
}

2577 2578 2579 2580
int
main(int argc, char **argv)
{
    vshControl _ctl, *ctl = &_ctl;
2581
    char *defaultConn;
K
Karel Zak 已提交
2582 2583
    int ret = TRUE;

2584
    if (!(progname = strrchr(argv[0], '/')))
K
Karel Zak 已提交
2585 2586 2587
        progname = argv[0];
    else
        progname++;
2588

K
Karel Zak 已提交
2589
    memset(ctl, 0, sizeof(vshControl));
2590
    ctl->imode = TRUE;          /* default is interactive mode */
K
Karel Zak 已提交
2591

2592 2593 2594 2595
    if ((defaultConn = getenv("VIRSH_DEFAULT_CONNECT_URI"))) {
      ctl->name = strdup(defaultConn);
    }

K
Karel Zak 已提交
2596 2597
    if (!vshParseArgv(ctl, argc, argv))
        exit(EXIT_FAILURE);
2598

K
Karel Zak 已提交
2599 2600
    if (!vshInit(ctl))
        exit(EXIT_FAILURE);
2601

K
Karel Zak 已提交
2602
    if (!ctl->imode) {
2603
        ret = vshCommandRun(ctl, ctl->cmd);
2604
    } else {
K
Karel Zak 已提交
2605 2606
        /* interactive mode */
        if (!ctl->quiet) {
K
Karel Zak 已提交
2607
            vshPrint(ctl,
2608 2609
                     "Welcome to %s, the virtualization interactive terminal.\n\n",
                     progname);
K
Karel Zak 已提交
2610
            vshPrint(ctl,
2611 2612
                     "Type:  'help' for help with commands\n"
                     "       'quit' to quit\n\n");
K
Karel Zak 已提交
2613
        }
K
Karel Zak 已提交
2614
        vshReadlineInit();
K
Karel Zak 已提交
2615
        do {
2616 2617 2618 2619
            ctl->cmdstr =
                readline(ctl->uid == 0 ? VSH_PROMPT_RW : VSH_PROMPT_RO);
            if (ctl->cmdstr == NULL)
                break;          /* EOF */
K
Karel Zak 已提交
2620 2621 2622 2623 2624 2625 2626
            if (*ctl->cmdstr) {
                add_history(ctl->cmdstr);
                if (vshCommandParse(ctl, ctl->cmdstr))
                    vshCommandRun(ctl, ctl->cmd);
            }
            free(ctl->cmdstr);
            ctl->cmdstr = NULL;
2627
        } while (ctl->imode);
K
Karel Zak 已提交
2628

2629 2630
        if (ctl->cmdstr == NULL)
            fputc('\n', stdout);        /* line break after alone prompt */
K
Karel Zak 已提交
2631
    }
2632

K
Karel Zak 已提交
2633 2634
    vshDeinit(ctl);
    exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
2635
}
K
Karel Zak 已提交
2636 2637 2638 2639 2640 2641

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