virsh.c 362.0 KB
Newer Older
1
/*
2
 * virsh.c: a shell to exercise the libvirt API
3
 *
4
 * Copyright (C) 2005, 2007-2011 Red Hat, Inc.
5 6 7 8
 *
 * 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
 * Daniel P. Berrange <berrange@redhat.com>
11 12
 */

13
#include <config.h>
14

15
#include <stdio.h>
K
Karel Zak 已提交
16 17 18
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
19
#include <unistd.h>
20
#include <errno.h>
K
Karel Zak 已提交
21
#include <getopt.h>
22
#include <sys/types.h>
K
Karel Zak 已提交
23
#include <sys/time.h>
E
Eric Blake 已提交
24
#include <sys/wait.h>
J
Jim Meyering 已提交
25
#include "c-ctype.h"
26
#include <fcntl.h>
27
#include <locale.h>
28
#include <time.h>
29
#include <limits.h>
30
#include <assert.h>
31
#include <sys/stat.h>
32
#include <inttypes.h>
33
#include <signal.h>
34
#include <poll.h>
K
Karel Zak 已提交
35

36 37 38
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
39
#include <libxml/xmlsave.h>
40

41
#ifdef HAVE_READLINE_READLINE_H
42 43
# include <readline/readline.h>
# include <readline/history.h>
44
#endif
K
Karel Zak 已提交
45

46
#include "internal.h"
47
#include "virterror_internal.h"
48
#include "base64.h"
49
#include "buf.h"
50
#include "console.h"
51
#include "util.h"
52
#include "memory.h"
53
#include "xml.h"
54
#include "libvirt/libvirt-qemu.h"
55
#include "files.h"
56
#include "event_poll.h"
57
#include "configmake.h"
58
#include "threads.h"
E
Eric Blake 已提交
59
#include "command.h"
60
#include "count-one-bits.h"
K
Karel Zak 已提交
61 62 63

static char *progname;

64 65
#define VIRSH_MAX_XML_FILE 10*1024*1024

K
Karel Zak 已提交
66 67 68 69 70 71 72 73
#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)

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
/**
 * The log configuration
 */
#define MSG_BUFFER    4096
#define SIGN_NAME     "virsh"
#define DIR_MODE      (S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)  /* 0755 */
#define FILE_MODE     (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)                                /* 0644 */
#define LOCK_MODE     (S_IWUSR | S_IRUSR)                                                    /* 0600 */
#define LVL_DEBUG     "DEBUG"
#define LVL_INFO      "INFO"
#define LVL_NOTICE    "NOTICE"
#define LVL_WARNING   "WARNING"
#define LVL_ERROR     "ERROR"

/**
 * vshErrorLevel:
 *
J
Jim Meyering 已提交
91
 * Indicates the level of a log message
92 93 94 95 96 97 98 99 100
 */
typedef enum {
    VSH_ERR_DEBUG = 0,
    VSH_ERR_INFO,
    VSH_ERR_NOTICE,
    VSH_ERR_WARNING,
    VSH_ERR_ERROR
} vshErrorLevel;

K
Karel Zak 已提交
101 102 103 104 105
/*
 * virsh command line grammar:
 *
 *    command_line    =     <command>\n | <command>; <command>; ...
 *
E
Eric Blake 已提交
106
 *    command         =    <keyword> <option> [--] <data>
K
Karel Zak 已提交
107 108 109 110 111
 *
 *    option          =     <bool_option> | <int_option> | <string_option>
 *    data            =     <string>
 *
 *    bool_option     =     --optionname
E
Eric Blake 已提交
112 113
 *    int_option      =     --optionname <number> | --optionname=<number>
 *    string_option   =     --optionname <string> | --optionname=<string>
114
 *
E
Eric Blake 已提交
115
 *    keyword         =     [a-zA-Z][a-zA-Z-]*
116
 *    number          =     [0-9]+
E
Eric Blake 已提交
117
 *    string          =     ('[^']*'|"([^\\"]|\\.)*"|([^ \t\n\\'"]|\\.))+
K
Karel Zak 已提交
118 119 120 121
 *
 */

/*
122
 * vshCmdOptType - command option type
123
 */
K
Karel Zak 已提交
124
typedef enum {
125 126 127
    VSH_OT_BOOL,     /* optional boolean option */
    VSH_OT_STRING,   /* optional string option */
    VSH_OT_INT,      /* optional or mandatory int option */
128 129
    VSH_OT_DATA,     /* string data (as non-option) */
    VSH_OT_ARGV      /* remaining arguments, opt->name should be "" */
K
Karel Zak 已提交
130 131
} vshCmdOptType;

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
/*
 * Command group types
 */
#define VSH_CMD_GRP_DOM_MANAGEMENT   "Domain Management"
#define VSH_CMD_GRP_DOM_MONITORING   "Domain Monitoring"
#define VSH_CMD_GRP_STORAGE_POOL     "Storage Pool"
#define VSH_CMD_GRP_STORAGE_VOL      "Storage Volume"
#define VSH_CMD_GRP_NETWORK          "Networking"
#define VSH_CMD_GRP_NODEDEV          "Node Device"
#define VSH_CMD_GRP_IFACE            "Interface"
#define VSH_CMD_GRP_NWFILTER         "Network Filter"
#define VSH_CMD_GRP_SECRET           "Secret"
#define VSH_CMD_GRP_SNAPSHOT         "Snapshot"
#define VSH_CMD_GRP_HOST_AND_HV      "Host and Hypervisor"
#define VSH_CMD_GRP_VIRSH            "Virsh itself"

K
Karel Zak 已提交
148 149 150
/*
 * Command Option Flags
 */
E
Eric Blake 已提交
151 152 153 154 155
enum {
    VSH_OFLAG_NONE     = 0,        /* without flags */
    VSH_OFLAG_REQ      = (1 << 0), /* option required */
    VSH_OFLAG_EMPTY_OK = (1 << 1), /* empty string option allowed */
};
K
Karel Zak 已提交
156 157 158 159 160 161 162 163

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

/*
 * vshCmdInfo -- information about command
 */
164 165 166
typedef struct {
    const char *name;           /* name of information */
    const char *data;           /* information */
K
Karel Zak 已提交
167 168 169 170 171
} vshCmdInfo;

/*
 * vshCmdOptDef - command option definition
 */
172 173 174 175 176
typedef struct {
    const char *name;           /* the name of option */
    vshCmdOptType type;         /* option type */
    int flag;                   /* flags */
    const char *help;           /* help string */
K
Karel Zak 已提交
177 178 179 180 181 182
} vshCmdOptDef;

/*
 * vshCmdOpt - command options
 */
typedef struct vshCmdOpt {
183
    const vshCmdOptDef *def;    /* pointer to relevant option */
184 185
    char *data;                 /* allocated data */
    struct vshCmdOpt *next;
K
Karel Zak 已提交
186 187 188 189 190
} vshCmdOpt;

/*
 * vshCmdDef - command definition
 */
191 192
typedef struct {
    const char *name;
E
Eric Blake 已提交
193
    bool (*handler) (vshControl *, const vshCmd *);    /* command handler */
194 195
    const vshCmdOptDef *opts;   /* definition of command options */
    const vshCmdInfo *info;     /* details about command */
K
Karel Zak 已提交
196 197 198 199 200 201
} vshCmdDef;

/*
 * vshCmd - parsed command
 */
typedef struct __vshCmd {
202
    const vshCmdDef *def;       /* command definition */
203 204
    vshCmdOpt *opts;            /* list of command arguments */
    struct __vshCmd *next;      /* next command */
K
Karel Zak 已提交
205 206 207 208 209 210
} __vshCmd;

/*
 * vshControl
 */
typedef struct __vshControl {
K
Karel Zak 已提交
211
    char *name;                 /* connection name */
212
    virConnectPtr conn;         /* connection to hypervisor (MAY BE NULL) */
213 214
    vshCmd *cmd;                /* the current command */
    char *cmdstr;               /* string with command */
E
Eric Blake 已提交
215 216
    bool imode;                 /* interactive mode? */
    bool quiet;                 /* quiet mode */
217
    int debug;                  /* print debug messages? */
E
Eric Blake 已提交
218 219
    bool timing;                /* print timing info? */
    bool readonly;              /* connect readonly (first time only, not
220 221
                                 * during explicit connect command)
                                 */
222 223
    char *logfile;              /* log file name */
    int log_fd;                 /* log file descriptor */
224 225
    char *historydir;           /* readline history directory name */
    char *historyfile;          /* readline history file name */
K
Karel Zak 已提交
226
} __vshControl;
227

228 229 230 231 232
typedef struct vshCmdGrp {
    const char *name;
    const char *keyword; /* help keyword */
    const vshCmdDef *commands;
} vshCmdGrp;
233

234
static const vshCmdGrp cmdGroups[];
K
Karel Zak 已提交
235

236 237
static void vshError(vshControl *ctl, const char *format, ...)
    ATTRIBUTE_FMT_PRINTF(2, 3);
E
Eric Blake 已提交
238 239
static bool vshInit(vshControl *ctl);
static bool vshDeinit(vshControl *ctl);
240
static void vshUsage(void);
241
static void vshOpenLogFile(vshControl *ctl);
242 243
static void vshOutputLogFile(vshControl *ctl, int log_level, const char *format, va_list ap)
    ATTRIBUTE_FMT_PRINTF(3, 0);
244
static void vshCloseLogFile(vshControl *ctl);
K
Karel Zak 已提交
245

E
Eric Blake 已提交
246
static bool vshParseArgv(vshControl *ctl, int argc, char **argv);
K
Karel Zak 已提交
247

248
static const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info);
249
static const vshCmdDef *vshCmddefSearch(const char *cmdname);
E
Eric Blake 已提交
250
static bool vshCmddefHelp(vshControl *ctl, const char *name);
251
static const vshCmdGrp *vshCmdGrpSearch(const char *grpname);
E
Eric Blake 已提交
252
static bool vshCmdGrpHelp(vshControl *ctl, const char *name);
K
Karel Zak 已提交
253

254
static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
255 256 257 258 259 260 261 262 263 264 265
static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *value)
    ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static int vshCommandOptUL(const vshCmd *cmd, const char *name,
                           unsigned long *value)
    ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static int vshCommandOptString(const vshCmd *cmd, const char *name,
                               const char **value)
    ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static int vshCommandOptLongLong(const vshCmd *cmd, const char *name,
                                 long long *value)
    ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
266 267 268
static int vshCommandOptULongLong(const vshCmd *cmd, const char *name,
                                  unsigned long long *value)
    ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
E
Eric Blake 已提交
269
static bool vshCommandOptBool(const vshCmd *cmd, const char *name);
270
static char *vshCommandOptArgv(const vshCmd *cmd, int count);
K
Karel Zak 已提交
271

272 273 274
#define VSH_BYID     (1 << 1)
#define VSH_BYUUID   (1 << 2)
#define VSH_BYNAME   (1 << 3)
275
#define VSH_BYMAC    (1 << 4)
K
Karel Zak 已提交
276

277
static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
278
                                          const char **name, int flag);
K
Karel Zak 已提交
279 280

/* default is lookup by Id, Name and UUID */
J
Jim Meyering 已提交
281 282
#define vshCommandOptDomain(_ctl, _cmd, _name)                      \
    vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME)
283

284
static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
285
                                            const char **name, int flag);
286 287

/* default is lookup by Name and UUID */
J
Jim Meyering 已提交
288 289
#define vshCommandOptNetwork(_ctl, _cmd, _name)                    \
    vshCommandOptNetworkBy(_ctl, _cmd, _name,                      \
290 291
                           VSH_BYUUID|VSH_BYNAME)

292
static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
293
                                                  const char **name, int flag);
294 295 296 297 298 299

/* default is lookup by Name and UUID */
#define vshCommandOptNWFilter(_ctl, _cmd, _name)                    \
    vshCommandOptNWFilterBy(_ctl, _cmd, _name,                      \
                            VSH_BYUUID|VSH_BYNAME)

300
static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
301
                                                const char **name, int flag);
302 303 304 305 306 307

/* default is lookup by Name and MAC */
#define vshCommandOptInterface(_ctl, _cmd, _name)                    \
    vshCommandOptInterfaceBy(_ctl, _cmd, _name,                      \
                           VSH_BYMAC|VSH_BYNAME)

308
static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd,
309
                            const char *optname, const char **name, int flag);
310 311 312 313 314 315

/* default is lookup by Name and UUID */
#define vshCommandOptPool(_ctl, _cmd, _optname, _name)           \
    vshCommandOptPoolBy(_ctl, _cmd, _optname, _name,             \
                           VSH_BYUUID|VSH_BYNAME)

316
static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
317 318
                                           const char *optname,
                                           const char *pooloptname,
319
                                           const char **name, int flag);
320 321

/* default is lookup by Name and UUID */
322
#define vshCommandOptVol(_ctl, _cmd, _optname, _pooloptname, _name)   \
323 324 325
    vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name,     \
                           VSH_BYUUID|VSH_BYNAME)

326
static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd,
327
                                        const char **name);
328

329
static void vshPrintExtra(vshControl *ctl, const char *format, ...)
330
    ATTRIBUTE_FMT_PRINTF(2, 3);
331
static void vshDebug(vshControl *ctl, int level, const char *format, ...)
332
    ATTRIBUTE_FMT_PRINTF(3, 4);
K
Karel Zak 已提交
333 334

/* XXX: add batch support */
335
#define vshPrint(_ctl, ...)   vshPrintExtra(NULL, __VA_ARGS__)
K
Karel Zak 已提交
336

K
Karel Zak 已提交
337
static const char *vshDomainStateToString(int state);
338
static const char *vshDomainVcpuStateToString(int state);
E
Eric Blake 已提交
339
static bool vshConnectionUsability(vshControl *ctl, virConnectPtr conn);
K
Karel Zak 已提交
340

341 342 343 344
static char *editWriteToTempFile (vshControl *ctl, const char *doc);
static int   editFile (vshControl *ctl, const char *filename);
static char *editReadBackFile (vshControl *ctl, const char *filename);

345
static void *_vshMalloc(vshControl *ctl, size_t sz, const char *filename, int line);
346 347
#define vshMalloc(_ctl, _sz)    _vshMalloc(_ctl, _sz, __FILE__, __LINE__)

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

351
static void *_vshRealloc(vshControl *ctl, void *ptr, size_t sz, const char *filename, int line);
352 353
#define vshRealloc(_ctl, _ptr, _sz)    _vshRealloc(_ctl, _ptr, _sz, __FILE__, __LINE__)

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

E
Eric Blake 已提交
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
static void *
_vshMalloc(vshControl *ctl, size_t size, const char *filename, int line)
{
    void *x;

    if ((x = malloc(size)))
        return x;
    vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
             filename, line, (int) size);
    exit(EXIT_FAILURE);
}

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, _("%s: %d: failed to allocate %d bytes"),
             filename, line, (int) (size*nmemb));
    exit(EXIT_FAILURE);
}

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

    if ((x = realloc(ptr, size)))
        return x;
    VIR_FREE(ptr);
    vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
             filename, line, (int) size);
    exit(EXIT_FAILURE);
}

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

    if (s == NULL)
        return(NULL);
    if ((x = strdup(s)))
        return x;
    vshError(ctl, _("%s: %d: failed to allocate %lu bytes"),
             filename, line, (unsigned long)strlen(s));
    exit(EXIT_FAILURE);
}

/* Poison the raw allocating identifiers in favor of our vsh variants.  */
#undef malloc
#undef calloc
#undef realloc
#undef strdup
#define malloc use_vshMalloc_instead_of_malloc
#define calloc use_vshCalloc_instead_of_calloc
#define realloc use_vshRealloc_instead_of_realloc
#define strdup use_vshStrdup_instead_of_strdup
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431

static int idsorter(const void *a, const void *b) {
  const int *ia = (const int *)a;
  const int *ib = (const int *)b;

  if (*ia > *ib)
    return 1;
  else if (*ia < *ib)
    return -1;
  return 0;
}
static int namesorter(const void *a, const void *b) {
  const char **sa = (const char**)a;
  const char **sb = (const char**)b;

432
  /* User visible sort, so we want locale-specific case comparison.  */
433 434 435
  return strcasecmp(*sa, *sb);
}

436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
static double
prettyCapacity(unsigned long long val,
               const char **unit) {
    if (val < 1024) {
        *unit = "";
        return (double)val;
    } else if (val < (1024.0l * 1024.0l)) {
        *unit = "KB";
        return (((double)val / 1024.0l));
    } else if (val < (1024.0l * 1024.0l * 1024.0l)) {
        *unit = "MB";
        return ((double)val / (1024.0l * 1024.0l));
    } else if (val < (1024.0l * 1024.0l * 1024.0l * 1024.0l)) {
        *unit = "GB";
        return ((double)val / (1024.0l * 1024.0l * 1024.0l));
    } else {
        *unit = "TB";
        return ((double)val / (1024.0l * 1024.0l * 1024.0l * 1024.0l));
    }
}


J
John Levon 已提交
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
static virErrorPtr last_error;

/*
 * Quieten libvirt until we're done with the command.
 */
static void
virshErrorHandler(void *unused ATTRIBUTE_UNUSED, virErrorPtr error)
{
    virFreeError(last_error);
    last_error = virSaveLastError();
    if (getenv("VIRSH_DEBUG") != NULL)
        virDefaultErrorFunc(error);
}

/*
 * Report an error when a command finishes.  This is better than before
 * (when correct operation would report errors), but it has some
 * problems: we lose the smarter formatting of virDefaultErrorFunc(),
 * and it can become harder to debug problems, if errors get reported
 * twice during one command.  This case shouldn't really happen anyway,
 * and it's IMHO a bug that libvirt does that sometimes.
 */
static void
virshReportError(vshControl *ctl)
{
483 484 485 486 487 488 489 490
    if (last_error == NULL) {
        /* Calling directly into libvirt util functions won't trigger the
         * error callback (which sets last_error), so check it ourselves.
         *
         * If the returned error has CODE_OK, this most likely means that
         * no error was ever raised, so just ignore */
        last_error = virSaveLastError();
        if (!last_error || last_error->code == VIR_ERR_OK)
491
            goto out;
492
    }
J
John Levon 已提交
493 494

    if (last_error->code == VIR_ERR_OK) {
495
        vshError(ctl, "%s", _("unknown error"));
J
John Levon 已提交
496 497 498
        goto out;
    }

499
    vshError(ctl, "%s", last_error->message);
J
John Levon 已提交
500 501 502 503 504 505

out:
    virFreeError(last_error);
    last_error = NULL;
}

506 507 508 509 510 511 512 513 514
static volatile sig_atomic_t intCaught = 0;

static void vshCatchInt(int sig ATTRIBUTE_UNUSED,
                        siginfo_t *siginfo ATTRIBUTE_UNUSED,
                        void *context ATTRIBUTE_UNUSED)
{
    intCaught = 1;
}

515 516 517 518 519
/*
 * Detection of disconnections and automatic reconnection support
 */
static int disconnected = 0; /* we may have been disconnected */

520 521 522 523 524
/* Gnulib doesn't guarantee SA_SIGINFO support.  */
#ifndef SA_SIGINFO
# define SA_SIGINFO 0
#endif

525 526 527 528 529 530
/*
 * vshCatchDisconnect:
 *
 * We get here when a SIGPIPE is being raised, we can't do much in the
 * handler, just save the fact it was raised
 */
531 532 533 534
static void vshCatchDisconnect(int sig, siginfo_t *siginfo,
                               void *context ATTRIBUTE_UNUSED) {
    if ((sig == SIGPIPE) ||
        (SA_SIGINFO && siginfo->si_signo == SIGPIPE))
535 536 537 538 539 540 541 542 543
        disconnected++;
}

/*
 * vshSetupSignals:
 *
 * Catch SIGPIPE signals which may arise when disconnection
 * from libvirtd occurs
 */
L
Laine Stump 已提交
544
static void
545 546 547 548 549 550 551 552 553 554 555 556 557
vshSetupSignals(void) {
    struct sigaction sig_action;

    sig_action.sa_sigaction = vshCatchDisconnect;
    sig_action.sa_flags = SA_SIGINFO;
    sigemptyset(&sig_action.sa_mask);

    sigaction(SIGPIPE, &sig_action, NULL);
}

/*
 * vshReconnect:
 *
L
Laine Stump 已提交
558
 * Reconnect after a disconnect from libvirtd
559 560
 *
 */
L
Laine Stump 已提交
561
static void
562 563 564 565 566 567 568 569 570 571 572 573 574
vshReconnect(vshControl *ctl) {
    if (ctl->conn != NULL)
        virConnectClose(ctl->conn);

    ctl->conn = virConnectOpenAuth(ctl->name,
                                   virConnectAuthPtrDefault,
                                   ctl->readonly ? VIR_CONNECT_RO : 0);
    if (!ctl->conn)
        vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
    else
        vshError(ctl, "%s", _("Reconnected to the hypervisor"));
    disconnected = 0;
}
575

K
Karel Zak 已提交
576 577 578 579 580 581
/* ---------------
 * Commands
 * ---------------
 */

/*
582
 * "help" command
K
Karel Zak 已提交
583
 */
584
static const vshCmdInfo info_help[] = {
585
    {"help", N_("print help")},
586 587
    {"desc", N_("Prints global help, command specific help, or help for a\n"
                "    group of related commands")},
588

589
    {NULL, NULL}
K
Karel Zak 已提交
590 591
};

592
static const vshCmdOptDef opts_help[] = {
593
    {"command", VSH_OT_DATA, 0, N_("Prints global help, command specific help, or help for a group of related commands")},
594
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
595 596
};

E
Eric Blake 已提交
597
static bool
598
cmdHelp(vshControl *ctl, const vshCmd *cmd)
599
 {
600
    const char *name = NULL;
601

602
    if (vshCommandOptString(cmd, "command", &name) <= 0) {
603
        const vshCmdGrp *grp;
604
        const vshCmdDef *def;
605

606 607 608 609 610 611 612 613 614 615 616 617 618
        vshPrint(ctl, "%s", _("Grouped commands:\n\n"));

        for (grp = cmdGroups; grp->name; grp++) {
            vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
                     grp->keyword);

            for (def = grp->commands; def->name; def++)
                vshPrint(ctl, "    %-30s %s\n", def->name,
                         _(vshCmddefGetInfo(def, "help")));

            vshPrint(ctl, "\n");
        }

E
Eric Blake 已提交
619
        return true;
620
    }
621

E
Eric Blake 已提交
622
    if (vshCmddefSearch(name)) {
623
        return vshCmddefHelp(ctl, name);
E
Eric Blake 已提交
624
    } else if (vshCmdGrpSearch(name)) {
625 626 627
        return vshCmdGrpHelp(ctl, name);
    } else {
        vshError(ctl, _("command or command group '%s' doesn't exist"), name);
E
Eric Blake 已提交
628
        return false;
K
Karel Zak 已提交
629 630 631
    }
}

632 633 634
/*
 * "autostart" command
 */
635
static const vshCmdInfo info_autostart[] = {
636
    {"help", N_("autostart a domain")},
637
    {"desc",
638
     N_("Configure a domain to be automatically started at boot.")},
639 640 641
    {NULL, NULL}
};

642
static const vshCmdOptDef opts_autostart[] = {
643 644
    {"domain",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
645 646 647
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
648
static bool
649
cmdAutostart(vshControl *ctl, const vshCmd *cmd)
650 651
{
    virDomainPtr dom;
652
    const char *name;
653 654
    int autostart;

655
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
656
        return false;
657

J
Jim Meyering 已提交
658
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
659
        return false;
660 661 662 663

    autostart = !vshCommandOptBool(cmd, "disable");

    if (virDomainSetAutostart(dom, autostart) < 0) {
664
        if (autostart)
665
            vshError(ctl, _("Failed to mark domain %s as autostarted"), name);
666
        else
667
            vshError(ctl, _("Failed to unmark domain %s as autostarted"), name);
668
        virDomainFree(dom);
E
Eric Blake 已提交
669
        return false;
670 671
    }

672
    if (autostart)
673
        vshPrint(ctl, _("Domain %s marked as autostarted\n"), name);
674
    else
675
        vshPrint(ctl, _("Domain %s unmarked as autostarted\n"), name);
676

677
    virDomainFree(dom);
E
Eric Blake 已提交
678
    return true;
679 680
}

K
Karel Zak 已提交
681
/*
682
 * "connect" command
K
Karel Zak 已提交
683
 */
684
static const vshCmdInfo info_connect[] = {
685
    {"help", N_("(re)connect to hypervisor")},
686
    {"desc",
687
     N_("Connect to local hypervisor. This is built-in command after shell start up.")},
688
    {NULL, NULL}
K
Karel Zak 已提交
689 690
};

691
static const vshCmdOptDef opts_connect[] = {
E
Eric Blake 已提交
692 693
    {"name",     VSH_OT_DATA, VSH_OFLAG_EMPTY_OK,
     N_("hypervisor connection URI")},
694
    {"readonly", VSH_OT_BOOL, 0, N_("read-only connection")},
695
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
696 697
};

E
Eric Blake 已提交
698
static bool
699
cmdConnect(vshControl *ctl, const vshCmd *cmd)
700
{
E
Eric Blake 已提交
701
    bool ro = vshCommandOptBool(cmd, "readonly");
702
    const char *name = NULL;
703

K
Karel Zak 已提交
704
    if (ctl->conn) {
705 706 707
        int ret;
        if ((ret = virConnectClose(ctl->conn)) != 0) {
            vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret);
E
Eric Blake 已提交
708
            return false;
K
Karel Zak 已提交
709 710 711
        }
        ctl->conn = NULL;
    }
712

713
    VIR_FREE(ctl->name);
714 715
    if (vshCommandOptString(cmd, "name", &name) < 0) {
        vshError(ctl, "%s", _("Please specify valid connection URI"));
E
Eric Blake 已提交
716
        return false;
717
    }
718
    ctl->name = vshStrdup(ctl, name);
K
Karel Zak 已提交
719

E
Eric Blake 已提交
720
    ctl->readonly = ro;
K
Karel Zak 已提交
721

722 723 724
    ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault,
                                   ctl->readonly ? VIR_CONNECT_RO : 0);

K
Karel Zak 已提交
725
    if (!ctl->conn)
726
        vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
727

E
Eric Blake 已提交
728
    return !!ctl->conn;
K
Karel Zak 已提交
729 730
}

731 732
#ifndef WIN32

733
/*
734
 * "console" command
735
 */
736
static const vshCmdInfo info_console[] = {
737
    {"help", N_("connect to the guest console")},
738
    {"desc",
739
     N_("Connect the virtual serial console for the guest")},
740 741 742
    {NULL, NULL}
};

743
static const vshCmdOptDef opts_console[] = {
744
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
745
    {"devname", VSH_OT_STRING, 0, N_("character device name")},
746 747 748
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
749
static bool
750
cmdRunConsole(vshControl *ctl, virDomainPtr dom, const char *name)
751
{
E
Eric Blake 已提交
752
    bool ret = false;
753
    virDomainInfo dominfo;
754

755 756 757 758 759 760 761 762 763 764
    if (virDomainGetInfo(dom, &dominfo) < 0) {
        vshError(ctl, "%s", _("Unable to get domain status"));
        goto cleanup;
    }

    if (dominfo.state == VIR_DOMAIN_SHUTOFF) {
        vshError(ctl, "%s", _("The domain is not running"));
        goto cleanup;
    }

765 766
    vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom));
    vshPrintExtra(ctl, "%s", _("Escape character is ^]\n"));
767
    if (vshRunConsole(dom, name) == 0)
E
Eric Blake 已提交
768
        ret = true;
769 770

 cleanup:
771

772 773 774
    return ret;
}

E
Eric Blake 已提交
775
static bool
776 777 778
cmdConsole(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
E
Eric Blake 已提交
779
    bool ret = false;
780
    const char *name = NULL;
781

782
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
783
        return false;
784 785

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
786
        return false;
787

788 789 790 791
    if (vshCommandOptString(cmd, "devname", &name) < 0) {
        vshError(ctl, "%s", _("Invalid devname"));
        goto cleanup;
    }
792

793
    ret = cmdRunConsole(ctl, dom, name);
794

795
cleanup:
796 797 798 799
    virDomainFree(dom);
    return ret;
}

800 801 802
#endif /* WIN32 */


K
Karel Zak 已提交
803 804 805
/*
 * "list" command
 */
806
static const vshCmdInfo info_list[] = {
807 808
    {"help", N_("list domains")},
    {"desc", N_("Returns list of domains.")},
809
    {NULL, NULL}
K
Karel Zak 已提交
810 811
};

812
static const vshCmdOptDef opts_list[] = {
813 814
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")},
815 816 817
    {NULL, 0, 0, NULL}
};

K
Karel Zak 已提交
818

E
Eric Blake 已提交
819
static bool
820
cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
821
{
822 823 824 825
    int inactive = vshCommandOptBool(cmd, "inactive");
    int all = vshCommandOptBool(cmd, "all");
    int active = !inactive || all ? 1 : 0;
    int *ids = NULL, maxid = 0, i;
826
    char **names = NULL;
827 828
    int maxname = 0;
    inactive |= all;
K
Karel Zak 已提交
829

830
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
831
        return false;
832

833
    if (active) {
834 835
        maxid = virConnectNumOfDomains(ctl->conn);
        if (maxid < 0) {
836
            vshError(ctl, "%s", _("Failed to list active domains"));
E
Eric Blake 已提交
837
            return false;
838 839 840 841 842
        }
        if (maxid) {
            ids = vshMalloc(ctl, sizeof(int) * maxid);

            if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
843
                vshError(ctl, "%s", _("Failed to list active domains"));
844
                VIR_FREE(ids);
E
Eric Blake 已提交
845
                return false;
846 847
            }

848
            qsort(&ids[0], maxid, sizeof(int), idsorter);
849
        }
850 851
    }
    if (inactive) {
852 853
        maxname = virConnectNumOfDefinedDomains(ctl->conn);
        if (maxname < 0) {
854
            vshError(ctl, "%s", _("Failed to list inactive domains"));
855
            VIR_FREE(ids);
E
Eric Blake 已提交
856
            return false;
857
        }
858 859 860 861
        if (maxname) {
            names = vshMalloc(ctl, sizeof(char *) * maxname);

            if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
862
                vshError(ctl, "%s", _("Failed to list inactive domains"));
863 864
                VIR_FREE(ids);
                VIR_FREE(names);
E
Eric Blake 已提交
865
                return false;
866
            }
867

868
            qsort(&names[0], maxname, sizeof(char*), namesorter);
869
        }
870
    }
871
    vshPrintExtra(ctl, "%3s %-20s %s\n", _("Id"), _("Name"), _("State"));
K
Karel Zak 已提交
872
    vshPrintExtra(ctl, "----------------------------------\n");
873 874

    for (i = 0; i < maxid; i++) {
K
Karel Zak 已提交
875 876
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
877
        const char *state;
878 879

        /* this kind of work with domains is not atomic operation */
K
Karel Zak 已提交
880 881
        if (!dom)
            continue;
882 883 884 885

        if (virDomainGetInfo(dom, &info) < 0)
            state = _("no state");
        else
E
Eric Blake 已提交
886
            state = _(vshDomainStateToString(info.state));
887

K
Karel Zak 已提交
888
        vshPrint(ctl, "%3d %-20s %s\n",
889 890
                 virDomainGetID(dom),
                 virDomainGetName(dom),
891
                 state);
892
        virDomainFree(dom);
K
Karel Zak 已提交
893
    }
894 895 896
    for (i = 0; i < maxname; i++) {
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
897
        const char *state;
898 899

        /* this kind of work with domains is not atomic operation */
900
        if (!dom) {
901
            VIR_FREE(names[i]);
902
            continue;
903
        }
904 905 906 907

        if (virDomainGetInfo(dom, &info) < 0)
            state = _("no state");
        else
E
Eric Blake 已提交
908
            state = _(vshDomainStateToString(info.state));
909 910

        vshPrint(ctl, "%3s %-20s %s\n", "-", names[i], state);
911

912
        virDomainFree(dom);
913
        VIR_FREE(names[i]);
914
    }
915 916
    VIR_FREE(ids);
    VIR_FREE(names);
E
Eric Blake 已提交
917
    return true;
K
Karel Zak 已提交
918 919 920
}

/*
K
Karel Zak 已提交
921
 * "domstate" command
K
Karel Zak 已提交
922
 */
923
static const vshCmdInfo info_domstate[] = {
924 925
    {"help", N_("domain state")},
    {"desc", N_("Returns state about a domain.")},
926
    {NULL, NULL}
K
Karel Zak 已提交
927 928
};

929
static const vshCmdOptDef opts_domstate[] = {
930
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
931
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
932 933
};

E
Eric Blake 已提交
934
static bool
935
cmdDomstate(vshControl *ctl, const vshCmd *cmd)
936
{
937
    virDomainInfo info;
K
Karel Zak 已提交
938
    virDomainPtr dom;
E
Eric Blake 已提交
939
    bool ret = true;
940

941
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
942
        return false;
943

J
Jim Meyering 已提交
944
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
945
        return false;
946 947

    if (virDomainGetInfo(dom, &info) == 0)
K
Karel Zak 已提交
948
        vshPrint(ctl, "%s\n",
E
Eric Blake 已提交
949
                 _(vshDomainStateToString(info.state)));
K
Karel Zak 已提交
950
    else
E
Eric Blake 已提交
951
        ret = false;
952

953 954 955 956
    virDomainFree(dom);
    return ret;
}

957 958
/* "domblkstat" command
 */
959
static const vshCmdInfo info_domblkstat[] = {
960 961
    {"help", N_("get device block stats for a domain")},
    {"desc", N_("Get device block stats for a running domain.")},
962 963 964
    {NULL,NULL}
};

965
static const vshCmdOptDef opts_domblkstat[] = {
966 967
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
968 969 970
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
971
static bool
972
cmdDomblkstat (vshControl *ctl, const vshCmd *cmd)
973 974
{
    virDomainPtr dom;
975
    const char *name = NULL, *device = NULL;
976 977
    struct _virDomainBlockStats stats;

978
    if (!vshConnectionUsability (ctl, ctl->conn))
E
Eric Blake 已提交
979
        return false;
980

J
Jim Meyering 已提交
981
    if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
E
Eric Blake 已提交
982
        return false;
983

984
    if (vshCommandOptString (cmd, "device", &device) <= 0) {
L
Laine Stump 已提交
985
        virDomainFree(dom);
E
Eric Blake 已提交
986
        return false;
L
Laine Stump 已提交
987
    }
988 989

    if (virDomainBlockStats (dom, device, &stats, sizeof stats) == -1) {
990
        vshError(ctl, _("Failed to get block stats %s %s"), name, device);
991
        virDomainFree(dom);
E
Eric Blake 已提交
992
        return false;
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
    }

    if (stats.rd_req >= 0)
        vshPrint (ctl, "%s rd_req %lld\n", device, stats.rd_req);

    if (stats.rd_bytes >= 0)
        vshPrint (ctl, "%s rd_bytes %lld\n", device, stats.rd_bytes);

    if (stats.wr_req >= 0)
        vshPrint (ctl, "%s wr_req %lld\n", device, stats.wr_req);

    if (stats.wr_bytes >= 0)
        vshPrint (ctl, "%s wr_bytes %lld\n", device, stats.wr_bytes);

    if (stats.errs >= 0)
        vshPrint (ctl, "%s errs %lld\n", device, stats.errs);

    virDomainFree(dom);
E
Eric Blake 已提交
1011
    return true;
1012 1013 1014 1015
}

/* "domifstat" command
 */
1016
static const vshCmdInfo info_domifstat[] = {
1017 1018
    {"help", N_("get network interface stats for a domain")},
    {"desc", N_("Get network interface stats for a running domain.")},
1019 1020 1021
    {NULL,NULL}
};

1022
static const vshCmdOptDef opts_domifstat[] = {
1023 1024
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")},
1025 1026 1027
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1028
static bool
1029
cmdDomIfstat (vshControl *ctl, const vshCmd *cmd)
1030 1031
{
    virDomainPtr dom;
1032
    const char *name = NULL, *device = NULL;
1033 1034
    struct _virDomainInterfaceStats stats;

1035
    if (!vshConnectionUsability (ctl, ctl->conn))
E
Eric Blake 已提交
1036
        return false;
1037

J
Jim Meyering 已提交
1038
    if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
E
Eric Blake 已提交
1039
        return false;
1040

1041
    if (vshCommandOptString (cmd, "interface", &device) <= 0) {
L
Laine Stump 已提交
1042
        virDomainFree(dom);
E
Eric Blake 已提交
1043
        return false;
L
Laine Stump 已提交
1044
    }
1045 1046

    if (virDomainInterfaceStats (dom, device, &stats, sizeof stats) == -1) {
1047
        vshError(ctl, _("Failed to get interface stats %s %s"), name, device);
1048
        virDomainFree(dom);
E
Eric Blake 已提交
1049
        return false;
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
    }

    if (stats.rx_bytes >= 0)
        vshPrint (ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes);

    if (stats.rx_packets >= 0)
        vshPrint (ctl, "%s rx_packets %lld\n", device, stats.rx_packets);

    if (stats.rx_errs >= 0)
        vshPrint (ctl, "%s rx_errs %lld\n", device, stats.rx_errs);

    if (stats.rx_drop >= 0)
        vshPrint (ctl, "%s rx_drop %lld\n", device, stats.rx_drop);

    if (stats.tx_bytes >= 0)
        vshPrint (ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes);

    if (stats.tx_packets >= 0)
        vshPrint (ctl, "%s tx_packets %lld\n", device, stats.tx_packets);

    if (stats.tx_errs >= 0)
        vshPrint (ctl, "%s tx_errs %lld\n", device, stats.tx_errs);

    if (stats.tx_drop >= 0)
        vshPrint (ctl, "%s tx_drop %lld\n", device, stats.tx_drop);

    virDomainFree(dom);
E
Eric Blake 已提交
1077
    return true;
1078 1079
}

1080 1081 1082
/*
 * "dommemstats" command
 */
1083
static const vshCmdInfo info_dommemstat[] = {
1084 1085
    {"help", N_("get memory statistics for a domain")},
    {"desc", N_("Get memory statistics for a runnng domain.")},
1086 1087 1088
    {NULL,NULL}
};

1089
static const vshCmdOptDef opts_dommemstat[] = {
1090
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1091 1092 1093
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1094
static bool
1095
cmdDomMemStat(vshControl *ctl, const vshCmd *cmd)
1096 1097
{
    virDomainPtr dom;
1098
    const char *name;
1099 1100 1101
    struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR];
    unsigned int nr_stats, i;

1102
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1103
        return false;
1104 1105

    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1106
        return false;
1107 1108 1109 1110 1111

    nr_stats = virDomainMemoryStats (dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0);
    if (nr_stats == -1) {
        vshError(ctl, _("Failed to get memory statistics for domain %s"), name);
        virDomainFree(dom);
E
Eric Blake 已提交
1112
        return false;
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
    }

    for (i = 0; i < nr_stats; i++) {
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
            vshPrint (ctl, "swap_in %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
            vshPrint (ctl, "swap_out %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
            vshPrint (ctl, "major_fault %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
            vshPrint (ctl, "minor_fault %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED)
            vshPrint (ctl, "unused %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE)
            vshPrint (ctl, "available %llu\n", stats[i].val);
    }

    virDomainFree(dom);
E
Eric Blake 已提交
1131
    return true;
1132 1133
}

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
/*
 * "domblkinfo" command
 */
static const vshCmdInfo info_domblkinfo[] = {
    {"help", N_("domain block device size information")},
    {"desc", N_("Get block device size info for a domain.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_domblkinfo[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1149
static bool
1150 1151 1152 1153
cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd)
{
    virDomainBlockInfo info;
    virDomainPtr dom;
E
Eric Blake 已提交
1154
    bool ret = true;
1155
    const char *device = NULL;
1156

1157
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1158
        return false;
1159 1160

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
1161
        return false;
1162

1163
    if (vshCommandOptString (cmd, "device", &device) <= 0) {
1164
        virDomainFree(dom);
E
Eric Blake 已提交
1165
        return false;
1166 1167 1168 1169
    }

    if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) {
        virDomainFree(dom);
E
Eric Blake 已提交
1170
        return false;
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
    }

    vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity);
    vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation);
    vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical);

    virDomainFree(dom);
    return ret;
}

1181 1182 1183
/*
 * "suspend" command
 */
1184
static const vshCmdInfo info_suspend[] = {
1185 1186
    {"help", N_("suspend a domain")},
    {"desc", N_("Suspend a running domain.")},
1187
    {NULL, NULL}
1188 1189
};

1190
static const vshCmdOptDef opts_suspend[] = {
1191
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1192
    {NULL, 0, 0, NULL}
1193 1194
};

E
Eric Blake 已提交
1195
static bool
1196
cmdSuspend(vshControl *ctl, const vshCmd *cmd)
1197
{
1198
    virDomainPtr dom;
1199
    const char *name;
E
Eric Blake 已提交
1200
    bool ret = true;
1201

1202
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1203
        return false;
1204

J
Jim Meyering 已提交
1205
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1206
        return false;
1207 1208

    if (virDomainSuspend(dom) == 0) {
1209
        vshPrint(ctl, _("Domain %s suspended\n"), name);
1210
    } else {
1211
        vshError(ctl, _("Failed to suspend domain %s"), name);
E
Eric Blake 已提交
1212
        ret = false;
1213
    }
1214

1215 1216 1217 1218
    virDomainFree(dom);
    return ret;
}

1219 1220 1221
/*
 * "create" command
 */
1222
static const vshCmdInfo info_create[] = {
1223 1224
    {"help", N_("create a domain from an XML file")},
    {"desc", N_("Create a domain.")},
1225 1226 1227
    {NULL, NULL}
};

1228
static const vshCmdOptDef opts_create[] = {
1229
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1230
#ifndef WIN32
1231
    {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1232
#endif
1233
    {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
1234 1235 1236
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1237
static bool
1238
cmdCreate(vshControl *ctl, const vshCmd *cmd)
1239 1240
{
    virDomainPtr dom;
1241
    const char *from = NULL;
E
Eric Blake 已提交
1242
    bool ret = true;
1243
    char *buffer;
1244
#ifndef WIN32
1245
    int console = vshCommandOptBool(cmd, "console");
1246
#endif
1247
    unsigned int flags = VIR_DOMAIN_NONE;
1248

1249
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1250
        return false;
1251

1252
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
1253
        return false;
1254

1255
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
1256
        return false;
1257

1258 1259 1260 1261
    if (vshCommandOptBool(cmd, "paused"))
        flags |= VIR_DOMAIN_START_PAUSED;

    dom = virDomainCreateXML(ctl->conn, buffer, flags);
1262
    VIR_FREE(buffer);
1263

1264
    if (dom != NULL) {
1265
        vshPrint(ctl, _("Domain %s created from %s\n"),
1266
                 virDomainGetName(dom), from);
1267
#ifndef WIN32
1268
        if (console)
1269
            cmdRunConsole(ctl, dom, NULL);
1270
#endif
1271
        virDomainFree(dom);
1272
    } else {
1273
        vshError(ctl, _("Failed to create domain from %s"), from);
E
Eric Blake 已提交
1274
        ret = false;
1275 1276 1277 1278
    }
    return ret;
}

1279 1280 1281
/*
 * "define" command
 */
1282
static const vshCmdInfo info_define[] = {
1283 1284
    {"help", N_("define (but don't start) a domain from an XML file")},
    {"desc", N_("Define a domain.")},
1285 1286 1287
    {NULL, NULL}
};

1288
static const vshCmdOptDef opts_define[] = {
1289
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1290 1291 1292
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1293
static bool
1294
cmdDefine(vshControl *ctl, const vshCmd *cmd)
1295 1296
{
    virDomainPtr dom;
1297
    const char *from = NULL;
E
Eric Blake 已提交
1298
    bool ret = true;
1299
    char *buffer;
1300

1301
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1302
        return false;
1303

1304
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
1305
        return false;
1306

1307
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
1308
        return false;
1309 1310

    dom = virDomainDefineXML(ctl->conn, buffer);
1311
    VIR_FREE(buffer);
1312

1313
    if (dom != NULL) {
1314
        vshPrint(ctl, _("Domain %s defined from %s\n"),
1315
                 virDomainGetName(dom), from);
1316
        virDomainFree(dom);
1317
    } else {
1318
        vshError(ctl, _("Failed to define domain from %s"), from);
E
Eric Blake 已提交
1319
        ret = false;
1320 1321 1322 1323 1324 1325 1326
    }
    return ret;
}

/*
 * "undefine" command
 */
1327
static const vshCmdInfo info_undefine[] = {
1328 1329
    {"help", N_("undefine an inactive domain")},
    {"desc", N_("Undefine the configuration for an inactive domain.")},
1330 1331 1332
    {NULL, NULL}
};

1333
static const vshCmdOptDef opts_undefine[] = {
1334
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
1335 1336 1337
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1338
static bool
1339
cmdUndefine(vshControl *ctl, const vshCmd *cmd)
1340 1341
{
    virDomainPtr dom;
E
Eric Blake 已提交
1342
    bool ret = true;
1343
    const char *name = NULL;
1344
    int id;
1345

1346
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1347
        return false;
1348

1349
    if (vshCommandOptString(cmd, "domain", &name) <= 0)
E
Eric Blake 已提交
1350
        return false;
1351 1352 1353

    if (name && virStrToLong_i(name, NULL, 10, &id) == 0
        && id >= 0 && (dom = virDomainLookupByID(ctl->conn, id))) {
1354 1355 1356 1357 1358
        vshError(ctl,
                 _("a running domain like %s cannot be undefined;\n"
                   "to undefine, first shutdown then undefine"
                   " using its name or UUID"),
                 name);
1359
        virDomainFree(dom);
E
Eric Blake 已提交
1360
        return false;
1361
    }
J
Jim Meyering 已提交
1362
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, &name,
1363
                                      VSH_BYNAME|VSH_BYUUID)))
E
Eric Blake 已提交
1364
        return false;
1365 1366

    if (virDomainUndefine(dom) == 0) {
1367
        vshPrint(ctl, _("Domain %s has been undefined\n"), name);
1368
    } else {
1369
        vshError(ctl, _("Failed to undefine domain %s"), name);
E
Eric Blake 已提交
1370
        ret = false;
1371 1372
    }

1373
    virDomainFree(dom);
1374 1375 1376 1377 1378 1379 1380
    return ret;
}


/*
 * "start" command
 */
1381
static const vshCmdInfo info_start[] = {
1382
    {"help", N_("start a (previously defined) inactive domain")},
1383 1384 1385
    {"desc", N_("Start a domain, either from the last managedsave\n"
                "    state, or via a fresh boot if no managedsave state\n"
                "    is present.")},
1386 1387 1388
    {NULL, NULL}
};

1389
static const vshCmdOptDef opts_start[] = {
1390
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive domain")},
1391
#ifndef WIN32
1392
    {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1393
#endif
E
Eric Blake 已提交
1394
    {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
1395 1396 1397
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1398
static bool
1399
cmdStart(vshControl *ctl, const vshCmd *cmd)
1400 1401
{
    virDomainPtr dom;
E
Eric Blake 已提交
1402
    bool ret = true;
1403
#ifndef WIN32
1404
    int console = vshCommandOptBool(cmd, "console");
1405
#endif
E
Eric Blake 已提交
1406
    unsigned int flags = VIR_DOMAIN_NONE;
1407

1408
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1409
        return false;
1410

1411 1412
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
                                      VSH_BYNAME | VSH_BYUUID)))
E
Eric Blake 已提交
1413
        return false;
1414 1415

    if (virDomainGetID(dom) != (unsigned int)-1) {
1416
        vshError(ctl, "%s", _("Domain is already active"));
1417
        virDomainFree(dom);
E
Eric Blake 已提交
1418
        return false;
1419 1420
    }

E
Eric Blake 已提交
1421 1422 1423 1424 1425 1426
    if (vshCommandOptBool(cmd, "paused"))
        flags |= VIR_DOMAIN_START_PAUSED;

    /* Prefer older API unless we have to pass a flag.  */
    if ((flags ? virDomainCreateWithFlags(dom, flags)
         : virDomainCreate(dom)) == 0) {
1427
        vshPrint(ctl, _("Domain %s started\n"),
1428
                 virDomainGetName(dom));
1429
#ifndef WIN32
1430
        if (console)
1431
            cmdRunConsole(ctl, dom, NULL);
1432
#endif
1433
    } else {
1434
        vshError(ctl, _("Failed to start domain %s"), virDomainGetName(dom));
E
Eric Blake 已提交
1435
        ret = false;
1436
    }
1437
    virDomainFree(dom);
1438 1439 1440
    return ret;
}

1441 1442 1443
/*
 * "save" command
 */
1444
static const vshCmdInfo info_save[] = {
1445 1446
    {"help", N_("save a domain state to a file")},
    {"desc", N_("Save a running domain.")},
1447
    {NULL, NULL}
1448 1449
};

1450
static const vshCmdOptDef opts_save[] = {
1451 1452
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to save the data")},
1453
    {NULL, 0, 0, NULL}
1454 1455
};

E
Eric Blake 已提交
1456
static bool
1457
cmdSave(vshControl *ctl, const vshCmd *cmd)
1458
{
1459
    virDomainPtr dom;
1460 1461
    const char *name = NULL;
    const char *to = NULL;
E
Eric Blake 已提交
1462
    bool ret = true;
1463

1464
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1465
        return false;
1466

1467
    if (vshCommandOptString(cmd, "file", &to) <= 0)
E
Eric Blake 已提交
1468
        return false;
1469

J
Jim Meyering 已提交
1470
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1471
        return false;
1472 1473

    if (virDomainSave(dom, to) == 0) {
1474
        vshPrint(ctl, _("Domain %s saved to %s\n"), name, to);
1475
    } else {
1476
        vshError(ctl, _("Failed to save domain %s to %s"), name, to);
E
Eric Blake 已提交
1477
        ret = false;
1478
    }
1479

1480 1481 1482 1483
    virDomainFree(dom);
    return ret;
}

1484 1485 1486 1487 1488
/*
 * "managedsave" command
 */
static const vshCmdInfo info_managedsave[] = {
    {"help", N_("managed save of a domain state")},
1489 1490 1491 1492
    {"desc", N_("Save and destroy a running domain, so it can be restarted from\n"
                "    the same state at a later time.  When the virsh 'start'\n"
                "    command is next run for the domain, it will automatically\n"
                "    be started from this saved state.")},
1493 1494 1495 1496 1497 1498 1499 1500
    {NULL, NULL}
};

static const vshCmdOptDef opts_managedsave[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1501
static bool
1502 1503 1504
cmdManagedSave(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
1505
    const char *name;
E
Eric Blake 已提交
1506
    bool ret = true;
1507

1508
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1509
        return false;
1510 1511

    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1512
        return false;
1513 1514 1515 1516 1517

    if (virDomainManagedSave(dom, 0) == 0) {
        vshPrint(ctl, _("Domain %s state saved by libvirt\n"), name);
    } else {
        vshError(ctl, _("Failed to save domain %s state"), name);
E
Eric Blake 已提交
1518
        ret = false;
1519 1520 1521 1522 1523 1524
    }

    virDomainFree(dom);
    return ret;
}

1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
/*
 * "managedsave-remove" command
 */
static const vshCmdInfo info_managedsaveremove[] = {
    {"help", N_("Remove managed save of a domain")},
    {"desc", N_("Remove an existing managed save state file from a domain")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_managedsaveremove[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1539
static bool
1540 1541 1542
cmdManagedSaveRemove(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
1543
    const char *name;
E
Eric Blake 已提交
1544
    bool ret = false;
1545 1546
    int hassave;

1547
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1548
        return false;
1549 1550

    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1551
        return false;
1552 1553 1554

    hassave = virDomainHasManagedSaveImage(dom, 0);
    if (hassave < 0) {
1555
        vshError(ctl, "%s", _("Failed to check for domain managed save image"));
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
        goto cleanup;
    }

    if (hassave) {
        if (virDomainManagedSaveRemove(dom, 0) < 0) {
            vshError(ctl, _("Failed to remove managed save image for domain %s"),
                     name);
            goto cleanup;
        }
        else
            vshPrint(ctl, _("Removed managedsave image for domain %s"), name);
    }
    else
        vshPrint(ctl, _("Domain %s has no manage save image; removal skipped"),
                 name);

E
Eric Blake 已提交
1572
    ret = true;
1573 1574 1575 1576 1577 1578

cleanup:
    virDomainFree(dom);
    return ret;
}

1579 1580 1581
/*
 * "schedinfo" command
 */
1582
static const vshCmdInfo info_schedinfo[] = {
1583 1584
    {"help", N_("show/set scheduler parameters")},
    {"desc", N_("Show/Set scheduler parameters.")},
1585 1586 1587
    {NULL, NULL}
};

1588
static const vshCmdOptDef opts_schedinfo[] = {
1589 1590 1591 1592
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"set", VSH_OT_STRING, VSH_OFLAG_NONE, N_("parameter=value")},
    {"weight", VSH_OT_INT, VSH_OFLAG_NONE, N_("weight for XEN_CREDIT")},
    {"cap", VSH_OT_INT, VSH_OFLAG_NONE, N_("cap for XEN_CREDIT")},
1593 1594 1595
    {NULL, 0, 0, NULL}
};

W
Wen Congyang 已提交
1596
static int
1597 1598
cmdSchedInfoUpdate(vshControl *ctl, const vshCmd *cmd,
                   virSchedParameterPtr param)
1599
{
1600
    const char *data = NULL;
1601 1602 1603 1604 1605 1606

    /* Legacy 'weight' parameter */
    if (STREQ(param->field, "weight") &&
        param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
        vshCommandOptBool(cmd, "weight")) {
        int val;
1607
        if (vshCommandOptInt(cmd, "weight", &val) <= 0) {
1608
            vshError(ctl, "%s", _("Invalid value of weight"));
1609
            return -1;
1610
        } else {
1611
            param->value.ui = val;
1612
        }
1613
        return 1;
1614 1615
    }

1616 1617 1618 1619 1620
    /* Legacy 'cap' parameter */
    if (STREQ(param->field, "cap") &&
        param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
        vshCommandOptBool(cmd, "cap")) {
        int val;
1621
        if (vshCommandOptInt(cmd, "cap", &val) <= 0) {
1622
            vshError(ctl, "%s", _("Invalid value of cap"));
1623
            return -1;
1624
        } else {
1625
            param->value.ui = val;
1626
        }
1627
        return 1;
1628
    }
1629

1630
    if (vshCommandOptString(cmd, "set", &data) > 0) {
1631 1632 1633
        char *val = strchr(data, '=');
        int match = 0;
        if (!val) {
1634
            vshError(ctl, "%s", _("Invalid syntax for --set, expecting name=value"));
1635
            return -1;
1636
        }
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
        *val = '\0';
        match = STREQ(data, param->field);
        *val = '=';
        val++;

        if (!match)
            return 0;

        switch (param->type) {
        case VIR_DOMAIN_SCHED_FIELD_INT:
            if (virStrToLong_i(val, NULL, 10, &param->value.i) < 0) {
1648
                vshError(ctl, "%s",
1649 1650 1651 1652 1653 1654
                         _("Invalid value for parameter, expecting an int"));
                return -1;
            }
            break;
        case VIR_DOMAIN_SCHED_FIELD_UINT:
            if (virStrToLong_ui(val, NULL, 10, &param->value.ui) < 0) {
1655
                vshError(ctl, "%s",
1656 1657 1658 1659 1660 1661
                         _("Invalid value for parameter, expecting an unsigned int"));
                return -1;
            }
            break;
        case VIR_DOMAIN_SCHED_FIELD_LLONG:
            if (virStrToLong_ll(val, NULL, 10, &param->value.l) < 0) {
1662
                vshError(ctl, "%s",
J
Jim Meyering 已提交
1663
                         _("Invalid value for parameter, expecting a long long"));
1664 1665 1666 1667 1668
                return -1;
            }
            break;
        case VIR_DOMAIN_SCHED_FIELD_ULLONG:
            if (virStrToLong_ull(val, NULL, 10, &param->value.ul) < 0) {
1669
                vshError(ctl, "%s",
1670 1671 1672 1673 1674 1675
                         _("Invalid value for parameter, expecting an unsigned long long"));
                return -1;
            }
            break;
        case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
            if (virStrToDouble(val, NULL, &param->value.d) < 0) {
1676
                vshError(ctl, "%s", _("Invalid value for parameter, expecting a double"));
1677 1678 1679 1680 1681
                return -1;
            }
            break;
        case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
            param->value.b = STREQ(val, "0") ? 0 : 1;
1682
        }
1683
        return 1;
1684
    }
1685

1686 1687
    return 0;
}
1688

1689

E
Eric Blake 已提交
1690
static bool
1691 1692 1693 1694 1695 1696 1697 1698
cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
{
    char *schedulertype;
    virDomainPtr dom;
    virSchedParameterPtr params = NULL;
    int nparams = 0;
    int update = 0;
    int i, ret;
W
Wen Congyang 已提交
1699
    bool ret_val = false;
1700

1701
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1702
        return false;
1703

1704
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
1705
        return false;
1706 1707 1708 1709

    /* Print SchedulerType */
    schedulertype = virDomainGetSchedulerType(dom, &nparams);
    if (schedulertype!= NULL){
1710
        vshPrint(ctl, "%-15s: %s\n", _("Scheduler"),
1711
             schedulertype);
1712
        VIR_FREE(schedulertype);
1713
    } else {
1714
        vshPrint(ctl, "%-15s: %s\n", _("Scheduler"), _("Unknown"));
1715
        goto cleanup;
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
    if (nparams) {
        params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams);

        memset(params, 0, sizeof(virSchedParameter)* nparams);
        ret = virDomainGetSchedulerParameters(dom, params, &nparams);
        if (ret == -1)
            goto cleanup;

        /* See if any params are being set */
        for (i = 0; i < nparams; i++){
            ret = cmdSchedInfoUpdate(ctl, cmd, &(params[i]));
            if (ret == -1)
                goto cleanup;

            if (ret == 1)
                update = 1;
        }

        /* Update parameters & refresh data */
        if (update) {
            ret = virDomainSetSchedulerParameters(dom, params, nparams);
            if (ret == -1)
                goto cleanup;

            ret = virDomainGetSchedulerParameters(dom, params, &nparams);
            if (ret == -1)
                goto cleanup;
1745 1746 1747 1748
        } else {
            /* See if we've tried to --set var=val.  If so, the fact that
               we reach this point (with update == 0) means that "var" did
               not match any of the settable parameters.  Report the error.  */
1749 1750
            const char *var_value_pair = NULL;
            if (vshCommandOptString(cmd, "set", &var_value_pair) > 0) {
1751 1752 1753 1754
                vshError(ctl, _("invalid scheduler option: %s"),
                         var_value_pair);
                goto cleanup;
            }
1755 1756
        }

E
Eric Blake 已提交
1757
        ret_val = true;
1758 1759 1760
        for (i = 0; i < nparams; i++){
            switch (params[i].type) {
            case VIR_DOMAIN_SCHED_FIELD_INT:
1761
                 vshPrint(ctl, "%-15s: %d\n",  params[i].field, params[i].value.i);
1762 1763
                 break;
            case VIR_DOMAIN_SCHED_FIELD_UINT:
1764
                 vshPrint(ctl, "%-15s: %u\n",  params[i].field, params[i].value.ui);
1765 1766
                 break;
            case VIR_DOMAIN_SCHED_FIELD_LLONG:
1767
                 vshPrint(ctl, "%-15s: %lld\n",  params[i].field, params[i].value.l);
1768 1769
                 break;
            case VIR_DOMAIN_SCHED_FIELD_ULLONG:
1770
                 vshPrint(ctl, "%-15s: %llu\n",  params[i].field, params[i].value.ul);
1771 1772
                 break;
            case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
1773
                 vshPrint(ctl, "%-15s: %f\n",  params[i].field, params[i].value.d);
1774 1775
                 break;
            case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
1776
                 vshPrint(ctl, "%-15s: %d\n",  params[i].field, params[i].value.b);
1777 1778
                 break;
            default:
1779
                 vshPrint(ctl, "not implemented scheduler parameter type\n");
1780 1781 1782
            }
        }
    }
1783

1784
 cleanup:
1785
    VIR_FREE(params);
1786
    virDomainFree(dom);
1787
    return ret_val;
1788 1789
}

1790 1791 1792
/*
 * "restore" command
 */
1793
static const vshCmdInfo info_restore[] = {
1794 1795
    {"help", N_("restore a domain from a saved state in a file")},
    {"desc", N_("Restore a domain.")},
1796
    {NULL, NULL}
1797 1798
};

1799
static const vshCmdOptDef opts_restore[] = {
1800
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("the state to restore")},
1801
    {NULL, 0, 0, NULL}
1802 1803
};

E
Eric Blake 已提交
1804
static bool
1805
cmdRestore(vshControl *ctl, const vshCmd *cmd)
1806
{
1807
    const char *from = NULL;
E
Eric Blake 已提交
1808
    bool ret = true;
1809

1810
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1811
        return false;
1812

1813
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
1814
        return false;
1815 1816

    if (virDomainRestore(ctl->conn, from) == 0) {
1817
        vshPrint(ctl, _("Domain restored from %s\n"), from);
1818
    } else {
1819
        vshError(ctl, _("Failed to restore domain from %s"), from);
E
Eric Blake 已提交
1820
        ret = false;
1821 1822 1823 1824
    }
    return ret;
}

D
Daniel Veillard 已提交
1825 1826 1827
/*
 * "dump" command
 */
1828
static const vshCmdInfo info_dump[] = {
1829 1830
    {"help", N_("dump the core of a domain to a file for analysis")},
    {"desc", N_("Core dump a domain.")},
D
Daniel Veillard 已提交
1831 1832 1833
    {NULL, NULL}
};

1834
static const vshCmdOptDef opts_dump[] = {
1835 1836 1837 1838
    {"live", VSH_OT_BOOL, 0, N_("perform a live core dump if supported")},
    {"crash", VSH_OT_BOOL, 0, N_("crash the domain after core dump")},
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to dump the core")},
D
Daniel Veillard 已提交
1839 1840 1841
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1842
static bool
1843
cmdDump(vshControl *ctl, const vshCmd *cmd)
D
Daniel Veillard 已提交
1844 1845
{
    virDomainPtr dom;
1846 1847
    const char *name = NULL;
    const char *to = NULL;
E
Eric Blake 已提交
1848
    bool ret = true;
1849
    int flags = 0;
D
Daniel Veillard 已提交
1850

1851
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1852
        return false;
D
Daniel Veillard 已提交
1853

1854
    if (vshCommandOptString(cmd, "file", &to) <= 0)
E
Eric Blake 已提交
1855
        return false;
D
Daniel Veillard 已提交
1856

J
Jim Meyering 已提交
1857
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1858
        return false;
D
Daniel Veillard 已提交
1859

P
Paolo Bonzini 已提交
1860 1861
    if (vshCommandOptBool (cmd, "live"))
        flags |= VIR_DUMP_LIVE;
1862 1863 1864 1865
    if (vshCommandOptBool (cmd, "crash"))
        flags |= VIR_DUMP_CRASH;

    if (virDomainCoreDump(dom, to, flags) == 0) {
1866
        vshPrint(ctl, _("Domain %s dumped to %s\n"), name, to);
D
Daniel Veillard 已提交
1867
    } else {
1868
        vshError(ctl, _("Failed to core dump domain %s to %s"), name, to);
E
Eric Blake 已提交
1869
        ret = false;
D
Daniel Veillard 已提交
1870 1871 1872 1873 1874 1875
    }

    virDomainFree(dom);
    return ret;
}

1876 1877 1878
/*
 * "resume" command
 */
1879
static const vshCmdInfo info_resume[] = {
1880 1881
    {"help", N_("resume a domain")},
    {"desc", N_("Resume a previously suspended domain.")},
1882
    {NULL, NULL}
1883 1884
};

1885
static const vshCmdOptDef opts_resume[] = {
1886
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1887
    {NULL, 0, 0, NULL}
1888 1889
};

E
Eric Blake 已提交
1890
static bool
1891
cmdResume(vshControl *ctl, const vshCmd *cmd)
1892
{
1893
    virDomainPtr dom;
E
Eric Blake 已提交
1894
    bool ret = true;
1895
    const char *name;
1896

1897
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1898
        return false;
1899

J
Jim Meyering 已提交
1900
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1901
        return false;
1902 1903

    if (virDomainResume(dom) == 0) {
1904
        vshPrint(ctl, _("Domain %s resumed\n"), name);
1905
    } else {
1906
        vshError(ctl, _("Failed to resume domain %s"), name);
E
Eric Blake 已提交
1907
        ret = false;
1908
    }
1909

1910 1911 1912 1913
    virDomainFree(dom);
    return ret;
}

1914 1915 1916
/*
 * "shutdown" command
 */
1917
static const vshCmdInfo info_shutdown[] = {
1918 1919
    {"help", N_("gracefully shutdown a domain")},
    {"desc", N_("Run shutdown in the target domain.")},
1920
    {NULL, NULL}
1921 1922
};

1923
static const vshCmdOptDef opts_shutdown[] = {
1924
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1925
    {NULL, 0, 0, NULL}
1926 1927
};

E
Eric Blake 已提交
1928
static bool
1929
cmdShutdown(vshControl *ctl, const vshCmd *cmd)
1930
{
1931
    virDomainPtr dom;
E
Eric Blake 已提交
1932
    bool ret = true;
1933
    const char *name;
1934

1935
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1936
        return false;
1937

J
Jim Meyering 已提交
1938
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1939
        return false;
1940 1941

    if (virDomainShutdown(dom) == 0) {
1942
        vshPrint(ctl, _("Domain %s is being shutdown\n"), name);
1943
    } else {
1944
        vshError(ctl, _("Failed to shutdown domain %s"), name);
E
Eric Blake 已提交
1945
        ret = false;
1946
    }
1947

1948 1949 1950 1951
    virDomainFree(dom);
    return ret;
}

1952 1953 1954
/*
 * "reboot" command
 */
1955
static const vshCmdInfo info_reboot[] = {
1956 1957
    {"help", N_("reboot a domain")},
    {"desc", N_("Run a reboot command in the target domain.")},
1958 1959 1960
    {NULL, NULL}
};

1961
static const vshCmdOptDef opts_reboot[] = {
1962
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1963 1964 1965
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
1966
static bool
1967
cmdReboot(vshControl *ctl, const vshCmd *cmd)
1968 1969
{
    virDomainPtr dom;
E
Eric Blake 已提交
1970
    bool ret = true;
1971
    const char *name;
1972

1973
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
1974
        return false;
1975

J
Jim Meyering 已提交
1976
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
1977
        return false;
1978 1979

    if (virDomainReboot(dom, 0) == 0) {
1980
        vshPrint(ctl, _("Domain %s is being rebooted\n"), name);
1981
    } else {
1982
        vshError(ctl, _("Failed to reboot domain %s"), name);
E
Eric Blake 已提交
1983
        ret = false;
1984 1985 1986 1987 1988 1989
    }

    virDomainFree(dom);
    return ret;
}

1990 1991 1992
/*
 * "destroy" command
 */
1993
static const vshCmdInfo info_destroy[] = {
1994 1995
    {"help", N_("destroy a domain")},
    {"desc", N_("Destroy a given domain.")},
1996
    {NULL, NULL}
1997 1998
};

1999
static const vshCmdOptDef opts_destroy[] = {
2000
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2001
    {NULL, 0, 0, NULL}
2002 2003
};

E
Eric Blake 已提交
2004
static bool
2005
cmdDestroy(vshControl *ctl, const vshCmd *cmd)
2006
{
2007
    virDomainPtr dom;
E
Eric Blake 已提交
2008
    bool ret = true;
2009
    const char *name;
2010

2011
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2012
        return false;
2013

J
Jim Meyering 已提交
2014
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
E
Eric Blake 已提交
2015
        return false;
2016 2017

    if (virDomainDestroy(dom) == 0) {
2018
        vshPrint(ctl, _("Domain %s destroyed\n"), name);
2019
    } else {
2020
        vshError(ctl, _("Failed to destroy domain %s"), name);
E
Eric Blake 已提交
2021
        ret = false;
2022
    }
2023

2024
    virDomainFree(dom);
K
Karel Zak 已提交
2025 2026 2027 2028
    return ret;
}

/*
2029
 * "dominfo" command
K
Karel Zak 已提交
2030
 */
2031
static const vshCmdInfo info_dominfo[] = {
2032 2033
    {"help", N_("domain information")},
    {"desc", N_("Returns basic information about the domain.")},
2034
    {NULL, NULL}
K
Karel Zak 已提交
2035 2036
};

2037
static const vshCmdOptDef opts_dominfo[] = {
2038
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2039
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
2040 2041
};

E
Eric Blake 已提交
2042
static bool
2043
cmdDominfo(vshControl *ctl, const vshCmd *cmd)
2044
{
K
Karel Zak 已提交
2045 2046
    virDomainInfo info;
    virDomainPtr dom;
2047
    virSecurityModel secmodel;
2048
    virSecurityLabelPtr seclabel;
2049
    int persistent = 0;
E
Eric Blake 已提交
2050 2051
    bool ret = true;
    int autostart;
2052
    unsigned int id;
2053
    char *str, uuid[VIR_UUID_STRING_BUFLEN];
2054

2055
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2056
        return false;
K
Karel Zak 已提交
2057

J
Jim Meyering 已提交
2058
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2059
        return false;
2060

2061 2062
    id = virDomainGetID(dom);
    if (id == ((unsigned int)-1))
2063
        vshPrint(ctl, "%-15s %s\n", _("Id:"), "-");
2064
    else
2065
        vshPrint(ctl, "%-15s %d\n", _("Id:"), id);
2066 2067
    vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom));

K
Karel Zak 已提交
2068
    if (virDomainGetUUIDString(dom, &uuid[0])==0)
2069
        vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
2070 2071

    if ((str = virDomainGetOSType(dom))) {
2072
        vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str);
2073
        VIR_FREE(str);
2074 2075 2076
    }

    if (virDomainGetInfo(dom, &info) == 0) {
2077
        vshPrint(ctl, "%-15s %s\n", _("State:"),
E
Eric Blake 已提交
2078
                 _(vshDomainStateToString(info.state)));
2079

2080
        vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu);
2081 2082

        if (info.cpuTime != 0) {
2083
            double cpuUsed = info.cpuTime;
2084

2085
            cpuUsed /= 1000000000.0;
2086

2087
            vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed);
K
Karel Zak 已提交
2088
        }
2089

2090 2091
        if (info.maxMem != UINT_MAX)
            vshPrint(ctl, "%-15s %lu kB\n", _("Max memory:"),
2092
                 info.maxMem);
2093
        else
2094
            vshPrint(ctl, "%-15s %s\n", _("Max memory:"),
2095 2096
                 _("no limit"));

2097
        vshPrint(ctl, "%-15s %lu kB\n", _("Used memory:"),
2098 2099
                 info.memory);

K
Karel Zak 已提交
2100
    } else {
E
Eric Blake 已提交
2101
        ret = false;
K
Karel Zak 已提交
2102
    }
2103

2104 2105 2106 2107 2108 2109 2110 2111 2112
    /* Check and display whether the domain is persistent or not */
    persistent = virDomainIsPersistent(dom);
    vshDebug(ctl, 5, "Domain persistent flag value: %d\n", persistent);
    if (persistent < 0)
        vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
    else
        vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));

    /* Check and display whether the domain autostarts or not */
2113
    if (!virDomainGetAutostart(dom, &autostart)) {
2114
        vshPrint(ctl, "%-15s %s\n", _("Autostart:"),
2115 2116 2117
                 autostart ? _("enable") : _("disable") );
    }

2118 2119 2120
    /* Security model and label information */
    memset(&secmodel, 0, sizeof secmodel);
    if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) {
2121 2122
        if (last_error->code != VIR_ERR_NO_SUPPORT) {
            virDomainFree(dom);
E
Eric Blake 已提交
2123
            return false;
2124 2125 2126
        } else {
            virFreeError(last_error);
            last_error = NULL;
2127
        }
2128 2129 2130 2131 2132 2133 2134
    } else {
        /* Only print something if a security model is active */
        if (secmodel.model[0] != '\0') {
            vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model);
            vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi);

            /* Security labels are only valid for active domains */
2135
            if (VIR_ALLOC(seclabel) < 0) {
2136
                virDomainFree(dom);
E
Eric Blake 已提交
2137
                return false;
2138 2139 2140 2141 2142
            }

            if (virDomainGetSecurityLabel(dom, seclabel) == -1) {
                virDomainFree(dom);
                VIR_FREE(seclabel);
E
Eric Blake 已提交
2143
                return false;
2144
            } else {
2145
                if (seclabel->label[0] != '\0')
2146
                    vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"),
2147
                             seclabel->label, seclabel->enforcing ? "enforcing" : "permissive");
2148
            }
2149 2150

            VIR_FREE(seclabel);
2151 2152
        }
    }
2153
    virDomainFree(dom);
K
Karel Zak 已提交
2154 2155 2156
    return ret;
}

2157 2158 2159 2160
/*
 * "domjobinfo" command
 */
static const vshCmdInfo info_domjobinfo[] = {
2161 2162
    {"help", N_("domain job information")},
    {"desc", N_("Returns information about jobs running on a domain.")},
2163 2164 2165 2166
    {NULL, NULL}
};

static const vshCmdOptDef opts_domjobinfo[] = {
2167
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2168 2169 2170 2171
    {NULL, 0, 0, NULL}
};


E
Eric Blake 已提交
2172
static bool
2173 2174 2175 2176
cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd)
{
    virDomainJobInfo info;
    virDomainPtr dom;
E
Eric Blake 已提交
2177
    bool ret = true;
2178

2179
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2180
        return false;
2181 2182

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2183
        return false;
2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209

    if (virDomainGetJobInfo(dom, &info) == 0) {
        const char *unit;
        double val;

        vshPrint(ctl, "%-17s ", _("Job type:"));
        switch (info.type) {
        case VIR_DOMAIN_JOB_BOUNDED:
            vshPrint(ctl, "%-12s\n", _("Bounded"));
            break;

        case VIR_DOMAIN_JOB_UNBOUNDED:
            vshPrint(ctl, "%-12s\n", _("Unbounded"));
            break;

        case VIR_DOMAIN_JOB_NONE:
        default:
            vshPrint(ctl, "%-12s\n", _("None"));
            goto cleanup;
        }

        vshPrint(ctl, "%-17s %-12llu ms\n", _("Time elapsed:"), info.timeElapsed);
        if (info.type == VIR_DOMAIN_JOB_BOUNDED)
            vshPrint(ctl, "%-17s %-12llu ms\n", _("Time remaining:"), info.timeRemaining);
        if (info.dataTotal || info.dataRemaining || info.dataProcessed) {
            val = prettyCapacity(info.dataProcessed, &unit);
E
Eric Blake 已提交
2210
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data processed:"), val, unit);
2211
            val = prettyCapacity(info.dataRemaining, &unit);
E
Eric Blake 已提交
2212
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data remaining:"), val, unit);
2213
            val = prettyCapacity(info.dataTotal, &unit);
E
Eric Blake 已提交
2214
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data total:"), val, unit);
2215 2216 2217
        }
        if (info.memTotal || info.memRemaining || info.memProcessed) {
            val = prettyCapacity(info.memProcessed, &unit);
E
Eric Blake 已提交
2218
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory processed:"), val, unit);
2219
            val = prettyCapacity(info.memRemaining, &unit);
E
Eric Blake 已提交
2220
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory remaining:"), val, unit);
2221
            val = prettyCapacity(info.memTotal, &unit);
E
Eric Blake 已提交
2222
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory total:"), val, unit);
2223 2224 2225
        }
        if (info.fileTotal || info.fileRemaining || info.fileProcessed) {
            val = prettyCapacity(info.fileProcessed, &unit);
E
Eric Blake 已提交
2226
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("File processed:"), val, unit);
2227
            val = prettyCapacity(info.fileRemaining, &unit);
E
Eric Blake 已提交
2228
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("File remaining:"), val, unit);
2229
            val = prettyCapacity(info.fileTotal, &unit);
E
Eric Blake 已提交
2230
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("File total:"), val, unit);
2231 2232
        }
    } else {
E
Eric Blake 已提交
2233
        ret = false;
2234 2235 2236 2237 2238 2239
    }
cleanup:
    virDomainFree(dom);
    return ret;
}

2240 2241 2242 2243
/*
 * "domjobabort" command
 */
static const vshCmdInfo info_domjobabort[] = {
2244 2245
    {"help", N_("abort active domain job")},
    {"desc", N_("Aborts the currently running domain job")},
2246 2247 2248 2249
    {NULL, NULL}
};

static const vshCmdOptDef opts_domjobabort[] = {
2250
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2251 2252 2253
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2254
static bool
2255 2256 2257
cmdDomjobabort(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
E
Eric Blake 已提交
2258
    bool ret = true;
2259

2260
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2261
        return false;
2262 2263

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2264
        return false;
2265 2266

    if (virDomainAbortJob(dom) < 0)
E
Eric Blake 已提交
2267
        ret = false;
2268 2269 2270 2271 2272

    virDomainFree(dom);
    return ret;
}

2273 2274 2275
/*
 * "freecell" command
 */
2276
static const vshCmdInfo info_freecell[] = {
2277 2278
    {"help", N_("NUMA free memory")},
    {"desc", N_("display available free memory for the NUMA cell.")},
2279 2280 2281
    {NULL, NULL}
};

2282
static const vshCmdOptDef opts_freecell[] = {
2283
    {"cellno", VSH_OT_INT, 0, N_("NUMA cell number")},
2284
    {"all", VSH_OT_BOOL, 0, N_("show free memory for all NUMA cells")},
2285 2286 2287
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2288
static bool
2289
cmdFreecell(vshControl *ctl, const vshCmd *cmd)
2290
{
W
Wen Congyang 已提交
2291
    bool func_ret = false;
2292
    int ret;
2293
    int cell = -1, cell_given;
2294
    unsigned long long memory;
2295 2296 2297 2298
    xmlNodePtr *nodes = NULL;
    unsigned long nodes_cnt;
    unsigned long *nodes_id = NULL;
    unsigned long long *nodes_free = NULL;
2299
    int all_given;
2300 2301 2302 2303
    int i;
    char *cap_xml = NULL;
    xmlDocPtr xml = NULL;
    xmlXPathContextPtr ctxt = NULL;
2304

2305

2306
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2307
        return false;
2308

2309 2310 2311 2312
    if ( (cell_given = vshCommandOptInt(cmd, "cellno", &cell)) < 0) {
        vshError(ctl, "%s", _("cell number has to be a number"));
        goto cleanup;
    }
2313 2314 2315 2316 2317 2318 2319 2320 2321
    all_given = vshCommandOptBool(cmd, "all");

    if (all_given && cell_given) {
        vshError(ctl, "%s", _("--cellno and --all are mutually exclusive. "
                              "Please choose only one."));
        goto cleanup;
    }

    if (all_given) {
2322 2323 2324
        cap_xml = virConnectGetCapabilities(ctl->conn);
        if (!cap_xml) {
            vshError(ctl, "%s", _("unable to get node capabilities"));
2325 2326 2327
            goto cleanup;
        }

2328 2329 2330
        xml = xmlReadDoc((const xmlChar *) cap_xml, "node.xml", NULL,
                          XML_PARSE_NOENT | XML_PARSE_NONET |
                          XML_PARSE_NOWARNING);
2331

2332 2333
        if (!xml) {
            vshError(ctl, "%s", _("unable to get node capabilities"));
2334 2335 2336
            goto cleanup;
        }

2337 2338 2339 2340 2341
        ctxt = xmlXPathNewContext(xml);
        nodes_cnt = virXPathNodeSet("/capabilities/host/topology/cells/cell",
                                    ctxt, &nodes);

        if (nodes_cnt == -1) {
2342
            vshError(ctl, "%s", _("could not get information about "
2343
                                  "NUMA topology"));
2344 2345 2346
            goto cleanup;
        }

2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367
        nodes_free = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_free));
        nodes_id = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_id));

        for (i = 0; i < nodes_cnt; i++) {
            unsigned long id;
            char *val = virXMLPropString(nodes[i], "id");
            if (virStrToLong_ul(val, NULL, 10, &id)) {
                vshError(ctl, "%s", _("conversion from string failed"));
                VIR_FREE(val);
                goto cleanup;
            }
            VIR_FREE(val);
            nodes_id[i]=id;
            ret = virNodeGetCellsFreeMemory(ctl->conn, &(nodes_free[i]), id, 1);
            if (ret != 1) {
                vshError(ctl, _("failed to get free memory for NUMA node "
                                "number: %lu"), id);
                goto cleanup;
            }
        }

2368
        memory = 0;
2369 2370 2371 2372
        for (cell = 0; cell < nodes_cnt; cell++) {
            vshPrint(ctl, "%5lu: %10llu kB\n", nodes_id[cell],
                    (nodes_free[cell]/1024));
            memory += nodes_free[cell];
2373 2374 2375 2376
        }

        vshPrintExtra(ctl, "--------------------\n");
        vshPrintExtra(ctl, "%5s: %10llu kB\n", _("Total"), memory/1024);
2377
    } else {
2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391
        if (!cell_given) {
            memory = virNodeGetFreeMemory(ctl->conn);
            if (memory == 0)
                goto cleanup;
        } else {
            ret = virNodeGetCellsFreeMemory(ctl->conn, &memory, cell, 1);
            if (ret != 1)
                goto cleanup;
        }

        if (cell == -1)
            vshPrint(ctl, "%s: %llu kB\n", _("Total"), (memory/1024));
        else
            vshPrint(ctl, "%d: %llu kB\n", cell, (memory/1024));
2392 2393
    }

E
Eric Blake 已提交
2394
    func_ret = true;
2395

2396
cleanup:
2397 2398 2399
    xmlXPathFreeContext(ctxt);
    if (xml)
        xmlFreeDoc(xml);
2400
    VIR_FREE(nodes);
2401 2402 2403
    VIR_FREE(nodes_free);
    VIR_FREE(nodes_id);
    VIR_FREE(cap_xml);
2404
    return func_ret;
2405 2406
}

E
Eric Blake 已提交
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420
/*
 * "maxvcpus" command
 */
static const vshCmdInfo info_maxvcpus[] = {
    {"help", N_("connection vcpu maximum")},
    {"desc", N_("Show maximum number of virtual CPUs for guests on this connection.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_maxvcpus[] = {
    {"type", VSH_OT_STRING, 0, N_("domain type")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2421
static bool
E
Eric Blake 已提交
2422 2423
cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd)
{
2424
    const char *type = NULL;
E
Eric Blake 已提交
2425 2426
    int vcpus;

2427 2428
    if (vshCommandOptString(cmd, "type", &type) < 0) {
        vshError(ctl, "%s", _("Invalid type"));
E
Eric Blake 已提交
2429
        return false;
2430
    }
E
Eric Blake 已提交
2431 2432

    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2433
        return false;
E
Eric Blake 已提交
2434 2435 2436

    vcpus = virConnectGetMaxVcpus(ctl->conn, type);
    if (vcpus < 0)
E
Eric Blake 已提交
2437
        return false;
E
Eric Blake 已提交
2438 2439
    vshPrint(ctl, "%d\n", vcpus);

E
Eric Blake 已提交
2440
    return true;
E
Eric Blake 已提交
2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460
}

/*
 * "vcpucount" command
 */
static const vshCmdInfo info_vcpucount[] = {
    {"help", N_("domain vcpu counts")},
    {"desc", N_("Returns the number of virtual CPUs used by the domain.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_vcpucount[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"maximum", VSH_OT_BOOL, 0, N_("get maximum cap on vcpus")},
    {"current", VSH_OT_BOOL, 0, N_("get current vcpu usage")},
    {"config", VSH_OT_BOOL, 0, N_("get value to be used on next boot")},
    {"live", VSH_OT_BOOL, 0, N_("get value from running domain")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2461
static bool
E
Eric Blake 已提交
2462 2463 2464
cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
E
Eric Blake 已提交
2465
    bool ret = true;
E
Eric Blake 已提交
2466 2467 2468 2469 2470 2471 2472 2473 2474 2475
    int maximum = vshCommandOptBool(cmd, "maximum");
    int current = vshCommandOptBool(cmd, "current");
    int config = vshCommandOptBool(cmd, "config");
    int live = vshCommandOptBool(cmd, "live");
    bool all = maximum + current + config + live == 0;
    int count;

    if (maximum && current) {
        vshError(ctl, "%s",
                 _("--maximum and --current cannot both be specified"));
E
Eric Blake 已提交
2476
        return false;
E
Eric Blake 已提交
2477 2478 2479 2480
    }
    if (config && live) {
        vshError(ctl, "%s",
                 _("--config and --live cannot both be specified"));
E
Eric Blake 已提交
2481
        return false;
E
Eric Blake 已提交
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
    }
    /* We want one of each pair of mutually exclusive options; that
     * is, use of flags requires exactly two options.  */
    if (maximum + current + config + live == 1) {
        vshError(ctl,
                 _("when using --%s, either --%s or --%s must be specified"),
                 (maximum ? "maximum" : current ? "current"
                  : config ? "config" : "live"),
                 maximum + current ? "config" : "maximum",
                 maximum + current ? "live" : "current");
E
Eric Blake 已提交
2492
        return false;
E
Eric Blake 已提交
2493 2494 2495
    }

    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2496
        return false;
E
Eric Blake 已提交
2497 2498

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2499
        return false;
E
Eric Blake 已提交
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515

    /* In all cases, try the new API first; if it fails because we are
     * talking to an older client, try a fallback API before giving
     * up.  */
    if (all || (maximum && config)) {
        count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
                                             VIR_DOMAIN_VCPU_CONFIG));
        if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                          || last_error->code == VIR_ERR_INVALID_ARG)) {
            char *tmp;
            char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
            if (xml && (tmp = strstr(xml, "<vcpu"))) {
                tmp = strchr(tmp, '>');
                if (!tmp || virStrToLong_i(tmp + 1, &tmp, 10, &count) < 0)
                    count = -1;
            }
2516 2517
            virFreeError(last_error);
            last_error = NULL;
E
Eric Blake 已提交
2518 2519 2520 2521 2522
            VIR_FREE(xml);
        }

        if (count < 0) {
            virshReportError(ctl);
E
Eric Blake 已提交
2523
            ret = false;
E
Eric Blake 已提交
2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543
        } else if (all) {
            vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("config"),
                     count);
        } else {
            vshPrint(ctl, "%d\n", count);
        }
        virFreeError(last_error);
        last_error = NULL;
    }

    if (all || (maximum && live)) {
        count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
                                             VIR_DOMAIN_VCPU_LIVE));
        if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                          || last_error->code == VIR_ERR_INVALID_ARG)) {
            count = virDomainGetMaxVcpus(dom);
        }

        if (count < 0) {
            virshReportError(ctl);
E
Eric Blake 已提交
2544
            ret = false;
E
Eric Blake 已提交
2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580
        } else if (all) {
            vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("live"),
                     count);
        } else {
            vshPrint(ctl, "%d\n", count);
        }
        virFreeError(last_error);
        last_error = NULL;
    }

    if (all || (current && config)) {
        count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_CONFIG);
        if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                          || last_error->code == VIR_ERR_INVALID_ARG)) {
            char *tmp, *end;
            char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
            if (xml && (tmp = strstr(xml, "<vcpu"))) {
                end = strchr(tmp, '>');
                if (end) {
                    *end = '\0';
                    tmp = strstr(tmp, "current=");
                    if (!tmp)
                        tmp = end + 1;
                    else {
                        tmp += strlen("current=");
                        tmp += *tmp == '\'' || *tmp == '"';
                    }
                }
                if (!tmp || virStrToLong_i(tmp, &tmp, 10, &count) < 0)
                    count = -1;
            }
            VIR_FREE(xml);
        }

        if (count < 0) {
            virshReportError(ctl);
E
Eric Blake 已提交
2581
            ret = false;
E
Eric Blake 已提交
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602
        } else if (all) {
            vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("config"),
                     count);
        } else {
            vshPrint(ctl, "%d\n", count);
        }
        virFreeError(last_error);
        last_error = NULL;
    }

    if (all || (current && live)) {
        count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_LIVE);
        if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                          || last_error->code == VIR_ERR_INVALID_ARG)) {
            virDomainInfo info;
            if (virDomainGetInfo(dom, &info) == 0)
                count = info.nrVirtCpu;
        }

        if (count < 0) {
            virshReportError(ctl);
E
Eric Blake 已提交
2603
            ret = false;
E
Eric Blake 已提交
2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617
        } else if (all) {
            vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("live"),
                     count);
        } else {
            vshPrint(ctl, "%d\n", count);
        }
        virFreeError(last_error);
        last_error = NULL;
    }

    virDomainFree(dom);
    return ret;
}

2618 2619 2620
/*
 * "vcpuinfo" command
 */
2621
static const vshCmdInfo info_vcpuinfo[] = {
E
Eric Blake 已提交
2622
    {"help", N_("detailed domain vcpu information")},
2623
    {"desc", N_("Returns basic information about the domain virtual CPUs.")},
2624 2625 2626
    {NULL, NULL}
};

2627
static const vshCmdOptDef opts_vcpuinfo[] = {
2628
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2629 2630 2631
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2632
static bool
2633
cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
2634 2635 2636 2637 2638 2639 2640 2641
{
    virDomainInfo info;
    virDomainPtr dom;
    virNodeInfo nodeinfo;
    virVcpuInfoPtr cpuinfo;
    unsigned char *cpumap;
    int ncpus;
    size_t cpumaplen;
E
Eric Blake 已提交
2642
    bool ret = true;
2643

2644
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2645
        return false;
2646

J
Jim Meyering 已提交
2647
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2648
        return false;
2649 2650 2651

    if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
        virDomainFree(dom);
E
Eric Blake 已提交
2652
        return false;
2653 2654 2655 2656
    }

    if (virDomainGetInfo(dom, &info) != 0) {
        virDomainFree(dom);
E
Eric Blake 已提交
2657
        return false;
2658 2659
    }

2660
    cpuinfo = vshMalloc(ctl, sizeof(virVcpuInfo)*info.nrVirtCpu);
2661
    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2662
    cpumap = vshMalloc(ctl, info.nrVirtCpu * cpumaplen);
2663

2664 2665 2666
    if ((ncpus = virDomainGetVcpus(dom,
                                   cpuinfo, info.nrVirtCpu,
                                   cpumap, cpumaplen)) >= 0) {
2667
        int n;
2668 2669 2670 2671 2672
        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:"),
E
Eric Blake 已提交
2673
                     _(vshDomainVcpuStateToString(cpuinfo[n].state)));
2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689
            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");
            }
        }
2690
    } else {
2691
        if (info.state == VIR_DOMAIN_SHUTOFF) {
2692 2693
            vshError(ctl, "%s",
                     _("Domain shut off, virtual CPUs not present."));
2694
        }
E
Eric Blake 已提交
2695
        ret = false;
2696 2697
    }

2698 2699
    VIR_FREE(cpumap);
    VIR_FREE(cpuinfo);
2700 2701 2702 2703 2704 2705 2706
    virDomainFree(dom);
    return ret;
}

/*
 * "vcpupin" command
 */
2707
static const vshCmdInfo info_vcpupin[] = {
2708 2709
    {"help", N_("control domain vcpu affinity")},
    {"desc", N_("Pin domain VCPUs to host physical CPUs.")},
2710 2711 2712
    {NULL, NULL}
};

2713
static const vshCmdOptDef opts_vcpupin[] = {
2714
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2715
    {"vcpu", VSH_OT_INT, VSH_OFLAG_REQ, N_("vcpu number")},
2716
    {"cpulist", VSH_OT_DATA, VSH_OFLAG_REQ, N_("host cpu number(s) (comma separated)")},
2717 2718 2719
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2720
static bool
2721
cmdVcpupin(vshControl *ctl, const vshCmd *cmd)
2722 2723 2724 2725 2726
{
    virDomainInfo info;
    virDomainPtr dom;
    virNodeInfo nodeinfo;
    int vcpu;
2727
    const char *cpulist = NULL;
E
Eric Blake 已提交
2728
    bool ret = true;
2729 2730
    unsigned char *cpumap;
    int cpumaplen;
2731 2732
    int i;
    enum { expect_num, expect_num_or_comma } state;
2733

2734
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2735
        return false;
2736

J
Jim Meyering 已提交
2737
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2738
        return false;
2739

2740
    if (vshCommandOptInt(cmd, "vcpu", &vcpu) <= 0) {
2741
        vshError(ctl, "%s", _("vcpupin: Invalid or missing vCPU number."));
2742
        virDomainFree(dom);
E
Eric Blake 已提交
2743
        return false;
2744 2745
    }

2746
    if (vshCommandOptString(cmd, "cpulist", &cpulist) <= 0) {
2747
        virDomainFree(dom);
E
Eric Blake 已提交
2748
        return false;
2749
    }
2750

2751 2752
    if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
        virDomainFree(dom);
E
Eric Blake 已提交
2753
        return false;
2754 2755 2756
    }

    if (virDomainGetInfo(dom, &info) != 0) {
2757
        vshError(ctl, "%s", _("vcpupin: failed to get domain informations."));
2758
        virDomainFree(dom);
E
Eric Blake 已提交
2759
        return false;
2760 2761 2762
    }

    if (vcpu >= info.nrVirtCpu) {
2763
        vshError(ctl, "%s", _("vcpupin: Invalid vCPU number."));
2764
        virDomainFree(dom);
E
Eric Blake 已提交
2765
        return false;
2766 2767
    }

2768 2769 2770 2771
    /* Check that the cpulist parameter is a comma-separated list of
     * numbers and give an intelligent error message if not.
     */
    if (cpulist[0] == '\0') {
2772
        vshError(ctl, "%s", _("cpulist: Invalid format. Empty string."));
2773
        virDomainFree (dom);
E
Eric Blake 已提交
2774
        return false;
2775 2776 2777 2778 2779 2780
    }

    state = expect_num;
    for (i = 0; cpulist[i]; i++) {
        switch (state) {
        case expect_num:
2781
          if (!c_isdigit (cpulist[i])) {
2782 2783 2784
                vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
                                "digit at position %d (near '%c')."),
                         cpulist, i, cpulist[i]);
2785
                virDomainFree (dom);
E
Eric Blake 已提交
2786
                return false;
2787 2788 2789 2790 2791 2792
            }
            state = expect_num_or_comma;
            break;
        case expect_num_or_comma:
            if (cpulist[i] == ',')
                state = expect_num;
2793
            else if (!c_isdigit (cpulist[i])) {
2794 2795 2796
                vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
                                "digit or comma at position %d (near '%c')."),
                         cpulist, i, cpulist[i]);
2797
                virDomainFree (dom);
E
Eric Blake 已提交
2798
                return false;
2799 2800 2801 2802
            }
        }
    }
    if (state == expect_num) {
2803 2804 2805
        vshError(ctl, _("cpulist: %s: Invalid format. Trailing comma "
                        "at position %d."),
                 cpulist, i);
2806
        virDomainFree (dom);
E
Eric Blake 已提交
2807
        return false;
2808 2809
    }

2810
    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2811
    cpumap = vshCalloc(ctl, 1, cpumaplen);
2812 2813 2814 2815 2816 2817

    do {
        unsigned int cpu = atoi(cpulist);

        if (cpu < VIR_NODEINFO_MAXCPUS(nodeinfo)) {
            VIR_USE_CPU(cpumap, cpu);
2818
        } else {
2819
            vshError(ctl, _("Physical CPU %d doesn't exist."), cpu);
2820
            VIR_FREE(cpumap);
2821
            virDomainFree(dom);
E
Eric Blake 已提交
2822
            return false;
2823
        }
2824
        cpulist = strchr(cpulist, ',');
2825 2826 2827 2828 2829
        if (cpulist)
            cpulist++;
    } while (cpulist);

    if (virDomainPinVcpu(dom, vcpu, cpumap, cpumaplen) != 0) {
E
Eric Blake 已提交
2830
        ret = false;
2831 2832
    }

2833
    VIR_FREE(cpumap);
2834 2835 2836 2837
    virDomainFree(dom);
    return ret;
}

2838 2839 2840
/*
 * "setvcpus" command
 */
2841
static const vshCmdInfo info_setvcpus[] = {
2842 2843
    {"help", N_("change number of virtual CPUs")},
    {"desc", N_("Change the number of virtual CPUs in the guest domain.")},
2844 2845 2846
    {NULL, NULL}
};

2847
static const vshCmdOptDef opts_setvcpus[] = {
2848
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2849
    {"count", VSH_OT_INT, VSH_OFLAG_REQ, N_("number of virtual CPUs")},
E
Eric Blake 已提交
2850 2851 2852
    {"maximum", VSH_OT_BOOL, 0, N_("set maximum limit on next boot")},
    {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
    {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
2853 2854 2855
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2856
static bool
2857
cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
2858 2859
{
    virDomainPtr dom;
2860
    int count = 0;
E
Eric Blake 已提交
2861
    bool ret = true;
E
Eric Blake 已提交
2862 2863 2864 2865 2866 2867
    int maximum = vshCommandOptBool(cmd, "maximum");
    int config = vshCommandOptBool(cmd, "config");
    int live = vshCommandOptBool(cmd, "live");
    int flags = ((maximum ? VIR_DOMAIN_VCPU_MAXIMUM : 0) |
                 (config ? VIR_DOMAIN_VCPU_CONFIG : 0) |
                 (live ? VIR_DOMAIN_VCPU_LIVE : 0));
2868

2869
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2870
        return false;
2871

J
Jim Meyering 已提交
2872
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2873
        return false;
2874

2875 2876 2877 2878
    if (vshCommandOptInt(cmd, "count", &count) < 0) {
        vshError(ctl, "%s", _("Invalid number of virtual CPUs"));
        goto cleanup;
    }
2879

E
Eric Blake 已提交
2880 2881
    if (!flags) {
        if (virDomainSetVcpus(dom, count) != 0) {
E
Eric Blake 已提交
2882
            ret = false;
E
Eric Blake 已提交
2883 2884
        }
    } else {
2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897
        /* If the --maximum flag was given, we need to ensure only the
           --config flag is in effect as well */
        if (maximum) {
            vshDebug(ctl, 5, "--maximum flag was given\n");

            /* If neither the --config nor --live flags were given, OR
               if just the --live flag was given, we need to error out
               warning the user that the --maximum flag can only be used
               with the --config flag */
            if (live || !config) {

                /* Warn the user about the invalid flag combination */
                vshError(ctl, _("--maximum must be used with --config only"));
E
Eric Blake 已提交
2898
                ret = false;
2899 2900 2901 2902 2903
                goto cleanup;
            }
        }

        /* Apply the virtual cpu changes */
E
Eric Blake 已提交
2904
        if (virDomainSetVcpusFlags(dom, count, flags) < 0) {
E
Eric Blake 已提交
2905
            ret = false;
E
Eric Blake 已提交
2906
        }
2907 2908
    }

2909
  cleanup:
2910 2911 2912 2913
    virDomainFree(dom);
    return ret;
}

2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947
/*
 * "inject-nmi" command
 */
static const vshCmdInfo info_inject_nmi[] = {
    {"help", N_("Inject NMI to the guest")},
    {"desc", N_("Inject NMI to the guest domain.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_inject_nmi[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {NULL, 0, 0, NULL}
};


static bool
cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
    int ret = true;

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

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
        return false;

    if (virDomainInjectNMI(dom, 0) < 0)
            ret = false;

    virDomainFree(dom);
    return ret;
}

2948 2949 2950
/*
 * "setmemory" command
 */
2951
static const vshCmdInfo info_setmem[] = {
2952 2953
    {"help", N_("change memory allocation")},
    {"desc", N_("Change the current memory allocation in the guest domain.")},
2954 2955 2956
    {NULL, NULL}
};

2957
static const vshCmdOptDef opts_setmem[] = {
2958
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2959
    {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("number of kilobytes of memory")},
2960 2961
    {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
    {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
2962
    {"current", VSH_OT_BOOL, 0, N_("affect current domain")},
2963 2964 2965
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
2966
static bool
2967
cmdSetmem(vshControl *ctl, const vshCmd *cmd)
2968 2969
{
    virDomainPtr dom;
2970
    virDomainInfo info;
2971
    unsigned long kilobytes = 0;
E
Eric Blake 已提交
2972
    bool ret = true;
2973 2974
    int config = vshCommandOptBool(cmd, "config");
    int live = vshCommandOptBool(cmd, "live");
2975
    int current = vshCommandOptBool(cmd, "current");
2976 2977
    int flags = 0;

2978 2979 2980
    if (current) {
        if (live || config) {
            vshError(ctl, "%s", _("--current must be specified exclusively"));
E
Eric Blake 已提交
2981
            return false;
2982 2983 2984 2985 2986
        }
        flags = VIR_DOMAIN_MEM_CURRENT;
    } else {
        if (config)
            flags |= VIR_DOMAIN_MEM_CONFIG;
2987 2988
        if (live)
            flags |= VIR_DOMAIN_MEM_LIVE;
2989 2990 2991
        /* neither option is specified */
        if (!live && !config)
            flags = -1;
2992
    }
2993

2994
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
2995
        return false;
2996

J
Jim Meyering 已提交
2997
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
2998
        return false;
2999

3000 3001
    if (vshCommandOptUL(cmd, "kilobytes", &kilobytes) < 0) {
        vshError(ctl, "%s", _("memory size has to be a number"));
E
Eric Blake 已提交
3002
        return false;
3003 3004
    }

3005
    if (kilobytes <= 0) {
3006
        virDomainFree(dom);
3007
        vshError(ctl, _("Invalid value of %lu for memory size"), kilobytes);
E
Eric Blake 已提交
3008
        return false;
3009 3010
    }

3011 3012
    if (virDomainGetInfo(dom, &info) != 0) {
        virDomainFree(dom);
3013
        vshError(ctl, "%s", _("Unable to verify MaxMemorySize"));
E
Eric Blake 已提交
3014
        return false;
3015 3016 3017 3018
    }

    if (kilobytes > info.maxMem) {
        virDomainFree(dom);
3019
        vshError(ctl, _("Requested memory size %lu kb is larger than maximum of %lu kb"),
3020
                 kilobytes, info.maxMem);
E
Eric Blake 已提交
3021
        return false;
3022 3023
    }

3024
    if (flags == -1) {
3025
        if (virDomainSetMemory(dom, kilobytes) != 0) {
E
Eric Blake 已提交
3026
            ret = false;
3027 3028 3029
        }
    } else {
        if (virDomainSetMemoryFlags(dom, kilobytes, flags) < 0) {
E
Eric Blake 已提交
3030
            ret = false;
3031
        }
3032 3033 3034 3035 3036 3037 3038 3039 3040
    }

    virDomainFree(dom);
    return ret;
}

/*
 * "setmaxmem" command
 */
3041
static const vshCmdInfo info_setmaxmem[] = {
3042 3043
    {"help", N_("change maximum memory limit")},
    {"desc", N_("Change the maximum memory allocation limit in the guest domain.")},
3044 3045 3046
    {NULL, NULL}
};

3047
static const vshCmdOptDef opts_setmaxmem[] = {
3048
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3049
    {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("maximum memory limit in kilobytes")},
3050 3051 3052
    {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
    {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
    {"current", VSH_OT_BOOL, 0, N_("affect current domain")},
3053 3054 3055
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
3056
static bool
3057
cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
3058 3059
{
    virDomainPtr dom;
3060
    virDomainInfo info;
3061
    int kilobytes = 0;
E
Eric Blake 已提交
3062
    bool ret = true;
3063 3064 3065 3066 3067 3068 3069 3070
    int config = vshCommandOptBool(cmd, "config");
    int live = vshCommandOptBool(cmd, "live");
    int current = vshCommandOptBool(cmd, "current");
    int flags = VIR_DOMAIN_MEM_MAXIMUM;

    if (current) {
        if (live || config) {
            vshError(ctl, "%s", _("--current must be specified exclusively"));
E
Eric Blake 已提交
3071
            return false;
3072 3073 3074 3075 3076 3077 3078 3079 3080 3081
        }
    } else {
        if (config)
            flags |= VIR_DOMAIN_MEM_CONFIG;
        if (live)
            flags |= VIR_DOMAIN_MEM_LIVE;
        /* neither option is specified */
        if (!live && !config)
            flags = -1;
    }
3082

3083
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3084
        return false;
3085

J
Jim Meyering 已提交
3086
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
3087
        return false;
3088

3089 3090
    if (vshCommandOptInt(cmd, "kilobytes", &kilobytes) < 0) {
        vshError(ctl, "%s", _("memory size has to be a number"));
E
Eric Blake 已提交
3091
        return false;
3092 3093
    }

3094
    if (kilobytes <= 0) {
3095
        virDomainFree(dom);
3096
        vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
E
Eric Blake 已提交
3097
        return false;
3098 3099
    }

3100 3101
    if (virDomainGetInfo(dom, &info) != 0) {
        virDomainFree(dom);
3102
        vshError(ctl, "%s", _("Unable to verify current MemorySize"));
E
Eric Blake 已提交
3103
        return false;
3104 3105
    }

3106 3107 3108
    if (flags == -1) {
        if (virDomainSetMaxMemory(dom, kilobytes) != 0) {
            vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
E
Eric Blake 已提交
3109
            ret = false;
3110 3111 3112 3113
        }
    } else {
        if (virDomainSetMemoryFlags(dom, kilobytes, flags) < 0) {
            vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
E
Eric Blake 已提交
3114
            ret = false;
3115
        }
3116 3117
    }

3118 3119 3120 3121
    virDomainFree(dom);
    return ret;
}

3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140
/*
 * "blkiotune" command
 */
static const vshCmdInfo info_blkiotune[] = {
    {"help", N_("Get or set blkio parameters")},
    {"desc", N_("Get or set the current blkio parameters for a guest" \
                " domain.\n" \
                "    To get the blkio parameters use following command: \n\n" \
                "    virsh # blkiotune <domain>")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_blkiotune[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"weight", VSH_OT_INT, VSH_OFLAG_NONE,
     N_("IO Weight in range [100, 1000]")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
3141
static bool
3142 3143 3144 3145 3146 3147 3148
cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
{
    virDomainPtr dom;
    int weight = 0;
    int nparams = 0;
    unsigned int i = 0;
    virBlkioParameterPtr params = NULL, temp = NULL;
E
Eric Blake 已提交
3149
    bool ret = false;
3150 3151

    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3152
        return false;
3153 3154

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
3155
        return false;
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181

    if (vshCommandOptInt(cmd, "weight", &weight) < 0) {
        vshError(ctl, "%s",
                 _("Unable to parse integer parameter"));
        goto cleanup;
    }

    if (weight) {
        nparams++;
        if (weight < 0) {
            virDomainFree(dom);
            vshError(ctl, _("Invalid value of %d for I/O weight"), weight);
            goto cleanup;
        }
    }

    if (nparams == 0) {
        /* get the number of blkio parameters */
        if (virDomainGetBlkioParameters(dom, NULL, &nparams, 0) != 0) {
            vshError(ctl, "%s",
                     _("Unable to get number of blkio parameters"));
            goto cleanup;
        }

        if (nparams == 0) {
            /* nothing to output */
E
Eric Blake 已提交
3182
            ret = true;
3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223
            goto cleanup;
        }

        /* now go get all the blkio parameters */
        params = vshCalloc(ctl, nparams, sizeof(*params));
        if (virDomainGetBlkioParameters(dom, params, &nparams, 0) != 0) {
            vshError(ctl, "%s", _("Unable to get blkio parameters"));
            goto cleanup;
        }

        for (i = 0; i < nparams; i++) {
            switch (params[i].type) {
                case VIR_DOMAIN_BLKIO_PARAM_INT:
                    vshPrint(ctl, "%-15s: %d\n", params[i].field,
                             params[i].value.i);
                    break;
                case VIR_DOMAIN_BLKIO_PARAM_UINT:
                    vshPrint(ctl, "%-15s: %u\n", params[i].field,
                             params[i].value.ui);
                    break;
                case VIR_DOMAIN_BLKIO_PARAM_LLONG:
                    vshPrint(ctl, "%-15s: %lld\n", params[i].field,
                             params[i].value.l);
                    break;
                case VIR_DOMAIN_BLKIO_PARAM_ULLONG:
                    vshPrint(ctl, "%-15s: %llu\n", params[i].field,
                                 params[i].value.ul);
                    break;
                case VIR_DOMAIN_BLKIO_PARAM_DOUBLE:
                    vshPrint(ctl, "%-15s: %f\n", params[i].field,
                             params[i].value.d);
                    break;
                case VIR_DOMAIN_BLKIO_PARAM_BOOLEAN:
                    vshPrint(ctl, "%-15s: %d\n", params[i].field,
                             params[i].value.b);
                    break;
                default:
                    vshPrint(ctl, "unimplemented blkio parameter type\n");
            }
        }

E
Eric Blake 已提交
3224
        ret = true;
3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242
    } else {
        /* set the blkio parameters */
        params = vshCalloc(ctl, nparams, sizeof(*params));

        for (i = 0; i < nparams; i++) {
            temp = &params[i];
            temp->type = VIR_DOMAIN_BLKIO_PARAM_UINT;

            if (weight) {
                temp->value.ui = weight;
                strncpy(temp->field, VIR_DOMAIN_BLKIO_WEIGHT,
                        sizeof(temp->field));
                weight = 0;
            }
        }
        if (virDomainSetBlkioParameters(dom, params, nparams, 0) != 0)
            vshError(ctl, "%s", _("Unable to change blkio parameters"));
        else
E
Eric Blake 已提交
3243
            ret = true;
3244 3245 3246 3247 3248 3249 3250 3251
    }

  cleanup:
    VIR_FREE(params);
    virDomainFree(dom);
    return ret;
}

3252 3253 3254 3255
/*
 * "memtune" command
 */
static const vshCmdInfo info_memtune[] = {
3256 3257 3258
    {"help", N_("Get or set memory parameters")},
    {"desc", N_("Get or set the current memory parameters for a guest" \
                " domain.\n" \
3259 3260 3261 3262 3263 3264 3265
                "    To get the memory parameters use following command: \n\n" \
                "    virsh # memtune <domain>")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_memtune[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3266
    {"hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
3267
     N_("Max memory in kilobytes")},
3268
    {"soft-limit", VSH_OT_INT, VSH_OFLAG_NONE,
3269
     N_("Memory during contention in kilobytes")},
3270
    {"swap-hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
3271
     N_("Max memory plus swap in kilobytes")},
3272
    {"min-guarantee", VSH_OT_INT, VSH_OFLAG_NONE,
3273
     N_("Min guaranteed memory in kilobytes")},
3274 3275 3276
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
3277
static bool
3278 3279 3280
cmdMemtune(vshControl * ctl, const vshCmd * cmd)
{
    virDomainPtr dom;
3281 3282
    long long hard_limit = 0, soft_limit = 0, swap_hard_limit = 0;
    long long min_guarantee = 0;
3283 3284 3285
    int nparams = 0;
    unsigned int i = 0;
    virMemoryParameterPtr params = NULL, temp = NULL;
E
Eric Blake 已提交
3286
    bool ret = false;
3287 3288

    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3289
        return false;
3290 3291

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
3292
        return false;
3293

3294 3295 3296 3297 3298 3299 3300 3301 3302
    if (vshCommandOptLongLong(cmd, "hard-limit", &hard_limit) < 0 ||
        vshCommandOptLongLong(cmd, "soft-limit", &soft_limit) < 0 ||
        vshCommandOptLongLong(cmd, "swap-hard-limit", &swap_hard_limit) < 0 ||
        vshCommandOptLongLong(cmd, "min-guarantee", &min_guarantee) < 0) {
        vshError(ctl, "%s",
                 _("Unable to parse integer parameter"));
        goto cleanup;
    }

3303 3304 3305 3306 3307 3308 3309 3310 3311
    if (hard_limit)
        nparams++;

    if (soft_limit)
        nparams++;

    if (swap_hard_limit)
        nparams++;

3312 3313 3314
    if (min_guarantee)
        nparams++;

3315 3316
    if (nparams == 0) {
        /* get the number of memory parameters */
3317
        if (virDomainGetMemoryParameters(dom, NULL, &nparams, 0) != 0) {
3318 3319 3320 3321 3322
            vshError(ctl, "%s",
                     _("Unable to get number of memory parameters"));
            goto cleanup;
        }

3323 3324
        if (nparams == 0) {
            /* nothing to output */
E
Eric Blake 已提交
3325
            ret = true;
3326 3327 3328
            goto cleanup;
        }

3329
        /* now go get all the memory parameters */
E
Eric Blake 已提交
3330
        params = vshCalloc(ctl, nparams, sizeof(*params));
3331
        if (virDomainGetMemoryParameters(dom, params, &nparams, 0) != 0) {
3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350
            vshError(ctl, "%s", _("Unable to get memory parameters"));
            goto cleanup;
        }

        for (i = 0; i < nparams; i++) {
            switch (params[i].type) {
                case VIR_DOMAIN_MEMORY_PARAM_INT:
                    vshPrint(ctl, "%-15s: %d\n", params[i].field,
                             params[i].value.i);
                    break;
                case VIR_DOMAIN_MEMORY_PARAM_UINT:
                    vshPrint(ctl, "%-15s: %u\n", params[i].field,
                             params[i].value.ui);
                    break;
                case VIR_DOMAIN_MEMORY_PARAM_LLONG:
                    vshPrint(ctl, "%-15s: %lld\n", params[i].field,
                             params[i].value.l);
                    break;
                case VIR_DOMAIN_MEMORY_PARAM_ULLONG:
3351 3352 3353 3354 3355
                    if (params[i].value.ul == VIR_DOMAIN_MEMORY_PARAM_UNLIMITED)
                        vshPrint(ctl, "%-15s: unlimited\n", params[i].field);
                    else
                        vshPrint(ctl, "%-15s: %llu kB\n", params[i].field,
                                 params[i].value.ul);
3356 3357 3358 3359 3360 3361 3362 3363 3364 3365
                    break;
                case VIR_DOMAIN_MEMORY_PARAM_DOUBLE:
                    vshPrint(ctl, "%-15s: %f\n", params[i].field,
                             params[i].value.d);
                    break;
                case VIR_DOMAIN_MEMORY_PARAM_BOOLEAN:
                    vshPrint(ctl, "%-15s: %d\n", params[i].field,
                             params[i].value.b);
                    break;
                default:
3366
                    vshPrint(ctl, "unimplemented memory parameter type\n");
3367 3368 3369
            }
        }

E
Eric Blake 已提交
3370
        ret = true;
3371 3372
    } else {
        /* set the memory parameters */
E
Eric Blake 已提交
3373
        params = vshCalloc(ctl, nparams, sizeof(*params));
3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396

        for (i = 0; i < nparams; i++) {
            temp = &params[i];
            temp->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG;

            /*
             * Some magic here, this is used to fill the params structure with
             * the valid arguments passed, after filling the particular
             * argument we purposely make them 0, so on the next pass it goes
             * to the next valid argument and so on.
             */
            if (soft_limit) {
                temp->value.ul = soft_limit;
                strncpy(temp->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                        sizeof(temp->field));
                soft_limit = 0;
            } else if (hard_limit) {
                temp->value.ul = hard_limit;
                strncpy(temp->field, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                        sizeof(temp->field));
                hard_limit = 0;
            } else if (swap_hard_limit) {
                temp->value.ul = swap_hard_limit;
3397
                strncpy(temp->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
3398 3399
                        sizeof(temp->field));
                swap_hard_limit = 0;
3400 3401 3402 3403 3404
            } else if (min_guarantee) {
                temp->value.ul = min_guarantee;
                strncpy(temp->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
                        sizeof(temp->field));
                min_guarantee = 0;
3405
            }
3406 3407 3408 3409

            /* If the user has passed -1, we interpret it as unlimited */
            if (temp->value.ul == -1)
                temp->value.ul = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
3410 3411
        }
        if (virDomainSetMemoryParameters(dom, params, nparams, 0) != 0)
3412
            vshError(ctl, "%s", _("Unable to change memory parameters"));
3413
        else
E
Eric Blake 已提交
3414
            ret = true;
3415 3416 3417
    }

  cleanup:
E
Eric Blake 已提交
3418
    VIR_FREE(params);
3419 3420 3421 3422
    virDomainFree(dom);
    return ret;
}

3423 3424 3425
/*
 * "nodeinfo" command
 */
3426
static const vshCmdInfo info_nodeinfo[] = {
3427 3428
    {"help", N_("node information")},
    {"desc", N_("Returns basic information about the node.")},
3429 3430 3431
    {NULL, NULL}
};

E
Eric Blake 已提交
3432
static bool
3433
cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3434 3435
{
    virNodeInfo info;
3436

3437
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3438
        return false;
3439 3440

    if (virNodeGetInfo(ctl->conn, &info) < 0) {
3441
        vshError(ctl, "%s", _("failed to get node information"));
E
Eric Blake 已提交
3442
        return false;
3443 3444 3445 3446 3447 3448 3449 3450 3451 3452
    }
    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);

E
Eric Blake 已提交
3453
    return true;
3454 3455
}

3456 3457 3458
/*
 * "capabilities" command
 */
3459
static const vshCmdInfo info_capabilities[] = {
3460 3461
    {"help", N_("capabilities")},
    {"desc", N_("Returns capabilities of hypervisor/driver.")},
3462 3463 3464
    {NULL, NULL}
};

E
Eric Blake 已提交
3465
static bool
3466
cmdCapabilities (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3467 3468 3469
{
    char *caps;

3470
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3471
        return false;
3472 3473

    if ((caps = virConnectGetCapabilities (ctl->conn)) == NULL) {
3474
        vshError(ctl, "%s", _("failed to get capabilities"));
E
Eric Blake 已提交
3475
        return false;
3476 3477
    }
    vshPrint (ctl, "%s\n", caps);
3478
    VIR_FREE(caps);
3479

E
Eric Blake 已提交
3480
    return true;
3481 3482
}

3483 3484 3485
/*
 * "dumpxml" command
 */
3486
static const vshCmdInfo info_dumpxml[] = {
3487 3488
    {"help", N_("domain information in XML")},
    {"desc", N_("Output the domain information as an XML dump to stdout.")},
3489
    {NULL, NULL}
3490 3491
};

3492
static const vshCmdOptDef opts_dumpxml[] = {
3493 3494 3495
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")},
    {"security-info", VSH_OT_BOOL, 0, N_("include security sensitive information in XML dump")},
3496
    {"update-cpu", VSH_OT_BOOL, 0, N_("update guest CPU according to host CPU")},
3497
    {NULL, 0, 0, NULL}
3498 3499
};

E
Eric Blake 已提交
3500
static bool
3501
cmdDumpXML(vshControl *ctl, const vshCmd *cmd)
3502
{
3503
    virDomainPtr dom;
E
Eric Blake 已提交
3504
    bool ret = true;
3505
    char *dump;
3506 3507 3508
    int flags = 0;
    int inactive = vshCommandOptBool(cmd, "inactive");
    int secure = vshCommandOptBool(cmd, "security-info");
3509
    int update = vshCommandOptBool(cmd, "update-cpu");
3510 3511 3512 3513 3514

    if (inactive)
        flags |= VIR_DOMAIN_XML_INACTIVE;
    if (secure)
        flags |= VIR_DOMAIN_XML_SECURE;
3515 3516
    if (update)
        flags |= VIR_DOMAIN_XML_UPDATE_CPU;
3517

3518
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3519
        return false;
3520

J
Jim Meyering 已提交
3521
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
3522
        return false;
3523

3524
    dump = virDomainGetXMLDesc(dom, flags);
3525
    if (dump != NULL) {
3526
        vshPrint(ctl, "%s", dump);
3527
        VIR_FREE(dump);
3528
    } else {
E
Eric Blake 已提交
3529
        ret = false;
3530
    }
3531

3532 3533 3534 3535
    virDomainFree(dom);
    return ret;
}

3536 3537 3538 3539
/*
 * "domxml-from-native" command
 */
static const vshCmdInfo info_domxmlfromnative[] = {
3540 3541
    {"help", N_("Convert native config to domain XML")},
    {"desc", N_("Convert native guest configuration format to domain XML format.")},
3542 3543 3544 3545
    {NULL, NULL}
};

static const vshCmdOptDef opts_domxmlfromnative[] = {
3546 3547
    {"format", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source config data format")},
    {"config", VSH_OT_DATA, VSH_OFLAG_REQ, N_("config data file to import from")},
3548 3549 3550
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
3551
static bool
3552 3553
cmdDomXMLFromNative(vshControl *ctl, const vshCmd *cmd)
{
E
Eric Blake 已提交
3554
    bool ret = true;
3555 3556
    const char *format = NULL;
    const char *configFile = NULL;
3557 3558 3559 3560
    char *configData;
    char *xmlData;
    int flags = 0;

3561
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3562
        return false;
3563

3564 3565
    if (vshCommandOptString(cmd, "format", &format) < 0 ||
        vshCommandOptString(cmd, "config", &configFile) < 0)
E
Eric Blake 已提交
3566
        return false;
3567

3568
    if (virFileReadAll(configFile, 1024*1024, &configData) < 0)
E
Eric Blake 已提交
3569
        return false;
3570 3571 3572

    xmlData = virConnectDomainXMLFromNative(ctl->conn, format, configData, flags);
    if (xmlData != NULL) {
3573
        vshPrint(ctl, "%s", xmlData);
3574
        VIR_FREE(xmlData);
3575
    } else {
E
Eric Blake 已提交
3576
        ret = false;
3577 3578 3579 3580 3581 3582 3583 3584 3585
    }

    return ret;
}

/*
 * "domxml-to-native" command
 */
static const vshCmdInfo info_domxmltonative[] = {
3586 3587
    {"help", N_("Convert domain XML to native config")},
    {"desc", N_("Convert domain XML config to a native guest configuration format.")},
3588 3589 3590 3591
    {NULL, NULL}
};

static const vshCmdOptDef opts_domxmltonative[] = {
3592 3593
    {"format", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target config data type format")},
    {"xml", VSH_OT_DATA, VSH_OFLAG_REQ, N_("xml data file to export from")},
3594 3595 3596
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
3597
static bool
3598 3599
cmdDomXMLToNative(vshControl *ctl, const vshCmd *cmd)
{
E
Eric Blake 已提交
3600
    bool ret = true;
3601 3602
    const char *format = NULL;
    const char *xmlFile = NULL;
3603 3604 3605 3606
    char *configData;
    char *xmlData;
    int flags = 0;

3607
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3608
        return false;
3609

3610 3611
    if (vshCommandOptString(cmd, "format", &format) < 0
        || vshCommandOptString(cmd, "xml", &xmlFile) < 0)
E
Eric Blake 已提交
3612
        return false;
3613

3614
    if (virFileReadAll(xmlFile, 1024*1024, &xmlData) < 0)
E
Eric Blake 已提交
3615
        return false;
3616 3617 3618

    configData = virConnectDomainXMLToNative(ctl->conn, format, xmlData, flags);
    if (configData != NULL) {
3619
        vshPrint(ctl, "%s", configData);
3620
        VIR_FREE(configData);
3621
    } else {
E
Eric Blake 已提交
3622
        ret = false;
3623 3624 3625 3626 3627
    }

    return ret;
}

K
Karel Zak 已提交
3628
/*
K
Karel Zak 已提交
3629
 * "domname" command
K
Karel Zak 已提交
3630
 */
3631
static const vshCmdInfo info_domname[] = {
3632
    {"help", N_("convert a domain id or UUID to domain name")},
3633
    {"desc", ""},
3634
    {NULL, NULL}
K
Karel Zak 已提交
3635 3636
};

3637
static const vshCmdOptDef opts_domname[] = {
3638
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or uuid")},
3639
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
3640 3641
};

E
Eric Blake 已提交
3642
static bool
3643
cmdDomname(vshControl *ctl, const vshCmd *cmd)
3644
{
K
Karel Zak 已提交
3645 3646
    virDomainPtr dom;

3647
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3648
        return false;
J
Jim Meyering 已提交
3649
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3650
                                      VSH_BYID|VSH_BYUUID)))
E
Eric Blake 已提交
3651
        return false;
3652

K
Karel Zak 已提交
3653 3654
    vshPrint(ctl, "%s\n", virDomainGetName(dom));
    virDomainFree(dom);
E
Eric Blake 已提交
3655
    return true;
K
Karel Zak 已提交
3656 3657 3658
}

/*
K
Karel Zak 已提交
3659
 * "domid" command
K
Karel Zak 已提交
3660
 */
3661
static const vshCmdInfo info_domid[] = {
3662
    {"help", N_("convert a domain name or UUID to domain id")},
3663
    {"desc", ""},
3664
    {NULL, NULL}
K
Karel Zak 已提交
3665 3666
};

3667
static const vshCmdOptDef opts_domid[] = {
3668
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
3669
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
3670 3671
};

E
Eric Blake 已提交
3672
static bool
3673
cmdDomid(vshControl *ctl, const vshCmd *cmd)
3674
{
3675
    virDomainPtr dom;
3676
    unsigned int id;
K
Karel Zak 已提交
3677

3678
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3679
        return false;
J
Jim Meyering 已提交
3680
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3681
                                      VSH_BYNAME|VSH_BYUUID)))
E
Eric Blake 已提交
3682
        return false;
3683

3684 3685
    id = virDomainGetID(dom);
    if (id == ((unsigned int)-1))
3686
        vshPrint(ctl, "%s\n", "-");
3687
    else
3688
        vshPrint(ctl, "%d\n", id);
K
Karel Zak 已提交
3689
    virDomainFree(dom);
E
Eric Blake 已提交
3690
    return true;
K
Karel Zak 已提交
3691
}
3692

K
Karel Zak 已提交
3693 3694 3695
/*
 * "domuuid" command
 */
3696
static const vshCmdInfo info_domuuid[] = {
3697
    {"help", N_("convert a domain name or id to domain UUID")},
3698
    {"desc", ""},
K
Karel Zak 已提交
3699 3700 3701
    {NULL, NULL}
};

3702
static const vshCmdOptDef opts_domuuid[] = {
3703
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or name")},
K
Karel Zak 已提交
3704 3705 3706
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
3707
static bool
3708
cmdDomuuid(vshControl *ctl, const vshCmd *cmd)
K
Karel Zak 已提交
3709 3710
{
    virDomainPtr dom;
3711
    char uuid[VIR_UUID_STRING_BUFLEN];
K
Karel Zak 已提交
3712

3713
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
3714
        return false;
J
Jim Meyering 已提交
3715
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3716
                                      VSH_BYNAME|VSH_BYID)))
E
Eric Blake 已提交
3717
        return false;
3718

K
Karel Zak 已提交
3719 3720 3721
    if (virDomainGetUUIDString(dom, uuid) != -1)
        vshPrint(ctl, "%s\n", uuid);
    else
3722
        vshError(ctl, "%s", _("failed to get domain UUID"));
3723

3724
    virDomainFree(dom);
E
Eric Blake 已提交
3725
    return true;
K
Karel Zak 已提交
3726 3727
}

3728 3729 3730
/*
 * "migrate" command
 */
3731
static const vshCmdInfo info_migrate[] = {
3732 3733
    {"help", N_("migrate domain to another host")},
    {"desc", N_("Migrate domain to another host.  Add --live for live migration.")},
3734 3735 3736
    {NULL, NULL}
};

3737
static const vshCmdOptDef opts_migrate[] = {
3738 3739 3740 3741 3742 3743 3744
    {"live", VSH_OT_BOOL, 0, N_("live migration")},
    {"p2p", VSH_OT_BOOL, 0, N_("peer-2-peer migration")},
    {"direct", VSH_OT_BOOL, 0, N_("direct migration")},
    {"tunnelled", VSH_OT_BOOL, 0, N_("tunnelled migration")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist VM on destination")},
    {"undefinesource", VSH_OT_BOOL, 0, N_("undefine VM on source")},
    {"suspend", VSH_OT_BOOL, 0, N_("do not restart the domain on the destination host")},
3745 3746
    {"copy-storage-all", VSH_OT_BOOL, 0, N_("migration with non-shared storage with full disk copy")},
    {"copy-storage-inc", VSH_OT_BOOL, 0, N_("migration with non-shared storage with incremental copy (same base image shared between source and destination)")},
W
Wen Congyang 已提交
3747
    {"verbose", VSH_OT_BOOL, 0, N_("display the progress of migration")},
3748
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3749
    {"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, N_("connection URI of the destination host as seen from the client(normal migration) or source(p2p migration)")},
3750 3751
    {"migrateuri", VSH_OT_DATA, 0, N_("migration URI, usually can be omitted")},
    {"dname", VSH_OT_DATA, 0, N_("rename to new name during migration (if supported)")},
W
Wen Congyang 已提交
3752
    {"timeout", VSH_OT_INT, 0, N_("force guest to suspend if live migration exceeds timeout (in seconds)")},
3753 3754 3755
    {NULL, 0, 0, NULL}
};

3756 3757 3758 3759 3760 3761 3762 3763
typedef struct __vshCtrlData {
    vshControl *ctl;
    const vshCmd *cmd;
    int writefd;
} vshCtrlData;

static void
doMigrate (void *opaque)
3764
{
3765
    char ret = '1';
3766
    virDomainPtr dom = NULL;
3767 3768 3769 3770
    const char *desturi = NULL;
    const char *migrateuri = NULL;
    const char *dname = NULL;
    int flags = 0;
3771 3772 3773
    vshCtrlData *data = opaque;
    vshControl *ctl = data->ctl;
    const vshCmd *cmd = data->cmd;
3774 3775
#if HAVE_PTHREAD_SIGMASK
    sigset_t sigmask, oldsigmask;
3776 3777 3778 3779 3780

    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGINT);
    if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) < 0)
        goto out_sig;
3781
#endif
3782

3783
    if (!vshConnectionUsability (ctl, ctl->conn))
3784
        goto out;
3785

J
Jim Meyering 已提交
3786
    if (!(dom = vshCommandOptDomain (ctl, cmd, NULL)))
3787
        goto out;
3788

3789 3790
    if (vshCommandOptString(cmd, "desturi", &desturi) <= 0 ||
        vshCommandOptString(cmd, "migrateuri", &migrateuri) < 0 ||
3791 3792
        vshCommandOptString(cmd, "dname", &dname) < 0) {
        vshError(ctl, "%s", _("missing argument"));
3793
        goto out;
3794
    }
3795 3796 3797

    if (vshCommandOptBool (cmd, "live"))
        flags |= VIR_MIGRATE_LIVE;
3798 3799
    if (vshCommandOptBool (cmd, "p2p"))
        flags |= VIR_MIGRATE_PEER2PEER;
C
Chris Lalancette 已提交
3800 3801 3802
    if (vshCommandOptBool (cmd, "tunnelled"))
        flags |= VIR_MIGRATE_TUNNELLED;

C
Chris Lalancette 已提交
3803 3804 3805 3806 3807
    if (vshCommandOptBool (cmd, "persistent"))
        flags |= VIR_MIGRATE_PERSIST_DEST;
    if (vshCommandOptBool (cmd, "undefinesource"))
        flags |= VIR_MIGRATE_UNDEFINE_SOURCE;

3808 3809 3810
    if (vshCommandOptBool (cmd, "suspend"))
        flags |= VIR_MIGRATE_PAUSED;

3811 3812 3813 3814 3815 3816
    if (vshCommandOptBool (cmd, "copy-storage-all"))
        flags |= VIR_MIGRATE_NON_SHARED_DISK;

    if (vshCommandOptBool (cmd, "copy-storage-inc"))
        flags |= VIR_MIGRATE_NON_SHARED_INC;

3817 3818 3819 3820
    if ((flags & VIR_MIGRATE_PEER2PEER) ||
        vshCommandOptBool (cmd, "direct")) {
        /* For peer2peer migration or direct migration we only expect one URI
         * a libvirt URI, or a hypervisor specific URI. */
3821

3822
        if (migrateuri != NULL) {
J
Jim Fehlig 已提交
3823
            vshError(ctl, "%s", _("migrate: Unexpected migrateuri for peer2peer/direct migration"));
3824
            goto out;
3825
        }
3826

3827
        if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0)
3828
            ret = '0';
3829 3830 3831 3832 3833 3834
    } else {
        /* For traditional live migration, connect to the destination host directly. */
        virConnectPtr dconn = NULL;
        virDomainPtr ddom = NULL;

        dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
3835
        if (!dconn) goto out;
3836 3837 3838 3839

        ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
        if (ddom) {
            virDomainFree(ddom);
3840
            ret = '0';
3841 3842 3843
        }
        virConnectClose (dconn);
    }
3844

3845
out:
3846
#if HAVE_PTHREAD_SIGMASK
3847 3848
    pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
out_sig:
3849
#endif
3850
    if (dom) virDomainFree (dom);
3851 3852 3853
    ignore_value(safewrite(data->writefd, &ret, sizeof(ret)));
}

W
Wen Congyang 已提交
3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877
static void
print_job_progress(unsigned long long remaining, unsigned long long total)
{
    int progress;

    if (total == 0)
        /* migration has not been started */
        return;

    if (remaining == 0) {
        /* migration has completed */
        progress = 100;
    } else {
        /* use float to avoid overflow */
        progress = (int)(100.0 - remaining * 100.0 / total);
        if (progress >= 100) {
            /* migration has not completed, do not print [100 %] */
            progress = 99;
        }
    }

    fprintf(stderr, "\rMigration: [%3d %%]", progress);
}

E
Eric Blake 已提交
3878
static bool
3879 3880 3881 3882 3883
cmdMigrate (vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
    int p[2] = {-1, -1};
    int ret = -1;
W
Wen Congyang 已提交
3884
    bool functionReturn = false;
3885 3886 3887 3888 3889
    virThread workerThread;
    struct pollfd pollfd;
    char retchar;
    struct sigaction sig_action;
    struct sigaction old_sig_action;
W
Wen Congyang 已提交
3890 3891
    virDomainJobInfo jobinfo;
    bool verbose = false;
3892
    int timeout = 0;
W
Wen Congyang 已提交
3893 3894
    struct timeval start, curr;
    bool live_flag = false;
3895
    vshCtrlData data;
3896 3897 3898 3899 3900 3901
#if HAVE_PTHREAD_SIGMASK
    sigset_t sigmask, oldsigmask;

    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGINT);
#endif
3902 3903

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
3904
        return false;
3905

W
Wen Congyang 已提交
3906 3907 3908
    if (vshCommandOptBool (cmd, "verbose"))
        verbose = true;

W
Wen Congyang 已提交
3909
    if (vshCommandOptBool (cmd, "live"))
E
Eric Blake 已提交
3910
        live_flag = true;
3911
    if (vshCommandOptInt(cmd, "timeout", &timeout) > 0) {
W
Wen Congyang 已提交
3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928
        if (! live_flag) {
            vshError(ctl, "%s", _("migrate: Unexpected timeout for offline migration"));
            goto cleanup;
        }

        if (timeout < 1) {
            vshError(ctl, "%s", _("migrate: Invalid timeout"));
            goto cleanup;
        }

        /* Ensure that we can multiply by 1000 without overflowing. */
        if (timeout > INT_MAX / 1000) {
            vshError(ctl, "%s", _("migrate: Timeout is too big"));
            goto cleanup;
        }
    }

3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951
    if (pipe(p) < 0)
        goto cleanup;

    data.ctl = ctl;
    data.cmd = cmd;
    data.writefd = p[1];

    if (virThreadCreate(&workerThread,
                        true,
                        doMigrate,
                        &data) < 0)
        goto cleanup;

    intCaught = 0;
    sig_action.sa_sigaction = vshCatchInt;
    sig_action.sa_flags = SA_SIGINFO;
    sigemptyset(&sig_action.sa_mask);
    sigaction(SIGINT, &sig_action, &old_sig_action);

    pollfd.fd = p[0];
    pollfd.events = POLLIN;
    pollfd.revents = 0;

W
Wen Congyang 已提交
3952
    GETTIMEOFDAY(&start);
W
Wen Congyang 已提交
3953
    while (1) {
3954
repoll:
W
Wen Congyang 已提交
3955 3956 3957 3958
        ret = poll(&pollfd, 1, 500);
        if (ret > 0) {
            if (saferead(p[0], &retchar, sizeof(retchar)) > 0) {
                if (retchar == '0') {
W
Wen Congyang 已提交
3959
                    functionReturn = true;
W
Wen Congyang 已提交
3960 3961 3962 3963 3964
                    if (verbose) {
                        /* print [100 %] */
                        print_job_progress(0, 1);
                    }
                } else
W
Wen Congyang 已提交
3965
                    functionReturn = false;
3966
            } else
W
Wen Congyang 已提交
3967
                functionReturn = false;
W
Wen Congyang 已提交
3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978
            break;
        }

        if (ret < 0) {
            if (errno == EINTR) {
                if (intCaught) {
                    virDomainAbortJob(dom);
                    intCaught = 0;
                } else
                    goto repoll;
            }
W
Wen Congyang 已提交
3979
            functionReturn = false;
W
Wen Congyang 已提交
3980 3981 3982
            break;
        }

W
Wen Congyang 已提交
3983 3984 3985 3986 3987 3988 3989 3990 3991
        GETTIMEOFDAY(&curr);
        if ( timeout && ((int)(curr.tv_sec - start.tv_sec)  * 1000 + \
                         (int)(curr.tv_usec - start.tv_usec) / 1000) > timeout * 1000 ) {
            /* suspend the domain when migration timeouts. */
            vshDebug(ctl, 5, "suspend the domain when migration timeouts\n");
            virDomainSuspend(dom);
            timeout = 0;
        }

W
Wen Congyang 已提交
3992
        if (verbose) {
3993
#if HAVE_PTHREAD_SIGMASK
W
Wen Congyang 已提交
3994
            pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask);
3995
#endif
W
Wen Congyang 已提交
3996
            ret = virDomainGetJobInfo(dom, &jobinfo);
3997
#if HAVE_PTHREAD_SIGMASK
W
Wen Congyang 已提交
3998
            pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
3999
#endif
W
Wen Congyang 已提交
4000 4001
            if (ret == 0)
                print_job_progress(jobinfo.dataRemaining, jobinfo.dataTotal);
4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012
        }
    }

    sigaction(SIGINT, &old_sig_action, NULL);

    virThreadJoin(&workerThread);

cleanup:
    virDomainFree(dom);
    VIR_FORCE_CLOSE(p[0]);
    VIR_FORCE_CLOSE(p[1]);
W
Wen Congyang 已提交
4013
    return functionReturn;
4014 4015
}

4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026
/*
 * "migrate-setmaxdowntime" command
 */
static const vshCmdInfo info_migrate_setmaxdowntime[] = {
    {"help", N_("set maximum tolerable downtime")},
    {"desc", N_("Set maximum tolerable downtime of a domain which is being live-migrated to another host.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_migrate_setmaxdowntime[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
4027
    {"downtime", VSH_OT_INT, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in milliseconds) for migration")},
4028 4029 4030
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4031
static bool
4032 4033 4034
cmdMigrateSetMaxDowntime(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
4035
    long long downtime = 0;
E
Eric Blake 已提交
4036
    bool ret = false;
4037

4038
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4039
        return false;
4040 4041

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
4042
        return false;
4043

4044 4045
    if (vshCommandOptLongLong(cmd, "downtime", &downtime) < 0 ||
        downtime < 1) {
4046 4047 4048 4049 4050 4051 4052
        vshError(ctl, "%s", _("migrate: Invalid downtime"));
        goto done;
    }

    if (virDomainMigrateSetMaxDowntime(dom, downtime, 0))
        goto done;

E
Eric Blake 已提交
4053
    ret = true;
4054 4055 4056 4057 4058 4059

done:
    virDomainFree(dom);
    return ret;
}

4060 4061 4062
/*
 * "net-autostart" command
 */
4063
static const vshCmdInfo info_network_autostart[] = {
4064
    {"help", N_("autostart a network")},
4065
    {"desc",
4066
     N_("Configure a network to be automatically started at boot.")},
4067 4068 4069
    {NULL, NULL}
};

4070
static const vshCmdOptDef opts_network_autostart[] = {
4071 4072
    {"network",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
    {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
4073 4074 4075
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4076
static bool
4077
cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd)
4078 4079
{
    virNetworkPtr network;
4080
    const char *name;
4081 4082
    int autostart;

4083
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4084
        return false;
4085

J
Jim Meyering 已提交
4086
    if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
E
Eric Blake 已提交
4087
        return false;
4088 4089 4090 4091

    autostart = !vshCommandOptBool(cmd, "disable");

    if (virNetworkSetAutostart(network, autostart) < 0) {
4092
        if (autostart)
4093
            vshError(ctl, _("failed to mark network %s as autostarted"), name);
4094
        else
4095
            vshError(ctl, _("failed to unmark network %s as autostarted"), name);
4096
        virNetworkFree(network);
E
Eric Blake 已提交
4097
        return false;
4098 4099
    }

4100
    if (autostart)
4101
        vshPrint(ctl, _("Network %s marked as autostarted\n"), name);
4102
    else
4103
        vshPrint(ctl, _("Network %s unmarked as autostarted\n"), name);
4104

L
Laine Stump 已提交
4105
    virNetworkFree(network);
E
Eric Blake 已提交
4106
    return true;
4107
}
K
Karel Zak 已提交
4108

4109 4110 4111
/*
 * "net-create" command
 */
4112
static const vshCmdInfo info_network_create[] = {
4113 4114
    {"help", N_("create a network from an XML file")},
    {"desc", N_("Create a network.")},
4115 4116 4117
    {NULL, NULL}
};

4118
static const vshCmdOptDef opts_network_create[] = {
4119
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
4120 4121 4122
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4123
static bool
4124
cmdNetworkCreate(vshControl *ctl, const vshCmd *cmd)
4125 4126
{
    virNetworkPtr network;
4127
    const char *from = NULL;
E
Eric Blake 已提交
4128
    bool ret = true;
4129
    char *buffer;
4130

4131
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4132
        return false;
4133

4134
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
4135
        return false;
4136

4137
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
4138
        return false;
4139 4140

    network = virNetworkCreateXML(ctl->conn, buffer);
4141
    VIR_FREE(buffer);
4142

4143 4144 4145
    if (network != NULL) {
        vshPrint(ctl, _("Network %s created from %s\n"),
                 virNetworkGetName(network), from);
L
Laine Stump 已提交
4146
        virNetworkFree(network);
4147
    } else {
4148
        vshError(ctl, _("Failed to create network from %s"), from);
E
Eric Blake 已提交
4149
        ret = false;
4150 4151 4152 4153 4154 4155 4156 4157
    }
    return ret;
}


/*
 * "net-define" command
 */
4158
static const vshCmdInfo info_network_define[] = {
4159 4160
    {"help", N_("define (but don't start) a network from an XML file")},
    {"desc", N_("Define a network.")},
4161 4162 4163
    {NULL, NULL}
};

4164
static const vshCmdOptDef opts_network_define[] = {
4165
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
4166 4167 4168
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4169
static bool
4170
cmdNetworkDefine(vshControl *ctl, const vshCmd *cmd)
4171 4172
{
    virNetworkPtr network;
4173
    const char *from = NULL;
E
Eric Blake 已提交
4174
    bool ret = true;
4175
    char *buffer;
4176

4177
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4178
        return false;
4179

4180
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
4181
        return false;
4182

4183
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
4184
        return false;
4185 4186

    network = virNetworkDefineXML(ctl->conn, buffer);
4187
    VIR_FREE(buffer);
4188

4189 4190 4191
    if (network != NULL) {
        vshPrint(ctl, _("Network %s defined from %s\n"),
                 virNetworkGetName(network), from);
L
Laine Stump 已提交
4192
        virNetworkFree(network);
4193
    } else {
4194
        vshError(ctl, _("Failed to define network from %s"), from);
E
Eric Blake 已提交
4195
        ret = false;
4196 4197 4198 4199 4200 4201 4202 4203
    }
    return ret;
}


/*
 * "net-destroy" command
 */
4204
static const vshCmdInfo info_network_destroy[] = {
4205 4206
    {"help", N_("destroy a network")},
    {"desc", N_("Destroy a given network.")},
4207 4208 4209
    {NULL, NULL}
};

4210
static const vshCmdOptDef opts_network_destroy[] = {
4211
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
4212 4213 4214
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4215
static bool
4216
cmdNetworkDestroy(vshControl *ctl, const vshCmd *cmd)
4217 4218
{
    virNetworkPtr network;
E
Eric Blake 已提交
4219
    bool ret = true;
4220
    const char *name;
4221

4222
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4223
        return false;
4224

J
Jim Meyering 已提交
4225
    if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
E
Eric Blake 已提交
4226
        return false;
4227 4228 4229 4230

    if (virNetworkDestroy(network) == 0) {
        vshPrint(ctl, _("Network %s destroyed\n"), name);
    } else {
4231
        vshError(ctl, _("Failed to destroy network %s"), name);
E
Eric Blake 已提交
4232
        ret = false;
4233 4234
    }

4235
    virNetworkFree(network);
4236 4237 4238 4239 4240 4241 4242
    return ret;
}


/*
 * "net-dumpxml" command
 */
4243
static const vshCmdInfo info_network_dumpxml[] = {
4244 4245
    {"help", N_("network information in XML")},
    {"desc", N_("Output the network information as an XML dump to stdout.")},
4246 4247 4248
    {NULL, NULL}
};

4249
static const vshCmdOptDef opts_network_dumpxml[] = {
4250
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
4251 4252 4253
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4254
static bool
4255
cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd)
4256 4257
{
    virNetworkPtr network;
E
Eric Blake 已提交
4258
    bool ret = true;
4259 4260
    char *dump;

4261
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4262
        return false;
4263

J
Jim Meyering 已提交
4264
    if (!(network = vshCommandOptNetwork(ctl, cmd, NULL)))
E
Eric Blake 已提交
4265
        return false;
4266 4267 4268

    dump = virNetworkGetXMLDesc(network, 0);
    if (dump != NULL) {
4269
        vshPrint(ctl, "%s", dump);
4270
        VIR_FREE(dump);
4271
    } else {
E
Eric Blake 已提交
4272
        ret = false;
4273 4274 4275 4276 4277 4278
    }

    virNetworkFree(network);
    return ret;
}

O
Osier Yang 已提交
4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292
/*
 * "net-info" command
 */
static const vshCmdInfo info_network_info[] = {
    {"help", N_("network information")},
    {"desc", "Returns basic information about the network"},
    {NULL, NULL}
};

static const vshCmdOptDef opts_network_info[] = {
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4293
static bool
O
Osier Yang 已提交
4294 4295 4296 4297 4298 4299 4300 4301 4302 4303
cmdNetworkInfo(vshControl *ctl, const vshCmd *cmd)
{
    virNetworkPtr network;
    char uuid[VIR_UUID_STRING_BUFLEN];
    int autostart;
    int persistent = -1;
    int active = -1;
    char *bridge = NULL;

    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4304
        return false;
O
Osier Yang 已提交
4305 4306 4307

    if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
                                           VSH_BYNAME)))
E
Eric Blake 已提交
4308
        return false;
O
Osier Yang 已提交
4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334

    vshPrint(ctl, "%-15s %s\n", _("Name"), virNetworkGetName(network));

    if (virNetworkGetUUIDString(network, uuid) == 0)
        vshPrint(ctl, "%-15s %s\n", _("UUID"), uuid);

    active = virNetworkIsActive(network);
    if (active >= 0)
        vshPrint(ctl, "%-15s %s\n", _("Active:"), active? _("yes") : _("no"));

    persistent = virNetworkIsPersistent(network);
    if (persistent < 0)
        vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
    else
        vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));

    if (virNetworkGetAutostart(network, &autostart) < 0)
        vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart"));
    else
        vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));

    bridge = virNetworkGetBridgeName(network);
    if (bridge)
        vshPrint(ctl, "%-15s %s\n", _("Bridge:"), bridge);

    virNetworkFree(network);
E
Eric Blake 已提交
4335
    return true;
O
Osier Yang 已提交
4336
}
4337

4338 4339 4340 4341
/*
 * "iface-edit" command
 */
static const vshCmdInfo info_interface_edit[] = {
4342 4343
    {"help", N_("edit XML configuration for a physical host interface")},
    {"desc", N_("Edit the XML configuration for a physical host interface.")},
4344 4345 4346 4347
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_edit[] = {
4348
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4349 4350 4351
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4352
static bool
4353 4354
cmdInterfaceEdit (vshControl *ctl, const vshCmd *cmd)
{
E
Eric Blake 已提交
4355
    bool ret = false;
4356 4357 4358 4359 4360
    virInterfacePtr iface = NULL;
    char *tmp = NULL;
    char *doc = NULL;
    char *doc_edited = NULL;
    char *doc_reread = NULL;
4361
    int flags = VIR_INTERFACE_XML_INACTIVE;
4362

4363
    if (!vshConnectionUsability(ctl, ctl->conn))
4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389
        goto cleanup;

    iface = vshCommandOptInterface (ctl, cmd, NULL);
    if (iface == NULL)
        goto cleanup;

    /* Get the XML configuration of the interface. */
    doc = virInterfaceGetXMLDesc (iface, flags);
    if (!doc)
        goto cleanup;

    /* Create and open the temporary file. */
    tmp = editWriteToTempFile (ctl, doc);
    if (!tmp) goto cleanup;

    /* Start the editor. */
    if (editFile (ctl, tmp) == -1) goto cleanup;

    /* Read back the edited file. */
    doc_edited = editReadBackFile (ctl, tmp);
    if (!doc_edited) goto cleanup;

    /* Compare original XML with edited.  Has it changed at all? */
    if (STREQ (doc, doc_edited)) {
        vshPrint (ctl, _("Interface %s XML configuration not changed.\n"),
                  virInterfaceGetName (iface));
E
Eric Blake 已提交
4390
        ret = true;
4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402
        goto cleanup;
    }

    /* Now re-read the interface XML.  Did someone else change it while
     * it was being edited?  This also catches problems such as us
     * losing a connection or the interface going away.
     */
    doc_reread = virInterfaceGetXMLDesc (iface, flags);
    if (!doc_reread)
        goto cleanup;

    if (STRNEQ (doc, doc_reread)) {
4403 4404
        vshError(ctl, "%s",
                 _("ERROR: the XML configuration was changed by another user"));
4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416
        goto cleanup;
    }

    /* Everything checks out, so redefine the interface. */
    virInterfaceFree (iface);
    iface = virInterfaceDefineXML (ctl->conn, doc_edited, 0);
    if (!iface)
        goto cleanup;

    vshPrint (ctl, _("Interface %s XML configuration edited.\n"),
              virInterfaceGetName(iface));

E
Eric Blake 已提交
4417
    ret = true;
4418 4419 4420 4421 4422

cleanup:
    if (iface)
        virInterfaceFree (iface);

4423 4424 4425
    VIR_FREE(doc);
    VIR_FREE(doc_edited);
    VIR_FREE(doc_reread);
4426 4427 4428

    if (tmp) {
        unlink (tmp);
4429
        VIR_FREE(tmp);
4430 4431 4432 4433 4434
    }

    return ret;
}

4435 4436 4437
/*
 * "net-list" command
 */
4438
static const vshCmdInfo info_network_list[] = {
4439 4440
    {"help", N_("list networks")},
    {"desc", N_("Returns list of networks.")},
4441 4442 4443
    {NULL, NULL}
};

4444
static const vshCmdOptDef opts_network_list[] = {
4445 4446
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active networks")},
4447 4448 4449
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4450
static bool
4451
cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
4452 4453 4454 4455 4456
{
    int inactive = vshCommandOptBool(cmd, "inactive");
    int all = vshCommandOptBool(cmd, "all");
    int active = !inactive || all ? 1 : 0;
    int maxactive = 0, maxinactive = 0, i;
4457
    char **activeNames = NULL, **inactiveNames = NULL;
4458 4459
    inactive |= all;

4460
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4461
        return false;
4462 4463

    if (active) {
4464 4465
        maxactive = virConnectNumOfNetworks(ctl->conn);
        if (maxactive < 0) {
4466
            vshError(ctl, "%s", _("Failed to list active networks"));
E
Eric Blake 已提交
4467
            return false;
4468
        }
4469
        if (maxactive) {
4470
            activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
4471

4472
            if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
4473
                                                    maxactive)) < 0) {
4474
                vshError(ctl, "%s", _("Failed to list active networks"));
4475
                VIR_FREE(activeNames);
E
Eric Blake 已提交
4476
                return false;
4477
            }
4478

4479
            qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
4480
        }
4481 4482
    }
    if (inactive) {
4483 4484
        maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
        if (maxinactive < 0) {
4485
            vshError(ctl, "%s", _("Failed to list inactive networks"));
4486
            VIR_FREE(activeNames);
E
Eric Blake 已提交
4487
            return false;
4488
        }
4489 4490 4491
        if (maxinactive) {
            inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);

4492 4493 4494
            if ((maxinactive =
                     virConnectListDefinedNetworks(ctl->conn, inactiveNames,
                                                   maxinactive)) < 0) {
4495
                vshError(ctl, "%s", _("Failed to list inactive networks"));
4496 4497
                VIR_FREE(activeNames);
                VIR_FREE(inactiveNames);
E
Eric Blake 已提交
4498
                return false;
4499
            }
4500

4501 4502
            qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
        }
4503
    }
4504 4505
    vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
                  _("Autostart"));
4506
    vshPrintExtra(ctl, "-----------------------------------------\n");
4507 4508

    for (i = 0; i < maxactive; i++) {
4509 4510
        virNetworkPtr network =
            virNetworkLookupByName(ctl->conn, activeNames[i]);
4511 4512
        const char *autostartStr;
        int autostart = 0;
4513 4514 4515

        /* this kind of work with networks is not atomic operation */
        if (!network) {
4516
            VIR_FREE(activeNames[i]);
4517
            continue;
4518
        }
4519

4520 4521 4522
        if (virNetworkGetAutostart(network, &autostart) < 0)
            autostartStr = _("no autostart");
        else
4523
            autostartStr = autostart ? _("yes") : _("no");
4524 4525 4526 4527 4528

        vshPrint(ctl, "%-20s %-10s %-10s\n",
                 virNetworkGetName(network),
                 _("active"),
                 autostartStr);
4529
        virNetworkFree(network);
4530
        VIR_FREE(activeNames[i]);
4531 4532 4533
    }
    for (i = 0; i < maxinactive; i++) {
        virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
4534 4535
        const char *autostartStr;
        int autostart = 0;
4536 4537 4538

        /* this kind of work with networks is not atomic operation */
        if (!network) {
4539
            VIR_FREE(inactiveNames[i]);
4540
            continue;
4541
        }
4542

4543 4544 4545
        if (virNetworkGetAutostart(network, &autostart) < 0)
            autostartStr = _("no autostart");
        else
4546
            autostartStr = autostart ? _("yes") : _("no");
4547

4548
        vshPrint(ctl, "%-20s %-10s %-10s\n",
4549 4550 4551
                 inactiveNames[i],
                 _("inactive"),
                 autostartStr);
4552 4553

        virNetworkFree(network);
4554
        VIR_FREE(inactiveNames[i]);
4555
    }
4556 4557
    VIR_FREE(activeNames);
    VIR_FREE(inactiveNames);
E
Eric Blake 已提交
4558
    return true;
4559 4560 4561 4562 4563 4564
}


/*
 * "net-name" command
 */
4565
static const vshCmdInfo info_network_name[] = {
4566
    {"help", N_("convert a network UUID to network name")},
4567
    {"desc", ""},
4568 4569 4570
    {NULL, NULL}
};

4571
static const vshCmdOptDef opts_network_name[] = {
4572
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network uuid")},
4573 4574 4575
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4576
static bool
4577
cmdNetworkName(vshControl *ctl, const vshCmd *cmd)
4578 4579 4580
{
    virNetworkPtr network;

4581
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4582
        return false;
J
Jim Meyering 已提交
4583
    if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
4584
                                           VSH_BYUUID)))
E
Eric Blake 已提交
4585
        return false;
4586 4587 4588

    vshPrint(ctl, "%s\n", virNetworkGetName(network));
    virNetworkFree(network);
E
Eric Blake 已提交
4589
    return true;
4590 4591 4592 4593 4594 4595
}


/*
 * "net-start" command
 */
4596
static const vshCmdInfo info_network_start[] = {
4597 4598
    {"help", N_("start a (previously defined) inactive network")},
    {"desc", N_("Start a network.")},
4599 4600 4601
    {NULL, NULL}
};

4602
static const vshCmdOptDef opts_network_start[] = {
4603
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive network")},
4604 4605 4606
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4607
static bool
4608
cmdNetworkStart(vshControl *ctl, const vshCmd *cmd)
4609 4610
{
    virNetworkPtr network;
E
Eric Blake 已提交
4611
    bool ret = true;
4612

4613
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4614
        return false;
4615

J
Jim Meyering 已提交
4616
    if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, VSH_BYNAME)))
E
Eric Blake 已提交
4617
         return false;
4618 4619 4620

    if (virNetworkCreate(network) == 0) {
        vshPrint(ctl, _("Network %s started\n"),
4621
                 virNetworkGetName(network));
4622
    } else {
4623
        vshError(ctl, _("Failed to start network %s"),
4624
                 virNetworkGetName(network));
E
Eric Blake 已提交
4625
        ret = false;
4626
    }
L
Laine Stump 已提交
4627
    virNetworkFree(network);
4628 4629 4630 4631 4632 4633 4634
    return ret;
}


/*
 * "net-undefine" command
 */
4635
static const vshCmdInfo info_network_undefine[] = {
4636 4637
    {"help", N_("undefine an inactive network")},
    {"desc", N_("Undefine the configuration for an inactive network.")},
4638 4639 4640
    {NULL, NULL}
};

4641
static const vshCmdOptDef opts_network_undefine[] = {
4642
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
4643 4644 4645
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4646
static bool
4647
cmdNetworkUndefine(vshControl *ctl, const vshCmd *cmd)
4648 4649
{
    virNetworkPtr network;
E
Eric Blake 已提交
4650
    bool ret = true;
4651
    const char *name;
4652

4653
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4654
        return false;
4655

J
Jim Meyering 已提交
4656
    if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
E
Eric Blake 已提交
4657
        return false;
4658 4659 4660 4661

    if (virNetworkUndefine(network) == 0) {
        vshPrint(ctl, _("Network %s has been undefined\n"), name);
    } else {
4662
        vshError(ctl, _("Failed to undefine network %s"), name);
E
Eric Blake 已提交
4663
        ret = false;
4664 4665
    }

L
Laine Stump 已提交
4666
    virNetworkFree(network);
4667 4668 4669 4670 4671 4672 4673
    return ret;
}


/*
 * "net-uuid" command
 */
4674
static const vshCmdInfo info_network_uuid[] = {
4675
    {"help", N_("convert a network name to network UUID")},
4676
    {"desc", ""},
4677 4678 4679
    {NULL, NULL}
};

4680
static const vshCmdOptDef opts_network_uuid[] = {
4681
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")},
4682 4683 4684
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4685
static bool
4686
cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd)
4687 4688 4689 4690
{
    virNetworkPtr network;
    char uuid[VIR_UUID_STRING_BUFLEN];

4691
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4692
        return false;
4693

J
Jim Meyering 已提交
4694
    if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
4695
                                           VSH_BYNAME)))
E
Eric Blake 已提交
4696
        return false;
4697 4698 4699 4700

    if (virNetworkGetUUIDString(network, uuid) != -1)
        vshPrint(ctl, "%s\n", uuid);
    else
4701
        vshError(ctl, "%s", _("failed to get network UUID"));
4702

L
Laine Stump 已提交
4703
    virNetworkFree(network);
E
Eric Blake 已提交
4704
    return true;
4705 4706 4707
}


4708 4709 4710 4711 4712
/**************************************************************************/
/*
 * "iface-list" command
 */
static const vshCmdInfo info_interface_list[] = {
4713 4714
    {"help", N_("list physical host interfaces")},
    {"desc", N_("Returns list of physical host interfaces.")},
4715 4716 4717 4718
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_list[] = {
4719 4720
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive interfaces")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active interfaces")},
4721 4722
    {NULL, 0, 0, NULL}
};
E
Eric Blake 已提交
4723
static bool
4724 4725 4726 4727 4728 4729 4730 4731 4732
cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    int inactive = vshCommandOptBool(cmd, "inactive");
    int all = vshCommandOptBool(cmd, "all");
    int active = !inactive || all ? 1 : 0;
    int maxactive = 0, maxinactive = 0, i;
    char **activeNames = NULL, **inactiveNames = NULL;
    inactive |= all;

4733
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4734
        return false;
4735 4736 4737 4738

    if (active) {
        maxactive = virConnectNumOfInterfaces(ctl->conn);
        if (maxactive < 0) {
4739
            vshError(ctl, "%s", _("Failed to list active interfaces"));
E
Eric Blake 已提交
4740
            return false;
4741 4742 4743 4744 4745 4746
        }
        if (maxactive) {
            activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);

            if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames,
                                                    maxactive)) < 0) {
4747
                vshError(ctl, "%s", _("Failed to list active interfaces"));
4748
                VIR_FREE(activeNames);
E
Eric Blake 已提交
4749
                return false;
4750 4751 4752 4753 4754 4755 4756 4757
            }

            qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
        }
    }
    if (inactive) {
        maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn);
        if (maxinactive < 0) {
4758
            vshError(ctl, "%s", _("Failed to list inactive interfaces"));
4759
            VIR_FREE(activeNames);
E
Eric Blake 已提交
4760
            return false;
4761 4762 4763 4764
        }
        if (maxinactive) {
            inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);

4765 4766 4767
            if ((maxinactive =
                     virConnectListDefinedInterfaces(ctl->conn, inactiveNames,
                                                     maxinactive)) < 0) {
4768
                vshError(ctl, "%s", _("Failed to list inactive interfaces"));
4769 4770
                VIR_FREE(activeNames);
                VIR_FREE(inactiveNames);
E
Eric Blake 已提交
4771
                return false;
4772 4773 4774 4775 4776
            }

            qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
        }
    }
4777 4778
    vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
                  _("MAC Address"));
4779 4780 4781
    vshPrintExtra(ctl, "--------------------------------------------\n");

    for (i = 0; i < maxactive; i++) {
4782 4783
        virInterfacePtr iface =
            virInterfaceLookupByName(ctl->conn, activeNames[i]);
4784 4785 4786

        /* this kind of work with interfaces is not atomic */
        if (!iface) {
4787
            VIR_FREE(activeNames[i]);
4788 4789 4790 4791 4792 4793 4794 4795
            continue;
        }

        vshPrint(ctl, "%-20s %-10s %s\n",
                 virInterfaceGetName(iface),
                 _("active"),
                 virInterfaceGetMACString(iface));
        virInterfaceFree(iface);
4796
        VIR_FREE(activeNames[i]);
4797 4798
    }
    for (i = 0; i < maxinactive; i++) {
4799 4800
        virInterfacePtr iface =
            virInterfaceLookupByName(ctl->conn, inactiveNames[i]);
4801 4802 4803

        /* this kind of work with interfaces is not atomic */
        if (!iface) {
4804
            VIR_FREE(inactiveNames[i]);
4805 4806 4807 4808 4809 4810 4811 4812
            continue;
        }

        vshPrint(ctl, "%-20s %-10s %s\n",
                 virInterfaceGetName(iface),
                 _("inactive"),
                 virInterfaceGetMACString(iface));
        virInterfaceFree(iface);
4813
        VIR_FREE(inactiveNames[i]);
4814
    }
4815 4816
    VIR_FREE(activeNames);
    VIR_FREE(inactiveNames);
E
Eric Blake 已提交
4817
    return true;
4818 4819 4820 4821 4822 4823 4824

}

/*
 * "iface-name" command
 */
static const vshCmdInfo info_interface_name[] = {
4825
    {"help", N_("convert an interface MAC address to interface name")},
4826 4827 4828 4829 4830
    {"desc", ""},
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_name[] = {
4831
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface mac")},
4832 4833 4834
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4835
static bool
4836 4837 4838 4839
cmdInterfaceName(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;

4840
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4841
        return false;
4842 4843
    if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
                                           VSH_BYMAC)))
E
Eric Blake 已提交
4844
        return false;
4845 4846 4847

    vshPrint(ctl, "%s\n", virInterfaceGetName(iface));
    virInterfaceFree(iface);
E
Eric Blake 已提交
4848
    return true;
4849 4850 4851 4852 4853 4854
}

/*
 * "iface-mac" command
 */
static const vshCmdInfo info_interface_mac[] = {
4855
    {"help", N_("convert an interface name to interface MAC address")},
4856 4857 4858 4859 4860
    {"desc", ""},
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_mac[] = {
4861
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name")},
4862 4863 4864
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4865
static bool
4866 4867 4868 4869
cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;

4870
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4871
        return false;
4872 4873
    if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
                                           VSH_BYNAME)))
E
Eric Blake 已提交
4874
        return false;
4875 4876 4877

    vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface));
    virInterfaceFree(iface);
E
Eric Blake 已提交
4878
    return true;
4879 4880 4881 4882 4883 4884
}

/*
 * "iface-dumpxml" command
 */
static const vshCmdInfo info_interface_dumpxml[] = {
4885 4886
    {"help", N_("interface information in XML")},
    {"desc", N_("Output the physical host interface information as an XML dump to stdout.")},
4887 4888 4889 4890
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_dumpxml[] = {
4891 4892
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
    {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")},
4893 4894 4895
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4896
static bool
4897 4898 4899
cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
E
Eric Blake 已提交
4900
    bool ret = true;
4901
    char *dump;
4902 4903 4904 4905 4906
    int flags = 0;
    int inactive = vshCommandOptBool(cmd, "inactive");

    if (inactive)
        flags |= VIR_INTERFACE_XML_INACTIVE;
4907

4908
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4909
        return false;
4910 4911

    if (!(iface = vshCommandOptInterface(ctl, cmd, NULL)))
E
Eric Blake 已提交
4912
        return false;
4913

4914
    dump = virInterfaceGetXMLDesc(iface, flags);
4915
    if (dump != NULL) {
4916
        vshPrint(ctl, "%s", dump);
4917
        VIR_FREE(dump);
4918
    } else {
E
Eric Blake 已提交
4919
        ret = false;
4920 4921 4922 4923 4924 4925 4926 4927 4928 4929
    }

    virInterfaceFree(iface);
    return ret;
}

/*
 * "iface-define" command
 */
static const vshCmdInfo info_interface_define[] = {
4930 4931
    {"help", N_("define (but don't start) a physical host interface from an XML file")},
    {"desc", N_("Define a physical host interface.")},
4932 4933 4934 4935
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_define[] = {
4936
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML interface description")},
4937 4938 4939
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4940
static bool
4941 4942
cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd)
{
4943
    virInterfacePtr iface;
4944
    const char *from = NULL;
E
Eric Blake 已提交
4945
    bool ret = true;
4946 4947
    char *buffer;

4948
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4949
        return false;
4950

4951
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
4952
        return false;
4953 4954

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
4955
        return false;
4956

4957
    iface = virInterfaceDefineXML(ctl->conn, buffer, 0);
4958
    VIR_FREE(buffer);
4959

4960
    if (iface != NULL) {
4961
        vshPrint(ctl, _("Interface %s defined from %s\n"),
4962
                 virInterfaceGetName(iface), from);
L
Laine Stump 已提交
4963
        virInterfaceFree (iface);
4964
    } else {
4965
        vshError(ctl, _("Failed to define interface from %s"), from);
E
Eric Blake 已提交
4966
        ret = false;
4967 4968 4969 4970 4971 4972 4973 4974
    }
    return ret;
}

/*
 * "iface-undefine" command
 */
static const vshCmdInfo info_interface_undefine[] = {
4975 4976
    {"help", N_("undefine a physical host interface (remove it from configuration)")},
    {"desc", N_("undefine an interface.")},
4977 4978 4979 4980
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_undefine[] = {
4981
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4982 4983 4984
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
4985
static bool
4986 4987 4988
cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
E
Eric Blake 已提交
4989
    bool ret = true;
4990
    const char *name;
4991

4992
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
4993
        return false;
4994 4995

    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
E
Eric Blake 已提交
4996
        return false;
4997 4998 4999 5000

    if (virInterfaceUndefine(iface) == 0) {
        vshPrint(ctl, _("Interface %s undefined\n"), name);
    } else {
5001
        vshError(ctl, _("Failed to undefine interface %s"), name);
E
Eric Blake 已提交
5002
        ret = false;
5003 5004 5005 5006 5007 5008 5009 5010 5011 5012
    }

    virInterfaceFree(iface);
    return ret;
}

/*
 * "iface-start" command
 */
static const vshCmdInfo info_interface_start[] = {
5013 5014
    {"help", N_("start a physical host interface (enable it / \"if-up\")")},
    {"desc", N_("start a physical host interface.")},
5015 5016 5017 5018
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_start[] = {
5019
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
5020 5021 5022
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5023
static bool
5024 5025 5026
cmdInterfaceStart(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
E
Eric Blake 已提交
5027
    bool ret = true;
5028
    const char *name;
5029

5030
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5031
        return false;
5032 5033

    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
E
Eric Blake 已提交
5034
        return false;
5035 5036 5037 5038

    if (virInterfaceCreate(iface, 0) == 0) {
        vshPrint(ctl, _("Interface %s started\n"), name);
    } else {
5039
        vshError(ctl, _("Failed to start interface %s"), name);
E
Eric Blake 已提交
5040
        ret = false;
5041 5042 5043 5044 5045 5046 5047 5048 5049 5050
    }

    virInterfaceFree(iface);
    return ret;
}

/*
 * "iface-destroy" command
 */
static const vshCmdInfo info_interface_destroy[] = {
5051 5052
    {"help", N_("destroy a physical host interface (disable it / \"if-down\")")},
    {"desc", N_("destroy a physical host interface.")},
5053 5054 5055 5056
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_destroy[] = {
5057
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
5058 5059 5060
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5061
static bool
5062 5063 5064
cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
E
Eric Blake 已提交
5065
    bool ret = true;
5066
    const char *name;
5067

5068
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5069
        return false;
5070 5071

    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
E
Eric Blake 已提交
5072
        return false;
5073 5074 5075 5076

    if (virInterfaceDestroy(iface, 0) == 0) {
        vshPrint(ctl, _("Interface %s destroyed\n"), name);
    } else {
5077
        vshError(ctl, _("Failed to destroy interface %s"), name);
E
Eric Blake 已提交
5078
        ret = false;
5079 5080 5081 5082 5083 5084
    }

    virInterfaceFree(iface);
    return ret;
}

5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099

/*
 * "nwfilter-define" command
 */
static const vshCmdInfo info_nwfilter_define[] = {
    {"help", N_("define or update a network filter from an XML file")},
    {"desc", N_("Define a new network filter or update an existing one.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_nwfilter_define[] = {
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network filter description")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5100
static bool
5101 5102 5103
cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterPtr nwfilter;
5104
    const char *from = NULL;
E
Eric Blake 已提交
5105
    bool ret = true;
5106 5107
    char *buffer;

5108
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5109
        return false;
5110

5111
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
5112
        return false;
5113 5114

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
5115
        return false;
5116 5117 5118 5119 5120 5121 5122 5123 5124 5125

    nwfilter = virNWFilterDefineXML(ctl->conn, buffer);
    VIR_FREE(buffer);

    if (nwfilter != NULL) {
        vshPrint(ctl, _("Network filter %s defined from %s\n"),
                 virNWFilterGetName(nwfilter), from);
        virNWFilterFree(nwfilter);
    } else {
        vshError(ctl, _("Failed to define network filter from %s"), from);
E
Eric Blake 已提交
5126
        ret = false;
5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145
    }
    return ret;
}


/*
 * "nwfilter-undefine" command
 */
static const vshCmdInfo info_nwfilter_undefine[] = {
    {"help", N_("undefine a network filter")},
    {"desc", N_("Undefine a given network filter.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_nwfilter_undefine[] = {
    {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5146
static bool
5147 5148 5149
cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterPtr nwfilter;
E
Eric Blake 已提交
5150
    bool ret = true;
5151
    const char *name;
5152

5153
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5154
        return false;
5155 5156

    if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, &name)))
E
Eric Blake 已提交
5157
        return false;
5158 5159 5160 5161 5162

    if (virNWFilterUndefine(nwfilter) == 0) {
        vshPrint(ctl, _("Network filter %s undefined\n"), name);
    } else {
        vshError(ctl, _("Failed to undefine network filter %s"), name);
E
Eric Blake 已提交
5163
        ret = false;
5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184
    }

    virNWFilterFree(nwfilter);
    return ret;
}


/*
 * "nwfilter-dumpxml" command
 */
static const vshCmdInfo info_nwfilter_dumpxml[] = {
    {"help", N_("network filter information in XML")},
    {"desc", N_("Output the network filter information as an XML dump to stdout.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_nwfilter_dumpxml[] = {
    {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5185
static bool
5186 5187 5188
cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterPtr nwfilter;
E
Eric Blake 已提交
5189
    bool ret = true;
5190 5191
    char *dump;

5192
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5193
        return false;
5194 5195

    if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL)))
E
Eric Blake 已提交
5196
        return false;
5197 5198 5199

    dump = virNWFilterGetXMLDesc(nwfilter, 0);
    if (dump != NULL) {
5200
        vshPrint(ctl, "%s", dump);
5201 5202
        VIR_FREE(dump);
    } else {
E
Eric Blake 已提交
5203
        ret = false;
5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222
    }

    virNWFilterFree(nwfilter);
    return ret;
}

/*
 * "nwfilter-list" command
 */
static const vshCmdInfo info_nwfilter_list[] = {
    {"help", N_("list network filters")},
    {"desc", N_("Returns list of network filters.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_nwfilter_list[] = {
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5223
static bool
5224 5225 5226 5227 5228 5229
cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    int numfilters, i;
    char **names;
    char uuid[VIR_UUID_STRING_BUFLEN];

5230
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5231
        return false;
5232 5233 5234 5235

    numfilters = virConnectNumOfNWFilters(ctl->conn);
    if (numfilters < 0) {
        vshError(ctl, "%s", _("Failed to list network filters"));
E
Eric Blake 已提交
5236
        return false;
5237 5238 5239 5240 5241 5242 5243 5244
    }

    names = vshMalloc(ctl, sizeof(char *) * numfilters);

    if ((numfilters = virConnectListNWFilters(ctl->conn, names,
                                              numfilters)) < 0) {
        vshError(ctl, "%s", _("Failed to list network filters"));
        VIR_FREE(names);
E
Eric Blake 已提交
5245
        return false;
5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272
    }

    qsort(&names[0], numfilters, sizeof(char *), namesorter);

    vshPrintExtra(ctl, "%-36s  %-20s \n", _("UUID"), _("Name"));
    vshPrintExtra(ctl,
       "----------------------------------------------------------------\n");

    for (i = 0; i < numfilters; i++) {
        virNWFilterPtr nwfilter =
            virNWFilterLookupByName(ctl->conn, names[i]);

        /* this kind of work with networks is not atomic operation */
        if (!nwfilter) {
            VIR_FREE(names[i]);
            continue;
        }

        virNWFilterGetUUIDString(nwfilter, uuid);
        vshPrint(ctl, "%-36s  %-20s\n",
                 uuid,
                 virNWFilterGetName(nwfilter));
        virNWFilterFree(nwfilter);
        VIR_FREE(names[i]);
    }

    VIR_FREE(names);
E
Eric Blake 已提交
5273
    return true;
5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290
}


/*
 * "nwfilter-edit" command
 */
static const vshCmdInfo info_nwfilter_edit[] = {
    {"help", N_("edit XML configuration for a network filter")},
    {"desc", N_("Edit the XML configuration for a network filter.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_nwfilter_edit[] = {
    {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5291
static bool
5292 5293
cmdNWFilterEdit (vshControl *ctl, const vshCmd *cmd)
{
E
Eric Blake 已提交
5294
    bool ret = false;
5295 5296 5297 5298 5299 5300
    virNWFilterPtr nwfilter = NULL;
    char *tmp = NULL;
    char *doc = NULL;
    char *doc_edited = NULL;
    char *doc_reread = NULL;

5301
    if (!vshConnectionUsability(ctl, ctl->conn))
5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327
        goto cleanup;

    nwfilter = vshCommandOptNWFilter (ctl, cmd, NULL);
    if (nwfilter == NULL)
        goto cleanup;

    /* Get the XML configuration of the interface. */
    doc = virNWFilterGetXMLDesc (nwfilter, 0);
    if (!doc)
        goto cleanup;

    /* Create and open the temporary file. */
    tmp = editWriteToTempFile (ctl, doc);
    if (!tmp) goto cleanup;

    /* Start the editor. */
    if (editFile (ctl, tmp) == -1) goto cleanup;

    /* Read back the edited file. */
    doc_edited = editReadBackFile (ctl, tmp);
    if (!doc_edited) goto cleanup;

    /* Compare original XML with edited.  Has it changed at all? */
    if (STREQ (doc, doc_edited)) {
        vshPrint (ctl, _("Network filter %s XML configuration not changed.\n"),
                  virNWFilterGetName (nwfilter));
E
Eric Blake 已提交
5328
        ret = true;
5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354
        goto cleanup;
    }

    /* Now re-read the network filter XML.  Did someone else change it while
     * it was being edited?  This also catches problems such as us
     * losing a connection or the interface going away.
     */
    doc_reread = virNWFilterGetXMLDesc (nwfilter, 0);
    if (!doc_reread)
        goto cleanup;

    if (STRNEQ (doc, doc_reread)) {
        vshError(ctl, "%s",
                 _("ERROR: the XML configuration was changed by another user"));
        goto cleanup;
    }

    /* Everything checks out, so redefine the interface. */
    virNWFilterFree (nwfilter);
    nwfilter = virNWFilterDefineXML (ctl->conn, doc_edited);
    if (!nwfilter)
        goto cleanup;

    vshPrint (ctl, _("Network filter %s XML configuration edited.\n"),
              virNWFilterGetName(nwfilter));

E
Eric Blake 已提交
5355
    ret = true;
5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373

cleanup:
    if (nwfilter)
        virNWFilterFree (nwfilter);

    VIR_FREE(doc);
    VIR_FREE(doc_edited);
    VIR_FREE(doc_reread);

    if (tmp) {
        unlink (tmp);
        VIR_FREE(tmp);
    }

    return ret;
}


5374
/**************************************************************************/
5375
/*
5376
 * "pool-autostart" command
5377
 */
5378
static const vshCmdInfo info_pool_autostart[] = {
5379
    {"help", N_("autostart a pool")},
5380
    {"desc",
5381
     N_("Configure a pool to be automatically started at boot.")},
5382
    {NULL, NULL}
5383 5384
};

5385
static const vshCmdOptDef opts_pool_autostart[] = {
5386 5387
    {"pool",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
    {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
5388 5389
    {NULL, 0, 0, NULL}
};
5390

E
Eric Blake 已提交
5391
static bool
5392
cmdPoolAutostart(vshControl *ctl, const vshCmd *cmd)
5393
{
5394
    virStoragePoolPtr pool;
5395
    const char *name;
5396
    int autostart;
5397

5398
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5399
        return false;
5400

5401
    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
E
Eric Blake 已提交
5402
        return false;
5403

5404
    autostart = !vshCommandOptBool(cmd, "disable");
5405

5406 5407
    if (virStoragePoolSetAutostart(pool, autostart) < 0) {
        if (autostart)
5408
            vshError(ctl, _("failed to mark pool %s as autostarted"), name);
5409
        else
5410
            vshError(ctl, _("failed to unmark pool %s as autostarted"), name);
5411
        virStoragePoolFree(pool);
E
Eric Blake 已提交
5412
        return false;
5413 5414
    }

5415
    if (autostart)
5416
        vshPrint(ctl, _("Pool %s marked as autostarted\n"), name);
5417
    else
5418
        vshPrint(ctl, _("Pool %s unmarked as autostarted\n"), name);
5419

L
Laine Stump 已提交
5420
    virStoragePoolFree(pool);
E
Eric Blake 已提交
5421
    return true;
5422 5423
}

5424
/*
5425
 * "pool-create" command
5426
 */
5427
static const vshCmdInfo info_pool_create[] = {
5428 5429
    {"help", N_("create a pool from an XML file")},
    {"desc", N_("Create a pool.")},
5430 5431 5432
    {NULL, NULL}
};

5433
static const vshCmdOptDef opts_pool_create[] = {
J
Jim Meyering 已提交
5434
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
5435
     N_("file containing an XML pool description")},
5436 5437 5438
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5439
static bool
5440
cmdPoolCreate(vshControl *ctl, const vshCmd *cmd)
5441
{
5442
    virStoragePoolPtr pool;
5443
    const char *from = NULL;
E
Eric Blake 已提交
5444
    bool ret = true;
5445
    char *buffer;
5446

5447
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5448
        return false;
5449

5450
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
5451
        return false;
5452

5453
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
5454
        return false;
5455

5456
    pool = virStoragePoolCreateXML(ctl->conn, buffer, 0);
5457
    VIR_FREE(buffer);
5458 5459 5460 5461

    if (pool != NULL) {
        vshPrint(ctl, _("Pool %s created from %s\n"),
                 virStoragePoolGetName(pool), from);
L
Laine Stump 已提交
5462
        virStoragePoolFree(pool);
5463
    } else {
5464
        vshError(ctl, _("Failed to create pool from %s"), from);
E
Eric Blake 已提交
5465
        ret = false;
5466 5467
    }
    return ret;
5468 5469
}

5470

5471 5472 5473 5474
/*
 * "nodedev-create" command
 */
static const vshCmdInfo info_node_device_create[] = {
5475
    {"help", N_("create a device defined "
5476
                          "by an XML file on the node")},
5477
    {"desc", N_("Create a device on the node.  Note that this "
5478 5479 5480 5481 5482 5483 5484
                          "command creates devices on the physical host "
                          "that can then be assigned to a virtual machine.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_node_device_create[] = {
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
5485
     N_("file containing an XML description of the device")},
5486 5487 5488
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5489
static bool
5490 5491 5492
cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
{
    virNodeDevicePtr dev = NULL;
5493
    const char *from = NULL;
E
Eric Blake 已提交
5494
    bool ret = true;
5495 5496
    char *buffer;

5497
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5498
        return false;
5499

5500
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
5501
        return false;
5502

5503
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
5504
        return false;
5505 5506

    dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0);
5507
    VIR_FREE(buffer);
5508 5509 5510 5511

    if (dev != NULL) {
        vshPrint(ctl, _("Node device %s created from %s\n"),
                 virNodeDeviceGetName(dev), from);
L
Laine Stump 已提交
5512
        virNodeDeviceFree(dev);
5513
    } else {
5514
        vshError(ctl, _("Failed to create node device from %s"), from);
E
Eric Blake 已提交
5515
        ret = false;
5516 5517 5518 5519 5520 5521 5522 5523 5524 5525
    }

    return ret;
}


/*
 * "nodedev-destroy" command
 */
static const vshCmdInfo info_node_device_destroy[] = {
5526 5527
    {"help", N_("destroy a device on the node")},
    {"desc", N_("Destroy a device on the node.  Note that this "
5528 5529 5530 5531 5532 5533
                          "command destroys devices on the physical host ")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_node_device_destroy[] = {
    {"name", VSH_OT_DATA, VSH_OFLAG_REQ,
5534
     N_("name of the device to be destroyed")},
5535 5536 5537
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5538
static bool
5539 5540 5541
cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
{
    virNodeDevicePtr dev = NULL;
E
Eric Blake 已提交
5542
    bool ret = true;
5543
    const char *name = NULL;
5544

5545
    if (!vshConnectionUsability(ctl, ctl->conn)) {
E
Eric Blake 已提交
5546
        return false;
5547 5548
    }

5549
    if (vshCommandOptString(cmd, "name", &name) <= 0)
E
Eric Blake 已提交
5550
        return false;
5551 5552 5553 5554 5555 5556

    dev = virNodeDeviceLookupByName(ctl->conn, name);

    if (virNodeDeviceDestroy(dev) == 0) {
        vshPrint(ctl, _("Destroyed node device '%s'\n"), name);
    } else {
5557
        vshError(ctl, _("Failed to destroy node device '%s'"), name);
E
Eric Blake 已提交
5558
        ret = false;
5559 5560 5561 5562 5563 5564 5565
    }

    virNodeDeviceFree(dev);
    return ret;
}


5566
/*
5567
 * XML Building helper for pool-define-as and pool-create-as
5568
 */
5569
static const vshCmdOptDef opts_pool_X_as[] = {
5570 5571 5572 5573 5574 5575 5576 5577
    {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the pool")},
    {"print-xml", VSH_OT_BOOL, 0, N_("print XML document, but don't define/create")},
    {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("type of the pool")},
    {"source-host", VSH_OT_DATA, 0, N_("source-host for underlying storage")},
    {"source-path", VSH_OT_DATA, 0, N_("source path for underlying storage")},
    {"source-dev", VSH_OT_DATA, 0, N_("source device for underlying storage")},
    {"source-name", VSH_OT_DATA, 0, N_("source name for underlying storage")},
    {"target", VSH_OT_DATA, 0, N_("target for underlying storage")},
5578
    {"source-format", VSH_OT_STRING, 0, N_("format for underlying storage")},
5579 5580 5581
    {NULL, 0, 0, NULL}
};

5582
static int buildPoolXML(const vshCmd *cmd, const char **retname, char **xml) {
5583

5584 5585
    const char *name = NULL, *type = NULL, *srcHost = NULL, *srcPath = NULL,
               *srcDev = NULL, *srcName = NULL, *srcFormat = NULL, *target = NULL;
5586
    virBuffer buf = VIR_BUFFER_INITIALIZER;
5587

5588
    if (vshCommandOptString(cmd, "name", &name) <= 0)
5589
        goto cleanup;
5590
    if (vshCommandOptString(cmd, "type", &type) <= 0)
5591 5592
        goto cleanup;

5593 5594 5595 5596 5597
    if (vshCommandOptString(cmd, "source-host", &srcHost) < 0 ||
        vshCommandOptString(cmd, "source-path", &srcPath) < 0 ||
        vshCommandOptString(cmd, "source-dev", &srcDev) < 0 ||
        vshCommandOptString(cmd, "source-name", &srcName) < 0 ||
        vshCommandOptString(cmd, "source-format", &srcFormat) < 0 ||
5598 5599
        vshCommandOptString(cmd, "target", &target) < 0) {
        vshError(NULL, "%s", _("missing argument"));
5600
        goto cleanup;
5601
    }
5602

5603 5604
    virBufferAsprintf(&buf, "<pool type='%s'>\n", type);
    virBufferAsprintf(&buf, "  <name>%s</name>\n", name);
5605
    if (srcHost || srcPath || srcDev) {
5606
        virBufferAddLit(&buf, "  <source>\n");
5607

5608
        if (srcHost)
5609
            virBufferAsprintf(&buf, "    <host name='%s'/>\n", srcHost);
5610
        if (srcPath)
5611
            virBufferAsprintf(&buf, "    <dir path='%s'/>\n", srcPath);
5612
        if (srcDev)
5613
            virBufferAsprintf(&buf, "    <device path='%s'/>\n", srcDev);
5614
        if (srcFormat)
5615
            virBufferAsprintf(&buf, "    <format type='%s'/>\n", srcFormat);
5616
        if (srcName)
5617
            virBufferAsprintf(&buf, "    <name>%s</name>\n", srcName);
5618 5619

        virBufferAddLit(&buf, "  </source>\n");
5620 5621
    }
    if (target) {
5622
        virBufferAddLit(&buf, "  <target>\n");
5623
        virBufferAsprintf(&buf, "    <path>%s</path>\n", target);
5624
        virBufferAddLit(&buf, "  </target>\n");
5625
    }
5626 5627 5628 5629
    virBufferAddLit(&buf, "</pool>\n");

    if (virBufferError(&buf)) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
E
Eric Blake 已提交
5630
        return false;
5631
    }
5632 5633 5634

    *xml = virBufferContentAndReset(&buf);
    *retname = name;
E
Eric Blake 已提交
5635
    return true;
5636 5637

cleanup:
5638
    virBufferFreeAndReset(&buf);
E
Eric Blake 已提交
5639
    return false;
5640 5641 5642 5643 5644 5645
}

/*
 * "pool-create-as" command
 */
static const vshCmdInfo info_pool_create_as[] = {
5646 5647
    {"help", N_("create a pool from a set of args")},
    {"desc", N_("Create a pool.")},
5648 5649 5650
    {NULL, NULL}
};

E
Eric Blake 已提交
5651
static bool
5652 5653 5654
cmdPoolCreateAs(vshControl *ctl, const vshCmd *cmd)
{
    virStoragePoolPtr pool;
5655 5656
    const char *name;
    char *xml;
5657
    int printXML = vshCommandOptBool(cmd, "print-xml");
5658

5659
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5660
        return false;
5661 5662

    if (!buildPoolXML(cmd, &name, &xml))
E
Eric Blake 已提交
5663
        return false;
5664

5665
    if (printXML) {
5666
        vshPrint(ctl, "%s", xml);
5667
        VIR_FREE(xml);
5668
    } else {
5669
        pool = virStoragePoolCreateXML(ctl->conn, xml, 0);
5670
        VIR_FREE(xml);
5671

5672 5673 5674 5675
        if (pool != NULL) {
            vshPrint(ctl, _("Pool %s created\n"), name);
            virStoragePoolFree(pool);
        } else {
5676
            vshError(ctl, _("Failed to create pool %s"), name);
E
Eric Blake 已提交
5677
            return false;
5678 5679
        }
    }
E
Eric Blake 已提交
5680
    return true;
5681 5682
}

5683

5684
/*
5685
 * "pool-define" command
5686
 */
5687
static const vshCmdInfo info_pool_define[] = {
5688 5689
    {"help", N_("define (but don't start) a pool from an XML file")},
    {"desc", N_("Define a pool.")},
5690 5691 5692
    {NULL, NULL}
};

5693
static const vshCmdOptDef opts_pool_define[] = {
5694
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML pool description")},
5695 5696 5697
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5698
static bool
5699
cmdPoolDefine(vshControl *ctl, const vshCmd *cmd)
5700
{
5701
    virStoragePoolPtr pool;
5702
    const char *from = NULL;
E
Eric Blake 已提交
5703
    bool ret = true;
5704
    char *buffer;
5705

5706
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5707
        return false;
5708

5709
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
5710
        return false;
5711

5712
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
5713
        return false;
5714

5715
    pool = virStoragePoolDefineXML(ctl->conn, buffer, 0);
5716
    VIR_FREE(buffer);
5717 5718 5719 5720

    if (pool != NULL) {
        vshPrint(ctl, _("Pool %s defined from %s\n"),
                 virStoragePoolGetName(pool), from);
L
Laine Stump 已提交
5721
        virStoragePoolFree(pool);
5722
    } else {
5723
        vshError(ctl, _("Failed to define pool from %s"), from);
E
Eric Blake 已提交
5724
        ret = false;
5725 5726
    }
    return ret;
5727 5728
}

5729

5730 5731 5732
/*
 * "pool-define-as" command
 */
5733
static const vshCmdInfo info_pool_define_as[] = {
5734 5735
    {"help", N_("define a pool from a set of args")},
    {"desc", N_("Define a pool.")},
5736 5737 5738
    {NULL, NULL}
};

E
Eric Blake 已提交
5739
static bool
5740
cmdPoolDefineAs(vshControl *ctl, const vshCmd *cmd)
5741 5742
{
    virStoragePoolPtr pool;
5743 5744
    const char *name;
    char *xml;
5745
    int printXML = vshCommandOptBool(cmd, "print-xml");
5746

5747
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5748
        return false;
5749

5750
    if (!buildPoolXML(cmd, &name, &xml))
E
Eric Blake 已提交
5751
        return false;
5752

5753
    if (printXML) {
5754
        vshPrint(ctl, "%s", xml);
5755
        VIR_FREE(xml);
5756
    } else {
5757
        pool = virStoragePoolDefineXML(ctl->conn, xml, 0);
5758
        VIR_FREE(xml);
5759

5760 5761 5762 5763
        if (pool != NULL) {
            vshPrint(ctl, _("Pool %s defined\n"), name);
            virStoragePoolFree(pool);
        } else {
5764
            vshError(ctl, _("Failed to define pool %s"), name);
E
Eric Blake 已提交
5765
            return false;
5766 5767
        }
    }
E
Eric Blake 已提交
5768
    return true;
5769 5770 5771
}


5772
/*
5773
 * "pool-build" command
5774
 */
5775
static const vshCmdInfo info_pool_build[] = {
5776 5777
    {"help", N_("build a pool")},
    {"desc", N_("Build a given pool.")},
5778 5779 5780
    {NULL, NULL}
};

5781
static const vshCmdOptDef opts_pool_build[] = {
5782
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5783 5784 5785
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5786
static bool
5787
cmdPoolBuild(vshControl *ctl, const vshCmd *cmd)
5788
{
5789
    virStoragePoolPtr pool;
E
Eric Blake 已提交
5790
    bool ret = true;
5791
    const char *name;
5792

5793
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5794
        return false;
5795

5796
    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
E
Eric Blake 已提交
5797
        return false;
5798

5799
    if (virStoragePoolBuild(pool, 0) == 0) {
5800
        vshPrint(ctl, _("Pool %s built\n"), name);
5801
    } else {
5802
        vshError(ctl, _("Failed to build pool %s"), name);
E
Eric Blake 已提交
5803
        ret = false;
5804 5805
    }

5806 5807
    virStoragePoolFree(pool);

5808 5809 5810
    return ret;
}

5811

5812
/*
5813
 * "pool-destroy" command
5814
 */
5815
static const vshCmdInfo info_pool_destroy[] = {
5816 5817
    {"help", N_("destroy a pool")},
    {"desc", N_("Destroy a given pool.")},
5818 5819 5820
    {NULL, NULL}
};

5821
static const vshCmdOptDef opts_pool_destroy[] = {
5822
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5823 5824 5825
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5826
static bool
5827
cmdPoolDestroy(vshControl *ctl, const vshCmd *cmd)
5828
{
5829
    virStoragePoolPtr pool;
E
Eric Blake 已提交
5830
    bool ret = true;
5831
    const char *name;
5832

5833
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5834
        return false;
5835

5836
    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
E
Eric Blake 已提交
5837
        return false;
5838

5839 5840 5841
    if (virStoragePoolDestroy(pool) == 0) {
        vshPrint(ctl, _("Pool %s destroyed\n"), name);
    } else {
5842
        vshError(ctl, _("Failed to destroy pool %s"), name);
E
Eric Blake 已提交
5843
        ret = false;
5844 5845
    }

5846
    virStoragePoolFree(pool);
5847 5848 5849
    return ret;
}

5850

5851
/*
5852 5853
 * "pool-delete" command
 */
5854
static const vshCmdInfo info_pool_delete[] = {
5855 5856
    {"help", N_("delete a pool")},
    {"desc", N_("Delete a given pool.")},
5857 5858 5859
    {NULL, NULL}
};

5860
static const vshCmdOptDef opts_pool_delete[] = {
5861
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5862 5863 5864
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5865
static bool
5866
cmdPoolDelete(vshControl *ctl, const vshCmd *cmd)
5867 5868
{
    virStoragePoolPtr pool;
E
Eric Blake 已提交
5869
    bool ret = true;
5870
    const char *name;
5871

5872
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5873
        return false;
5874 5875

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
E
Eric Blake 已提交
5876
        return false;
5877 5878

    if (virStoragePoolDelete(pool, 0) == 0) {
D
Daniel Veillard 已提交
5879
        vshPrint(ctl, _("Pool %s deleted\n"), name);
5880
    } else {
5881
        vshError(ctl, _("Failed to delete pool %s"), name);
E
Eric Blake 已提交
5882
        ret = false;
5883 5884
    }

L
Laine Stump 已提交
5885
    virStoragePoolFree(pool);
5886 5887 5888 5889 5890 5891 5892
    return ret;
}


/*
 * "pool-refresh" command
 */
5893
static const vshCmdInfo info_pool_refresh[] = {
5894 5895
    {"help", N_("refresh a pool")},
    {"desc", N_("Refresh a given pool.")},
5896 5897 5898
    {NULL, NULL}
};

5899
static const vshCmdOptDef opts_pool_refresh[] = {
5900
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5901 5902 5903
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5904
static bool
5905
cmdPoolRefresh(vshControl *ctl, const vshCmd *cmd)
5906 5907
{
    virStoragePoolPtr pool;
E
Eric Blake 已提交
5908
    bool ret = true;
5909
    const char *name;
5910

5911
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5912
        return false;
5913 5914

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
E
Eric Blake 已提交
5915
        return false;
5916 5917 5918 5919

    if (virStoragePoolRefresh(pool, 0) == 0) {
        vshPrint(ctl, _("Pool %s refreshed\n"), name);
    } else {
5920
        vshError(ctl, _("Failed to refresh pool %s"), name);
E
Eric Blake 已提交
5921
        ret = false;
5922 5923 5924 5925 5926 5927 5928 5929 5930 5931
    }
    virStoragePoolFree(pool);

    return ret;
}


/*
 * "pool-dumpxml" command
 */
5932
static const vshCmdInfo info_pool_dumpxml[] = {
5933 5934
    {"help", N_("pool information in XML")},
    {"desc", N_("Output the pool information as an XML dump to stdout.")},
5935 5936 5937
    {NULL, NULL}
};

5938
static const vshCmdOptDef opts_pool_dumpxml[] = {
5939
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5940 5941 5942
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5943
static bool
5944
cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd)
5945 5946
{
    virStoragePoolPtr pool;
E
Eric Blake 已提交
5947
    bool ret = true;
5948 5949
    char *dump;

5950
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
5951
        return false;
5952 5953

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
E
Eric Blake 已提交
5954
        return false;
5955 5956 5957

    dump = virStoragePoolGetXMLDesc(pool, 0);
    if (dump != NULL) {
5958
        vshPrint(ctl, "%s", dump);
5959
        VIR_FREE(dump);
5960
    } else {
E
Eric Blake 已提交
5961
        ret = false;
5962 5963 5964 5965 5966 5967 5968 5969 5970 5971
    }

    virStoragePoolFree(pool);
    return ret;
}


/*
 * "pool-list" command
 */
5972
static const vshCmdInfo info_pool_list[] = {
5973 5974
    {"help", N_("list pools")},
    {"desc", N_("Returns list of pools.")},
5975 5976 5977
    {NULL, NULL}
};

5978
static const vshCmdOptDef opts_pool_list[] = {
5979 5980
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive pools")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active pools")},
5981
    {"details", VSH_OT_BOOL, 0, N_("display extended details for pools")},
5982 5983 5984
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
5985
static bool
5986
cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
5987
{
5988 5989
    virStoragePoolInfo info;
    char **poolNames = NULL;
W
Wen Congyang 已提交
5990 5991
    int i, ret;
    bool functionReturn;
5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007
    int numActivePools = 0, numInactivePools = 0, numAllPools = 0;
    size_t stringLength = 0, nameStrLength = 0;
    size_t autostartStrLength = 0, persistStrLength = 0;
    size_t stateStrLength = 0, capStrLength = 0;
    size_t allocStrLength = 0, availStrLength = 0;
    struct poolInfoText {
        char *state;
        char *autostart;
        char *persistent;
        char *capacity;
        char *allocation;
        char *available;
    };
    struct poolInfoText *poolInfoTexts = NULL;

    /* Determine the options passed by the user */
6008
    int all = vshCommandOptBool(cmd, "all");
6009 6010
    int details = vshCommandOptBool(cmd, "details");
    int inactive = vshCommandOptBool(cmd, "inactive");
6011 6012 6013
    int active = !inactive || all ? 1 : 0;
    inactive |= all;

6014
    /* Check the connection to libvirtd daemon is still working */
6015
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6016
        return false;
6017

6018
    /* Retrieve the number of active storage pools */
6019
    if (active) {
6020 6021
        numActivePools = virConnectNumOfStoragePools(ctl->conn);
        if (numActivePools < 0) {
6022
            vshError(ctl, "%s", _("Failed to list active pools"));
E
Eric Blake 已提交
6023
            return false;
6024 6025
        }
    }
6026 6027

    /* Retrieve the number of inactive storage pools */
6028
    if (inactive) {
6029 6030
        numInactivePools = virConnectNumOfDefinedStoragePools(ctl->conn);
        if (numInactivePools < 0) {
6031
            vshError(ctl, "%s", _("Failed to list inactive pools"));
E
Eric Blake 已提交
6032
            return false;
6033
        }
6034
    }
6035

6036 6037
    /* Determine the total number of pools to list */
    numAllPools = numActivePools + numInactivePools;
6038

6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050
    /* Allocate memory for arrays of storage pool names and info */
    poolNames = vshCalloc(ctl, numAllPools, sizeof(*poolNames));
    poolInfoTexts =
        vshCalloc(ctl, numAllPools, sizeof(*poolInfoTexts));

    /* Retrieve a list of active storage pool names */
    if (active) {
        if ((virConnectListStoragePools(ctl->conn,
                                        poolNames, numActivePools)) < 0) {
            vshError(ctl, "%s", _("Failed to list active pools"));
            VIR_FREE(poolInfoTexts);
            VIR_FREE(poolNames);
E
Eric Blake 已提交
6051
            return false;
6052 6053 6054
        }
    }

6055 6056 6057 6058 6059 6060 6061 6062
    /* Add the inactive storage pools to the end of the name list */
    if (inactive) {
        if ((virConnectListDefinedStoragePools(ctl->conn,
                                               &poolNames[numActivePools],
                                               numInactivePools)) < 0) {
            vshError(ctl, "%s", _("Failed to list inactive pools"));
            VIR_FREE(poolInfoTexts);
            VIR_FREE(poolNames);
E
Eric Blake 已提交
6063
            return false;
6064 6065
        }
    }
6066

6067 6068 6069 6070 6071 6072 6073 6074 6075 6076
    /* Sort the storage pool names */
    qsort(poolNames, numAllPools, sizeof(*poolNames), namesorter);

    /* Collect the storage pool information for display */
    for (i = 0; i < numAllPools; i++) {
        int autostart = 0, persistent = 0;

        /* Retrieve a pool object, looking it up by name */
        virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn,
                                                            poolNames[i]);
6077
        if (!pool) {
6078
            VIR_FREE(poolNames[i]);
6079 6080 6081
            continue;
        }

6082
        /* Retrieve the autostart status of the pool */
6083
        if (virStoragePoolGetAutostart(pool, &autostart) < 0)
6084
            poolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart"));
6085
        else
6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103
            poolInfoTexts[i].autostart = vshStrdup(ctl, autostart ?
                                                    _("yes") : _("no"));

        /* Retrieve the persistence status of the pool */
        if (details) {
            persistent = virStoragePoolIsPersistent(pool);
            vshDebug(ctl, 5, "Persistent flag value: %d\n", persistent);
            if (persistent < 0)
                poolInfoTexts[i].persistent = vshStrdup(ctl, _("unknown"));
            else
                poolInfoTexts[i].persistent = vshStrdup(ctl, persistent ?
                                                         _("yes") : _("no"));

            /* Keep the length of persistent string if longest so far */
            stringLength = strlen(poolInfoTexts[i].persistent);
            if (stringLength > persistStrLength)
                persistStrLength = stringLength;
        }
6104

6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216
        /* Collect further extended information about the pool */
        if (virStoragePoolGetInfo(pool, &info) != 0) {
            /* Something went wrong retrieving pool info, cope with it */
            vshError(ctl, "%s", _("Could not retrieve pool information"));
            poolInfoTexts[i].state = vshStrdup(ctl, _("unknown"));
            if (details) {
                poolInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
                poolInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
                poolInfoTexts[i].available = vshStrdup(ctl, _("unknown"));
            }
        } else {
            /* Decide which state string to display */
            if (details) {
                /* --details option was specified, we're using detailed state
                 * strings */
                switch (info.state) {
                case VIR_STORAGE_POOL_INACTIVE:
                    poolInfoTexts[i].state = vshStrdup(ctl, _("inactive"));
                    break;
                case VIR_STORAGE_POOL_BUILDING:
                    poolInfoTexts[i].state = vshStrdup(ctl, _("building"));
                    break;
                case VIR_STORAGE_POOL_RUNNING:
                    poolInfoTexts[i].state = vshStrdup(ctl, _("running"));
                    break;
                case VIR_STORAGE_POOL_DEGRADED:
                    poolInfoTexts[i].state = vshStrdup(ctl, _("degraded"));
                    break;
                case VIR_STORAGE_POOL_INACCESSIBLE:
                    poolInfoTexts[i].state = vshStrdup(ctl, _("inaccessible"));
                    break;
                }

                /* Create the pool size related strings */
                if (info.state == VIR_STORAGE_POOL_RUNNING ||
                    info.state == VIR_STORAGE_POOL_DEGRADED) {
                    double val;
                    const char *unit;

                    /* Create the capacity output string */
                    val = prettyCapacity(info.capacity, &unit);
                    ret = virAsprintf(&poolInfoTexts[i].capacity,
                                      "%.2lf %s", val, unit);
                    if (ret < 0) {
                        /* An error occurred creating the string, return */
                        goto asprintf_failure;
                    }

                    /* Create the allocation output string */
                    val = prettyCapacity(info.allocation, &unit);
                    ret = virAsprintf(&poolInfoTexts[i].allocation,
                                      "%.2lf %s", val, unit);
                    if (ret < 0) {
                        /* An error occurred creating the string, return */
                        goto asprintf_failure;
                    }

                    /* Create the available space output string */
                    val = prettyCapacity(info.available, &unit);
                    ret = virAsprintf(&poolInfoTexts[i].available,
                                      "%.2lf %s", val, unit);
                    if (ret < 0) {
                        /* An error occurred creating the string, return */
                        goto asprintf_failure;
                    }
                } else {
                    /* Capacity related information isn't available */
                    poolInfoTexts[i].capacity = vshStrdup(ctl, _("-"));
                    poolInfoTexts[i].allocation = vshStrdup(ctl, _("-"));
                    poolInfoTexts[i].available = vshStrdup(ctl, _("-"));
                }

                /* Keep the length of capacity string if longest so far */
                stringLength = strlen(poolInfoTexts[i].capacity);
                if (stringLength > capStrLength)
                    capStrLength = stringLength;

                /* Keep the length of allocation string if longest so far */
                stringLength = strlen(poolInfoTexts[i].allocation);
                if (stringLength > allocStrLength)
                    allocStrLength = stringLength;

                /* Keep the length of available string if longest so far */
                stringLength = strlen(poolInfoTexts[i].available);
                if (stringLength > availStrLength)
                    availStrLength = stringLength;
            } else {
                /* --details option was not specified, only active/inactive
                * state strings are used */
                if (info.state == VIR_STORAGE_POOL_INACTIVE)
                    poolInfoTexts[i].state = vshStrdup(ctl, _("inactive"));
                else
                    poolInfoTexts[i].state = vshStrdup(ctl, _("active"));
            }
        }

        /* Keep the length of name string if longest so far */
        stringLength = strlen(poolNames[i]);
        if (stringLength > nameStrLength)
            nameStrLength = stringLength;

        /* Keep the length of state string if longest so far */
        stringLength = strlen(poolInfoTexts[i].state);
        if (stringLength > stateStrLength)
            stateStrLength = stringLength;

        /* Keep the length of autostart string if longest so far */
        stringLength = strlen(poolInfoTexts[i].autostart);
        if (stringLength > autostartStrLength)
            autostartStrLength = stringLength;

        /* Free the pool object */
6217 6218 6219
        virStoragePoolFree(pool);
    }

6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237
    /* If the --details option wasn't selected, we output the pool
     * info using the fixed string format from previous versions to
     * maintain backward compatibility.
     */

    /* Output basic info then return if --details option not selected */
    if (!details) {
        /* Output old style header */
        vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("State"),
                      _("Autostart"));
        vshPrintExtra(ctl, "-----------------------------------------\n");

        /* Output old style pool info */
        for (i = 0; i < numAllPools; i++) {
            vshPrint(ctl, "%-20s %-10s %-10s\n",
                 poolNames[i],
                 poolInfoTexts[i].state,
                 poolInfoTexts[i].autostart);
6238 6239
        }

6240
        /* Cleanup and return */
E
Eric Blake 已提交
6241
        functionReturn = true;
6242 6243
        goto cleanup;
    }
6244

6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338
    /* We only get here if the --details option was selected. */

    /* Use the length of name header string if it's longest */
    stringLength = strlen(_("Name"));
    if (stringLength > nameStrLength)
        nameStrLength = stringLength;

    /* Use the length of state header string if it's longest */
    stringLength = strlen(_("State"));
    if (stringLength > stateStrLength)
        stateStrLength = stringLength;

    /* Use the length of autostart header string if it's longest */
    stringLength = strlen(_("Autostart"));
    if (stringLength > autostartStrLength)
        autostartStrLength = stringLength;

    /* Use the length of persistent header string if it's longest */
    stringLength = strlen(_("Persistent"));
    if (stringLength > persistStrLength)
        persistStrLength = stringLength;

    /* Use the length of capacity header string if it's longest */
    stringLength = strlen(_("Capacity"));
    if (stringLength > capStrLength)
        capStrLength = stringLength;

    /* Use the length of allocation header string if it's longest */
    stringLength = strlen(_("Allocation"));
    if (stringLength > allocStrLength)
        allocStrLength = stringLength;

    /* Use the length of available header string if it's longest */
    stringLength = strlen(_("Available"));
    if (stringLength > availStrLength)
        availStrLength = stringLength;

    /* Display the string lengths for debugging. */
    vshDebug(ctl, 5, "Longest name string = %lu chars\n",
             (unsigned long) nameStrLength);
    vshDebug(ctl, 5, "Longest state string = %lu chars\n",
             (unsigned long) stateStrLength);
    vshDebug(ctl, 5, "Longest autostart string = %lu chars\n",
             (unsigned long) autostartStrLength);
    vshDebug(ctl, 5, "Longest persistent string = %lu chars\n",
             (unsigned long) persistStrLength);
    vshDebug(ctl, 5, "Longest capacity string = %lu chars\n",
             (unsigned long) capStrLength);
    vshDebug(ctl, 5, "Longest allocation string = %lu chars\n",
             (unsigned long) allocStrLength);
    vshDebug(ctl, 5, "Longest available string = %lu chars\n",
             (unsigned long) availStrLength);

    /* Create the output template.  Each column is sized according to
     * the longest string.
     */
    char *outputStr;
    ret = virAsprintf(&outputStr,
              "%%-%lus  %%-%lus  %%-%lus  %%-%lus  %%%lus  %%%lus  %%%lus\n",
              (unsigned long) nameStrLength,
              (unsigned long) stateStrLength,
              (unsigned long) autostartStrLength,
              (unsigned long) persistStrLength,
              (unsigned long) capStrLength,
              (unsigned long) allocStrLength,
              (unsigned long) availStrLength);
    if (ret < 0) {
        /* An error occurred creating the string, return */
        goto asprintf_failure;
    }

    /* Display the header */
    vshPrint(ctl, outputStr, _("Name"), _("State"), _("Autostart"),
             _("Persistent"), _("Capacity"), _("Allocation"), _("Available"));
    for (i = nameStrLength + stateStrLength + autostartStrLength
                           + persistStrLength + capStrLength
                           + allocStrLength + availStrLength
                           + 12; i > 0; i--)
        vshPrintExtra(ctl, "-");
    vshPrintExtra(ctl, "\n");

    /* Display the pool info rows */
    for (i = 0; i < numAllPools; i++) {
        vshPrint(ctl, outputStr,
                 poolNames[i],
                 poolInfoTexts[i].state,
                 poolInfoTexts[i].autostart,
                 poolInfoTexts[i].persistent,
                 poolInfoTexts[i].capacity,
                 poolInfoTexts[i].allocation,
                 poolInfoTexts[i].available);
    }

    /* Cleanup and return */
E
Eric Blake 已提交
6339
    functionReturn = true;
6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353
    goto cleanup;

asprintf_failure:

    /* Display an appropriate error message then cleanup and return */
    switch (errno) {
    case ENOMEM:
        /* Couldn't allocate memory */
        vshError(ctl, "%s", _("Out of memory"));
        break;
    default:
        /* Some other error */
        vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
    }
E
Eric Blake 已提交
6354
    functionReturn = false;
6355

6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367
cleanup:

    /* Safely free the memory allocated in this function */
    for (i = 0; i < numAllPools; i++) {
        /* Cleanup the memory for one pool info structure */
        VIR_FREE(poolInfoTexts[i].state);
        VIR_FREE(poolInfoTexts[i].autostart);
        VIR_FREE(poolInfoTexts[i].persistent);
        VIR_FREE(poolInfoTexts[i].capacity);
        VIR_FREE(poolInfoTexts[i].allocation);
        VIR_FREE(poolInfoTexts[i].available);
        VIR_FREE(poolNames[i]);
6368
    }
6369 6370 6371 6372 6373 6374 6375

    /* Cleanup the memory for the initial arrays*/
    VIR_FREE(poolInfoTexts);
    VIR_FREE(poolNames);

    /* Return the desired value */
    return functionReturn;
6376 6377
}

6378 6379 6380 6381
/*
 * "find-storage-pool-sources-as" command
 */
static const vshCmdInfo info_find_storage_pool_sources_as[] = {
6382 6383
    {"help", N_("find potential storage pool sources")},
    {"desc", N_("Returns XML <sources> document.")},
6384 6385 6386 6387 6388
    {NULL, NULL}
};

static const vshCmdOptDef opts_find_storage_pool_sources_as[] = {
    {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
6389 6390 6391
     N_("type of storage pool sources to find")},
    {"host", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional host to query")},
    {"port", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional port to query")},
6392
    {"initiator", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional initiator IQN to use for query")},
6393 6394 6395
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6396
static bool
6397 6398
cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
{
6399
    const char *type = NULL, *host = NULL;
6400 6401
    char *srcSpec = NULL;
    char *srcList;
6402
    const char *initiator = NULL;
6403

6404 6405
    if (vshCommandOptString(cmd, "type", &type) <= 0 ||
        vshCommandOptString(cmd, "host", &host) < 0 ||
6406 6407
        vshCommandOptString(cmd, "initiator", &initiator) < 0) {
        vshError(ctl,"%s", _("missing argument"));
E
Eric Blake 已提交
6408
        return false;
6409
    }
6410

6411
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6412
        return false;
6413 6414

    if (host) {
6415
        const char *port = NULL;
6416
        virBuffer buf = VIR_BUFFER_INITIALIZER;
6417 6418 6419 6420

        if (vshCommandOptString(cmd, "port", &port) < 0) {
            vshError(ctl, "%s", _("missing argument"));
            virBufferFreeAndReset(&buf);
E
Eric Blake 已提交
6421
            return false;
6422
        }
6423
        virBufferAddLit(&buf, "<source>\n");
6424
        virBufferAsprintf(&buf, "  <host name='%s'", host);
6425
        if (port)
6426
            virBufferAsprintf(&buf, " port='%s'", port);
6427
        virBufferAddLit(&buf, "/>\n");
6428 6429
        if (initiator) {
            virBufferAddLit(&buf, "  <initiator>\n");
6430
            virBufferAsprintf(&buf, "    <iqn name='%s'/>\n", initiator);
6431 6432
            virBufferAddLit(&buf, "  </initiator>\n");
        }
6433 6434 6435
        virBufferAddLit(&buf, "</source>\n");
        if (virBufferError(&buf)) {
            vshError(ctl, "%s", _("Out of memory"));
E
Eric Blake 已提交
6436
            return false;
6437
        }
6438
        srcSpec = virBufferContentAndReset(&buf);
6439 6440 6441
    }

    srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
6442
    VIR_FREE(srcSpec);
6443
    if (srcList == NULL) {
6444
        vshError(ctl, _("Failed to find any %s pool sources"), type);
E
Eric Blake 已提交
6445
        return false;
6446 6447
    }
    vshPrint(ctl, "%s", srcList);
6448
    VIR_FREE(srcList);
6449

E
Eric Blake 已提交
6450
    return true;
6451 6452 6453 6454 6455 6456 6457
}


/*
 * "find-storage-pool-sources" command
 */
static const vshCmdInfo info_find_storage_pool_sources[] = {
6458 6459
    {"help", N_("discover potential storage pool sources")},
    {"desc", N_("Returns XML <sources> document.")},
6460 6461 6462 6463 6464
    {NULL, NULL}
};

static const vshCmdOptDef opts_find_storage_pool_sources[] = {
    {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
6465
     N_("type of storage pool sources to discover")},
6466
    {"srcSpec", VSH_OT_DATA, VSH_OFLAG_NONE,
6467
     N_("optional file of source xml to query for pools")},
6468 6469 6470
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6471
static bool
6472 6473
cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
{
6474
    const char *type = NULL, *srcSpecFile = NULL;
6475
    char *srcSpec = NULL, *srcList;
6476

6477
    if (vshCommandOptString(cmd, "type", &type) <= 0)
E
Eric Blake 已提交
6478
        return false;
6479

6480 6481
    if (vshCommandOptString(cmd, "srcSpec", &srcSpecFile) < 0) {
        vshError(ctl, "%s", _("missing option"));
E
Eric Blake 已提交
6482
        return false;
6483
    }
6484

6485
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6486
        return false;
6487 6488

    if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0)
E
Eric Blake 已提交
6489
        return false;
6490 6491

    srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
6492
    VIR_FREE(srcSpec);
6493
    if (srcList == NULL) {
6494
        vshError(ctl, _("Failed to find any %s pool sources"), type);
E
Eric Blake 已提交
6495
        return false;
6496 6497
    }
    vshPrint(ctl, "%s", srcList);
6498
    VIR_FREE(srcList);
6499

E
Eric Blake 已提交
6500
    return true;
6501 6502 6503
}


6504 6505 6506
/*
 * "pool-info" command
 */
6507
static const vshCmdInfo info_pool_info[] = {
6508 6509
    {"help", N_("storage pool information")},
    {"desc", N_("Returns basic information about the storage pool.")},
6510 6511 6512
    {NULL, NULL}
};

6513
static const vshCmdOptDef opts_pool_info[] = {
6514
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
6515 6516 6517
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6518
static bool
6519
cmdPoolInfo(vshControl *ctl, const vshCmd *cmd)
6520 6521 6522
{
    virStoragePoolInfo info;
    virStoragePoolPtr pool;
6523 6524
    int autostart = 0;
    int persistent = 0;
E
Eric Blake 已提交
6525
    bool ret = true;
6526 6527
    char uuid[VIR_UUID_STRING_BUFLEN];

6528
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6529
        return false;
6530 6531

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
E
Eric Blake 已提交
6532
        return false;
6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558

    vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool));

    if (virStoragePoolGetUUIDString(pool, &uuid[0])==0)
        vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);

    if (virStoragePoolGetInfo(pool, &info) == 0) {
        double val;
        const char *unit;
        switch (info.state) {
        case VIR_STORAGE_POOL_INACTIVE:
            vshPrint(ctl, "%-15s %s\n", _("State:"),
                     _("inactive"));
            break;
        case VIR_STORAGE_POOL_BUILDING:
            vshPrint(ctl, "%-15s %s\n", _("State:"),
                     _("building"));
            break;
        case VIR_STORAGE_POOL_RUNNING:
            vshPrint(ctl, "%-15s %s\n", _("State:"),
                     _("running"));
            break;
        case VIR_STORAGE_POOL_DEGRADED:
            vshPrint(ctl, "%-15s %s\n", _("State:"),
                     _("degraded"));
            break;
6559 6560 6561 6562
        case VIR_STORAGE_POOL_INACCESSIBLE:
            vshPrint(ctl, "%-15s %s\n", _("State:"),
                     _("inaccessible"));
            break;
6563 6564
        }

6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580
        /* Check and display whether the pool is persistent or not */
        persistent = virStoragePoolIsPersistent(pool);
        vshDebug(ctl, 5, "Pool persistent flag value: %d\n", persistent);
        if (persistent < 0)
            vshPrint(ctl, "%-15s %s\n", _("Persistent:"),  _("unknown"));
        else
            vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));

        /* Check and display whether the pool is autostarted or not */
        virStoragePoolGetAutostart(pool, &autostart);
        vshDebug(ctl, 5, "Pool autostart flag value: %d\n", autostart);
        if (autostart < 0)
            vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart"));
        else
            vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));

6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592
        if (info.state == VIR_STORAGE_POOL_RUNNING ||
            info.state == VIR_STORAGE_POOL_DEGRADED) {
            val = prettyCapacity(info.capacity, &unit);
            vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);

            val = prettyCapacity(info.allocation, &unit);
            vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);

            val = prettyCapacity(info.available, &unit);
            vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit);
        }
    } else {
E
Eric Blake 已提交
6593
        ret = false;
6594 6595 6596 6597 6598 6599 6600 6601 6602 6603
    }

    virStoragePoolFree(pool);
    return ret;
}


/*
 * "pool-name" command
 */
6604
static const vshCmdInfo info_pool_name[] = {
6605
    {"help", N_("convert a pool UUID to pool name")},
6606
    {"desc", ""},
6607 6608 6609
    {NULL, NULL}
};

6610
static const vshCmdOptDef opts_pool_name[] = {
6611
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")},
6612 6613 6614
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6615
static bool
6616
cmdPoolName(vshControl *ctl, const vshCmd *cmd)
6617 6618 6619
{
    virStoragePoolPtr pool;

6620
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6621
        return false;
6622
    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6623
                                           VSH_BYUUID)))
E
Eric Blake 已提交
6624
        return false;
6625 6626 6627

    vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
    virStoragePoolFree(pool);
E
Eric Blake 已提交
6628
    return true;
6629 6630 6631 6632 6633 6634
}


/*
 * "pool-start" command
 */
6635
static const vshCmdInfo info_pool_start[] = {
6636 6637
    {"help", N_("start a (previously defined) inactive pool")},
    {"desc", N_("Start a pool.")},
6638 6639 6640
    {NULL, NULL}
};

6641
static const vshCmdOptDef opts_pool_start[] = {
6642
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive pool")},
6643 6644 6645
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6646
static bool
6647
cmdPoolStart(vshControl *ctl, const vshCmd *cmd)
6648 6649
{
    virStoragePoolPtr pool;
E
Eric Blake 已提交
6650
    bool ret = true;
6651

6652
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6653
        return false;
6654

6655
    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
E
Eric Blake 已提交
6656
         return false;
6657 6658 6659 6660 6661

    if (virStoragePoolCreate(pool, 0) == 0) {
        vshPrint(ctl, _("Pool %s started\n"),
                 virStoragePoolGetName(pool));
    } else {
6662
        vshError(ctl, _("Failed to start pool %s"), virStoragePoolGetName(pool));
E
Eric Blake 已提交
6663
        ret = false;
6664
    }
L
Laine Stump 已提交
6665 6666

    virStoragePoolFree(pool);
6667 6668 6669 6670
    return ret;
}


6671 6672 6673
/*
 * "vol-create-as" command
 */
6674
static const vshCmdInfo info_vol_create_as[] = {
6675 6676
    {"help", N_("create a volume from a set of args")},
    {"desc", N_("Create a vol.")},
6677 6678 6679
    {NULL, NULL}
};

6680
static const vshCmdOptDef opts_vol_create_as[] = {
6681 6682 6683 6684 6685
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
    {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")},
    {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, N_("size of the vol with optional k,M,G,T suffix")},
    {"allocation", VSH_OT_STRING, 0, N_("initial allocation size with optional k,M,G,T suffix")},
    {"format", VSH_OT_STRING, 0, N_("file format type raw,bochs,qcow,qcow2,vmdk")},
6686 6687
    {"backing-vol", VSH_OT_STRING, 0, N_("the backing volume if taking a snapshot")},
    {"backing-vol-format", VSH_OT_STRING, 0, N_("format of backing volume if taking a snapshot")},
6688 6689 6690 6691 6692 6693 6694 6695 6696 6697
    {NULL, 0, 0, NULL}
};

static int cmdVolSize(const char *data, unsigned long long *val)
{
    char *end;
    if (virStrToLong_ull(data, &end, 10, val) < 0)
        return -1;

    if (end && *end) {
D
Daniel Veillard 已提交
6698
        /* Deliberate fallthrough cases here :-) */
6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718
        switch (*end) {
        case 'T':
            *val *= 1024;
        case 'G':
            *val *= 1024;
        case 'M':
            *val *= 1024;
        case 'k':
            *val *= 1024;
            break;
        default:
            return -1;
        }
        end++;
        if (*end)
            return -1;
    }
    return 0;
}

E
Eric Blake 已提交
6719
static bool
6720
cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd)
6721 6722 6723
{
    virStoragePoolPtr pool;
    virStorageVolPtr vol;
6724
    char *xml;
6725 6726
    const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL;
    const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL;
6727
    unsigned long long capacity, allocation = 0;
6728
    virBuffer buf = VIR_BUFFER_INITIALIZER;
6729

6730
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6731
        return false;
6732 6733 6734

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
                                     VSH_BYNAME)))
E
Eric Blake 已提交
6735
        return false;
6736

6737
    if (vshCommandOptString(cmd, "name", &name) <= 0)
6738 6739
        goto cleanup;

6740
    if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0)
6741 6742
        goto cleanup;
    if (cmdVolSize(capacityStr, &capacity) < 0)
6743
        vshError(ctl, _("Malformed size %s"), capacityStr);
6744

6745 6746
    if ((vshCommandOptString(cmd, "allocation", &allocationStr) > 0) &&
        (cmdVolSize(allocationStr, &allocation) < 0))
6747
        vshError(ctl, _("Malformed size %s"), allocationStr);
6748

6749 6750 6751 6752 6753 6754 6755
    if (vshCommandOptString(cmd, "format", &format) < 0 ||
        vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 ||
        vshCommandOptString(cmd, "backing-vol-format",
                            &snapshotStrFormat) < 0) {
        vshError(ctl, "%s", _("missing argument"));
    }

6756

6757
    virBufferAddLit(&buf, "<volume>\n");
6758 6759
    virBufferAsprintf(&buf, "  <name>%s</name>\n", name);
    virBufferAsprintf(&buf, "  <capacity>%llu</capacity>\n", capacity);
6760
    if (allocationStr)
6761
        virBufferAsprintf(&buf, "  <allocation>%llu</allocation>\n", allocation);
6762 6763

    if (format) {
6764
        virBufferAddLit(&buf, "  <target>\n");
6765
        virBufferAsprintf(&buf, "    <format type='%s'/>\n",format);
6766
        virBufferAddLit(&buf, "  </target>\n");
6767
    }
6768

6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801
    /* Convert the snapshot parameters into backingStore XML */
    if (snapshotStrVol) {
        /* Lookup snapshot backing volume.  Try the backing-vol
         *  parameter as a name */
        vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as name\n",
                 cmd->def->name, snapshotStrVol);
        virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol);
        if (snapVol)
                vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as name\n",
                         cmd->def->name, snapshotStrVol);

        if (snapVol == NULL) {
            /* Snapshot backing volume not found by name.  Try the
             *  backing-vol parameter as a key */
            vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as key\n",
                     cmd->def->name, snapshotStrVol);
            snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol);
            if (snapVol)
                vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as key\n",
                         cmd->def->name, snapshotStrVol);
        }
        if (snapVol == NULL) {
            /* Snapshot backing volume not found by key.  Try the
             *  backing-vol parameter as a path */
            vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as path\n",
                     cmd->def->name, snapshotStrVol);
            snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol);
            if (snapVol)
                vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as path\n",
                         cmd->def->name, snapshotStrVol);
        }
        if (snapVol == NULL) {
            vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol);
E
Eric Blake 已提交
6802
            return false;
6803 6804 6805 6806 6807
        }

        char *snapshotStrVolPath;
        if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) {
            virStorageVolFree(snapVol);
E
Eric Blake 已提交
6808
            return false;
6809 6810 6811 6812
        }

        /* Create XML for the backing store */
        virBufferAddLit(&buf, "  <backingStore>\n");
6813
        virBufferAsprintf(&buf, "    <path>%s</path>\n",snapshotStrVolPath);
6814
        if (snapshotStrFormat)
6815
            virBufferAsprintf(&buf, "    <format type='%s'/>\n",snapshotStrFormat);
6816 6817 6818 6819 6820 6821 6822 6823
        virBufferAddLit(&buf, "  </backingStore>\n");

        /* Cleanup snapshot allocations */
        VIR_FREE(snapshotStrVolPath);
        virStorageVolFree(snapVol);
    }

    virBufferAddLit(&buf, "</volume>\n");
6824

6825 6826
    if (virBufferError(&buf)) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
E
Eric Blake 已提交
6827
        return false;
6828 6829 6830
    }
    xml = virBufferContentAndReset(&buf);
    vol = virStorageVolCreateXML(pool, xml, 0);
6831
    VIR_FREE(xml);
6832 6833 6834 6835 6836
    virStoragePoolFree(pool);

    if (vol != NULL) {
        vshPrint(ctl, _("Vol %s created\n"), name);
        virStorageVolFree(vol);
E
Eric Blake 已提交
6837
        return true;
6838
    } else {
6839
        vshError(ctl, _("Failed to create vol %s"), name);
E
Eric Blake 已提交
6840
        return false;
6841 6842 6843
    }

 cleanup:
6844
    virBufferFreeAndReset(&buf);
6845
    virStoragePoolFree(pool);
E
Eric Blake 已提交
6846
    return false;
6847 6848 6849
}


6850 6851 6852
/*
 * "pool-undefine" command
 */
6853
static const vshCmdInfo info_pool_undefine[] = {
6854 6855
    {"help", N_("undefine an inactive pool")},
    {"desc", N_("Undefine the configuration for an inactive pool.")},
6856 6857 6858
    {NULL, NULL}
};

6859
static const vshCmdOptDef opts_pool_undefine[] = {
6860
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
6861 6862 6863
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6864
static bool
6865
cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd)
6866 6867
{
    virStoragePoolPtr pool;
E
Eric Blake 已提交
6868
    bool ret = true;
6869
    const char *name;
6870

6871
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6872
        return false;
6873 6874

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
E
Eric Blake 已提交
6875
        return false;
6876 6877 6878 6879

    if (virStoragePoolUndefine(pool) == 0) {
        vshPrint(ctl, _("Pool %s has been undefined\n"), name);
    } else {
6880
        vshError(ctl, _("Failed to undefine pool %s"), name);
E
Eric Blake 已提交
6881
        ret = false;
6882 6883
    }

L
Laine Stump 已提交
6884
    virStoragePoolFree(pool);
6885 6886 6887 6888 6889 6890 6891
    return ret;
}


/*
 * "pool-uuid" command
 */
6892
static const vshCmdInfo info_pool_uuid[] = {
6893
    {"help", N_("convert a pool name to pool UUID")},
6894
    {"desc", ""},
6895 6896 6897
    {NULL, NULL}
};

6898
static const vshCmdOptDef opts_pool_uuid[] = {
6899
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6900 6901 6902
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6903
static bool
6904
cmdPoolUuid(vshControl *ctl, const vshCmd *cmd)
6905 6906 6907 6908
{
    virStoragePoolPtr pool;
    char uuid[VIR_UUID_STRING_BUFLEN];

6909
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6910
        return false;
6911 6912

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6913
                                           VSH_BYNAME)))
E
Eric Blake 已提交
6914
        return false;
6915 6916 6917 6918

    if (virStoragePoolGetUUIDString(pool, uuid) != -1)
        vshPrint(ctl, "%s\n", uuid);
    else
6919
        vshError(ctl, "%s", _("failed to get pool UUID"));
6920

L
Laine Stump 已提交
6921
    virStoragePoolFree(pool);
E
Eric Blake 已提交
6922
    return true;
6923 6924 6925 6926 6927 6928
}


/*
 * "vol-create" command
 */
6929
static const vshCmdInfo info_vol_create[] = {
6930 6931
    {"help", N_("create a vol from an XML file")},
    {"desc", N_("Create a vol.")},
6932 6933 6934
    {NULL, NULL}
};

6935
static const vshCmdOptDef opts_vol_create[] = {
6936 6937
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
6938 6939 6940
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
6941
static bool
6942
cmdVolCreate(vshControl *ctl, const vshCmd *cmd)
6943 6944 6945
{
    virStoragePoolPtr pool;
    virStorageVolPtr vol;
6946
    const char *from = NULL;
E
Eric Blake 已提交
6947
    bool ret = true;
6948 6949
    char *buffer;

6950
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
6951
        return false;
6952 6953

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6954
                                           VSH_BYNAME)))
E
Eric Blake 已提交
6955
        return false;
6956

6957
    if (vshCommandOptString(cmd, "file", &from) <= 0) {
6958
        virStoragePoolFree(pool);
E
Eric Blake 已提交
6959
        return false;
6960 6961 6962
    }

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
6963
        virshReportError(ctl);
6964
        virStoragePoolFree(pool);
E
Eric Blake 已提交
6965
        return false;
6966 6967 6968
    }

    vol = virStorageVolCreateXML(pool, buffer, 0);
6969
    VIR_FREE(buffer);
6970 6971 6972 6973 6974 6975 6976
    virStoragePoolFree(pool);

    if (vol != NULL) {
        vshPrint(ctl, _("Vol %s created from %s\n"),
                 virStorageVolGetName(vol), from);
        virStorageVolFree(vol);
    } else {
6977
        vshError(ctl, _("Failed to create vol from %s"), from);
E
Eric Blake 已提交
6978
        ret = false;
6979 6980 6981 6982
    }
    return ret;
}

6983 6984 6985 6986
/*
 * "vol-create-from" command
 */
static const vshCmdInfo info_vol_create_from[] = {
6987 6988
    {"help", N_("create a vol, using another volume as input")},
    {"desc", N_("Create a vol from an existing volume.")},
6989 6990 6991 6992
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_create_from[] = {
6993 6994 6995
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")},
E
Eric Blake 已提交
6996
    {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")},
6997 6998 6999
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7000
static bool
7001 7002 7003 7004
cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd)
{
    virStoragePoolPtr pool = NULL;
    virStorageVolPtr newvol = NULL, inputvol = NULL;
7005
    const char *from = NULL;
E
Eric Blake 已提交
7006
    bool ret = false;
7007 7008
    char *buffer = NULL;

7009
    if (!vshConnectionUsability(ctl, ctl->conn))
7010 7011 7012 7013 7014
        goto cleanup;

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
        goto cleanup;

7015
    if (vshCommandOptString(cmd, "file", &from) <= 0) {
7016 7017 7018 7019 7020 7021 7022
        goto cleanup;
    }

    if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL)))
        goto cleanup;

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
7023
        virshReportError(ctl);
7024 7025 7026 7027 7028 7029 7030 7031 7032
        goto cleanup;
    }

    newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0);

    if (newvol != NULL) {
        vshPrint(ctl, _("Vol %s created from input vol %s\n"),
                 virStorageVolGetName(newvol), virStorageVolGetName(inputvol));
    } else {
7033
        vshError(ctl, _("Failed to create vol from %s"), from);
7034 7035 7036
        goto cleanup;
    }

E
Eric Blake 已提交
7037
    ret = true;
7038
cleanup:
7039
    VIR_FREE(buffer);
7040 7041 7042 7043
    if (pool)
        virStoragePoolFree(pool);
    if (inputvol)
        virStorageVolFree(inputvol);
L
Laine Stump 已提交
7044 7045
    if (newvol)
        virStorageVolFree(newvol);
7046 7047 7048 7049
    return ret;
}

static xmlChar *
7050
makeCloneXML(const char *origxml, const char *newname) {
7051

7052 7053 7054
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlXPathObjectPtr obj = NULL;
7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084
    xmlChar *newxml = NULL;
    int size;

    doc = xmlReadDoc((const xmlChar *) origxml, "domain.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOWARNING);
    if (!doc)
        goto cleanup;
    ctxt = xmlXPathNewContext(doc);
    if (!ctxt)
        goto cleanup;

    obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt);
    if ((obj == NULL) || (obj->nodesetval == NULL) ||
        (obj->nodesetval->nodeTab == NULL))
        goto cleanup;

    xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname);
    xmlDocDumpMemory(doc, &newxml, &size);

cleanup:
    xmlXPathFreeObject(obj);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);
    return newxml;
}

/*
 * "vol-clone" command
 */
static const vshCmdInfo info_vol_clone[] = {
7085 7086
    {"help", N_("clone a volume.")},
    {"desc", N_("Clone an existing volume.")},
7087 7088 7089 7090
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_clone[] = {
7091 7092
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")},
    {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")},
E
Eric Blake 已提交
7093
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7094 7095 7096
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7097
static bool
7098 7099 7100 7101
cmdVolClone(vshControl *ctl, const vshCmd *cmd)
{
    virStoragePoolPtr origpool = NULL;
    virStorageVolPtr origvol = NULL, newvol = NULL;
7102
    const char *name = NULL;
7103
    char *origxml = NULL;
7104
    xmlChar *newxml = NULL;
E
Eric Blake 已提交
7105
    bool ret = false;
7106

7107
    if (!vshConnectionUsability(ctl, ctl->conn))
7108 7109 7110 7111 7112 7113 7114
        goto cleanup;

    if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
        goto cleanup;

    origpool = virStoragePoolLookupByVolume(origvol);
    if (!origpool) {
7115
        vshError(ctl, "%s", _("failed to get parent pool"));
7116 7117 7118
        goto cleanup;
    }

7119
    if (vshCommandOptString(cmd, "newname", &name) <= 0)
7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137
        goto cleanup;

    origxml = virStorageVolGetXMLDesc(origvol, 0);
    if (!origxml)
        goto cleanup;

    newxml = makeCloneXML(origxml, name);
    if (!newxml) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
        goto cleanup;
    }

    newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0);

    if (newvol != NULL) {
        vshPrint(ctl, _("Vol %s cloned from %s\n"),
                 virStorageVolGetName(newvol), virStorageVolGetName(origvol));
    } else {
7138
        vshError(ctl, _("Failed to clone vol from %s"),
7139 7140 7141 7142
                 virStorageVolGetName(origvol));
        goto cleanup;
    }

E
Eric Blake 已提交
7143
    ret = true;
7144 7145

cleanup:
7146
    VIR_FREE(origxml);
7147 7148 7149
    xmlFree(newxml);
    if (origvol)
        virStorageVolFree(origvol);
L
Laine Stump 已提交
7150 7151
    if (newvol)
        virStorageVolFree(newvol);
7152 7153 7154 7155 7156
    if (origpool)
        virStoragePoolFree(origpool);
    return ret;
}

7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169

/*
 * "vol-upload" command
 */
static const vshCmdInfo info_vol_upload[] = {
    {"help", N_("upload a file into a volume")},
    {"desc", N_("Upload a file into a volume")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_upload[] = {
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")},
E
Eric Blake 已提交
7170
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184
    {"offset", VSH_OT_INT, 0, N_("volume offset to upload to") },
    {"length", VSH_OT_INT, 0, N_("amount of data to upload") },
    {NULL, 0, 0, NULL}
};

static int
cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED,
                   char *bytes, size_t nbytes, void *opaque)
{
    int *fd = opaque;

    return saferead(*fd, bytes, nbytes);
}

E
Eric Blake 已提交
7185
static bool
7186 7187 7188 7189
cmdVolUpload (vshControl *ctl, const vshCmd *cmd)
{
    const char *file = NULL;
    virStorageVolPtr vol = NULL;
E
Eric Blake 已提交
7190
    bool ret = false;
7191 7192 7193 7194 7195 7196 7197 7198 7199 7200
    int fd = -1;
    virStreamPtr st = NULL;
    const char *name = NULL;
    unsigned long long offset = 0, length = 0;

    if (!vshConnectionUsability(ctl, ctl->conn))
        goto cleanup;

    if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) {
        vshError(ctl, _("Unable to parse integer"));
E
Eric Blake 已提交
7201
        return false;
7202 7203 7204 7205
    }

    if (vshCommandOptULongLong(cmd, "length", &length) < 0) {
        vshError(ctl, _("Unable to parse integer"));
E
Eric Blake 已提交
7206
        return false;
7207 7208 7209
    }

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
E
Eric Blake 已提交
7210
        return false;
7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244
    }

    if (vshCommandOptString(cmd, "file", &file) < 0) {
        vshError(ctl, _("file must not be empty"));
        goto cleanup;
    }

    if ((fd = open(file, O_RDONLY)) < 0) {
        vshError(ctl, _("cannot read %s"), file);
        goto cleanup;
    }

    st = virStreamNew(ctl->conn, 0);
    if (virStorageVolUpload(vol, st, offset, length, 0) < 0) {
        vshError(ctl, _("cannot upload to volume %s"), name);
        goto cleanup;
    }

    if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) {
        vshError(ctl, _("cannot send data to volume %s"), name);
        goto cleanup;
    }

    if (VIR_CLOSE(fd) < 0) {
        vshError(ctl, _("cannot close file %s"), file);
        virStreamAbort(st);
        goto cleanup;
    }

    if (virStreamFinish(st) < 0) {
        vshError(ctl, _("cannot close volume %s"), name);
        goto cleanup;
    }

E
Eric Blake 已提交
7245
    ret = true;
7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269

cleanup:
    if (vol)
        virStorageVolFree(vol);
    if (st)
        virStreamFree(st);
    VIR_FORCE_CLOSE(fd);
    return ret;
}



/*
 * "vol-download" command
 */
static const vshCmdInfo info_vol_download[] = {
    {"help", N_("Download a volume to a file")},
    {"desc", N_("Download a volume to a file")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_download[] = {
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")},
E
Eric Blake 已提交
7270
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285
    {"offset", VSH_OT_INT, 0, N_("volume offset to download from") },
    {"length", VSH_OT_INT, 0, N_("amount of data to download") },
    {NULL, 0, 0, NULL}
};


static int
cmdVolDownloadSink(virStreamPtr st ATTRIBUTE_UNUSED,
                   const char *bytes, size_t nbytes, void *opaque)
{
    int *fd = opaque;

    return safewrite(*fd, bytes, nbytes);
}

E
Eric Blake 已提交
7286
static bool
7287 7288 7289 7290
cmdVolDownload (vshControl *ctl, const vshCmd *cmd)
{
    const char *file = NULL;
    virStorageVolPtr vol = NULL;
E
Eric Blake 已提交
7291
    bool ret = false;
7292 7293 7294 7295
    int fd = -1;
    virStreamPtr st = NULL;
    const char *name = NULL;
    unsigned long long offset = 0, length = 0;
7296
    bool created = false;
7297 7298

    if (!vshConnectionUsability(ctl, ctl->conn))
7299
        return false;
7300 7301 7302

    if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) {
        vshError(ctl, _("Unable to parse integer"));
E
Eric Blake 已提交
7303
        return false;
7304 7305 7306 7307
    }

    if (vshCommandOptULongLong(cmd, "length", &length) < 0) {
        vshError(ctl, _("Unable to parse integer"));
E
Eric Blake 已提交
7308
        return false;
7309 7310 7311
    }

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name)))
E
Eric Blake 已提交
7312
        return false;
7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324

    if (vshCommandOptString(cmd, "file", &file) < 0) {
        vshError(ctl, _("file must not be empty"));
        goto cleanup;
    }

    if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) {
        if (errno != EEXIST ||
            (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) {
            vshError(ctl, _("cannot create %s"), file);
            goto cleanup;
        }
7325 7326
    } else {
        created = true;
7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350
    }

    st = virStreamNew(ctl->conn, 0);
    if (virStorageVolDownload(vol, st, offset, length, 0) < 0) {
        vshError(ctl, _("cannot download from volume %s"), name);
        goto cleanup;
    }

    if (virStreamRecvAll(st, cmdVolDownloadSink, &fd) < 0) {
        vshError(ctl, _("cannot receive data from volume %s"), name);
        goto cleanup;
    }

    if (VIR_CLOSE(fd) < 0) {
        vshError(ctl, _("cannot close file %s"), file);
        virStreamAbort(st);
        goto cleanup;
    }

    if (virStreamFinish(st) < 0) {
        vshError(ctl, _("cannot close volume %s"), name);
        goto cleanup;
    }

E
Eric Blake 已提交
7351
    ret = true;
7352 7353

cleanup:
7354
    VIR_FORCE_CLOSE(fd);
7355
    if (!ret && created)
7356 7357 7358 7359 7360 7361 7362 7363 7364
        unlink(file);
    if (vol)
        virStorageVolFree(vol);
    if (st)
        virStreamFree(st);
    return ret;
}


7365 7366 7367
/*
 * "vol-delete" command
 */
7368
static const vshCmdInfo info_vol_delete[] = {
7369 7370
    {"help", N_("delete a vol")},
    {"desc", N_("Delete a given vol.")},
7371 7372 7373
    {NULL, NULL}
};

7374
static const vshCmdOptDef opts_vol_delete[] = {
7375
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
E
Eric Blake 已提交
7376
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7377 7378 7379
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7380
static bool
7381
cmdVolDelete(vshControl *ctl, const vshCmd *cmd)
7382 7383
{
    virStorageVolPtr vol;
E
Eric Blake 已提交
7384
    bool ret = true;
7385
    const char *name;
7386

7387
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7388
        return false;
7389 7390

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
E
Eric Blake 已提交
7391
        return false;
7392 7393 7394
    }

    if (virStorageVolDelete(vol, 0) == 0) {
D
Daniel Veillard 已提交
7395
        vshPrint(ctl, _("Vol %s deleted\n"), name);
7396
    } else {
7397
        vshError(ctl, _("Failed to delete vol %s"), name);
E
Eric Blake 已提交
7398
        ret = false;
7399 7400
    }

L
Laine Stump 已提交
7401
    virStorageVolFree(vol);
7402 7403 7404 7405
    return ret;
}


D
David Allan 已提交
7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416
/*
 * "vol-wipe" command
 */
static const vshCmdInfo info_vol_wipe[] = {
    {"help", N_("wipe a vol")},
    {"desc", N_("Ensure data previously on a volume is not accessible to future reads")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_wipe[] = {
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
E
Eric Blake 已提交
7417
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
D
David Allan 已提交
7418 7419 7420
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7421
static bool
D
David Allan 已提交
7422 7423 7424
cmdVolWipe(vshControl *ctl, const vshCmd *cmd)
{
    virStorageVolPtr vol;
E
Eric Blake 已提交
7425
    bool ret = true;
7426
    const char *name;
D
David Allan 已提交
7427

7428
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7429
        return false;
D
David Allan 已提交
7430 7431

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
E
Eric Blake 已提交
7432
        return false;
D
David Allan 已提交
7433 7434 7435 7436 7437 7438
    }

    if (virStorageVolWipe(vol, 0) == 0) {
        vshPrint(ctl, _("Vol %s wiped\n"), name);
    } else {
        vshError(ctl, _("Failed to wipe vol %s"), name);
E
Eric Blake 已提交
7439
        ret = false;
D
David Allan 已提交
7440 7441 7442 7443 7444 7445 7446
    }

    virStorageVolFree(vol);
    return ret;
}


7447 7448 7449
/*
 * "vol-info" command
 */
7450
static const vshCmdInfo info_vol_info[] = {
7451 7452
    {"help", N_("storage vol information")},
    {"desc", N_("Returns basic information about the storage vol.")},
7453 7454 7455
    {NULL, NULL}
};

7456
static const vshCmdOptDef opts_vol_info[] = {
7457
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
E
Eric Blake 已提交
7458
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7459 7460 7461
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7462
static bool
7463
cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
7464 7465 7466
{
    virStorageVolInfo info;
    virStorageVolPtr vol;
E
Eric Blake 已提交
7467
    bool ret = true;
7468

7469
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7470
        return false;
7471 7472

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
E
Eric Blake 已提交
7473
        return false;
7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489

    vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol));

    if (virStorageVolGetInfo(vol, &info) == 0) {
        double val;
        const char *unit;
        vshPrint(ctl, "%-15s %s\n", _("Type:"),
                 info.type == VIR_STORAGE_VOL_FILE ?
                 _("file") : _("block"));

        val = prettyCapacity(info.capacity, &unit);
        vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);

        val = prettyCapacity(info.allocation, &unit);
        vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
    } else {
E
Eric Blake 已提交
7490
        ret = false;
7491 7492 7493 7494 7495 7496 7497 7498 7499 7500
    }

    virStorageVolFree(vol);
    return ret;
}


/*
 * "vol-dumpxml" command
 */
7501
static const vshCmdInfo info_vol_dumpxml[] = {
7502 7503
    {"help", N_("vol information in XML")},
    {"desc", N_("Output the vol information as an XML dump to stdout.")},
7504 7505 7506
    {NULL, NULL}
};

7507
static const vshCmdOptDef opts_vol_dumpxml[] = {
7508
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
E
Eric Blake 已提交
7509
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7510 7511 7512
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7513
static bool
7514
cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd)
7515 7516
{
    virStorageVolPtr vol;
E
Eric Blake 已提交
7517
    bool ret = true;
7518 7519
    char *dump;

7520
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7521
        return false;
7522 7523

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
E
Eric Blake 已提交
7524
        return false;
7525 7526 7527

    dump = virStorageVolGetXMLDesc(vol, 0);
    if (dump != NULL) {
7528
        vshPrint(ctl, "%s", dump);
7529
        VIR_FREE(dump);
7530
    } else {
E
Eric Blake 已提交
7531
        ret = false;
7532 7533 7534 7535 7536 7537 7538 7539 7540 7541
    }

    virStorageVolFree(vol);
    return ret;
}


/*
 * "vol-list" command
 */
7542
static const vshCmdInfo info_vol_list[] = {
7543 7544
    {"help", N_("list vols")},
    {"desc", N_("Returns list of vols by pool.")},
7545 7546 7547
    {NULL, NULL}
};

7548
static const vshCmdOptDef opts_vol_list[] = {
7549
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
7550
    {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")},
7551 7552 7553
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7554
static bool
7555
cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7556
{
7557
    virStorageVolInfo volumeInfo;
7558 7559
    virStoragePoolPtr pool;
    char **activeNames = NULL;
7560 7561 7562 7563 7564
    char *outputStr = NULL;
    const char *unit;
    double val;
    int details = vshCommandOptBool(cmd, "details");
    int numVolumes = 0, i;
W
Wen Congyang 已提交
7565 7566
    int ret;
    bool functionReturn;
7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577
    int stringLength = 0;
    size_t allocStrLength = 0, capStrLength = 0;
    size_t nameStrLength = 0, pathStrLength = 0;
    size_t typeStrLength = 0;
    struct volInfoText {
        char *allocation;
        char *capacity;
        char *path;
        char *type;
    };
    struct volInfoText *volInfoTexts = NULL;
7578

7579
    /* Check the connection to libvirtd daemon is still working */
7580
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7581
        return false;
7582

7583
    /* Look up the pool information given to us by the user */
7584
    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
E
Eric Blake 已提交
7585
        return false;
7586

7587 7588
    /* Determine the number of volumes in the pool */
    numVolumes = virStoragePoolNumOfVolumes(pool);
7589

7590 7591 7592
    if (numVolumes < 0) {
        vshError(ctl, "%s", _("Failed to list storage volumes"));
        virStoragePoolFree(pool);
E
Eric Blake 已提交
7593
        return false;
7594 7595
    }

7596 7597 7598 7599 7600
    /* Retrieve the list of volume names in the pool */
    if (numVolumes > 0) {
        activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames));
        if ((numVolumes = virStoragePoolListVolumes(pool, activeNames,
                                                    numVolumes)) < 0) {
7601
            vshError(ctl, "%s", _("Failed to list active vols"));
7602
            VIR_FREE(activeNames);
7603
            virStoragePoolFree(pool);
E
Eric Blake 已提交
7604
            return false;
7605 7606
        }

7607 7608 7609 7610 7611
        /* Sort the volume names */
        qsort(&activeNames[0], numVolumes, sizeof(*activeNames), namesorter);

        /* Set aside memory for volume information pointers */
        volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts));
7612 7613
    }

7614 7615 7616 7617 7618
    /* Collect the rest of the volume information for display */
    for (i = 0; i < numVolumes; i++) {
        /* Retrieve volume info */
        virStorageVolPtr vol = virStorageVolLookupByName(pool,
                                                         activeNames[i]);
7619

7620 7621 7622 7623
        /* Retrieve the volume path */
        if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) {
            /* Something went wrong retrieving a volume path, cope with it */
            volInfoTexts[i].path = vshStrdup(ctl, _("unknown"));
7624 7625
        }

7626 7627 7628 7629 7630 7631 7632 7633 7634
        /* If requested, retrieve volume type and sizing information */
        if (details) {
            if (virStorageVolGetInfo(vol, &volumeInfo) != 0) {
                /* Something went wrong retrieving volume info, cope with it */
                volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
                volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
                volInfoTexts[i].type = vshStrdup(ctl, _("unknown"));
            } else {
                /* Convert the returned volume info into output strings */
7635

7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690
                /* Volume type */
                if (volumeInfo.type == VIR_STORAGE_VOL_FILE)
                    volInfoTexts[i].type = vshStrdup(ctl, _("file"));
                else
                    volInfoTexts[i].type = vshStrdup(ctl, _("block"));

                /* Create the capacity output string */
                val = prettyCapacity(volumeInfo.capacity, &unit);
                ret = virAsprintf(&volInfoTexts[i].capacity,
                                  "%.2lf %s", val, unit);
                if (ret < 0) {
                    /* An error occurred creating the string, return */
                    goto asprintf_failure;
                }

                /* Create the allocation output string */
                val = prettyCapacity(volumeInfo.allocation, &unit);
                ret = virAsprintf(&volInfoTexts[i].allocation,
                                  "%.2lf %s", val, unit);
                if (ret < 0) {
                    /* An error occurred creating the string, return */
                    goto asprintf_failure;
                }
            }

            /* Remember the largest length for each output string.
             * This lets us displaying header and volume information rows
             * using a single, properly sized, printf style output string.
             */

            /* Keep the length of name string if longest so far */
            stringLength = strlen(activeNames[i]);
            if (stringLength > nameStrLength)
                nameStrLength = stringLength;

            /* Keep the length of path string if longest so far */
            stringLength = strlen(volInfoTexts[i].path);
            if (stringLength > pathStrLength)
                pathStrLength = stringLength;

            /* Keep the length of type string if longest so far */
            stringLength = strlen(volInfoTexts[i].type);
            if (stringLength > typeStrLength)
                typeStrLength = stringLength;

            /* Keep the length of capacity string if longest so far */
            stringLength = strlen(volInfoTexts[i].capacity);
            if (stringLength > capStrLength)
                capStrLength = stringLength;

            /* Keep the length of allocation string if longest so far */
            stringLength = strlen(volInfoTexts[i].allocation);
            if (stringLength > allocStrLength)
                allocStrLength = stringLength;
        }
7691

7692
        /* Cleanup memory allocation */
7693
        virStorageVolFree(vol);
7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711
    }

    /* If the --details option wasn't selected, we output the volume
     * info using the fixed string format from previous versions to
     * maintain backward compatibility.
     */

    /* Output basic info then return if --details option not selected */
    if (!details) {
        /* The old output format */
        vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path"));
        vshPrintExtra(ctl, "-----------------------------------------\n");
        for (i = 0; i < numVolumes; i++) {
            vshPrint(ctl, "%-20s %-40s\n", activeNames[i],
                     volInfoTexts[i].path);
        }

        /* Cleanup and return */
E
Eric Blake 已提交
7712
        functionReturn = true;
7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743
        goto cleanup;
    }

    /* We only get here if the --details option was selected. */

    /* Use the length of name header string if it's longest */
    stringLength = strlen(_("Name"));
    if (stringLength > nameStrLength)
        nameStrLength = stringLength;

    /* Use the length of path header string if it's longest */
    stringLength = strlen(_("Path"));
    if (stringLength > pathStrLength)
        pathStrLength = stringLength;

    /* Use the length of type header string if it's longest */
    stringLength = strlen(_("Type"));
    if (stringLength > typeStrLength)
        typeStrLength = stringLength;

    /* Use the length of capacity header string if it's longest */
    stringLength = strlen(_("Capacity"));
    if (stringLength > capStrLength)
        capStrLength = stringLength;

    /* Use the length of allocation header string if it's longest */
    stringLength = strlen(_("Allocation"));
    if (stringLength > allocStrLength)
        allocStrLength = stringLength;

    /* Display the string lengths for debugging */
C
Chris Lalancette 已提交
7744 7745 7746 7747 7748
    vshDebug(ctl, 5, "Longest name string = %zu chars\n", nameStrLength);
    vshDebug(ctl, 5, "Longest path string = %zu chars\n", pathStrLength);
    vshDebug(ctl, 5, "Longest type string = %zu chars\n", typeStrLength);
    vshDebug(ctl, 5, "Longest capacity string = %zu chars\n", capStrLength);
    vshDebug(ctl, 5, "Longest allocation string = %zu chars\n", allocStrLength);
7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782

    /* Create the output template */
    ret = virAsprintf(&outputStr,
                      "%%-%lus  %%-%lus  %%-%lus  %%%lus  %%%lus\n",
                      (unsigned long) nameStrLength,
                      (unsigned long) pathStrLength,
                      (unsigned long) typeStrLength,
                      (unsigned long) capStrLength,
                      (unsigned long) allocStrLength);
    if (ret < 0) {
        /* An error occurred creating the string, return */
        goto asprintf_failure;
    }

    /* Display the header */
    vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"),
             ("Capacity"), _("Allocation"));
    for (i = nameStrLength + pathStrLength + typeStrLength
                           + capStrLength + allocStrLength
                           + 8; i > 0; i--)
        vshPrintExtra(ctl, "-");
    vshPrintExtra(ctl, "\n");

    /* Display the volume info rows */
    for (i = 0; i < numVolumes; i++) {
        vshPrint(ctl, outputStr,
                 activeNames[i],
                 volInfoTexts[i].path,
                 volInfoTexts[i].type,
                 volInfoTexts[i].capacity,
                 volInfoTexts[i].allocation);
    }

    /* Cleanup and return */
E
Eric Blake 已提交
7783
    functionReturn = true;
7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797
    goto cleanup;

asprintf_failure:

    /* Display an appropriate error message then cleanup and return */
    switch (errno) {
    case ENOMEM:
        /* Couldn't allocate memory */
        vshError(ctl, "%s", _("Out of memory"));
        break;
    default:
        /* Some other error */
        vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
    }
E
Eric Blake 已提交
7798
    functionReturn = false;
7799 7800 7801 7802 7803 7804 7805 7806 7807 7808

cleanup:

    /* Safely free the memory allocated in this function */
    for (i = 0; i < numVolumes; i++) {
        /* Cleanup the memory for one volume info structure per loop */
        VIR_FREE(volInfoTexts[i].path);
        VIR_FREE(volInfoTexts[i].type);
        VIR_FREE(volInfoTexts[i].capacity);
        VIR_FREE(volInfoTexts[i].allocation);
7809
        VIR_FREE(activeNames[i]);
7810
    }
7811 7812 7813 7814

    /* Cleanup remaining memory */
    VIR_FREE(outputStr);
    VIR_FREE(volInfoTexts);
7815
    VIR_FREE(activeNames);
7816
    virStoragePoolFree(pool);
7817 7818 7819

    /* Return the desired value */
    return functionReturn;
7820 7821 7822 7823 7824 7825
}


/*
 * "vol-name" command
 */
7826
static const vshCmdInfo info_vol_name[] = {
7827
    {"help", N_("returns the volume name for a given volume key or path")},
7828
    {"desc", ""},
7829 7830 7831
    {NULL, NULL}
};

7832
static const vshCmdOptDef opts_vol_name[] = {
7833
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")},
7834 7835 7836
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7837
static bool
7838
cmdVolName(vshControl *ctl, const vshCmd *cmd)
7839 7840 7841
{
    virStorageVolPtr vol;

7842
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7843
        return false;
7844 7845 7846

    if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
                                   VSH_BYUUID)))
E
Eric Blake 已提交
7847
        return false;
7848 7849 7850

    vshPrint(ctl, "%s\n", virStorageVolGetName(vol));
    virStorageVolFree(vol);
E
Eric Blake 已提交
7851
    return true;
7852 7853 7854
}


J
Justin Clift 已提交
7855 7856 7857 7858 7859 7860 7861 7862 7863 7864
/*
 * "vol-pool" command
 */
static const vshCmdInfo info_vol_pool[] = {
    {"help", N_("returns the storage pool for a given volume key or path")},
    {"desc", ""},
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_pool[] = {
7865
    {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")},
J
Justin Clift 已提交
7866 7867 7868 7869
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7870
static bool
J
Justin Clift 已提交
7871 7872 7873 7874
cmdVolPool(vshControl *ctl, const vshCmd *cmd)
{
    virStoragePoolPtr pool;
    virStorageVolPtr vol;
7875
    char uuid[VIR_UUID_STRING_BUFLEN];
J
Justin Clift 已提交
7876 7877

    /* Check the connection to libvirtd daemon is still working */
7878
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7879
        return false;
J
Justin Clift 已提交
7880 7881 7882 7883

    /* Use the supplied string to locate the volume */
    if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
                                   VSH_BYUUID))) {
E
Eric Blake 已提交
7884
        return false;
J
Justin Clift 已提交
7885 7886 7887 7888 7889 7890 7891
    }

    /* Look up the parent storage pool for the volume */
    pool = virStoragePoolLookupByVolume(vol);
    if (pool == NULL) {
        vshError(ctl, "%s", _("failed to get parent pool"));
        virStorageVolFree(vol);
E
Eric Blake 已提交
7892
        return false;
J
Justin Clift 已提交
7893 7894
    }

7895 7896 7897 7898 7899 7900 7901 7902 7903
    /* Return the requested details of the parent storage pool */
    if (vshCommandOptBool(cmd, "uuid")) {
        /* Retrieve and return pool UUID string */
        if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0)
            vshPrint(ctl, "%s\n", uuid);
    } else {
        /* Return the storage pool name */
        vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
    }
J
Justin Clift 已提交
7904 7905 7906 7907

    /* Cleanup */
    virStorageVolFree(vol);
    virStoragePoolFree(pool);
E
Eric Blake 已提交
7908
    return true;
J
Justin Clift 已提交
7909 7910
}

7911 7912 7913 7914

/*
 * "vol-key" command
 */
7915
static const vshCmdInfo info_vol_key[] = {
7916
    {"help", N_("returns the volume key for a given volume name or path")},
7917
    {"desc", ""},
7918 7919 7920
    {NULL, NULL}
};

7921
static const vshCmdOptDef opts_vol_key[] = {
7922
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")},
E
Eric Blake 已提交
7923
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7924 7925 7926
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7927
static bool
7928
cmdVolKey(vshControl *ctl, const vshCmd *cmd)
7929 7930 7931
{
    virStorageVolPtr vol;

7932
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7933
        return false;
7934

7935
    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
E
Eric Blake 已提交
7936
        return false;
7937 7938 7939

    vshPrint(ctl, "%s\n", virStorageVolGetKey(vol));
    virStorageVolFree(vol);
E
Eric Blake 已提交
7940
    return true;
7941 7942 7943 7944 7945 7946 7947
}



/*
 * "vol-path" command
 */
7948
static const vshCmdInfo info_vol_path[] = {
7949
    {"help", N_("returns the volume path for a given volume name or key")},
7950
    {"desc", ""},
7951 7952 7953
    {NULL, NULL}
};

7954
static const vshCmdOptDef opts_vol_path[] = {
7955
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")},
E
Eric Blake 已提交
7956
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7957 7958 7959
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
7960
static bool
7961
cmdVolPath(vshControl *ctl, const vshCmd *cmd)
7962 7963
{
    virStorageVolPtr vol;
7964
    const char *name = NULL;
7965

7966
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
7967
        return false;
7968 7969

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
E
Eric Blake 已提交
7970
        return false;
7971
    }
7972 7973 7974

    vshPrint(ctl, "%s\n", virStorageVolGetPath(vol));
    virStorageVolFree(vol);
E
Eric Blake 已提交
7975
    return true;
7976 7977 7978
}


7979 7980 7981 7982
/*
 * "secret-define" command
 */
static const vshCmdInfo info_secret_define[] = {
7983 7984
    {"help", N_("define or modify a secret from an XML file")},
    {"desc", N_("Define or modify a secret.")},
7985 7986
    {NULL, NULL}
};
7987

7988
static const vshCmdOptDef opts_secret_define[] = {
7989
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")},
7990 7991
    {NULL, 0, 0, NULL}
};
7992

E
Eric Blake 已提交
7993
static bool
7994 7995
cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
{
7996
    const char *from = NULL;
7997
    char *buffer;
7998
    virSecretPtr res;
7999
    char uuid[VIR_UUID_STRING_BUFLEN];
8000

8001
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8002
        return false;
8003

8004
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
8005
        return false;
8006 8007

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
8008
        return false;
8009 8010

    res = virSecretDefineXML(ctl->conn, buffer, 0);
8011
    VIR_FREE(buffer);
8012 8013

    if (res == NULL) {
8014
        vshError(ctl, _("Failed to set attributes from %s"), from);
E
Eric Blake 已提交
8015
        return false;
8016
    }
8017
    if (virSecretGetUUIDString(res, &(uuid[0])) < 0) {
8018
        vshError(ctl, "%s", _("Failed to get UUID of created secret"));
8019
        virSecretFree(res);
E
Eric Blake 已提交
8020
        return false;
8021 8022 8023
    }
    vshPrint(ctl, _("Secret %s created\n"), uuid);
    virSecretFree(res);
E
Eric Blake 已提交
8024
    return true;
8025 8026 8027 8028 8029 8030
}

/*
 * "secret-dumpxml" command
 */
static const vshCmdInfo info_secret_dumpxml[] = {
8031 8032
    {"help", N_("secret attributes in XML")},
    {"desc", N_("Output attributes of a secret as an XML dump to stdout.")},
8033 8034 8035 8036
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_dumpxml[] = {
8037
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
8038 8039 8040
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8041
static bool
8042 8043 8044
cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
E
Eric Blake 已提交
8045
    bool ret = false;
8046 8047
    char *xml;

8048
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8049
        return false;
8050 8051 8052

    secret = vshCommandOptSecret(ctl, cmd, NULL);
    if (secret == NULL)
E
Eric Blake 已提交
8053
        return false;
8054 8055 8056 8057

    xml = virSecretGetXMLDesc(secret, 0);
    if (xml == NULL)
        goto cleanup;
8058
    vshPrint(ctl, "%s", xml);
8059
    VIR_FREE(xml);
E
Eric Blake 已提交
8060
    ret = true;
8061 8062 8063 8064 8065 8066 8067 8068 8069 8070

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-set-value" command
 */
static const vshCmdInfo info_secret_set_value[] = {
8071 8072
    {"help", N_("set a secret value")},
    {"desc", N_("Set a secret value.")},
8073 8074 8075 8076
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_set_value[] = {
8077 8078
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
    {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")},
8079 8080 8081
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8082
static bool
8083 8084 8085 8086
cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
    size_t value_size;
8087
    const char *base64 = NULL;
8088
    char *value;
E
Eric Blake 已提交
8089 8090
    int res;
    bool ret = false;
8091

8092
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8093
        return false;
8094 8095 8096

    secret = vshCommandOptSecret(ctl, cmd, NULL);
    if (secret == NULL)
E
Eric Blake 已提交
8097
        return false;
8098

8099
    if (vshCommandOptString(cmd, "base64", &base64) <= 0)
8100 8101 8102
        goto cleanup;

    if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
J
Jim Meyering 已提交
8103
        vshError(ctl, "%s", _("Invalid base64 data"));
8104 8105 8106
        goto cleanup;
    }
    if (value == NULL) {
8107
        vshError(ctl, "%s", _("Failed to allocate memory"));
E
Eric Blake 已提交
8108
        return false;
8109 8110 8111 8112
    }

    res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
    memset(value, 0, value_size);
8113
    VIR_FREE(value);
8114 8115

    if (res != 0) {
8116
        vshError(ctl, "%s", _("Failed to set secret value"));
8117 8118 8119
        goto cleanup;
    }
    vshPrint(ctl, "%s", _("Secret value set\n"));
E
Eric Blake 已提交
8120
    ret = true;
8121 8122 8123 8124 8125 8126 8127 8128 8129 8130

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-get-value" command
 */
static const vshCmdInfo info_secret_get_value[] = {
8131 8132
    {"help", N_("Output a secret value")},
    {"desc", N_("Output a secret value to stdout.")},
8133 8134 8135 8136
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_get_value[] = {
8137
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
8138 8139 8140
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8141
static bool
8142 8143 8144 8145 8146 8147
cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
    char *base64;
    unsigned char *value;
    size_t value_size;
E
Eric Blake 已提交
8148
    bool ret = false;
8149

8150
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8151
        return false;
8152 8153 8154

    secret = vshCommandOptSecret(ctl, cmd, NULL);
    if (secret == NULL)
E
Eric Blake 已提交
8155
        return false;
8156 8157 8158 8159 8160 8161 8162

    value = virSecretGetValue(secret, &value_size, 0);
    if (value == NULL)
        goto cleanup;

    base64_encode_alloc((char *)value, value_size, &base64);
    memset(value, 0, value_size);
8163
    VIR_FREE(value);
8164 8165

    if (base64 == NULL) {
8166
        vshError(ctl, "%s", _("Failed to allocate memory"));
8167 8168
        goto cleanup;
    }
8169
    vshPrint(ctl, "%s", base64);
8170
    memset(base64, 0, strlen(base64));
8171
    VIR_FREE(base64);
E
Eric Blake 已提交
8172
    ret = true;
8173 8174 8175 8176 8177 8178 8179 8180 8181 8182

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-undefine" command
 */
static const vshCmdInfo info_secret_undefine[] = {
8183 8184
    {"help", N_("undefine a secret")},
    {"desc", N_("Undefine a secret.")},
8185 8186 8187 8188
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_undefine[] = {
8189
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
8190 8191 8192
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8193
static bool
8194 8195 8196
cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
E
Eric Blake 已提交
8197
    bool ret = false;
8198
    const char *uuid;
8199

8200
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8201
        return false;
8202 8203 8204

    secret = vshCommandOptSecret(ctl, cmd, &uuid);
    if (secret == NULL)
E
Eric Blake 已提交
8205
        return false;
8206 8207

    if (virSecretUndefine(secret) < 0) {
8208
        vshError(ctl, _("Failed to delete secret %s"), uuid);
8209 8210 8211
        goto cleanup;
    }
    vshPrint(ctl, _("Secret %s deleted\n"), uuid);
E
Eric Blake 已提交
8212
    ret = true;
8213 8214 8215 8216 8217 8218 8219 8220 8221 8222

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-list" command
 */
static const vshCmdInfo info_secret_list[] = {
8223 8224
    {"help", N_("list secrets")},
    {"desc", N_("Returns a list of secrets")},
8225 8226 8227
    {NULL, NULL}
};

E
Eric Blake 已提交
8228
static bool
8229 8230 8231 8232 8233
cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    int maxuuids = 0, i;
    char **uuids = NULL;

8234
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8235
        return false;
8236 8237 8238

    maxuuids = virConnectNumOfSecrets(ctl->conn);
    if (maxuuids < 0) {
8239
        vshError(ctl, "%s", _("Failed to list secrets"));
E
Eric Blake 已提交
8240
        return false;
8241 8242 8243 8244 8245
    }
    uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);

    maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
    if (maxuuids < 0) {
8246
        vshError(ctl, "%s", _("Failed to list secrets"));
8247
        VIR_FREE(uuids);
E
Eric Blake 已提交
8248
        return false;
8249 8250 8251 8252
    }

    qsort(uuids, maxuuids, sizeof(char *), namesorter);

8253 8254
    vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage"));
    vshPrintExtra(ctl, "-----------------------------------------------------------\n");
8255 8256

    for (i = 0; i < maxuuids; i++) {
8257 8258 8259 8260
        virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]);
        const char *usageType = NULL;

        if (!sec) {
8261
            VIR_FREE(uuids[i]);
8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279
            continue;
        }

        switch (virSecretGetUsageType(sec)) {
        case VIR_SECRET_USAGE_TYPE_VOLUME:
            usageType = _("Volume");
            break;
        }

        if (usageType) {
            vshPrint(ctl, "%-36s %s %s\n",
                     uuids[i], usageType,
                     virSecretGetUsageID(sec));
        } else {
            vshPrint(ctl, "%-36s %s\n",
                     uuids[i], _("Unused"));
        }
        virSecretFree(sec);
8280
        VIR_FREE(uuids[i]);
8281
    }
8282
    VIR_FREE(uuids);
E
Eric Blake 已提交
8283
    return true;
8284
}
8285 8286 8287 8288 8289


/*
 * "version" command
 */
8290
static const vshCmdInfo info_version[] = {
8291 8292
    {"help", N_("show version")},
    {"desc", N_("Display the system version information.")},
8293 8294 8295 8296
    {NULL, NULL}
};


E
Eric Blake 已提交
8297
static bool
8298
cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309
{
    unsigned long hvVersion;
    const char *hvType;
    unsigned long libVersion;
    unsigned long includeVersion;
    unsigned long apiVersion;
    int ret;
    unsigned int major;
    unsigned int minor;
    unsigned int rel;

8310
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8311
        return false;
8312 8313 8314

    hvType = virConnectGetType(ctl->conn);
    if (hvType == NULL) {
8315
        vshError(ctl, "%s", _("failed to get hypervisor type"));
E
Eric Blake 已提交
8316
        return false;
8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328
    }

    includeVersion = LIBVIR_VERSION_NUMBER;
    major = includeVersion / 1000000;
    includeVersion %= 1000000;
    minor = includeVersion / 1000;
    rel = includeVersion % 1000;
    vshPrint(ctl, _("Compiled against library: libvir %d.%d.%d\n"),
             major, minor, rel);

    ret = virGetVersion(&libVersion, hvType, &apiVersion);
    if (ret < 0) {
8329
        vshError(ctl, "%s", _("failed to get the library version"));
E
Eric Blake 已提交
8330
        return false;
8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347
    }
    major = libVersion / 1000000;
    libVersion %= 1000000;
    minor = libVersion / 1000;
    rel = libVersion % 1000;
    vshPrint(ctl, _("Using library: libvir %d.%d.%d\n"),
             major, minor, rel);

    major = apiVersion / 1000000;
    apiVersion %= 1000000;
    minor = apiVersion / 1000;
    rel = apiVersion % 1000;
    vshPrint(ctl, _("Using API: %s %d.%d.%d\n"), hvType,
             major, minor, rel);

    ret = virConnectGetVersion(ctl->conn, &hvVersion);
    if (ret < 0) {
8348
        vshError(ctl, "%s", _("failed to get the hypervisor version"));
E
Eric Blake 已提交
8349
        return false;
8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362
    }
    if (hvVersion == 0) {
        vshPrint(ctl,
                 _("Cannot extract running %s hypervisor version\n"), hvType);
    } else {
        major = hvVersion / 1000000;
        hvVersion %= 1000000;
        minor = hvVersion / 1000;
        rel = hvVersion % 1000;

        vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"),
                 hvType, major, minor, rel);
    }
E
Eric Blake 已提交
8363
    return true;
8364 8365
}

8366 8367 8368 8369
/*
 * "nodedev-list" command
 */
static const vshCmdInfo info_node_list_devices[] = {
8370
    {"help", N_("enumerate devices on this host")},
8371
    {"desc", ""},
8372 8373 8374 8375
    {NULL, NULL}
};

static const vshCmdOptDef opts_node_list_devices[] = {
8376 8377
    {"tree", VSH_OT_BOOL, 0, N_("list devices in a tree")},
    {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability name")},
8378 8379 8380
    {NULL, 0, 0, NULL}
};

8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402
#define MAX_DEPTH 100
#define INDENT_SIZE 4
#define INDENT_BUFLEN ((MAX_DEPTH * INDENT_SIZE) + 1)

static void
cmdNodeListDevicesPrint(vshControl *ctl,
                        char **devices,
                        char **parents,
                        int num_devices,
                        int devid,
                        int lastdev,
                        unsigned int depth,
                        unsigned int indentIdx,
                        char *indentBuf)
{
    int i;
    int nextlastdev = -1;

    /* Prepare indent for this device, but not if at root */
    if (depth && depth < MAX_DEPTH) {
        indentBuf[indentIdx] = '+';
        indentBuf[indentIdx+1] = '-';
8403 8404
        indentBuf[indentIdx+2] = ' ';
        indentBuf[indentIdx+3] = '\0';
8405 8406 8407
    }

    /* Print this device */
8408
    vshPrint(ctl, "%s", indentBuf);
8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431
    vshPrint(ctl, "%s\n", devices[devid]);


    /* Update indent to show '|' or ' ' for child devices */
    if (depth && depth < MAX_DEPTH) {
        if (devid == lastdev)
            indentBuf[indentIdx] = ' ';
        else
            indentBuf[indentIdx] = '|';
        indentBuf[indentIdx+1] = ' ';
        indentIdx+=2;
    }

    /* Determine the index of the last child device */
    for (i = 0 ; i < num_devices ; i++) {
        if (parents[i] &&
            STREQ(parents[i], devices[devid])) {
            nextlastdev = i;
        }
    }

    /* If there is a child device, then print another blank line */
    if (nextlastdev != -1) {
8432
        vshPrint(ctl, "%s", indentBuf);
8433
        vshPrint(ctl, " |\n");
8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455
    }

    /* Finally print all children */
    if (depth < MAX_DEPTH)
        indentBuf[indentIdx] = ' ';
    for (i = 0 ; i < num_devices ; i++) {
        if (depth < MAX_DEPTH) {
            indentBuf[indentIdx] = ' ';
            indentBuf[indentIdx+1] = ' ';
        }
        if (parents[i] &&
            STREQ(parents[i], devices[devid]))
            cmdNodeListDevicesPrint(ctl, devices, parents,
                                    num_devices, i, nextlastdev,
                                    depth + 1, indentIdx + 2, indentBuf);
        if (depth < MAX_DEPTH)
            indentBuf[indentIdx] = '\0';
    }

    /* If there was no child device, and we're the last in
     * a list of devices, then print another blank line */
    if (nextlastdev == -1 && devid == lastdev) {
8456
        vshPrint(ctl, "%s", indentBuf);
8457 8458 8459 8460
        vshPrint(ctl, "\n");
    }
}

E
Eric Blake 已提交
8461
static bool
8462 8463
cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
8464
    const char *cap = NULL;
8465
    char **devices;
8466
    int num_devices, i;
8467
    int tree = vshCommandOptBool(cmd, "tree");
8468

8469
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8470
        return false;
8471

8472
    if (vshCommandOptString(cmd, "cap", &cap) <= 0)
8473 8474 8475 8476
        cap = NULL;

    num_devices = virNodeNumOfDevices(ctl->conn, cap, 0);
    if (num_devices < 0) {
8477
        vshError(ctl, "%s", _("Failed to count node devices"));
E
Eric Blake 已提交
8478
        return false;
8479
    } else if (num_devices == 0) {
E
Eric Blake 已提交
8480
        return true;
8481 8482 8483 8484 8485 8486
    }

    devices = vshMalloc(ctl, sizeof(char *) * num_devices);
    num_devices =
        virNodeListDevices(ctl->conn, cap, devices, num_devices, 0);
    if (num_devices < 0) {
8487
        vshError(ctl, "%s", _("Failed to list node devices"));
8488
        VIR_FREE(devices);
E
Eric Blake 已提交
8489
        return false;
8490
    }
8491
    qsort(&devices[0], num_devices, sizeof(char*), namesorter);
8492 8493 8494 8495 8496 8497 8498
    if (tree) {
        char indentBuf[INDENT_BUFLEN];
        char **parents = vshMalloc(ctl, sizeof(char *) * num_devices);
        for (i = 0; i < num_devices; i++) {
            virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]);
            if (dev && STRNEQ(devices[i], "computer")) {
                const char *parent = virNodeDeviceGetParent(dev);
E
Eric Blake 已提交
8499
                parents[i] = parent ? vshStrdup(ctl, parent) : NULL;
8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518
            } else {
                parents[i] = NULL;
            }
            virNodeDeviceFree(dev);
        }
        for (i = 0 ; i < num_devices ; i++) {
            memset(indentBuf, '\0', sizeof indentBuf);
            if (parents[i] == NULL)
                cmdNodeListDevicesPrint(ctl,
                                        devices,
                                        parents,
                                        num_devices,
                                        i,
                                        i,
                                        0,
                                        0,
                                        indentBuf);
        }
        for (i = 0 ; i < num_devices ; i++) {
8519 8520
            VIR_FREE(devices[i]);
            VIR_FREE(parents[i]);
8521
        }
8522
        VIR_FREE(parents);
8523 8524 8525
    } else {
        for (i = 0; i < num_devices; i++) {
            vshPrint(ctl, "%s\n", devices[i]);
8526
            VIR_FREE(devices[i]);
8527
        }
8528
    }
8529
    VIR_FREE(devices);
E
Eric Blake 已提交
8530
    return true;
8531 8532 8533 8534 8535 8536
}

/*
 * "nodedev-dumpxml" command
 */
static const vshCmdInfo info_node_device_dumpxml[] = {
8537 8538
    {"help", N_("node device details in XML")},
    {"desc", N_("Output the node device details as an XML dump to stdout.")},
8539 8540 8541 8542 8543
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_dumpxml[] = {
8544
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
8545 8546 8547
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8548
static bool
8549 8550
cmdNodeDeviceDumpXML (vshControl *ctl, const vshCmd *cmd)
{
8551
    const char *name = NULL;
8552
    virNodeDevicePtr device;
L
Laine Stump 已提交
8553
    char *xml;
8554

8555
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8556
        return false;
8557
    if (vshCommandOptString(cmd, "device", &name) <= 0)
E
Eric Blake 已提交
8558
        return false;
8559
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
8560
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
E
Eric Blake 已提交
8561
        return false;
8562 8563
    }

L
Laine Stump 已提交
8564 8565 8566
    xml = virNodeDeviceGetXMLDesc(device, 0);
    if (!xml) {
        virNodeDeviceFree(device);
E
Eric Blake 已提交
8567
        return false;
L
Laine Stump 已提交
8568 8569 8570
    }

    vshPrint(ctl, "%s\n", xml);
8571
    VIR_FREE(xml);
8572
    virNodeDeviceFree(device);
E
Eric Blake 已提交
8573
    return true;
8574 8575
}

8576 8577 8578 8579
/*
 * "nodedev-dettach" command
 */
static const vshCmdInfo info_node_device_dettach[] = {
8580 8581
    {"help", N_("dettach node device from its device driver")},
    {"desc", N_("Dettach node device from its device driver before assigning to a domain.")},
8582 8583 8584 8585 8586
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_dettach[] = {
8587
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
8588 8589 8590
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8591
static bool
8592 8593
cmdNodeDeviceDettach (vshControl *ctl, const vshCmd *cmd)
{
8594
    const char *name = NULL;
8595
    virNodeDevicePtr device;
E
Eric Blake 已提交
8596
    bool ret = true;
8597

8598
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8599
        return false;
8600
    if (vshCommandOptString(cmd, "device", &name) <= 0)
E
Eric Blake 已提交
8601
        return false;
8602
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
8603
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
E
Eric Blake 已提交
8604
        return false;
8605 8606 8607 8608 8609
    }

    if (virNodeDeviceDettach(device) == 0) {
        vshPrint(ctl, _("Device %s dettached\n"), name);
    } else {
8610
        vshError(ctl, _("Failed to dettach device %s"), name);
E
Eric Blake 已提交
8611
        ret = false;
8612 8613 8614 8615 8616 8617 8618 8619 8620
    }
    virNodeDeviceFree(device);
    return ret;
}

/*
 * "nodedev-reattach" command
 */
static const vshCmdInfo info_node_device_reattach[] = {
8621 8622
    {"help", N_("reattach node device to its device driver")},
    {"desc", N_("Reattach node device to its device driver once released by the domain.")},
8623 8624 8625 8626 8627
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_reattach[] = {
8628
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
8629 8630 8631
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8632
static bool
8633 8634
cmdNodeDeviceReAttach (vshControl *ctl, const vshCmd *cmd)
{
8635
    const char *name = NULL;
8636
    virNodeDevicePtr device;
E
Eric Blake 已提交
8637
    bool ret = true;
8638

8639
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8640
        return false;
8641
    if (vshCommandOptString(cmd, "device", &name) <= 0)
E
Eric Blake 已提交
8642
        return false;
8643
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
8644
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
E
Eric Blake 已提交
8645
        return false;
8646 8647 8648 8649 8650
    }

    if (virNodeDeviceReAttach(device) == 0) {
        vshPrint(ctl, _("Device %s re-attached\n"), name);
    } else {
8651
        vshError(ctl, _("Failed to re-attach device %s"), name);
E
Eric Blake 已提交
8652
        ret = false;
8653 8654 8655 8656 8657 8658 8659 8660 8661
    }
    virNodeDeviceFree(device);
    return ret;
}

/*
 * "nodedev-reset" command
 */
static const vshCmdInfo info_node_device_reset[] = {
8662 8663
    {"help", N_("reset node device")},
    {"desc", N_("Reset node device before or after assigning to a domain.")},
8664 8665 8666 8667 8668
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_reset[] = {
8669
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
8670 8671 8672
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8673
static bool
8674 8675
cmdNodeDeviceReset (vshControl *ctl, const vshCmd *cmd)
{
8676
    const char *name = NULL;
8677
    virNodeDevicePtr device;
E
Eric Blake 已提交
8678
    bool ret = true;
8679

8680
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8681
        return false;
8682
    if (vshCommandOptString(cmd, "device", &name) <= 0)
E
Eric Blake 已提交
8683
        return false;
8684
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
8685
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
E
Eric Blake 已提交
8686
        return false;
8687 8688 8689 8690 8691
    }

    if (virNodeDeviceReset(device) == 0) {
        vshPrint(ctl, _("Device %s reset\n"), name);
    } else {
8692
        vshError(ctl, _("Failed to reset device %s"), name);
E
Eric Blake 已提交
8693
        ret = false;
8694 8695 8696 8697 8698
    }
    virNodeDeviceFree(device);
    return ret;
}

8699
/*
E
Eric Blake 已提交
8700
 * "hostname" command
8701
 */
8702
static const vshCmdInfo info_hostname[] = {
8703
    {"help", N_("print the hypervisor hostname")},
8704
    {"desc", ""},
8705 8706 8707
    {NULL, NULL}
};

E
Eric Blake 已提交
8708
static bool
8709
cmdHostname (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
8710 8711 8712
{
    char *hostname;

8713
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8714
        return false;
8715 8716 8717

    hostname = virConnectGetHostname (ctl->conn);
    if (hostname == NULL) {
8718
        vshError(ctl, "%s", _("failed to get hostname"));
E
Eric Blake 已提交
8719
        return false;
8720 8721 8722
    }

    vshPrint (ctl, "%s\n", hostname);
8723
    VIR_FREE(hostname);
8724

E
Eric Blake 已提交
8725
    return true;
8726 8727 8728 8729 8730
}

/*
 * "uri" command
 */
8731
static const vshCmdInfo info_uri[] = {
8732
    {"help", N_("print the hypervisor canonical URI")},
8733
    {"desc", ""},
8734 8735 8736
    {NULL, NULL}
};

E
Eric Blake 已提交
8737
static bool
8738
cmdURI (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
8739 8740 8741
{
    char *uri;

8742
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8743
        return false;
8744 8745 8746

    uri = virConnectGetURI (ctl->conn);
    if (uri == NULL) {
8747
        vshError(ctl, "%s", _("failed to get URI"));
E
Eric Blake 已提交
8748
        return false;
8749 8750 8751
    }

    vshPrint (ctl, "%s\n", uri);
8752
    VIR_FREE(uri);
8753

E
Eric Blake 已提交
8754
    return true;
8755 8756
}

E
Eric Blake 已提交
8757 8758 8759 8760 8761 8762 8763 8764 8765 8766
/*
 * "sysinfo" command
 */
static const vshCmdInfo info_sysinfo[] = {
    {"help", N_("print the hypervisor sysinfo")},
    {"desc",
     N_("output an XML string for the hypervisor sysinfo, if available")},
    {NULL, NULL}
};

E
Eric Blake 已提交
8767
static bool
E
Eric Blake 已提交
8768 8769 8770 8771 8772
cmdSysinfo (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    char *sysinfo;

    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8773
        return false;
E
Eric Blake 已提交
8774 8775 8776 8777

    sysinfo = virConnectGetSysinfo (ctl->conn, 0);
    if (sysinfo == NULL) {
        vshError(ctl, "%s", _("failed to get sysinfo"));
E
Eric Blake 已提交
8778
        return false;
E
Eric Blake 已提交
8779 8780 8781 8782 8783
    }

    vshPrint (ctl, "%s", sysinfo);
    VIR_FREE(sysinfo);

E
Eric Blake 已提交
8784
    return true;
E
Eric Blake 已提交
8785 8786
}

8787 8788 8789
/*
 * "vncdisplay" command
 */
8790
static const vshCmdInfo info_vncdisplay[] = {
8791 8792
    {"help", N_("vnc display")},
    {"desc", N_("Output the IP address and port number for the VNC display.")},
8793 8794 8795
    {NULL, NULL}
};

8796
static const vshCmdOptDef opts_vncdisplay[] = {
8797
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8798 8799 8800
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8801
static bool
8802
cmdVNCDisplay(vshControl *ctl, const vshCmd *cmd)
8803 8804 8805 8806 8807
{
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj = NULL;
    xmlXPathContextPtr ctxt = NULL;
    virDomainPtr dom;
E
Eric Blake 已提交
8808
    bool ret = false;
8809 8810 8811
    int port = 0;
    char *doc;

8812
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8813
        return false;
8814

J
Jim Meyering 已提交
8815
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
8816
        return false;
8817 8818 8819 8820 8821 8822 8823 8824

    doc = virDomainGetXMLDesc(dom, 0);
    if (!doc)
        goto cleanup;

    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOWARNING);
8825
    VIR_FREE(doc);
8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843
    if (!xml)
        goto cleanup;
    ctxt = xmlXPathNewContext(xml);
    if (!ctxt)
        goto cleanup;

    obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@port)", ctxt);
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
        goto cleanup;
    }
    if (virStrToLong_i((const char *)obj->stringval, NULL, 10, &port) || port < 0)
        goto cleanup;
    xmlXPathFreeObject(obj);

    obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@listen)", ctxt);
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
        (obj->stringval == NULL) || (obj->stringval[0] == 0) ||
8844
        STREQ((const char*)obj->stringval, "0.0.0.0")) {
8845 8846 8847 8848 8849 8850
        vshPrint(ctl, ":%d\n", port-5900);
    } else {
        vshPrint(ctl, "%s:%d\n", (const char *)obj->stringval, port-5900);
    }
    xmlXPathFreeObject(obj);
    obj = NULL;
E
Eric Blake 已提交
8851
    ret = true;
8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864

 cleanup:
    xmlXPathFreeObject(obj);
    xmlXPathFreeContext(ctxt);
    if (xml)
        xmlFreeDoc(xml);
    virDomainFree(dom);
    return ret;
}

/*
 * "ttyconsole" command
 */
8865
static const vshCmdInfo info_ttyconsole[] = {
8866 8867
    {"help", N_("tty console")},
    {"desc", N_("Output the device for the TTY console.")},
8868 8869 8870
    {NULL, NULL}
};

8871
static const vshCmdOptDef opts_ttyconsole[] = {
8872
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8873 8874 8875
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8876
static bool
8877
cmdTTYConsole(vshControl *ctl, const vshCmd *cmd)
8878 8879 8880 8881 8882
{
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj = NULL;
    xmlXPathContextPtr ctxt = NULL;
    virDomainPtr dom;
E
Eric Blake 已提交
8883
    bool ret = false;
8884 8885
    char *doc;

8886
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8887
        return false;
8888

J
Jim Meyering 已提交
8889
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
8890
        return false;
8891 8892 8893 8894 8895 8896 8897 8898

    doc = virDomainGetXMLDesc(dom, 0);
    if (!doc)
        goto cleanup;

    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOWARNING);
8899
    VIR_FREE(doc);
8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911
    if (!xml)
        goto cleanup;
    ctxt = xmlXPathNewContext(xml);
    if (!ctxt)
        goto cleanup;

    obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt);
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
        goto cleanup;
    }
    vshPrint(ctl, "%s\n", (const char *)obj->stringval);
E
Eric Blake 已提交
8912
    ret = true;
8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924

 cleanup:
    xmlXPathFreeObject(obj);
    xmlXPathFreeContext(ctxt);
    if (xml)
        xmlFreeDoc(xml);
    virDomainFree(dom);
    return ret;
}

/*
 * "attach-device" command
8925
 */
8926
static const vshCmdInfo info_attach_device[] = {
8927 8928
    {"help", N_("attach device from an XML file")},
    {"desc", N_("Attach device from an XML <file>.")},
8929 8930 8931
    {NULL, NULL}
};

8932
static const vshCmdOptDef opts_attach_device[] = {
8933 8934 8935
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"file",   VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist device attachment")},
8936 8937 8938
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
8939
static bool
8940
cmdAttachDevice(vshControl *ctl, const vshCmd *cmd)
8941 8942
{
    virDomainPtr dom;
8943
    const char *from = NULL;
8944
    char *buffer;
W
Wen Congyang 已提交
8945
    int ret;
J
Jim Fehlig 已提交
8946
    unsigned int flags;
8947

8948
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
8949
        return false;
8950

J
Jim Meyering 已提交
8951
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
8952
        return false;
8953

8954
    if (vshCommandOptString(cmd, "file", &from) <= 0) {
8955
        virDomainFree(dom);
E
Eric Blake 已提交
8956
        return false;
8957 8958
    }

8959
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
8960
        virshReportError(ctl);
8961
        virDomainFree(dom);
E
Eric Blake 已提交
8962
        return false;
8963
    }
8964

J
Jim Fehlig 已提交
8965 8966 8967 8968 8969 8970 8971 8972
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
           flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
        ret = virDomainAttachDeviceFlags(dom, buffer, flags);
    } else {
        ret = virDomainAttachDevice(dom, buffer);
    }
8973
    VIR_FREE(buffer);
8974 8975

    if (ret < 0) {
8976
        vshError(ctl, _("Failed to attach device from %s"), from);
8977
        virDomainFree(dom);
E
Eric Blake 已提交
8978
        return false;
8979
    } else {
J
Jim Meyering 已提交
8980
        vshPrint(ctl, "%s", _("Device attached successfully\n"));
8981 8982 8983
    }

    virDomainFree(dom);
E
Eric Blake 已提交
8984
    return true;
8985 8986 8987 8988 8989 8990
}


/*
 * "detach-device" command
 */
8991
static const vshCmdInfo info_detach_device[] = {
8992 8993
    {"help", N_("detach device from an XML file")},
    {"desc", N_("Detach device from an XML <file>")},
8994 8995 8996
    {NULL, NULL}
};

8997
static const vshCmdOptDef opts_detach_device[] = {
8998 8999 9000
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"file",   VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist device detachment")},
9001 9002 9003
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9004
static bool
9005
cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
9006 9007
{
    virDomainPtr dom;
9008
    const char *from = NULL;
9009
    char *buffer;
W
Wen Congyang 已提交
9010
    int ret;
J
Jim Fehlig 已提交
9011
    unsigned int flags;
9012

9013
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
9014
        return false;
9015

J
Jim Meyering 已提交
9016
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
9017
        return false;
9018

9019
    if (vshCommandOptString(cmd, "file", &from) <= 0) {
9020
        virDomainFree(dom);
E
Eric Blake 已提交
9021
        return false;
9022 9023
    }

9024
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
9025
        virshReportError(ctl);
9026
        virDomainFree(dom);
E
Eric Blake 已提交
9027
        return false;
9028
    }
9029

J
Jim Fehlig 已提交
9030 9031 9032 9033 9034 9035 9036 9037
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
           flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
        ret = virDomainDetachDeviceFlags(dom, buffer, flags);
    } else {
        ret = virDomainDetachDevice(dom, buffer);
    }
9038
    VIR_FREE(buffer);
9039 9040

    if (ret < 0) {
9041
        vshError(ctl, _("Failed to detach device from %s"), from);
9042
        virDomainFree(dom);
E
Eric Blake 已提交
9043
        return false;
9044
    } else {
J
Jim Meyering 已提交
9045
        vshPrint(ctl, "%s", _("Device detached successfully\n"));
9046 9047 9048
    }

    virDomainFree(dom);
E
Eric Blake 已提交
9049
    return true;
9050 9051
}

9052

9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065
/*
 * "update-device" command
 */
static const vshCmdInfo info_update_device[] = {
    {"help", N_("update device from an XML file")},
    {"desc", N_("Update device from an XML <file>.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_update_device[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"file",   VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist device update")},
9066
    {"force",  VSH_OT_BOOL, 0, N_("force device update")},
9067 9068 9069
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9070
static bool
9071 9072 9073
cmdUpdateDevice(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
9074
    const char *from = NULL;
9075
    char *buffer;
W
Wen Congyang 已提交
9076
    int ret;
9077 9078
    unsigned int flags;

9079
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
9080
        return false;
9081 9082

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
E
Eric Blake 已提交
9083
        return false;
9084

9085
    if (vshCommandOptString(cmd, "file", &from) <= 0) {
9086
        virDomainFree(dom);
E
Eric Blake 已提交
9087
        return false;
9088 9089 9090
    }

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
9091
        virshReportError(ctl);
9092
        virDomainFree(dom);
E
Eric Blake 已提交
9093
        return false;
9094 9095 9096 9097 9098 9099 9100 9101 9102
    }

    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
           flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
    } else {
        flags = VIR_DOMAIN_DEVICE_MODIFY_LIVE;
    }
9103 9104 9105 9106

    if (vshCommandOptBool(cmd, "force"))
        flags |= VIR_DOMAIN_DEVICE_MODIFY_FORCE;

9107 9108 9109 9110 9111 9112
    ret = virDomainUpdateDeviceFlags(dom, buffer, flags);
    VIR_FREE(buffer);

    if (ret < 0) {
        vshError(ctl, _("Failed to update device from %s"), from);
        virDomainFree(dom);
E
Eric Blake 已提交
9113
        return false;
9114 9115 9116 9117 9118
    } else {
        vshPrint(ctl, "%s", _("Device updated successfully\n"));
    }

    virDomainFree(dom);
E
Eric Blake 已提交
9119
    return true;
9120 9121 9122
}


9123 9124 9125
/*
 * "attach-interface" command
 */
9126
static const vshCmdInfo info_attach_interface[] = {
9127 9128
    {"help", N_("attach network interface")},
    {"desc", N_("Attach new network interface.")},
9129 9130 9131
    {NULL, NULL}
};

9132
static const vshCmdOptDef opts_attach_interface[] = {
9133 9134 9135 9136 9137 9138
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"type",   VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface type")},
    {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of network interface")},
    {"target", VSH_OT_DATA, 0, N_("target network name")},
    {"mac",    VSH_OT_DATA, 0, N_("MAC address")},
    {"script", VSH_OT_DATA, 0, N_("script used to bridge network interface")},
9139
    {"model", VSH_OT_DATA, 0, N_("model type")},
9140
    {"persistent", VSH_OT_BOOL, 0, N_("persist interface attachment")},
9141 9142 9143
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9144
static bool
9145
cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
9146 9147
{
    virDomainPtr dom = NULL;
9148 9149
    const char *mac = NULL, *target = NULL, *script = NULL,
                *type = NULL, *source = NULL, *model = NULL;
E
Eric Blake 已提交
9150
    int typ;
W
Wen Congyang 已提交
9151 9152
    int ret;
    bool functionReturn = false;
J
Jim Fehlig 已提交
9153
    unsigned int flags;
9154 9155
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *xml;
9156

9157
    if (!vshConnectionUsability(ctl, ctl->conn))
9158 9159
        goto cleanup;

J
Jim Meyering 已提交
9160
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
9161 9162
        goto cleanup;

9163
    if (vshCommandOptString(cmd, "type", &type) <= 0)
9164 9165
        goto cleanup;

9166 9167 9168 9169
    if (vshCommandOptString(cmd, "source", &source) < 0 ||
        vshCommandOptString(cmd, "target", &target) < 0 ||
        vshCommandOptString(cmd, "mac", &mac) < 0 ||
        vshCommandOptString(cmd, "script", &script) < 0 ||
9170 9171
        vshCommandOptString(cmd, "model", &model) < 0) {
        vshError(ctl, "missing argument");
9172
        goto cleanup;
9173
    }
9174 9175

    /* check interface type */
9176
    if (STREQ(type, "network")) {
9177
        typ = 1;
9178
    } else if (STREQ(type, "bridge")) {
9179 9180
        typ = 2;
    } else {
E
Eric Blake 已提交
9181 9182
        vshError(ctl, _("No support for %s in command 'attach-interface'"),
                 type);
9183 9184 9185 9186
        goto cleanup;
    }

    /* Make XML of interface */
9187
    virBufferAsprintf(&buf, "<interface type='%s'>\n", type);
9188

9189
    if (typ == 1)
9190
        virBufferAsprintf(&buf, "  <source network='%s'/>\n", source);
9191
    else if (typ == 2)
9192
        virBufferAsprintf(&buf, "  <source bridge='%s'/>\n", source);
9193

9194
    if (target != NULL)
9195
        virBufferAsprintf(&buf, "  <target dev='%s'/>\n", target);
9196
    if (mac != NULL)
9197
        virBufferAsprintf(&buf, "  <mac address='%s'/>\n", mac);
9198
    if (script != NULL)
9199
        virBufferAsprintf(&buf, "  <script path='%s'/>\n", script);
9200
    if (model != NULL)
9201
        virBufferAsprintf(&buf, "  <model type='%s'/>\n", model);
9202

9203
    virBufferAddLit(&buf, "</interface>\n");
9204

9205 9206
    if (virBufferError(&buf)) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
W
Wen Congyang 已提交
9207
        goto cleanup;
9208 9209
    }

9210
    xml = virBufferContentAndReset(&buf);
9211

J
Jim Fehlig 已提交
9212 9213 9214 9215
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
9216
        ret = virDomainAttachDeviceFlags(dom, xml, flags);
9217
    } else {
9218
        ret = virDomainAttachDevice(dom, xml);
9219
    }
9220

9221 9222
    VIR_FREE(xml);

J
Jim Fehlig 已提交
9223
    if (ret != 0) {
L
Laine Stump 已提交
9224
        vshError(ctl, "%s", _("Failed to attach interface"));
J
Jim Fehlig 已提交
9225 9226
    } else {
        vshPrint(ctl, "%s", _("Interface attached successfully\n"));
W
Wen Congyang 已提交
9227
        functionReturn = true;
J
Jim Fehlig 已提交
9228
    }
9229 9230 9231 9232

 cleanup:
    if (dom)
        virDomainFree(dom);
9233
    virBufferFreeAndReset(&buf);
W
Wen Congyang 已提交
9234
    return functionReturn;
9235 9236 9237 9238 9239
}

/*
 * "detach-interface" command
 */
9240
static const vshCmdInfo info_detach_interface[] = {
9241 9242
    {"help", N_("detach network interface")},
    {"desc", N_("Detach network interface.")},
9243 9244 9245
    {NULL, NULL}
};

9246
static const vshCmdOptDef opts_detach_interface[] = {
9247 9248 9249 9250
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"type",   VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface type")},
    {"mac",    VSH_OT_STRING, 0, N_("MAC address")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist interface detachment")},
9251 9252 9253
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9254
static bool
9255
cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
9256 9257 9258 9259 9260 9261 9262
{
    virDomainPtr dom = NULL;
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj=NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr cur = NULL;
    xmlBufferPtr xml_buf = NULL;
9263
    const char *mac =NULL, *type = NULL;
9264
    char *doc;
9265
    char buf[64];
E
Eric Blake 已提交
9266
    int i = 0, diff_mac;
W
Wen Congyang 已提交
9267 9268
    int ret;
    int functionReturn = false;
J
Jim Fehlig 已提交
9269
    unsigned int flags;
9270

9271
    if (!vshConnectionUsability(ctl, ctl->conn))
9272 9273
        goto cleanup;

J
Jim Meyering 已提交
9274
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
9275 9276
        goto cleanup;

9277
    if (vshCommandOptString(cmd, "type", &type) <= 0)
9278 9279
        goto cleanup;

9280 9281
    if (vshCommandOptString(cmd, "mac", &mac) < 0) {
        vshError(ctl, "%s", _("missing option"));
9282
        goto cleanup;
9283
    }
9284 9285 9286 9287 9288 9289 9290 9291

    doc = virDomainGetXMLDesc(dom, 0);
    if (!doc)
        goto cleanup;

    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOWARNING);
9292
    VIR_FREE(doc);
9293
    if (!xml) {
9294
        vshError(ctl, "%s", _("Failed to get interface information"));
9295 9296 9297 9298
        goto cleanup;
    }
    ctxt = xmlXPathNewContext(xml);
    if (!ctxt) {
9299
        vshError(ctl, "%s", _("Failed to get interface information"));
9300 9301 9302
        goto cleanup;
    }

E
Eric Blake 已提交
9303
    snprintf(buf, sizeof(buf), "/domain/devices/interface[@type='%s']", type);
9304 9305 9306
    obj = xmlXPathEval(BAD_CAST buf, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
9307
        vshError(ctl, _("No found interface whose type is %s"), type);
9308 9309 9310
        goto cleanup;
    }

9311 9312 9313 9314 9315 9316
    if ((!mac) && (obj->nodesetval->nodeNr > 1)) {
        vshError(ctl, _("Domain has %d interfaces. Please specify which one "
                        "to detach using --mac"), obj->nodesetval->nodeNr);
        goto cleanup;
    }

9317 9318 9319 9320 9321 9322 9323
    if (!mac)
        goto hit;

    /* search mac */
    for (; i < obj->nodesetval->nodeNr; i++) {
        cur = obj->nodesetval->nodeTab[i]->children;
        while (cur != NULL) {
9324 9325 9326 9327 9328
            if (cur->type == XML_ELEMENT_NODE &&
                xmlStrEqual(cur->name, BAD_CAST "mac")) {
                char *tmp_mac = virXMLPropString(cur, "address");
                diff_mac = virMacAddrCompare (tmp_mac, mac);
                VIR_FREE(tmp_mac);
9329 9330 9331 9332 9333 9334 9335
                if (!diff_mac) {
                    goto hit;
                }
            }
            cur = cur->next;
        }
    }
9336
    vshError(ctl, _("No found interface whose MAC address is %s"), mac);
9337 9338 9339 9340 9341
    goto cleanup;

 hit:
    xml_buf = xmlBufferCreate();
    if (!xml_buf) {
9342
        vshError(ctl, "%s", _("Failed to allocate memory"));
9343 9344 9345
        goto cleanup;
    }

9346
    if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0) {
9347
        vshError(ctl, "%s", _("Failed to create XML"));
9348 9349 9350
        goto cleanup;
    }

J
Jim Fehlig 已提交
9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
        ret = virDomainDetachDeviceFlags(dom,
                                         (char *)xmlBufferContent(xml_buf),
                                         flags);
    } else {
        ret = virDomainDetachDevice(dom, (char *)xmlBufferContent(xml_buf));
    }

    if (ret != 0) {
L
Laine Stump 已提交
9363
        vshError(ctl, "%s", _("Failed to detach interface"));
J
Jim Fehlig 已提交
9364
    } else {
J
Jim Meyering 已提交
9365
        vshPrint(ctl, "%s", _("Interface detached successfully\n"));
W
Wen Congyang 已提交
9366
        functionReturn = true;
9367
    }
9368 9369 9370 9371

 cleanup:
    if (dom)
        virDomainFree(dom);
9372
    xmlXPathFreeObject(obj);
9373
    xmlXPathFreeContext(ctxt);
9374 9375 9376 9377
    if (xml)
        xmlFreeDoc(xml);
    if (xml_buf)
        xmlBufferFree(xml_buf);
W
Wen Congyang 已提交
9378
    return functionReturn;
9379 9380 9381 9382 9383
}

/*
 * "attach-disk" command
 */
9384
static const vshCmdInfo info_attach_disk[] = {
9385 9386
    {"help", N_("attach disk device")},
    {"desc", N_("Attach new disk device.")},
9387 9388 9389
    {NULL, NULL}
};

9390
static const vshCmdOptDef opts_attach_disk[] = {
9391 9392 9393 9394 9395 9396 9397 9398
    {"domain",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"source",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of disk device")},
    {"target",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
    {"driver",    VSH_OT_STRING, 0, N_("driver of disk device")},
    {"subdriver", VSH_OT_STRING, 0, N_("subdriver of disk device")},
    {"type",    VSH_OT_STRING, 0, N_("target device type")},
    {"mode",    VSH_OT_STRING, 0, N_("mode of device reading and writing")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist disk attachment")},
9399
    {"sourcetype", VSH_OT_STRING, 0, N_("type of source (block|file)")},
9400 9401 9402
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9403
static bool
9404
cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
9405 9406
{
    virDomainPtr dom = NULL;
9407 9408
    const char *source = NULL, *target = NULL, *driver = NULL,
                *subdriver = NULL, *type = NULL, *mode = NULL;
W
Wen Congyang 已提交
9409 9410
    bool isFile = false, functionReturn = false;
    int ret;
J
Jim Fehlig 已提交
9411
    unsigned int flags;
9412
    const char *stype = NULL;
9413 9414
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *xml;
9415

9416
    if (!vshConnectionUsability(ctl, ctl->conn))
9417 9418
        goto cleanup;

J
Jim Meyering 已提交
9419
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
9420 9421
        goto cleanup;

9422
    if (vshCommandOptString(cmd, "source", &source) <= 0)
9423 9424
        goto cleanup;

9425
    if (vshCommandOptString(cmd, "target", &target) <= 0)
9426 9427
        goto cleanup;

9428 9429 9430 9431 9432
    if (vshCommandOptString(cmd, "driver", &driver) < 0 ||
        vshCommandOptString(cmd, "subdriver", &subdriver) < 0 ||
        vshCommandOptString(cmd, "type", &type) < 0 ||
        vshCommandOptString(cmd, "mode", &mode) < 0 ||
        vshCommandOptString(cmd, "sourcetype", &stype) < 0) {
9433
        vshError(ctl, "%s", _("missing option"));
9434 9435
        goto cleanup;
    }
9436

9437 9438
    if (!stype) {
        if (driver && (STREQ(driver, "file") || STREQ(driver, "tap")))
E
Eric Blake 已提交
9439
            isFile = true;
9440
    } else if (STREQ(stype, "file")) {
E
Eric Blake 已提交
9441
        isFile = true;
9442 9443 9444
    } else if (STRNEQ(stype, "block")) {
        vshError(ctl, _("Unknown source type: '%s'"), stype);
        goto cleanup;
9445 9446 9447
    }

    if (mode) {
9448
        if (STRNEQ(mode, "readonly") && STRNEQ(mode, "shareable")) {
E
Eric Blake 已提交
9449 9450
            vshError(ctl, _("No support for %s in command 'attach-disk'"),
                     mode);
9451 9452 9453 9454 9455
            goto cleanup;
        }
    }

    /* Make XML of disk */
9456
    virBufferAsprintf(&buf, "<disk type='%s'",
9457 9458
                      (isFile) ? "file" : "block");
    if (type)
9459
        virBufferAsprintf(&buf, " device='%s'", type);
9460 9461
    virBufferAddLit(&buf, ">\n");

9462
    if (driver || subdriver)
9463
        virBufferAsprintf(&buf, "  <driver");
9464 9465

    if (driver)
9466
        virBufferAsprintf(&buf, " name='%s'", driver);
9467
    if (subdriver)
9468
        virBufferAsprintf(&buf, " type='%s'", subdriver);
9469 9470 9471

    if (driver || subdriver)
        virBufferAddLit(&buf, "/>\n");
9472

9473
    virBufferAsprintf(&buf, "  <source %s='%s'/>\n",
9474 9475
                      (isFile) ? "file" : "dev",
                      source);
9476
    virBufferAsprintf(&buf, "  <target dev='%s'/>\n", target);
9477
    if (mode)
9478
        virBufferAsprintf(&buf, "  <%s/>\n", mode);
9479 9480

    virBufferAddLit(&buf, "</disk>\n");
9481

9482 9483
    if (virBufferError(&buf)) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
E
Eric Blake 已提交
9484
        return false;
9485 9486
    }

9487
    xml = virBufferContentAndReset(&buf);
9488

J
Jim Fehlig 已提交
9489 9490 9491 9492
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
9493
        ret = virDomainAttachDeviceFlags(dom, xml, flags);
J
Jim Fehlig 已提交
9494
    } else {
9495
        ret = virDomainAttachDevice(dom, xml);
J
Jim Fehlig 已提交
9496
    }
9497

9498 9499
    VIR_FREE(xml);

J
Jim Fehlig 已提交
9500
    if (ret != 0) {
L
Laine Stump 已提交
9501
        vshError(ctl, "%s", _("Failed to attach disk"));
J
Jim Fehlig 已提交
9502 9503
    } else {
        vshPrint(ctl, "%s", _("Disk attached successfully\n"));
W
Wen Congyang 已提交
9504
        functionReturn = true;
J
Jim Fehlig 已提交
9505
    }
9506 9507 9508 9509

 cleanup:
    if (dom)
        virDomainFree(dom);
9510
    virBufferFreeAndReset(&buf);
W
Wen Congyang 已提交
9511
    return functionReturn;
9512 9513 9514 9515 9516
}

/*
 * "detach-disk" command
 */
9517
static const vshCmdInfo info_detach_disk[] = {
9518 9519
    {"help", N_("detach disk device")},
    {"desc", N_("Detach disk device.")},
9520 9521 9522
    {NULL, NULL}
};

9523
static const vshCmdOptDef opts_detach_disk[] = {
9524 9525 9526
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist disk detachment")},
9527 9528 9529
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9530
static bool
9531
cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
9532 9533 9534 9535 9536 9537 9538
{
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj=NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr cur = NULL;
    xmlBufferPtr xml_buf = NULL;
    virDomainPtr dom = NULL;
9539
    const char *target = NULL;
9540
    char *doc;
E
Eric Blake 已提交
9541
    int i = 0, diff_tgt;
W
Wen Congyang 已提交
9542 9543
    int ret;
    bool functionReturn = false;
J
Jim Fehlig 已提交
9544
    unsigned int flags;
9545

9546
    if (!vshConnectionUsability(ctl, ctl->conn))
9547 9548
        goto cleanup;

J
Jim Meyering 已提交
9549
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
9550 9551
        goto cleanup;

9552
    if (vshCommandOptString(cmd, "target", &target) <= 0)
9553 9554 9555 9556 9557 9558 9559 9560 9561
        goto cleanup;

    doc = virDomainGetXMLDesc(dom, 0);
    if (!doc)
        goto cleanup;

    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOWARNING);
9562
    VIR_FREE(doc);
9563
    if (!xml) {
9564
        vshError(ctl, "%s", _("Failed to get disk information"));
9565 9566 9567 9568
        goto cleanup;
    }
    ctxt = xmlXPathNewContext(xml);
    if (!ctxt) {
9569
        vshError(ctl, "%s", _("Failed to get disk information"));
9570 9571 9572 9573 9574 9575
        goto cleanup;
    }

    obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
9576
        vshError(ctl, "%s", _("Failed to get disk information"));
9577 9578 9579 9580 9581 9582 9583
        goto cleanup;
    }

    /* search target */
    for (; i < obj->nodesetval->nodeNr; i++) {
        cur = obj->nodesetval->nodeTab[i]->children;
        while (cur != NULL) {
9584 9585 9586 9587 9588
            if (cur->type == XML_ELEMENT_NODE &&
                xmlStrEqual(cur->name, BAD_CAST "target")) {
                char *tmp_tgt = virXMLPropString(cur, "dev");
                diff_tgt = STREQ(tmp_tgt, target);
                VIR_FREE(tmp_tgt);
9589 9590 9591 9592 9593 9594 9595
                if (diff_tgt) {
                    goto hit;
                }
            }
            cur = cur->next;
        }
    }
9596
    vshError(ctl, _("No found disk whose target is %s"), target);
9597 9598 9599 9600 9601
    goto cleanup;

 hit:
    xml_buf = xmlBufferCreate();
    if (!xml_buf) {
9602
        vshError(ctl, "%s", _("Failed to allocate memory"));
9603 9604 9605
        goto cleanup;
    }

9606
    if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0) {
9607
        vshError(ctl, "%s", _("Failed to create XML"));
9608 9609 9610
        goto cleanup;
    }

J
Jim Fehlig 已提交
9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
        ret = virDomainDetachDeviceFlags(dom,
                                         (char *)xmlBufferContent(xml_buf),
                                         flags);
    } else {
        ret = virDomainDetachDevice(dom, (char *)xmlBufferContent(xml_buf));
    }

    if (ret != 0) {
L
Laine Stump 已提交
9623
        vshError(ctl, "%s", _("Failed to detach disk"));
J
Jim Fehlig 已提交
9624
    } else {
J
Jim Meyering 已提交
9625
        vshPrint(ctl, "%s", _("Disk detached successfully\n"));
W
Wen Congyang 已提交
9626
        functionReturn = true;
9627
    }
9628 9629

 cleanup:
9630
    xmlXPathFreeObject(obj);
9631
    xmlXPathFreeContext(ctxt);
9632 9633 9634 9635 9636 9637
    if (xml)
        xmlFreeDoc(xml);
    if (xml_buf)
        xmlBufferFree(xml_buf);
    if (dom)
        virDomainFree(dom);
W
Wen Congyang 已提交
9638
    return functionReturn;
9639 9640
}

9641 9642 9643 9644
/*
 * "cpu-compare" command
 */
static const vshCmdInfo info_cpu_compare[] = {
9645 9646
    {"help", N_("compare host CPU with a CPU described by an XML file")},
    {"desc", N_("compare CPU with host CPU")},
9647 9648 9649 9650
    {NULL, NULL}
};

static const vshCmdOptDef opts_cpu_compare[] = {
9651
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML CPU description")},
9652 9653 9654
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9655
static bool
9656 9657
cmdCPUCompare(vshControl *ctl, const vshCmd *cmd)
{
9658
    const char *from = NULL;
E
Eric Blake 已提交
9659
    bool ret = true;
9660 9661 9662
    char *buffer;
    int result;

9663
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
9664
        return false;
9665

9666
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
9667
        return false;
9668 9669

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
9670
        return false;
9671 9672

    result = virConnectCompareCPU(ctl->conn, buffer, 0);
9673
    VIR_FREE(buffer);
9674 9675 9676 9677 9678

    switch (result) {
    case VIR_CPU_COMPARE_INCOMPATIBLE:
        vshPrint(ctl, _("CPU described in %s is incompatible with host CPU\n"),
                 from);
E
Eric Blake 已提交
9679
        ret = false;
9680 9681 9682 9683 9684
        break;

    case VIR_CPU_COMPARE_IDENTICAL:
        vshPrint(ctl, _("CPU described in %s is identical to host CPU\n"),
                 from);
E
Eric Blake 已提交
9685
        ret = true;
9686 9687 9688 9689 9690
        break;

    case VIR_CPU_COMPARE_SUPERSET:
        vshPrint(ctl, _("Host CPU is a superset of CPU described in %s\n"),
                 from);
E
Eric Blake 已提交
9691
        ret = true;
9692 9693 9694 9695 9696
        break;

    case VIR_CPU_COMPARE_ERROR:
    default:
        vshError(ctl, _("Failed to compare host CPU with %s"), from);
E
Eric Blake 已提交
9697
        ret = false;
9698 9699 9700 9701 9702
    }

    return ret;
}

9703 9704 9705 9706
/*
 * "cpu-baseline" command
 */
static const vshCmdInfo info_cpu_baseline[] = {
9707 9708
    {"help", N_("compute baseline CPU")},
    {"desc", N_("Compute baseline CPU for a set of given CPUs.")},
9709 9710 9711 9712
    {NULL, NULL}
};

static const vshCmdOptDef opts_cpu_baseline[] = {
9713
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing XML CPU descriptions")},
9714 9715 9716
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9717
static bool
9718 9719
cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
{
9720
    const char *from = NULL;
E
Eric Blake 已提交
9721
    bool ret = true;
9722 9723 9724 9725 9726
    char *buffer;
    char *result = NULL;
    const char **list = NULL;
    unsigned int count = 0;
    xmlDocPtr doc = NULL;
9727
    xmlNodePtr node_list;
9728 9729 9730 9731 9732 9733
    xmlXPathContextPtr ctxt = NULL;
    xmlSaveCtxtPtr sctxt = NULL;
    xmlBufferPtr buf = NULL;
    xmlXPathObjectPtr obj = NULL;
    int res, i;

9734
    if (!vshConnectionUsability(ctl, ctl->conn))
E
Eric Blake 已提交
9735
        return false;
9736

9737
    if (vshCommandOptString(cmd, "file", &from) <= 0)
E
Eric Blake 已提交
9738
        return false;
9739 9740

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
E
Eric Blake 已提交
9741
        return false;
9742 9743 9744 9745 9746

    doc = xmlNewDoc(NULL);
    if (doc == NULL)
        goto no_memory;

L
Laine Stump 已提交
9747 9748
    res = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
                                      (const xmlChar *)buffer, &node_list);
9749 9750
    if (res != 0) {
        vshError(ctl, _("Failed to parse XML fragment %s"), from);
E
Eric Blake 已提交
9751
        ret = false;
9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787
        goto cleanup;
    }

    xmlAddChildList((xmlNodePtr) doc, node_list);

    ctxt = xmlXPathNewContext(doc);
    if (!ctxt)
        goto no_memory;

    obj = xmlXPathEval(BAD_CAST "//cpu[not(ancestor::cpu)]", ctxt);
    if ((obj == NULL) || (obj->nodesetval == NULL) ||
        (obj->nodesetval->nodeTab == NULL))
        goto cleanup;

    for (i = 0;i < obj->nodesetval->nodeNr;i++) {
        buf = xmlBufferCreate();
        if (buf == NULL)
            goto no_memory;
        sctxt = xmlSaveToBuffer(buf, NULL, 0);
        if (sctxt == NULL) {
            xmlBufferFree(buf);
            goto no_memory;
        }

        xmlSaveTree(sctxt, obj->nodesetval->nodeTab[i]);
        xmlSaveClose(sctxt);

        list = vshRealloc(ctl, list, sizeof(char *) * (count + 1));
        list[count++] = (char *) buf->content;
        buf->content = NULL;
        xmlBufferFree(buf);
        buf = NULL;
    }

    if (count == 0) {
        vshError(ctl, _("No host CPU specified in '%s'"), from);
E
Eric Blake 已提交
9788
        ret = false;
9789 9790 9791 9792 9793 9794 9795 9796
        goto cleanup;
    }

    result = virConnectBaselineCPU(ctl->conn, list, count, 0);

    if (result)
        vshPrint(ctl, "%s", result);
    else
E
Eric Blake 已提交
9797
        ret = false;
9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814

cleanup:
    xmlXPathFreeObject(obj);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);
    VIR_FREE(result);
    if ((list != NULL) && (count > 0)) {
        for (i = 0;i < count;i++)
            VIR_FREE(list[i]);
    }
    VIR_FREE(list);
    VIR_FREE(buffer);

    return ret;

no_memory:
    vshError(ctl, "%s", _("Out of memory"));
E
Eric Blake 已提交
9815
    ret = false;
9816
    goto cleanup;
9817 9818
}

9819 9820 9821 9822 9823 9824 9825 9826
/* Common code for the edit / net-edit / pool-edit functions which follow. */
static char *
editWriteToTempFile (vshControl *ctl, const char *doc)
{
    char *ret;
    const char *tmpdir;
    int fd;

9827
    ret = vshMalloc(ctl, PATH_MAX);
9828 9829 9830

    tmpdir = getenv ("TMPDIR");
    if (!tmpdir) tmpdir = "/tmp";
9831 9832
    snprintf (ret, PATH_MAX, "%s/virshXXXXXX.xml", tmpdir);
    fd = mkstemps(ret, 4);
9833
    if (fd == -1) {
9834
        vshError(ctl, _("mkstemps: failed to create temporary file: %s"),
9835
                 strerror(errno));
9836
        VIR_FREE(ret);
9837 9838 9839 9840
        return NULL;
    }

    if (safewrite (fd, doc, strlen (doc)) == -1) {
9841 9842
        vshError(ctl, _("write: %s: failed to write to temporary file: %s"),
                 ret, strerror(errno));
S
Stefan Berger 已提交
9843
        VIR_FORCE_CLOSE(fd);
9844
        unlink (ret);
9845
        VIR_FREE(ret);
9846 9847
        return NULL;
    }
S
Stefan Berger 已提交
9848
    if (VIR_CLOSE(fd) < 0) {
9849 9850
        vshError(ctl, _("close: %s: failed to write or close temporary file: %s"),
                 ret, strerror(errno));
9851
        unlink (ret);
9852
        VIR_FREE(ret);
9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867
        return NULL;
    }

    /* Temporary filename: caller frees. */
    return ret;
}

/* Characters permitted in $EDITOR environment variable and temp filename. */
#define ACCEPTED_CHARS \
  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/_.:@"

static int
editFile (vshControl *ctl, const char *filename)
{
    const char *editor;
E
Eric Blake 已提交
9868 9869 9870 9871
    virCommandPtr cmd;
    int ret = -1;
    int outfd = STDOUT_FILENO;
    int errfd = STDERR_FILENO;
9872

9873
    editor = getenv ("VISUAL");
E
Eric Blake 已提交
9874 9875 9876 9877
    if (!editor)
        editor = getenv ("EDITOR");
    if (!editor)
        editor = "vi"; /* could be cruel & default to ed(1) here */
9878

9879 9880 9881 9882 9883
    /* Check that filename doesn't contain shell meta-characters, and
     * if it does, refuse to run.  Follow the Unix conventions for
     * EDITOR: the user can intentionally specify command options, so
     * we don't protect any shell metacharacters there.  Lots more
     * than virsh will misbehave if EDITOR has bogus contents (which
E
Eric Blake 已提交
9884 9885
     * is why sudo scrubs it by default).  Conversely, if the editor
     * is safe, we can run it directly rather than wasting a shell.
9886
     */
E
Eric Blake 已提交
9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898
    if (strspn (editor, ACCEPTED_CHARS) != strlen (editor)) {
        if (strspn (filename, ACCEPTED_CHARS) != strlen (filename)) {
            vshError(ctl,
                     _("%s: temporary filename contains shell meta or other "
                       "unacceptable characters (is $TMPDIR wrong?)"),
                     filename);
            return -1;
        }
        cmd = virCommandNewArgList("sh", "-c", NULL);
        virCommandAddArgFormat(cmd, "%s %s", editor, filename);
    } else {
        cmd = virCommandNewArgList(editor, filename, NULL);
9899 9900
    }

E
Eric Blake 已提交
9901 9902 9903 9904 9905 9906 9907
    virCommandSetInputFD(cmd, STDIN_FILENO);
    virCommandSetOutputFD(cmd, &outfd);
    virCommandSetErrorFD(cmd, &errfd);
    if (virCommandRunAsync(cmd, NULL) < 0 ||
        virCommandWait(cmd, NULL) < 0) {
        virshReportError(ctl);
        goto cleanup;
9908
    }
E
Eric Blake 已提交
9909
    ret = 0;
9910

E
Eric Blake 已提交
9911 9912 9913
cleanup:
    virCommandFree(cmd);
    return ret;
9914 9915 9916 9917 9918 9919 9920 9921
}

static char *
editReadBackFile (vshControl *ctl, const char *filename)
{
    char *ret;

    if (virFileReadAll (filename, VIRSH_MAX_XML_FILE, &ret) == -1) {
9922
        vshError(ctl,
9923
                 _("%s: failed to read temporary file: %s"),
9924
                 filename, strerror(errno));
9925 9926 9927 9928 9929
        return NULL;
    }
    return ret;
}

9930

P
Paolo Bonzini 已提交
9931 9932 9933 9934
/*
 * "cd" command
 */
static const vshCmdInfo info_cd[] = {
9935 9936
    {"help", N_("change the current directory")},
    {"desc", N_("Change the current directory.")},
P
Paolo Bonzini 已提交
9937 9938 9939 9940
    {NULL, NULL}
};

static const vshCmdOptDef opts_cd[] = {
9941
    {"dir", VSH_OT_DATA, 0, N_("directory to switch to (default: home or else root)")},
P
Paolo Bonzini 已提交
9942 9943 9944
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
9945
static bool
P
Paolo Bonzini 已提交
9946 9947
cmdCd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
9948
    const char *dir = NULL;
9949
    char *dir_malloced = NULL;
E
Eric Blake 已提交
9950
    bool ret = true;
P
Paolo Bonzini 已提交
9951 9952

    if (!ctl->imode) {
9953
        vshError(ctl, "%s", _("cd: command valid only in interactive mode"));
E
Eric Blake 已提交
9954
        return false;
P
Paolo Bonzini 已提交
9955 9956
    }

9957
    if (vshCommandOptString(cmd, "dir", &dir) <= 0) {
P
Paolo Bonzini 已提交
9958
        uid_t uid = geteuid();
9959
        dir = dir_malloced = virGetUserDirectory(uid);
P
Paolo Bonzini 已提交
9960 9961 9962 9963
    }
    if (!dir)
        dir = "/";

P
Phil Petty 已提交
9964
    if (chdir(dir) == -1) {
9965
        vshError(ctl, _("cd: %s: %s"), strerror(errno), dir);
E
Eric Blake 已提交
9966
        ret = false;
P
Paolo Bonzini 已提交
9967 9968
    }

9969
    VIR_FREE(dir_malloced);
P
Phil Petty 已提交
9970
    return ret;
P
Paolo Bonzini 已提交
9971 9972 9973 9974 9975 9976
}

/*
 * "pwd" command
 */
static const vshCmdInfo info_pwd[] = {
9977 9978
    {"help", N_("print the current directory")},
    {"desc", N_("Print the current directory.")},
P
Paolo Bonzini 已提交
9979 9980 9981
    {NULL, NULL}
};

E
Eric Blake 已提交
9982
static bool
P
Paolo Bonzini 已提交
9983 9984 9985
cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    char *cwd;
9986
    bool ret = true;
P
Paolo Bonzini 已提交
9987

9988 9989
    cwd = getcwd(NULL, 0);
    if (!cwd) {
9990 9991
        vshError(ctl, _("pwd: cannot get current directory: %s"),
                 strerror(errno));
9992 9993
        ret = false;
    } else {
P
Paolo Bonzini 已提交
9994
        vshPrint (ctl, _("%s\n"), cwd);
9995 9996
        VIR_FREE(cwd);
    }
P
Paolo Bonzini 已提交
9997

9998
    return ret;
P
Paolo Bonzini 已提交
9999 10000
}

E
Eric Blake 已提交
10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019
/*
 * "echo" command
 */
static const vshCmdInfo info_echo[] = {
    {"help", N_("echo arguments")},
    {"desc", N_("Echo back arguments, possibly with quoting.")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_echo[] = {
    {"shell", VSH_OT_BOOL, 0, N_("escape for shell use")},
    {"xml", VSH_OT_BOOL, 0, N_("escape for XML use")},
    {"", VSH_OT_ARGV, 0, N_("arguments to echo")},
    {NULL, 0, 0, NULL}
};

/* Exists mainly for debugging virsh, but also handy for adding back
 * quotes for later evaluation.
 */
E
Eric Blake 已提交
10020
static bool
E
Eric Blake 已提交
10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065
cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd)
{
    bool shell = false;
    bool xml = false;
    int count = 0;
    char *arg;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if (vshCommandOptBool(cmd, "shell"))
        shell = true;
    if (vshCommandOptBool(cmd, "xml"))
        xml = true;

    while ((arg = vshCommandOptArgv(cmd, count)) != NULL) {
        bool close_quote = false;
        char *q;

        if (count)
            virBufferAddChar(&buf, ' ');
        /* Add outer '' only if arg included shell metacharacters.  */
        if (shell &&
            (strpbrk(arg, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") || !*arg)) {
            virBufferAddChar(&buf, '\'');
            close_quote = true;
        }
        if (xml) {
            virBufferEscapeString(&buf, "%s", arg);
        } else {
            if (shell && (q = strchr(arg, '\''))) {
                do {
                    virBufferAdd(&buf, arg, q - arg);
                    virBufferAddLit(&buf, "'\\''");
                    arg = q + 1;
                    q = strchr(arg, '\'');
                } while (q);
            }
            virBufferAdd(&buf, arg, strlen(arg));
        }
        if (close_quote)
            virBufferAddChar(&buf, '\'');
        count++;
    }

    if (virBufferError(&buf)) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
E
Eric Blake 已提交
10066
        return false;
E
Eric Blake 已提交
10067 10068 10069 10070 10071
    }
    arg = virBufferContentAndReset(&buf);
    if (arg)
        vshPrint(ctl, "%s", arg);
    VIR_FREE(arg);
E
Eric Blake 已提交
10072
    return true;
E
Eric Blake 已提交
10073 10074
}

10075 10076 10077 10078
/*
 * "edit" command
 */
static const vshCmdInfo info_edit[] = {
10079 10080
    {"help", N_("edit XML configuration for a domain")},
    {"desc", N_("Edit the XML configuration for a domain.")},
10081 10082 10083 10084
    {NULL, NULL}
};

static const vshCmdOptDef opts_edit[] = {
10085
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
10086 10087 10088 10089 10090 10091
    {NULL, 0, 0, NULL}
};

/* This function also acts as a template to generate cmdNetworkEdit
 * and cmdPoolEdit functions (below) using a sed script in the Makefile.
 */
E
Eric Blake 已提交
10092
static bool
10093 10094
cmdEdit (vshControl *ctl, const vshCmd *cmd)
{
E
Eric Blake 已提交
10095
    bool ret = false;
10096 10097 10098 10099 10100
    virDomainPtr dom = NULL;
    char *tmp = NULL;
    char *doc = NULL;
    char *doc_edited = NULL;
    char *doc_reread = NULL;
10101
    int flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_INACTIVE;
10102

10103
    if (!vshConnectionUsability(ctl, ctl->conn))
10104 10105
        goto cleanup;

J
Jim Meyering 已提交
10106
    dom = vshCommandOptDomain (ctl, cmd, NULL);
10107 10108 10109 10110
    if (dom == NULL)
        goto cleanup;

    /* Get the XML configuration of the domain. */
10111
    doc = virDomainGetXMLDesc (dom, flags);
10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129
    if (!doc)
        goto cleanup;

    /* Create and open the temporary file. */
    tmp = editWriteToTempFile (ctl, doc);
    if (!tmp) goto cleanup;

    /* Start the editor. */
    if (editFile (ctl, tmp) == -1) goto cleanup;

    /* Read back the edited file. */
    doc_edited = editReadBackFile (ctl, tmp);
    if (!doc_edited) goto cleanup;

    /* Compare original XML with edited.  Has it changed at all? */
    if (STREQ (doc, doc_edited)) {
        vshPrint (ctl, _("Domain %s XML configuration not changed.\n"),
                  virDomainGetName (dom));
E
Eric Blake 已提交
10130
        ret = true;
10131 10132 10133 10134 10135 10136 10137
        goto cleanup;
    }

    /* Now re-read the domain XML.  Did someone else change it while
     * it was being edited?  This also catches problems such as us
     * losing a connection or the domain going away.
     */
10138
    doc_reread = virDomainGetXMLDesc (dom, flags);
10139 10140 10141 10142
    if (!doc_reread)
        goto cleanup;

    if (STRNEQ (doc, doc_reread)) {
10143 10144
        vshError(ctl,
                 "%s", _("ERROR: the XML configuration was changed by another user"));
10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156
        goto cleanup;
    }

    /* Everything checks out, so redefine the domain. */
    virDomainFree (dom);
    dom = virDomainDefineXML (ctl->conn, doc_edited);
    if (!dom)
        goto cleanup;

    vshPrint (ctl, _("Domain %s XML configuration edited.\n"),
              virDomainGetName(dom));

E
Eric Blake 已提交
10157
    ret = true;
10158 10159 10160 10161 10162

 cleanup:
    if (dom)
        virDomainFree (dom);

10163 10164 10165
    VIR_FREE(doc);
    VIR_FREE(doc_edited);
    VIR_FREE(doc_reread);
10166 10167 10168

    if (tmp) {
        unlink (tmp);
10169
        VIR_FREE(tmp);
10170 10171 10172 10173 10174
    }

    return ret;
}

10175

10176 10177 10178 10179
/*
 * "net-edit" command
 */
static const vshCmdInfo info_network_edit[] = {
10180 10181
    {"help", N_("edit XML configuration for a network")},
    {"desc", N_("Edit the XML configuration for a network.")},
10182 10183 10184 10185
    {NULL, NULL}
};

static const vshCmdOptDef opts_network_edit[] = {
10186
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
10187 10188 10189 10190 10191 10192 10193 10194 10195 10196
    {NULL, 0, 0, NULL}
};

/* This is generated from this file by a sed script in the Makefile. */
#include "virsh-net-edit.c"

/*
 * "pool-edit" command
 */
static const vshCmdInfo info_pool_edit[] = {
10197 10198
    {"help", N_("edit XML configuration for a storage pool")},
    {"desc", N_("Edit the XML configuration for a storage pool.")},
10199 10200 10201 10202
    {NULL, NULL}
};

static const vshCmdOptDef opts_pool_edit[] = {
10203
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
10204 10205 10206 10207 10208 10209
    {NULL, 0, 0, NULL}
};

/* This is generated from this file by a sed script in the Makefile. */
#include "virsh-pool-edit.c"

K
Karel Zak 已提交
10210 10211 10212
/*
 * "quit" command
 */
10213
static const vshCmdInfo info_quit[] = {
10214
    {"help", N_("quit this interactive terminal")},
10215
    {"desc", ""},
10216
    {NULL, NULL}
K
Karel Zak 已提交
10217 10218
};

E
Eric Blake 已提交
10219
static bool
10220
cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
10221
{
E
Eric Blake 已提交
10222 10223
    ctl->imode = false;
    return true;
K
Karel Zak 已提交
10224 10225
}

10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240
/*
 * "snapshot-create" command
 */
static const vshCmdInfo info_snapshot_create[] = {
    {"help", N_("Create a snapshot")},
    {"desc", N_("Snapshot create")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_snapshot_create[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"xmlfile", VSH_OT_DATA, 0, N_("domain snapshot XML")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
10241
static bool
10242 10243 10244
cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
10245
    bool ret = false;
10246
    const char *from = NULL;
10247 10248 10249 10250 10251 10252 10253
    char *buffer = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    xmlDocPtr xml = NULL;
    xmlXPathContextPtr ctxt = NULL;
    char *doc = NULL;
    char *name = NULL;

10254
    if (!vshConnectionUsability(ctl, ctl->conn))
10255 10256 10257 10258 10259 10260
        goto cleanup;

    dom = vshCommandOptDomain(ctl, cmd, NULL);
    if (dom == NULL)
        goto cleanup;

10261
    if (vshCommandOptString(cmd, "xmlfile", &from) <= 0)
E
Eric Blake 已提交
10262
        buffer = vshStrdup(ctl, "<domainsnapshot/>");
10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306
    else {
        if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
            /* we have to report the error here because during cleanup
             * we'll run through virDomainFree(), which loses the
             * last error
             */
            virshReportError(ctl);
            goto cleanup;
        }
    }
    if (buffer == NULL) {
        vshError(ctl, "%s", _("Out of memory"));
        goto cleanup;
    }

    snapshot = virDomainSnapshotCreateXML(dom, buffer, 0);
    if (snapshot == NULL)
        goto cleanup;

    doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
    if (!doc)
        goto cleanup;

    xml = xmlReadDoc((const xmlChar *) doc, "domainsnapshot.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOWARNING);
    if (!xml)
        goto cleanup;
    ctxt = xmlXPathNewContext(xml);
    if (!ctxt)
        goto cleanup;

    name = virXPathString("string(/domainsnapshot/name)", ctxt);
    if (!name) {
        vshError(ctl, "%s",
                 _("Could not find 'name' element in domain snapshot XML"));
        goto cleanup;
    }

    vshPrint(ctl, _("Domain snapshot %s created"), name);
    if (from)
        vshPrint(ctl, _(" from '%s'"), from);
    vshPrint(ctl, "\n");

E
Eric Blake 已提交
10307
    ret = true;
10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337

cleanup:
    VIR_FREE(name);
    xmlXPathFreeContext(ctxt);
    if (xml)
        xmlFreeDoc(xml);
    if (snapshot)
        virDomainSnapshotFree(snapshot);
    VIR_FREE(doc);
    VIR_FREE(buffer);
    if (dom)
        virDomainFree(dom);

    return ret;
}

/*
 * "snapshot-current" command
 */
static const vshCmdInfo info_snapshot_current[] = {
    {"help", N_("Get the current snapshot")},
    {"desc", N_("Get the current snapshot")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_snapshot_current[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
10338
static bool
10339 10340 10341
cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
10342
    bool ret = false;
10343 10344 10345
    int current;
    virDomainSnapshotPtr snapshot = NULL;

10346
    if (!vshConnectionUsability(ctl, ctl->conn))
10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369
        goto cleanup;

    dom = vshCommandOptDomain(ctl, cmd, NULL);
    if (dom == NULL)
        goto cleanup;

    current = virDomainHasCurrentSnapshot(dom, 0);
    if (current < 0)
        goto cleanup;
    else if (current) {
        char *xml;

        if (!(snapshot = virDomainSnapshotCurrent(dom, 0)))
            goto cleanup;

        xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
        if (!xml)
            goto cleanup;

        vshPrint(ctl, "%s", xml);
        VIR_FREE(xml);
    }

E
Eric Blake 已提交
10370
    ret = true;
10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394

cleanup:
    if (snapshot)
        virDomainSnapshotFree(snapshot);
    if (dom)
        virDomainFree(dom);

    return ret;
}

/*
 * "snapshot-list" command
 */
static const vshCmdInfo info_snapshot_list[] = {
    {"help", N_("List snapshots for a domain")},
    {"desc", N_("Snapshot List")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_snapshot_list[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
10395
static bool
10396 10397 10398
cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
10399
    bool ret = false;
10400 10401
    int numsnaps;
    char **names = NULL;
10402
    int actual = 0;
10403 10404 10405 10406 10407 10408 10409 10410 10411 10412
    int i;
    xmlDocPtr xml = NULL;
    xmlXPathContextPtr ctxt = NULL;
    char *doc = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char *state = NULL;
    long creation;
    char timestr[100];
    struct tm time_info;

10413
    if (!vshConnectionUsability(ctl, ctl->conn))
10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424
        goto cleanup;

    dom = vshCommandOptDomain(ctl, cmd, NULL);
    if (dom == NULL)
        goto cleanup;

    numsnaps = virDomainSnapshotNum(dom, 0);

    if (numsnaps < 0)
        goto cleanup;

10425 10426
    vshPrintExtra(ctl, " %-20s %-25s %s\n", _("Name"), _("Creation Time"), _("State"));
    vshPrintExtra(ctl, "---------------------------------------------------\n");
10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471

    if (numsnaps) {
        if (VIR_ALLOC_N(names, numsnaps) < 0)
            goto cleanup;

        actual = virDomainSnapshotListNames(dom, names, numsnaps, 0);
        if (actual < 0)
            goto cleanup;

        qsort(&names[0], actual, sizeof(char*), namesorter);

        for (i = 0; i < actual; i++) {
            /* free up memory from previous iterations of the loop */
            VIR_FREE(state);
            if (snapshot)
                virDomainSnapshotFree(snapshot);
            xmlXPathFreeContext(ctxt);
            if (xml)
                xmlFreeDoc(xml);
            VIR_FREE(doc);

            snapshot = virDomainSnapshotLookupByName(dom, names[i], 0);
            if (snapshot == NULL)
                continue;

            doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
            if (!doc)
                continue;

            xml = xmlReadDoc((const xmlChar *) doc, "domainsnapshot.xml", NULL,
                             XML_PARSE_NOENT | XML_PARSE_NONET |
                             XML_PARSE_NOWARNING);
            if (!xml)
                continue;
            ctxt = xmlXPathNewContext(xml);
            if (!ctxt)
                continue;

            state = virXPathString("string(/domainsnapshot/state)", ctxt);
            if (state == NULL)
                continue;
            if (virXPathLong("string(/domainsnapshot/creationTime)", ctxt,
                             &creation) < 0)
                continue;
            localtime_r(&creation, &time_info);
10472
            strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", &time_info);
10473 10474 10475 10476 10477

            vshPrint(ctl, " %-20s %-25s %s\n", names[i], timestr, state);
        }
    }

E
Eric Blake 已提交
10478
    ret = true;
10479 10480 10481 10482 10483 10484 10485 10486 10487 10488

cleanup:
    /* this frees up memory from the last iteration of the loop */
    VIR_FREE(state);
    if (snapshot)
        virDomainSnapshotFree(snapshot);
    xmlXPathFreeContext(ctxt);
    if (xml)
        xmlFreeDoc(xml);
    VIR_FREE(doc);
10489 10490
    for (i = 0; i < actual; i++)
        VIR_FREE(names[i]);
10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512
    VIR_FREE(names);
    if (dom)
        virDomainFree(dom);

    return ret;
}

/*
 * "snapshot-dumpxml" command
 */
static const vshCmdInfo info_snapshot_dumpxml[] = {
    {"help", N_("Dump XML for a domain snapshot")},
    {"desc", N_("Snapshot Dump XML")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_snapshot_dumpxml[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
10513
static bool
10514 10515 10516
cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
10517
    bool ret = false;
10518
    const char *name = NULL;
10519 10520 10521
    virDomainSnapshotPtr snapshot = NULL;
    char *xml = NULL;

10522
    if (!vshConnectionUsability(ctl, ctl->conn))
10523 10524 10525 10526 10527 10528
        goto cleanup;

    dom = vshCommandOptDomain(ctl, cmd, NULL);
    if (dom == NULL)
        goto cleanup;

10529
    if (vshCommandOptString(cmd, "snapshotname", &name) <= 0)
10530 10531 10532 10533 10534 10535 10536 10537 10538 10539
        goto cleanup;

    snapshot = virDomainSnapshotLookupByName(dom, name, 0);
    if (snapshot == NULL)
        goto cleanup;

    xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
    if (!xml)
        goto cleanup;

10540
    vshPrint(ctl, "%s", xml);
10541

E
Eric Blake 已提交
10542
    ret = true;
10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554

cleanup:
    VIR_FREE(xml);
    if (snapshot)
        virDomainSnapshotFree(snapshot);
    if (dom)
        virDomainFree(dom);

    return ret;
}

/*
10555
 * "snapshot-revert" command
10556
 */
10557
static const vshCmdInfo info_snapshot_revert[] = {
10558 10559 10560 10561 10562
    {"help", N_("Revert a domain to a snapshot")},
    {"desc", N_("Revert domain to snapshot")},
    {NULL, NULL}
};

10563
static const vshCmdOptDef opts_snapshot_revert[] = {
10564 10565 10566 10567 10568
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
10569
static bool
10570
cmdDomainSnapshotRevert(vshControl *ctl, const vshCmd *cmd)
10571 10572
{
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
10573
    bool ret = false;
10574
    const char *name = NULL;
10575 10576
    virDomainSnapshotPtr snapshot = NULL;

10577
    if (!vshConnectionUsability(ctl, ctl->conn))
10578 10579 10580 10581 10582 10583
        goto cleanup;

    dom = vshCommandOptDomain(ctl, cmd, NULL);
    if (dom == NULL)
        goto cleanup;

10584
    if (vshCommandOptString(cmd, "snapshotname", &name) <= 0)
10585 10586 10587 10588 10589 10590 10591 10592 10593
        goto cleanup;

    snapshot = virDomainSnapshotLookupByName(dom, name, 0);
    if (snapshot == NULL)
        goto cleanup;

    if (virDomainRevertToSnapshot(snapshot, 0) < 0)
        goto cleanup;

E
Eric Blake 已提交
10594
    ret = true;
10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620

cleanup:
    if (snapshot)
        virDomainSnapshotFree(snapshot);
    if (dom)
        virDomainFree(dom);

    return ret;
}

/*
 * "snapshot-delete" command
 */
static const vshCmdInfo info_snapshot_delete[] = {
    {"help", N_("Delete a domain snapshot")},
    {"desc", N_("Snapshot Delete")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_snapshot_delete[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
    {"children", VSH_OT_BOOL, 0, N_("delete snapshot and all children")},
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
10621
static bool
10622 10623 10624
cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
10625
    bool ret = false;
10626
    const char *name = NULL;
10627 10628 10629
    virDomainSnapshotPtr snapshot = NULL;
    unsigned int flags = 0;

10630
    if (!vshConnectionUsability(ctl, ctl->conn))
10631 10632 10633 10634 10635 10636
        goto cleanup;

    dom = vshCommandOptDomain(ctl, cmd, NULL);
    if (dom == NULL)
        goto cleanup;

10637
    if (vshCommandOptString(cmd, "snapshotname", &name) <= 0)
10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649
        goto cleanup;

    if (vshCommandOptBool(cmd, "children"))
        flags |= VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN;

    snapshot = virDomainSnapshotLookupByName(dom, name, 0);
    if (snapshot == NULL)
        goto cleanup;

    if (virDomainSnapshotDelete(snapshot, flags) < 0)
        goto cleanup;

E
Eric Blake 已提交
10650
    ret = true;
10651 10652 10653 10654 10655 10656 10657 10658 10659 10660

cleanup:
    if (snapshot)
        virDomainSnapshotFree(snapshot);
    if (dom)
        virDomainFree(dom);

    return ret;
}

10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672
/*
 * "qemu-monitor-command" command
 */
static const vshCmdInfo info_qemu_monitor_command[] = {
    {"help", N_("Qemu Monitor Command")},
    {"desc", N_("Qemu Monitor Command")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_qemu_monitor_command[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"cmd", VSH_OT_DATA, VSH_OFLAG_REQ, N_("command")},
10673
    {"hmp", VSH_OT_BOOL, 0, N_("command is in human monitor protocol")},
10674 10675 10676
    {NULL, 0, 0, NULL}
};

E
Eric Blake 已提交
10677
static bool
10678 10679 10680
cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom = NULL;
E
Eric Blake 已提交
10681
    bool ret = false;
10682
    const char *monitor_cmd = NULL;
10683
    char *result = NULL;
10684
    unsigned int flags = 0;
10685 10686 10687 10688 10689 10690 10691 10692

    if (!vshConnectionUsability(ctl, ctl->conn))
        goto cleanup;

    dom = vshCommandOptDomain(ctl, cmd, NULL);
    if (dom == NULL)
        goto cleanup;

10693
    if (vshCommandOptString(cmd, "cmd", &monitor_cmd) <= 0) {
10694 10695 10696 10697
        vshError(ctl, "%s", _("missing monitor command"));
        goto cleanup;
    }

10698 10699 10700 10701
    if (vshCommandOptBool(cmd, "hmp"))
        flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP;

    if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0)
10702 10703 10704 10705
        goto cleanup;

    printf("%s\n", result);

E
Eric Blake 已提交
10706
    ret = true;
10707 10708 10709 10710 10711 10712 10713 10714 10715

cleanup:
    VIR_FREE(result);
    if (dom)
        virDomainFree(dom);

    return ret;
}

10716
static const vshCmdDef domManagementCmds[] = {
10717 10718 10719
    {"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device},
    {"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk},
    {"attach-interface", cmdAttachInterface, opts_attach_interface, info_attach_interface},
10720
    {"autostart", cmdAutostart, opts_autostart, info_autostart},
10721
    {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune},
10722
#ifndef WIN32
10723
    {"console", cmdConsole, opts_console, info_console},
10724
#endif
10725
    {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline},
10726
    {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare},
10727
    {"create", cmdCreate, opts_create, info_create},
10728
    {"define", cmdDefine, opts_define, info_define},
K
Karel Zak 已提交
10729
    {"destroy", cmdDestroy, opts_destroy, info_destroy},
10730 10731 10732
    {"detach-device", cmdDetachDevice, opts_detach_device, info_detach_device},
    {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk},
    {"detach-interface", cmdDetachInterface, opts_detach_interface, info_detach_interface},
K
Karel Zak 已提交
10733
    {"domid", cmdDomid, opts_domid, info_domid},
10734
    {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort},
10735
    {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo},
K
Karel Zak 已提交
10736
    {"domname", cmdDomname, opts_domname, info_domname},
10737
    {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
10738 10739
    {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, info_domxmlfromnative},
    {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, info_domxmltonative},
10740
    {"dump", cmdDump, opts_dump, info_dump},
10741
    {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
10742
    {"edit", cmdEdit, opts_edit, info_edit},
10743 10744
    {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave},
    {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, info_managedsaveremove},
E
Eric Blake 已提交
10745
    {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus},
10746
    {"memtune", cmdMemtune, opts_memtune, info_memtune},
10747
    {"migrate", cmdMigrate, opts_migrate, info_migrate},
10748
    {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime},
10749 10750 10751 10752 10753 10754 10755 10756
    {"reboot", cmdReboot, opts_reboot, info_reboot},
    {"restore", cmdRestore, opts_restore, info_restore},
    {"resume", cmdResume, opts_resume, info_resume},
    {"save", cmdSave, opts_save, info_save},
    {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo},
    {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
    {"setmem", cmdSetmem, opts_setmem, info_setmem},
    {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
10757
    {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi},
10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783
    {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
    {"start", cmdStart, opts_start, info_start},
    {"suspend", cmdSuspend, opts_suspend, info_suspend},
    {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},
    {"undefine", cmdUndefine, opts_undefine, info_undefine},
    {"update-device", cmdUpdateDevice, opts_update_device, info_update_device},
    {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount},
    {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
    {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
    {"version", cmdVersion, NULL, info_version},
    {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
    {NULL, NULL, NULL, NULL}
};

static const vshCmdDef domMonitoringCmds[] = {
    {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo},
    {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
    {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat},
    {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
    {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat},
    {"domstate", cmdDomstate, opts_domstate, info_domstate},
    {"list", cmdList, opts_list, info_list},
    {NULL, NULL, NULL, NULL}
};

static const vshCmdDef storagePoolCmds[] = {
10784 10785 10786 10787
    {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs,
     opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as},
    {"find-storage-pool-sources", cmdPoolDiscoverSources,
     opts_find_storage_pool_sources, info_find_storage_pool_sources},
10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813
    {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
    {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
    {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as},
    {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create},
    {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as},
    {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define},
    {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete},
    {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy},
    {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml},
    {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit},
    {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info},
    {"pool-list", cmdPoolList, opts_pool_list, info_pool_list},
    {"pool-name", cmdPoolName, opts_pool_name, info_pool_name},
    {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh},
    {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start},
    {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine},
    {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid},
    {NULL, NULL, NULL, NULL}
};

static const vshCmdDef storageVolCmds[] = {
    {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone},
    {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
    {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
    {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from},
    {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete},
10814
    {"vol-download", cmdVolDownload, opts_vol_download, info_vol_download },
10815 10816 10817 10818 10819 10820 10821
    {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml},
    {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info},
    {"vol-key", cmdVolKey, opts_vol_key, info_vol_key},
    {"vol-list", cmdVolList, opts_vol_list, info_vol_list},
    {"vol-name", cmdVolName, opts_vol_name, info_vol_name},
    {"vol-path", cmdVolPath, opts_vol_path, info_vol_path},
    {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool},
10822
    {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload },
10823 10824 10825
    {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe},
    {NULL, NULL, NULL, NULL}
};
10826

10827
static const vshCmdDef networkCmds[] = {
10828
    {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart},
10829 10830 10831 10832
    {"net-create", cmdNetworkCreate, opts_network_create, info_network_create},
    {"net-define", cmdNetworkDefine, opts_network_define, info_network_define},
    {"net-destroy", cmdNetworkDestroy, opts_network_destroy, info_network_destroy},
    {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, info_network_dumpxml},
10833
    {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit},
O
Osier Yang 已提交
10834
    {"net-info", cmdNetworkInfo, opts_network_info, info_network_info},
10835 10836 10837 10838 10839
    {"net-list", cmdNetworkList, opts_network_list, info_network_list},
    {"net-name", cmdNetworkName, opts_network_name, info_network_name},
    {"net-start", cmdNetworkStart, opts_network_start, info_network_start},
    {"net-undefine", cmdNetworkUndefine, opts_network_undefine, info_network_undefine},
    {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid},
10840 10841
    {NULL, NULL, NULL, NULL}
};
10842

10843 10844 10845
static const vshCmdDef nodedevCmds[] = {
    {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
    {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},
10846
    {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach},
10847 10848
    {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml},
    {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices},
10849 10850
    {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach},
    {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset},
10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865
    {NULL, NULL, NULL, NULL}
};

static const vshCmdDef ifaceCmds[] = {
    {"iface-define", cmdInterfaceDefine, opts_interface_define, info_interface_define},
    {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, info_interface_destroy},
    {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, info_interface_dumpxml},
    {"iface-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit},
    {"iface-list", cmdInterfaceList, opts_interface_list, info_interface_list},
    {"iface-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac},
    {"iface-name", cmdInterfaceName, opts_interface_name, info_interface_name},
    {"iface-start", cmdInterfaceStart, opts_interface_start, info_interface_start},
    {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, info_interface_undefine},
    {NULL, NULL, NULL, NULL}
};
10866

10867
static const vshCmdDef nwfilterCmds[] = {
10868 10869 10870
    {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, info_nwfilter_define},
    {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, info_nwfilter_dumpxml},
    {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, info_nwfilter_edit},
10871 10872 10873 10874
    {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, info_nwfilter_list},
    {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, info_nwfilter_undefine},
    {NULL, NULL, NULL, NULL}
};
10875

10876
static const vshCmdDef secretCmds[] = {
10877 10878 10879 10880
    {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define},
    {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml},
    {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value},
    {"secret-list", cmdSecretList, NULL, info_secret_list},
10881 10882 10883 10884
    {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value},
    {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine},
    {NULL, NULL, NULL, NULL}
};
10885

10886 10887 10888 10889 10890
static const vshCmdDef virshCmds[] = {
    {"cd", cmdCd, opts_cd, info_cd},
    {"echo", cmdEcho, opts_echo, info_echo},
    {"exit", cmdQuit, NULL, info_quit},
    {"help", cmdHelp, opts_help, info_help},
P
Paolo Bonzini 已提交
10891
    {"pwd", cmdPwd, NULL, info_pwd},
K
Karel Zak 已提交
10892
    {"quit", cmdQuit, NULL, info_quit},
10893 10894
    {NULL, NULL, NULL, NULL}
};
10895

10896
static const vshCmdDef snapshotCmds[] = {
10897 10898 10899 10900 10901
    {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create},
    {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, info_snapshot_current},
    {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete},
    {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, info_snapshot_dumpxml},
    {"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list},
10902
    {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, info_snapshot_revert},
10903 10904
    {NULL, NULL, NULL, NULL}
};
10905

10906 10907 10908 10909 10910
static const vshCmdDef hostAndHypervisorCmds[] = {
    {"capabilities", cmdCapabilities, NULL, info_capabilities},
    {"connect", cmdConnect, opts_connect, info_connect},
    {"freecell", cmdFreecell, opts_freecell, info_freecell},
    {"hostname", cmdHostname, NULL, info_hostname},
10911
    {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
10912
    {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, info_qemu_monitor_command},
E
Eric Blake 已提交
10913
    {"sysinfo", cmdSysinfo, NULL, info_sysinfo},
10914
    {"uri", cmdURI, NULL, info_uri},
10915
    {NULL, NULL, NULL, NULL}
K
Karel Zak 已提交
10916 10917
};

10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934
static const vshCmdGrp cmdGroups[] = {
    {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds},
    {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds},
    {VSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds},
    {VSH_CMD_GRP_IFACE, "interface", ifaceCmds},
    {VSH_CMD_GRP_NWFILTER, "filter", nwfilterCmds},
    {VSH_CMD_GRP_NETWORK, "network", networkCmds},
    {VSH_CMD_GRP_NODEDEV, "nodedev", nodedevCmds},
    {VSH_CMD_GRP_SECRET, "secret", secretCmds},
    {VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds},
    {VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds},
    {VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds},
    {VSH_CMD_GRP_VIRSH, "virsh", virshCmds},
    {NULL, NULL, NULL}
};


K
Karel Zak 已提交
10935 10936 10937 10938
/* ---------------
 * Utils for work with command definition
 * ---------------
 */
K
Karel Zak 已提交
10939
static const char *
10940
vshCmddefGetInfo(const vshCmdDef * cmd, const char *name)
10941
{
10942
    const vshCmdInfo *info;
10943

K
Karel Zak 已提交
10944
    for (info = cmd->info; info && info->name; info++) {
10945
        if (STREQ(info->name, name))
K
Karel Zak 已提交
10946 10947 10948 10949 10950
            return info->data;
    }
    return NULL;
}

10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982
static int
vshCmddefOptParse(const vshCmdDef *cmd, uint32_t* opts_need_arg,
                  uint32_t *opts_required)
{
    int i;
    bool optional = false;

    if (!cmd->opts)
        return 0;

    for (i = 0; cmd->opts[i].name; i++) {
        const vshCmdOptDef *opt = &cmd->opts[i];

        if (i > 31)
            return -1; /* too many options */
        if (opt->type == VSH_OT_BOOL) {
            if (opt->flag & VSH_OFLAG_REQ)
                return -1; /* bool options can't be mandatory */
            continue;
        }
        *opts_need_arg |= 1 << i;
        if (opt->flag & VSH_OFLAG_REQ) {
            if (optional)
                return -1; /* mandatory options must be listed first */
            *opts_required |= 1 << i;
        } else {
            optional = true;
        }
    }
    return 0;
}

10983
static const vshCmdOptDef *
10984 10985
vshCmddefGetOption(vshControl *ctl, const vshCmdDef *cmd, const char *name,
                   uint32_t *opts_seen)
10986
{
10987 10988 10989 10990
    int i;

    for (i = 0; cmd->opts && cmd->opts[i].name; i++) {
        const vshCmdOptDef *opt = &cmd->opts[i];
10991

10992 10993 10994 10995 10996 10997
        if (STREQ(opt->name, name)) {
            if (*opts_seen & (1 << i)) {
                vshError(ctl, _("option --%s already seen"), name);
                return NULL;
            }
            *opts_seen |= 1 << i;
K
Karel Zak 已提交
10998
            return opt;
10999 11000 11001 11002 11003
        }
    }

    vshError(ctl, _("command '%s' doesn't support option --%s"),
             cmd->name, name);
K
Karel Zak 已提交
11004 11005 11006
    return NULL;
}

11007
static const vshCmdOptDef *
11008 11009
vshCmddefGetData(const vshCmdDef *cmd, uint32_t *opts_need_arg,
                 uint32_t *opts_seen)
11010
{
11011
    int i;
11012
    const vshCmdOptDef *opt;
K
Karel Zak 已提交
11013

11014 11015 11016 11017 11018 11019 11020 11021 11022 11023
    if (!*opts_need_arg)
        return NULL;

    /* Grab least-significant set bit */
    i = count_one_bits(*opts_need_arg ^ (*opts_need_arg - 1)) - 1;
    opt = &cmd->opts[i];
    if (opt->type != VSH_OT_ARGV)
        *opts_need_arg &= ~(1 << i);
    *opts_seen |= 1 << i;
    return opt;
K
Karel Zak 已提交
11024 11025
}

11026 11027 11028
/*
 * Checks for required options
 */
11029
static int
11030 11031
vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd, uint32_t opts_required,
                    uint32_t opts_seen)
11032
{
11033
    const vshCmdDef *def = cmd->def;
11034 11035 11036 11037 11038 11039 11040 11041 11042
    int i;

    opts_required &= ~opts_seen;
    if (!opts_required)
        return 0;

    for (i = 0; def->opts[i].name; i++) {
        if (opts_required & (1 << i)) {
            const vshCmdOptDef *opt = &def->opts[i];
11043

11044 11045 11046 11047 11048
            vshError(ctl,
                     opt->type == VSH_OT_DATA ?
                     _("command '%s' requires <%s> option") :
                     _("command '%s' requires --%s option"),
                     def->name, opt->name);
11049 11050
        }
    }
11051
    return -1;
11052 11053
}

11054
static const vshCmdDef *
11055 11056
vshCmddefSearch(const char *cmdname)
{
11057
    const vshCmdGrp *g;
11058
    const vshCmdDef *c;
11059

11060 11061
    for (g = cmdGroups; g->name; g++) {
        for (c = g->commands; c->name; c++) {
11062
            if (STREQ(c->name, cmdname))
11063 11064 11065 11066
                return c;
        }
    }

K
Karel Zak 已提交
11067 11068 11069
    return NULL;
}

11070 11071 11072 11073 11074 11075
static const vshCmdGrp *
vshCmdGrpSearch(const char *grpname)
{
    const vshCmdGrp *g;

    for (g = cmdGroups; g->name; g++) {
11076
        if (STREQ(g->name, grpname) || STREQ(g->keyword, grpname))
11077 11078 11079 11080 11081 11082
            return g;
    }

    return NULL;
}

E
Eric Blake 已提交
11083
static bool
11084 11085 11086 11087 11088 11089 11090
vshCmdGrpHelp(vshControl *ctl, const char *grpname)
{
    const vshCmdGrp *grp = vshCmdGrpSearch(grpname);
    const vshCmdDef *cmd = NULL;

    if (!grp) {
        vshError(ctl, _("command group '%s' doesn't exist"), grpname);
E
Eric Blake 已提交
11091
        return false;
11092 11093 11094 11095 11096 11097 11098 11099 11100 11101
    } else {
        vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
                 grp->keyword);

        for (cmd = grp->commands; cmd->name; cmd++) {
            vshPrint(ctl, "    %-30s %s\n", cmd->name,
                     _(vshCmddefGetInfo(cmd, "help")));
        }
    }

E
Eric Blake 已提交
11102
    return true;
11103 11104
}

E
Eric Blake 已提交
11105
static bool
11106
vshCmddefHelp(vshControl *ctl, const char *cmdname)
11107
{
11108
    const vshCmdDef *def = vshCmddefSearch(cmdname);
11109

K
Karel Zak 已提交
11110
    if (!def) {
11111
        vshError(ctl, _("command '%s' doesn't exist"), cmdname);
E
Eric Blake 已提交
11112
        return false;
11113
    } else {
E
Eric Blake 已提交
11114 11115
        const char *desc = _(vshCmddefGetInfo(def, "desc"));
        const char *help = _(vshCmddefGetInfo(def, "help"));
11116
        char buf[256];
11117 11118 11119 11120 11121 11122
        uint32_t opts_need_arg;
        uint32_t opts_required;

        if (vshCmddefOptParse(def, &opts_need_arg, &opts_required)) {
            vshError(ctl, _("internal error: bad options in command: '%s'"),
                     def->name);
E
Eric Blake 已提交
11123
            return false;
11124
        }
K
Karel Zak 已提交
11125

11126
        fputs(_("  NAME\n"), stdout);
11127 11128
        fprintf(stdout, "    %s - %s\n", def->name, help);

11129 11130 11131 11132 11133
        fputs(_("\n  SYNOPSIS\n"), stdout);
        fprintf(stdout, "    %s", def->name);
        if (def->opts) {
            const vshCmdOptDef *opt;
            for (opt = def->opts; opt->name; opt++) {
11134
                const char *fmt = "%s";
11135 11136
                switch (opt->type) {
                case VSH_OT_BOOL:
11137
                    fmt = "[--%s]";
11138 11139
                    break;
                case VSH_OT_INT:
E
Eric Blake 已提交
11140
                    /* xgettext:c-format */
11141 11142
                    fmt = ((opt->flag & VSH_OFLAG_REQ) ? "<%s>"
                           : _("[--%s <number>]"));
11143 11144
                    break;
                case VSH_OT_STRING:
E
Eric Blake 已提交
11145 11146
                    /* xgettext:c-format */
                    fmt = _("[--%s <string>]");
11147 11148
                    break;
                case VSH_OT_DATA:
11149
                    fmt = ((opt->flag & VSH_OFLAG_REQ) ? "<%s>" : "[<%s>]");
11150 11151 11152 11153 11154 11155
                    break;
                case VSH_OT_ARGV:
                    /* xgettext:c-format */
                    fmt = _("[<string>]...");
                    break;
                default:
11156
                    assert(0);
11157
                }
11158
                fputc(' ', stdout);
E
Eric Blake 已提交
11159
                fprintf(stdout, fmt, opt->name);
11160
            }
K
Karel Zak 已提交
11161
        }
11162 11163 11164
        fputc('\n', stdout);

        if (desc[0]) {
11165
            /* Print the description only if it's not empty.  */
11166
            fputs(_("\n  DESCRIPTION\n"), stdout);
K
Karel Zak 已提交
11167 11168
            fprintf(stdout, "    %s\n", desc);
        }
11169

K
Karel Zak 已提交
11170
        if (def->opts) {
11171
            const vshCmdOptDef *opt;
11172
            fputs(_("\n  OPTIONS\n"), stdout);
11173
            for (opt = def->opts; opt->name; opt++) {
11174 11175
                switch (opt->type) {
                case VSH_OT_BOOL:
K
Karel Zak 已提交
11176
                    snprintf(buf, sizeof(buf), "--%s", opt->name);
11177 11178
                    break;
                case VSH_OT_INT:
11179 11180 11181
                    snprintf(buf, sizeof(buf),
                             (opt->flag & VSH_OFLAG_REQ) ? _("[--%s] <number>")
                             : _("--%s <number>"), opt->name);
11182 11183
                    break;
                case VSH_OT_STRING:
11184
                    /* OT_STRING should never be VSH_OFLAG_REQ */
11185
                    snprintf(buf, sizeof(buf), _("--%s <string>"), opt->name);
11186 11187
                    break;
                case VSH_OT_DATA:
11188 11189
                    snprintf(buf, sizeof(buf), _("[--%s] <string>"),
                             opt->name);
11190 11191 11192 11193 11194 11195 11196
                    break;
                case VSH_OT_ARGV:
                    /* Not really an option. */
                    continue;
                default:
                    assert(0);
                }
11197

E
Eric Blake 已提交
11198
                fprintf(stdout, "    %-15s  %s\n", buf, _(opt->help));
11199
            }
K
Karel Zak 已提交
11200 11201 11202
        }
        fputc('\n', stdout);
    }
E
Eric Blake 已提交
11203
    return true;
K
Karel Zak 已提交
11204 11205 11206 11207 11208 11209
}

/* ---------------
 * Utils for work with runtime commands data
 * ---------------
 */
11210 11211 11212
static void
vshCommandOptFree(vshCmdOpt * arg)
{
K
Karel Zak 已提交
11213 11214
    vshCmdOpt *a = arg;

11215
    while (a) {
K
Karel Zak 已提交
11216
        vshCmdOpt *tmp = a;
11217

K
Karel Zak 已提交
11218 11219
        a = a->next;

11220 11221
        VIR_FREE(tmp->data);
        VIR_FREE(tmp);
K
Karel Zak 已提交
11222 11223 11224 11225
    }
}

static void
11226
vshCommandFree(vshCmd *cmd)
11227
{
K
Karel Zak 已提交
11228 11229
    vshCmd *c = cmd;

11230
    while (c) {
K
Karel Zak 已提交
11231
        vshCmd *tmp = c;
11232

K
Karel Zak 已提交
11233 11234 11235 11236
        c = c->next;

        if (tmp->opts)
            vshCommandOptFree(tmp->opts);
11237
        VIR_FREE(tmp);
K
Karel Zak 已提交
11238 11239 11240 11241 11242 11243 11244
    }
}

/*
 * Returns option by name
 */
static vshCmdOpt *
11245
vshCommandOpt(const vshCmd *cmd, const char *name)
11246
{
K
Karel Zak 已提交
11247
    vshCmdOpt *opt = cmd->opts;
11248 11249

    while (opt) {
11250
        if (opt->def && STREQ(opt->def->name, name))
K
Karel Zak 已提交
11251 11252 11253 11254 11255 11256 11257
            return opt;
        opt = opt->next;
    }
    return NULL;
}

/*
11258 11259 11260 11261 11262 11263 11264 11265 11266
 * @cmd command reference
 * @name option name
 * @value result
 *
 * Convert option to int
 * Return value:
 * >0 if option found and valid (@value updated)
 * 0 in case option not found (@value untouched)
 * <0 in all other cases (@value untouched)
K
Karel Zak 已提交
11267 11268
 */
static int
11269
vshCommandOptInt(const vshCmd *cmd, const char *name, int *value)
11270
{
K
Karel Zak 已提交
11271
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
11272
    int ret = 0, num;
11273
    char *end_p = NULL;
11274

11275
    if ((arg != NULL) && (arg->data != NULL)) {
11276 11277 11278 11279 11280 11281
        num = strtol(arg->data, &end_p, 10);
        ret = -1;
        if ((arg->data != end_p) && (*end_p == 0)) {
            *value = num;
            ret = 1;
        }
11282
    }
11283
    return ret;
K
Karel Zak 已提交
11284 11285
}

11286 11287 11288 11289 11290 11291
/*
 * Convert option to unsigned long
 * See vshCommandOptInt()
 */
static int
vshCommandOptUL(const vshCmd *cmd, const char *name, unsigned long *value)
11292 11293
{
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
11294 11295
    int ret = 0;
    unsigned long num;
11296 11297 11298
    char *end_p = NULL;

    if ((arg != NULL) && (arg->data != NULL)) {
11299 11300 11301 11302 11303 11304
        num = strtoul(arg->data, &end_p, 10);
        ret = -1;
        if ((arg->data != end_p) && (*end_p == 0)) {
            *value = num;
            ret = 1;
        }
11305
    }
11306
    return ret;
11307 11308
}

K
Karel Zak 已提交
11309 11310
/*
 * Returns option as STRING
11311
 * See vshCommandOptInt()
K
Karel Zak 已提交
11312
 */
11313 11314
static int
vshCommandOptString(const vshCmd *cmd, const char *name, const char **value)
11315
{
K
Karel Zak 已提交
11316
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
11317 11318 11319
    int ret = 0;

    if (arg && arg->data) {
E
Eric Blake 已提交
11320 11321 11322 11323
        if (*arg->data
            || (arg->def && (arg->def->flag & VSH_OFLAG_EMPTY_OK))) {
            *value = arg->data;
            ret = 1;
11324 11325
        } else if (arg->def && ((arg->def->flag) & VSH_OFLAG_REQ)) {
            vshError(NULL, _("Missing required option '%s'"), name);
E
Eric Blake 已提交
11326 11327 11328 11329
            ret = -1;
        } else {
            /* Treat "--option ''" as if option had not been specified. */
            ret = 0;
11330 11331
        }
    }
11332

11333
    return ret;
K
Karel Zak 已提交
11334 11335
}

11336 11337
/*
 * Returns option as long long
11338
 * See vshCommandOptInt()
11339
 */
11340 11341 11342
static int
vshCommandOptLongLong(const vshCmd *cmd, const char *name,
                      long long *value)
11343 11344
{
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
11345 11346
    int ret = 0;
    long long num;
11347 11348
    char *end_p = NULL;

11349 11350 11351 11352 11353 11354 11355 11356 11357
    if ((arg != NULL) && (arg->data != NULL)) {
        num = strtoll(arg->data, &end_p, 10);
        ret = -1;
        if ((arg->data != end_p) && (*end_p == 0)) {
            *value = num;
            ret = 1;
        }
    }
    return ret;
11358 11359
}

11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380
static int
vshCommandOptULongLong(const vshCmd *cmd, const char *name,
                       unsigned long long *value)
{
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
    int ret = 0;
    unsigned long long num;
    char *end_p = NULL;

    if ((arg != NULL) && (arg->data != NULL)) {
        num = strtoull(arg->data, &end_p, 10);
        ret = -1;
        if ((arg->data != end_p) && (*end_p == 0)) {
            *value = num;
            ret = 1;
        }
    }
    return ret;
}


K
Karel Zak 已提交
11381
/*
E
Eric Blake 已提交
11382
 * Returns true/false if the option exists
K
Karel Zak 已提交
11383
 */
E
Eric Blake 已提交
11384
static bool
11385
vshCommandOptBool(const vshCmd *cmd, const char *name)
11386
{
E
Eric Blake 已提交
11387
    return vshCommandOpt(cmd, name) != NULL;
K
Karel Zak 已提交
11388 11389
}

11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410
/*
 * Returns the COUNT argv argument, or NULL after last argument.
 *
 * Requires that a VSH_OT_ARGV option with the name "" be last in the
 * list of supported options in CMD->def->opts.
 */
static char *
vshCommandOptArgv(const vshCmd *cmd, int count)
{
    vshCmdOpt *opt = cmd->opts;

    while (opt) {
        if (opt->def && opt->def->type == VSH_OT_ARGV) {
            if (count-- == 0)
                return opt->data;
        }
        opt = opt->next;
    }
    return NULL;
}

J
Jim Meyering 已提交
11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428
/* Determine whether CMD->opts includes an option with name OPTNAME.
   If not, give a diagnostic and return false.
   If so, return true.  */
static bool
cmd_has_option (vshControl *ctl, const vshCmd *cmd, const char *optname)
{
    /* Iterate through cmd->opts, to ensure that there is an entry
       with name OPTNAME and type VSH_OT_DATA. */
    bool found = false;
    const vshCmdOpt *opt;
    for (opt = cmd->opts; opt; opt = opt->next) {
        if (STREQ (opt->def->name, optname) && opt->def->type == VSH_OT_DATA) {
            found = true;
            break;
        }
    }

    if (!found)
11429
        vshError(ctl, _("internal error: virsh %s: no %s VSH_OT_DATA option"),
J
Jim Meyering 已提交
11430 11431 11432
                 cmd->def->name, optname);
    return found;
}
11433

K
Karel Zak 已提交
11434
static virDomainPtr
J
Jim Meyering 已提交
11435
vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
11436
                      const char **name, int flag)
11437
{
K
Karel Zak 已提交
11438
    virDomainPtr dom = NULL;
11439
    const char *n = NULL;
K
Karel Zak 已提交
11440
    int id;
J
Jim Meyering 已提交
11441 11442 11443
    const char *optname = "domain";
    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;
11444

11445
    if (vshCommandOptString(cmd, optname, &n) <= 0)
11446 11447
        return NULL;

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

K
Karel Zak 已提交
11451 11452
    if (name)
        *name = n;
11453

K
Karel Zak 已提交
11454
    /* try it by ID */
11455
    if (flag & VSH_BYID) {
11456
        if (virStrToLong_i(n, NULL, 10, &id) == 0 && id >= 0) {
K
Karel Zak 已提交
11457 11458 11459 11460
            vshDebug(ctl, 5, "%s: <%s> seems like domain ID\n",
                     cmd->def->name, optname);
            dom = virDomainLookupByID(ctl->conn, id);
        }
11461
    }
K
Karel Zak 已提交
11462
    /* try it by UUID */
11463
    if (dom==NULL && (flag & VSH_BYUUID) && strlen(n)==VIR_UUID_STRING_BUFLEN-1) {
D
Daniel Veillard 已提交
11464
        vshDebug(ctl, 5, "%s: <%s> trying as domain UUID\n",
11465
                 cmd->def->name, optname);
K
Karel Zak 已提交
11466
        dom = virDomainLookupByUUIDString(ctl->conn, n);
K
Karel Zak 已提交
11467
    }
K
Karel Zak 已提交
11468
    /* try it by NAME */
11469
    if (dom==NULL && (flag & VSH_BYNAME)) {
D
Daniel Veillard 已提交
11470
        vshDebug(ctl, 5, "%s: <%s> trying as domain NAME\n",
11471
                 cmd->def->name, optname);
K
Karel Zak 已提交
11472
        dom = virDomainLookupByName(ctl->conn, n);
11473
    }
K
Karel Zak 已提交
11474

11475
    if (!dom)
11476
        vshError(ctl, _("failed to get domain '%s'"), n);
11477

K
Karel Zak 已提交
11478 11479 11480
    return dom;
}

11481
static virNetworkPtr
J
Jim Meyering 已提交
11482
vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
11483
                       const char **name, int flag)
11484 11485
{
    virNetworkPtr network = NULL;
11486
    const char *n = NULL;
J
Jim Meyering 已提交
11487 11488 11489
    const char *optname = "network";
    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;
11490

11491
    if (vshCommandOptString(cmd, optname, &n) <= 0)
11492 11493 11494 11495 11496 11497 11498 11499 11500
        return NULL;

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

    if (name)
        *name = n;

    /* try it by UUID */
11501
    if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
D
Daniel Veillard 已提交
11502
        vshDebug(ctl, 5, "%s: <%s> trying as network UUID\n",
11503
                 cmd->def->name, optname);
11504 11505 11506 11507
        network = virNetworkLookupByUUIDString(ctl->conn, n);
    }
    /* try it by NAME */
    if (network==NULL && (flag & VSH_BYNAME)) {
D
Daniel Veillard 已提交
11508
        vshDebug(ctl, 5, "%s: <%s> trying as network NAME\n",
11509 11510 11511 11512 11513
                 cmd->def->name, optname);
        network = virNetworkLookupByName(ctl->conn, n);
    }

    if (!network)
11514
        vshError(ctl, _("failed to get network '%s'"), n);
11515 11516 11517 11518

    return network;
}

11519 11520 11521

static virNWFilterPtr
vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
11522
                        const char **name, int flag)
11523 11524
{
    virNWFilterPtr nwfilter = NULL;
11525
    const char *n = NULL;
11526 11527 11528 11529
    const char *optname = "nwfilter";
    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;

11530
    if (vshCommandOptString(cmd, optname, &n) <= 0)
11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557
        return NULL;

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

    if (name)
        *name = n;

    /* try it by UUID */
    if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
        vshDebug(ctl, 5, "%s: <%s> trying as nwfilter UUID\n",
                 cmd->def->name, optname);
        nwfilter = virNWFilterLookupByUUIDString(ctl->conn, n);
    }
    /* try it by NAME */
    if (nwfilter == NULL && (flag & VSH_BYNAME)) {
        vshDebug(ctl, 5, "%s: <%s> trying as nwfilter NAME\n",
                 cmd->def->name, optname);
        nwfilter = virNWFilterLookupByName(ctl->conn, n);
    }

    if (!nwfilter)
        vshError(ctl, _("failed to get nwfilter '%s'"), n);

    return nwfilter;
}

11558 11559
static virInterfacePtr
vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
11560
                         const char **name, int flag)
11561 11562
{
    virInterfacePtr iface = NULL;
11563
    const char *n = NULL;
11564 11565 11566 11567
    const char *optname = "interface";
    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;

11568
    if (vshCommandOptString(cmd, optname, &n) <= 0)
11569 11570 11571 11572 11573 11574 11575 11576 11577
        return NULL;

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

    if (name)
        *name = n;

    /* try it by NAME */
11578
    if ((flag & VSH_BYNAME)) {
11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590
        vshDebug(ctl, 5, "%s: <%s> trying as interface NAME\n",
                 cmd->def->name, optname);
        iface = virInterfaceLookupByName(ctl->conn, n);
    }
    /* try it by MAC */
    if ((iface == NULL) && (flag & VSH_BYMAC)) {
        vshDebug(ctl, 5, "%s: <%s> trying as interface MAC\n",
                 cmd->def->name, optname);
        iface = virInterfaceLookupByMACString(ctl->conn, n);
    }

    if (!iface)
11591
        vshError(ctl, _("failed to get interface '%s'"), n);
11592 11593 11594 11595

    return iface;
}

11596
static virStoragePoolPtr
11597
vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
11598
                    const char **name, int flag)
11599 11600
{
    virStoragePoolPtr pool = NULL;
11601
    const char *n = NULL;
11602

11603
    if (vshCommandOptString(cmd, optname, &n) <= 0)
11604 11605 11606 11607 11608 11609 11610 11611 11612
        return NULL;

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

    if (name)
        *name = n;

    /* try it by UUID */
11613
    if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
11614
        vshDebug(ctl, 5, "%s: <%s> trying as pool UUID\n",
11615
                 cmd->def->name, optname);
11616 11617 11618
        pool = virStoragePoolLookupByUUIDString(ctl->conn, n);
    }
    /* try it by NAME */
11619
    if (pool == NULL && (flag & VSH_BYNAME)) {
11620 11621 11622 11623 11624 11625
        vshDebug(ctl, 5, "%s: <%s> trying as pool NAME\n",
                 cmd->def->name, optname);
        pool = virStoragePoolLookupByName(ctl->conn, n);
    }

    if (!pool)
11626
        vshError(ctl, _("failed to get pool '%s'"), n);
11627 11628 11629 11630 11631

    return pool;
}

static virStorageVolPtr
11632
vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
11633 11634
                   const char *optname,
                   const char *pooloptname,
11635
                   const char **name, int flag)
11636 11637 11638
{
    virStorageVolPtr vol = NULL;
    virStoragePoolPtr pool = NULL;
11639
    const char *n = NULL, *p = NULL;
11640

11641
    if (vshCommandOptString(cmd, optname, &n) <= 0)
11642 11643
        return NULL;

11644 11645
    if (vshCommandOptString(cmd, pooloptname, &p) < 0) {
        vshError(ctl, "%s", _("missing option"));
11646
        return NULL;
11647
    }
11648 11649 11650 11651 11652 11653 11654 11655 11656 11657

    if (p)
        pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag);

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

    if (name)
        *name = n;

11658
    /* try it by name */
11659
    if (pool && (flag & VSH_BYNAME)) {
11660
        vshDebug(ctl, 5, "%s: <%s> trying as vol name\n",
11661 11662 11663
                 cmd->def->name, optname);
        vol = virStorageVolLookupByName(pool, n);
    }
11664
    /* try it by key */
11665 11666 11667 11668 11669
    if (vol == NULL && (flag & VSH_BYUUID)) {
        vshDebug(ctl, 5, "%s: <%s> trying as vol key\n",
                 cmd->def->name, optname);
        vol = virStorageVolLookupByKey(ctl->conn, n);
    }
11670
    /* try it by path */
11671 11672 11673 11674 11675 11676 11677
    if (vol == NULL && (flag & VSH_BYUUID)) {
        vshDebug(ctl, 5, "%s: <%s> trying as vol path\n",
                 cmd->def->name, optname);
        vol = virStorageVolLookupByPath(ctl->conn, n);
    }

    if (!vol)
11678
        vshError(ctl, _("failed to get vol '%s'"), n);
11679 11680 11681 11682 11683 11684 11685

    if (pool)
        virStoragePoolFree(pool);

    return vol;
}

11686
static virSecretPtr
11687
vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name)
11688 11689
{
    virSecretPtr secret = NULL;
11690
    const char *n = NULL;
11691 11692 11693 11694 11695
    const char *optname = "secret";

    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;

11696
    if (vshCommandOptString(cmd, optname, &n) <= 0)
11697 11698 11699 11700 11701 11702 11703 11704 11705 11706
        return NULL;

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

    if (name != NULL)
        *name = n;

    secret = virSecretLookupByUUIDString(ctl->conn, n);

    if (secret == NULL)
11707
        vshError(ctl, _("failed to get secret '%s'"), n);
11708 11709 11710 11711

    return secret;
}

K
Karel Zak 已提交
11712 11713 11714
/*
 * Executes command(s) and returns return code from last command
 */
E
Eric Blake 已提交
11715
static bool
11716
vshCommandRun(vshControl *ctl, const vshCmd *cmd)
11717
{
E
Eric Blake 已提交
11718
    bool ret = true;
11719 11720

    while (cmd) {
K
Karel Zak 已提交
11721
        struct timeval before, after;
11722
        bool enable_timing = ctl->timing;
11723

11724 11725 11726
        if ((ctl->conn == NULL) || (disconnected != 0))
            vshReconnect(ctl);

11727
        if (enable_timing)
K
Karel Zak 已提交
11728
            GETTIMEOFDAY(&before);
11729

K
Karel Zak 已提交
11730 11731
        ret = cmd->def->handler(ctl, cmd);

11732
        if (enable_timing)
K
Karel Zak 已提交
11733
            GETTIMEOFDAY(&after);
11734

11735
        if (!ret)
J
John Levon 已提交
11736 11737
            virshReportError(ctl);

11738
        /* try to automatically catch disconnections */
11739
        if (!ret &&
11740 11741 11742 11743 11744 11745 11746 11747 11748
            ((disconnected != 0) ||
             ((last_error != NULL) &&
              (((last_error->code == VIR_ERR_SYSTEM_ERROR) &&
                (last_error->domain == VIR_FROM_REMOTE)) ||
               (last_error->code == VIR_ERR_RPC) ||
               (last_error->code == VIR_ERR_NO_CONNECT) ||
               (last_error->code == VIR_ERR_INVALID_CONN)))))
            vshReconnect(ctl);

11749
        if (STREQ(cmd->def->name, "quit"))        /* hack ... */
K
Karel Zak 已提交
11750 11751
            return ret;

11752
        if (enable_timing)
11753
            vshPrint(ctl, _("\n(Time: %.3f ms)\n\n"),
11754 11755
                     DIFF_MSEC(&after, &before));
        else
K
Karel Zak 已提交
11756
            vshPrintExtra(ctl, "\n");
K
Karel Zak 已提交
11757 11758 11759 11760 11761 11762
        cmd = cmd->next;
    }
    return ret;
}

/* ---------------
11763
 * Command parsing
K
Karel Zak 已提交
11764 11765 11766
 * ---------------
 */

11767 11768 11769 11770 11771 11772 11773 11774 11775 11776
typedef enum {
    VSH_TK_ERROR, /* Failed to parse a token */
    VSH_TK_ARG, /* Arbitrary argument, might be option or empty */
    VSH_TK_SUBCMD_END, /* Separation between commands */
    VSH_TK_END /* No more commands */
} vshCommandToken;

typedef struct __vshCommandParser {
    vshCommandToken (*getNextArg)(vshControl *, struct __vshCommandParser *,
                                  char **);
L
Lai Jiangshan 已提交
11777
    /* vshCommandStringGetArg() */
11778
    char *pos;
L
Lai Jiangshan 已提交
11779 11780 11781
    /* vshCommandArgvGetArg() */
    char **arg_pos;
    char **arg_end;
11782 11783
} vshCommandParser;

E
Eric Blake 已提交
11784
static bool
11785
vshCommandParse(vshControl *ctl, vshCommandParser *parser)
11786
{
K
Karel Zak 已提交
11787 11788 11789
    char *tkdata = NULL;
    vshCmd *clast = NULL;
    vshCmdOpt *first = NULL;
11790

K
Karel Zak 已提交
11791 11792 11793 11794
    if (ctl->cmd) {
        vshCommandFree(ctl->cmd);
        ctl->cmd = NULL;
    }
11795

11796
    while (1) {
K
Karel Zak 已提交
11797
        vshCmdOpt *last = NULL;
11798
        const vshCmdDef *cmd = NULL;
11799
        vshCommandToken tk;
L
Lai Jiangshan 已提交
11800
        bool data_only = false;
11801 11802 11803
        uint32_t opts_need_arg = 0;
        uint32_t opts_required = 0;
        uint32_t opts_seen = 0;
11804

K
Karel Zak 已提交
11805
        first = NULL;
11806

11807
        while (1) {
11808
            const vshCmdOptDef *opt = NULL;
11809

K
Karel Zak 已提交
11810
            tkdata = NULL;
11811
            tk = parser->getNextArg(ctl, parser, &tkdata);
11812 11813

            if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
11814
                goto syntaxError;
H
Hu Tao 已提交
11815 11816
            if (tk != VSH_TK_ARG) {
                VIR_FREE(tkdata);
11817
                break;
H
Hu Tao 已提交
11818
            }
11819 11820

            if (cmd == NULL) {
K
Karel Zak 已提交
11821 11822
                /* first token must be command name */
                if (!(cmd = vshCmddefSearch(tkdata))) {
11823
                    vshError(ctl, _("unknown command: '%s'"), tkdata);
11824
                    goto syntaxError;   /* ... or ignore this command only? */
K
Karel Zak 已提交
11825
                }
11826 11827 11828 11829 11830 11831 11832
                if (vshCmddefOptParse(cmd, &opts_need_arg,
                                      &opts_required) < 0) {
                    vshError(ctl,
                             _("internal error: bad options in command: '%s'"),
                             tkdata);
                    goto syntaxError;
                }
11833
                VIR_FREE(tkdata);
L
Lai Jiangshan 已提交
11834 11835 11836 11837
            } else if (data_only) {
                goto get_data;
            } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
                       c_isalnum(tkdata[2])) {
11838 11839 11840 11841 11842
                char *optstr = strchr(tkdata + 2, '=');
                if (optstr) {
                    *optstr = '\0'; /* convert the '=' to '\0' */
                    optstr = vshStrdup(ctl, optstr + 1);
                }
11843 11844
                if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
                                               &opts_seen))) {
11845
                    VIR_FREE(optstr);
K
Karel Zak 已提交
11846 11847
                    goto syntaxError;
                }
11848
                VIR_FREE(tkdata);
K
Karel Zak 已提交
11849 11850 11851

                if (opt->type != VSH_OT_BOOL) {
                    /* option data */
11852 11853 11854
                    if (optstr)
                        tkdata = optstr;
                    else
11855
                        tk = parser->getNextArg(ctl, parser, &tkdata);
11856
                    if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
11857
                        goto syntaxError;
11858
                    if (tk != VSH_TK_ARG) {
11859
                        vshError(ctl,
11860
                                 _("expected syntax: --%s <%s>"),
11861 11862
                                 opt->name,
                                 opt->type ==
11863
                                 VSH_OT_INT ? _("number") : _("string"));
K
Karel Zak 已提交
11864 11865
                        goto syntaxError;
                    }
11866
                    opts_need_arg &= ~opts_seen;
11867 11868 11869 11870 11871 11872 11873 11874
                } else {
                    tkdata = NULL;
                    if (optstr) {
                        vshError(ctl, _("invalid '=' after option --%s"),
                                opt->name);
                        VIR_FREE(optstr);
                        goto syntaxError;
                    }
K
Karel Zak 已提交
11875
                }
L
Lai Jiangshan 已提交
11876 11877 11878 11879
            } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
                       tkdata[2] == '\0') {
                data_only = true;
                continue;
11880
            } else {
L
Lai Jiangshan 已提交
11881
get_data:
11882 11883
                if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
                                             &opts_seen))) {
11884
                    vshError(ctl, _("unexpected data '%s'"), tkdata);
K
Karel Zak 已提交
11885 11886 11887 11888 11889
                    goto syntaxError;
                }
            }
            if (opt) {
                /* save option */
11890
                vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
11891

K
Karel Zak 已提交
11892 11893 11894 11895
                arg->def = opt;
                arg->data = tkdata;
                arg->next = NULL;
                tkdata = NULL;
11896

K
Karel Zak 已提交
11897 11898 11899 11900 11901
                if (!first)
                    first = arg;
                if (last)
                    last->next = arg;
                last = arg;
11902

K
Karel Zak 已提交
11903
                vshDebug(ctl, 4, "%s: %s(%s): %s\n",
11904 11905
                         cmd->name,
                         opt->name,
11906 11907
                         opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
                         opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
K
Karel Zak 已提交
11908 11909
            }
        }
11910

D
Daniel Veillard 已提交
11911
        /* command parsed -- allocate new struct for the command */
K
Karel Zak 已提交
11912
        if (cmd) {
11913
            vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
11914

K
Karel Zak 已提交
11915 11916 11917 11918
            c->opts = first;
            c->def = cmd;
            c->next = NULL;

11919
            if (vshCommandCheckOpts(ctl, c, opts_required, opts_seen) < 0) {
11920
                VIR_FREE(c);
11921
                goto syntaxError;
11922
            }
11923

K
Karel Zak 已提交
11924 11925 11926 11927 11928 11929
            if (!ctl->cmd)
                ctl->cmd = c;
            if (clast)
                clast->next = c;
            clast = c;
        }
11930 11931 11932

        if (tk == VSH_TK_END)
            break;
K
Karel Zak 已提交
11933
    }
11934

E
Eric Blake 已提交
11935
    return true;
K
Karel Zak 已提交
11936

11937
 syntaxError:
11938
    if (ctl->cmd) {
K
Karel Zak 已提交
11939
        vshCommandFree(ctl->cmd);
11940 11941
        ctl->cmd = NULL;
    }
K
Karel Zak 已提交
11942 11943
    if (first)
        vshCommandOptFree(first);
11944
    VIR_FREE(tkdata);
E
Eric Blake 已提交
11945
    return false;
K
Karel Zak 已提交
11946 11947
}

11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965
/* --------------------
 * Command argv parsing
 * --------------------
 */

static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
{
    if (parser->arg_pos == parser->arg_end) {
        *res = NULL;
        return VSH_TK_END;
    }

    *res = vshStrdup(ctl, *parser->arg_pos);
    parser->arg_pos++;
    return VSH_TK_ARG;
}

E
Eric Blake 已提交
11966 11967
static bool
vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
11968 11969 11970 11971
{
    vshCommandParser parser;

    if (nargs <= 0)
E
Eric Blake 已提交
11972
        return false;
11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 12000 12001 12002 12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027 12028 12029 12030 12031 12032 12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044

    parser.arg_pos = argv;
    parser.arg_end = argv + nargs;
    parser.getNextArg = vshCommandArgvGetArg;
    return vshCommandParse(ctl, &parser);
}

/* ----------------------
 * Command string parsing
 * ----------------------
 */

static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
{
    bool single_quote = false;
    bool double_quote = false;
    int sz = 0;
    char *p = parser->pos;
    char *q = vshStrdup(ctl, p);

    *res = q;

    while (*p && (*p == ' ' || *p == '\t'))
        p++;

    if (*p == '\0')
        return VSH_TK_END;
    if (*p == ';') {
        parser->pos = ++p;             /* = \0 or begin of next command */
        return VSH_TK_SUBCMD_END;
    }

    while (*p) {
        /* end of token is blank space or ';' */
        if (!double_quote && !single_quote &&
            (*p == ' ' || *p == '\t' || *p == ';'))
            break;

        if (!double_quote && *p == '\'') { /* single quote */
            single_quote = !single_quote;
            p++;
            continue;
        } else if (!single_quote && *p == '\\') { /* escape */
            /*
             * The same as the bash, a \ in "" is an escaper,
             * but a \ in '' is not an escaper.
             */
            p++;
            if (*p == '\0') {
                vshError(ctl, "%s", _("dangling \\"));
                return VSH_TK_ERROR;
            }
        } else if (!single_quote && *p == '"') { /* double quote */
            double_quote = !double_quote;
            p++;
            continue;
        }

        *q++ = *p++;
        sz++;
    }
    if (double_quote) {
        vshError(ctl, "%s", _("missing \""));
        return VSH_TK_ERROR;
    }

    *q = '\0';
    parser->pos = p;
    return VSH_TK_ARG;
}

E
Eric Blake 已提交
12045 12046
static bool
vshCommandStringParse(vshControl *ctl, char *cmdstr)
12047 12048 12049 12050
{
    vshCommandParser parser;

    if (cmdstr == NULL || *cmdstr == '\0')
E
Eric Blake 已提交
12051
        return false;
12052 12053 12054 12055 12056 12057

    parser.pos = cmdstr;
    parser.getNextArg = vshCommandStringGetArg;
    return vshCommandParse(ctl, &parser);
}

K
Karel Zak 已提交
12058
/* ---------------
12059
 * Misc utils
K
Karel Zak 已提交
12060 12061
 * ---------------
 */
K
Karel Zak 已提交
12062
static const char *
12063 12064
vshDomainStateToString(int state)
{
K
Karel Zak 已提交
12065
    switch (state) {
12066
    case VIR_DOMAIN_RUNNING:
12067
        return N_("running");
12068
    case VIR_DOMAIN_BLOCKED:
12069
        return N_("idle");
12070
    case VIR_DOMAIN_PAUSED:
12071
        return N_("paused");
12072
    case VIR_DOMAIN_SHUTDOWN:
12073
        return N_("in shutdown");
12074
    case VIR_DOMAIN_SHUTOFF:
12075
        return N_("shut off");
12076
    case VIR_DOMAIN_CRASHED:
12077
        return N_("crashed");
12078
    default:
12079
        ;/*FALLTHROUGH*/
K
Karel Zak 已提交
12080
    }
12081
    return N_("no state");  /* = dom0 state */
K
Karel Zak 已提交
12082 12083
}

12084 12085 12086 12087
static const char *
vshDomainVcpuStateToString(int state)
{
    switch (state) {
12088
    case VIR_VCPU_OFFLINE:
12089
        return N_("offline");
12090
    case VIR_VCPU_BLOCKED:
12091
        return N_("idle");
12092
    case VIR_VCPU_RUNNING:
12093
        return N_("running");
12094
    default:
12095
        ;/*FALLTHROUGH*/
12096
    }
12097
    return N_("no state");
12098 12099
}

E
Eric Blake 已提交
12100
static bool
12101
vshConnectionUsability(vshControl *ctl, virConnectPtr conn)
12102
{
12103 12104
    /* TODO: use something like virConnectionState() to
     *       check usability of the connection
K
Karel Zak 已提交
12105 12106
     */
    if (!conn) {
12107
        vshError(ctl, "%s", _("no valid connection"));
E
Eric Blake 已提交
12108
        return false;
K
Karel Zak 已提交
12109
    }
E
Eric Blake 已提交
12110
    return true;
K
Karel Zak 已提交
12111 12112
}

K
Karel Zak 已提交
12113
static void
12114
vshDebug(vshControl *ctl, int level, const char *format, ...)
12115
{
K
Karel Zak 已提交
12116
    va_list ap;
12117
    char *str;
K
Karel Zak 已提交
12118

12119 12120 12121 12122
    va_start(ap, format);
    vshOutputLogFile(ctl, VSH_ERR_DEBUG, format, ap);
    va_end(ap);

K
Karel Zak 已提交
12123 12124 12125 12126
    if (level > ctl->debug)
        return;

    va_start(ap, format);
12127 12128 12129 12130 12131
    if (virVasprintf(&str, format, ap) < 0) {
        /* Skip debug messages on low memory */
        va_end(ap);
        return;
    }
K
Karel Zak 已提交
12132
    va_end(ap);
12133 12134
    fputs(str, stdout);
    VIR_FREE(str);
K
Karel Zak 已提交
12135 12136 12137
}

static void
12138
vshPrintExtra(vshControl *ctl, const char *format, ...)
12139
{
K
Karel Zak 已提交
12140
    va_list ap;
12141
    char *str;
12142

12143
    if (ctl && ctl->quiet)
K
Karel Zak 已提交
12144
        return;
12145

K
Karel Zak 已提交
12146
    va_start(ap, format);
12147 12148 12149 12150 12151
    if (virVasprintf(&str, format, ap) < 0) {
        vshError(ctl, "%s", _("Out of memory"));
        va_end(ap);
        return;
    }
K
Karel Zak 已提交
12152
    va_end(ap);
12153
    fputs(str, stdout);
12154
    VIR_FREE(str);
K
Karel Zak 已提交
12155 12156
}

K
Karel Zak 已提交
12157

K
Karel Zak 已提交
12158
static void
12159
vshError(vshControl *ctl, const char *format, ...)
12160
{
K
Karel Zak 已提交
12161
    va_list ap;
12162
    char *str;
12163

12164 12165 12166 12167 12168
    if (ctl != NULL) {
        va_start(ap, format);
        vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
        va_end(ap);
    }
12169

12170
    fputs(_("error: "), stderr);
12171

K
Karel Zak 已提交
12172
    va_start(ap, format);
12173 12174 12175
    /* We can't recursively call vshError on an OOM situation, so ignore
       failure here. */
    ignore_value(virVasprintf(&str, format, ap));
K
Karel Zak 已提交
12176 12177
    va_end(ap);

12178 12179
    fprintf(stderr, "%s\n", NULLSTR(str));
    VIR_FREE(str);
K
Karel Zak 已提交
12180 12181 12182
}

/*
12183
 * Initialize connection.
K
Karel Zak 已提交
12184
 */
E
Eric Blake 已提交
12185
static bool
12186
vshInit(vshControl *ctl)
12187
{
K
Karel Zak 已提交
12188
    if (ctl->conn)
E
Eric Blake 已提交
12189
        return false;
K
Karel Zak 已提交
12190

12191 12192
    vshOpenLogFile(ctl);

12193 12194
    /* set up the library error handler */
    virSetErrorFunc(NULL, virshErrorHandler);
12195

12196 12197 12198
    /* set up the signals handlers to catch disconnections */
    vshSetupSignals();

12199
    if (virEventRegisterDefaultImpl() < 0)
E
Eric Blake 已提交
12200
        return false;
12201

12202 12203 12204 12205
    ctl->conn = virConnectOpenAuth(ctl->name,
                                   virConnectAuthPtrDefault,
                                   ctl->readonly ? VIR_CONNECT_RO : 0);

12206

12207 12208 12209 12210
    /* This is not necessarily fatal.  All the individual commands check
     * vshConnectionUsability, except ones which don't need a connection
     * such as "help".
     */
12211
    if (!ctl->conn) {
12212
        virshReportError(ctl);
12213
        vshError(ctl, "%s", _("failed to connect to the hypervisor"));
E
Eric Blake 已提交
12214
        return false;
12215
    }
K
Karel Zak 已提交
12216

E
Eric Blake 已提交
12217
    return true;
K
Karel Zak 已提交
12218 12219
}

12220 12221
#define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT | O_SYNC)

12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240
/**
 * vshOpenLogFile:
 *
 * Open log file.
 */
static void
vshOpenLogFile(vshControl *ctl)
{
    struct stat st;

    if (ctl->logfile == NULL)
        return;

    /* check log file */
    if (stat(ctl->logfile, &st) == -1) {
        switch (errno) {
            case ENOENT:
                break;
            default:
12241
                vshError(ctl, "%s",
J
Jim Meyering 已提交
12242
                         _("failed to get the log file information"));
12243
                exit(EXIT_FAILURE);
12244 12245 12246
        }
    } else {
        if (!S_ISREG(st.st_mode)) {
12247 12248
            vshError(ctl, "%s", _("the log path is not a file"));
            exit(EXIT_FAILURE);
12249 12250 12251 12252
        }
    }

    /* log file open */
12253
    if ((ctl->log_fd = open(ctl->logfile, LOGFILE_FLAGS, FILE_MODE)) < 0) {
12254
        vshError(ctl, "%s",
J
Jim Meyering 已提交
12255
                 _("failed to open the log file. check the log file path"));
12256
        exit(EXIT_FAILURE);
12257 12258 12259 12260 12261 12262 12263 12264 12265
    }
}

/**
 * vshOutputLogFile:
 *
 * Outputting an error to log file.
 */
static void
12266 12267
vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format,
                 va_list ap)
12268
{
12269 12270 12271
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *str;
    size_t len;
12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285
    const char *lvl = "";
    struct timeval stTimeval;
    struct tm *stTm;

    if (ctl->log_fd == -1)
        return;

    /**
     * create log format
     *
     * [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message
    */
    gettimeofday(&stTimeval, NULL);
    stTm = localtime(&stTimeval.tv_sec);
12286 12287 12288 12289 12290 12291 12292 12293
    virBufferAsprintf(&buf, "[%d.%02d.%02d %02d:%02d:%02d %s] ",
                      (1900 + stTm->tm_year),
                      (1 + stTm->tm_mon),
                      stTm->tm_mday,
                      stTm->tm_hour,
                      stTm->tm_min,
                      stTm->tm_sec,
                      SIGN_NAME);
12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313
    switch (log_level) {
        case VSH_ERR_DEBUG:
            lvl = LVL_DEBUG;
            break;
        case VSH_ERR_INFO:
            lvl = LVL_INFO;
            break;
        case VSH_ERR_NOTICE:
            lvl = LVL_INFO;
            break;
        case VSH_ERR_WARNING:
            lvl = LVL_WARNING;
            break;
        case VSH_ERR_ERROR:
            lvl = LVL_ERROR;
            break;
        default:
            lvl = LVL_DEBUG;
            break;
    }
12314 12315 12316
    virBufferAsprintf(&buf, "%s ", lvl);
    virBufferVasprintf(&buf, msg_format, ap);
    virBufferAddChar(&buf, '\n');
12317

12318 12319
    if (virBufferError(&buf))
        goto error;
12320

12321 12322 12323 12324 12325
    str = virBufferContentAndReset(&buf);
    len = strlen(str);
    if (len > 1 && str[len - 2] == '\n') {
        str[len - 1] = '\0';
        len--;
12326
    }
12327

12328 12329 12330 12331 12332 12333 12334 12335 12336 12337 12338
    /* write log */
    if (safewrite(ctl->log_fd, str, len) < 0)
        goto error;

    return;

error:
    vshCloseLogFile(ctl);
    vshError(ctl, "%s", _("failed to write the log file"));
    virBufferFreeAndReset(&buf);
    VIR_FREE(str);
12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349
}

/**
 * vshCloseLogFile:
 *
 * Close log file.
 */
static void
vshCloseLogFile(vshControl *ctl)
{
    /* log file close */
12350 12351 12352
    if (VIR_CLOSE(ctl->log_fd) < 0) {
        vshError(ctl, _("%s: failed to write log file: %s"),
                 ctl->logfile ? ctl->logfile : "?", strerror (errno));
12353 12354 12355
    }

    if (ctl->logfile) {
12356
        VIR_FREE(ctl->logfile);
12357 12358 12359 12360
        ctl->logfile = NULL;
    }
}

12361
#ifdef USE_READLINE
12362

K
Karel Zak 已提交
12363 12364 12365 12366 12367
/* -----------------
 * Readline stuff
 * -----------------
 */

12368
/*
K
Karel Zak 已提交
12369 12370
 * Generator function for command completion.  STATE lets us
 * know whether to start from scratch; without any state
12371
 * (i.e. STATE == 0), then we start at the top of the list.
K
Karel Zak 已提交
12372 12373
 */
static char *
12374 12375
vshReadlineCommandGenerator(const char *text, int state)
{
12376
    static int grp_list_index, cmd_list_index, len;
K
Karel Zak 已提交
12377
    const char *name;
12378 12379
    const vshCmdGrp *grp;
    const vshCmdDef *cmds;
K
Karel Zak 已提交
12380 12381

    if (!state) {
12382 12383
        grp_list_index = 0;
        cmd_list_index = 0;
12384
        len = strlen(text);
K
Karel Zak 已提交
12385 12386
    }

12387 12388
    grp = cmdGroups;

K
Karel Zak 已提交
12389
    /* Return the next name which partially matches from the
12390
     * command list.
K
Karel Zak 已提交
12391
     */
12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405
    while (grp[grp_list_index].name) {
        cmds = grp[grp_list_index].commands;

        if (cmds[cmd_list_index].name) {
            while ((name = cmds[cmd_list_index].name)) {
                cmd_list_index++;

                if (STREQLEN(name, text, len))
                    return vshStrdup(NULL, name);
            }
        } else {
            cmd_list_index = 0;
            grp_list_index++;
        }
K
Karel Zak 已提交
12406 12407 12408 12409 12410 12411 12412
    }

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

static char *
12413 12414
vshReadlineOptionsGenerator(const char *text, int state)
{
K
Karel Zak 已提交
12415
    static int list_index, len;
12416
    static const vshCmdDef *cmd = NULL;
K
Karel Zak 已提交
12417
    const char *name;
K
Karel Zak 已提交
12418 12419 12420 12421 12422 12423 12424 12425 12426

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

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

12427
        cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
12428
        memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
K
Karel Zak 已提交
12429 12430 12431

        cmd = vshCmddefSearch(cmdname);
        list_index = 0;
12432
        len = strlen(text);
12433
        VIR_FREE(cmdname);
K
Karel Zak 已提交
12434 12435 12436 12437
    }

    if (!cmd)
        return NULL;
12438

12439 12440 12441
    if (!cmd->opts)
        return NULL;

K
Karel Zak 已提交
12442
    while ((name = cmd->opts[list_index].name)) {
12443
        const vshCmdOptDef *opt = &cmd->opts[list_index];
K
Karel Zak 已提交
12444
        char *res;
12445

K
Karel Zak 已提交
12446
        list_index++;
12447

K
Karel Zak 已提交
12448
        if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
12449 12450
            /* ignore non --option */
            continue;
12451

K
Karel Zak 已提交
12452
        if (len > 2) {
12453
            if (STRNEQLEN(name, text + 2, len - 2))
K
Karel Zak 已提交
12454 12455
                continue;
        }
12456
        res = vshMalloc(NULL, strlen(name) + 3);
12457
        snprintf(res, strlen(name) + 3,  "--%s", name);
K
Karel Zak 已提交
12458 12459 12460 12461 12462 12463 12464 12465
        return res;
    }

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

static char **
12466 12467 12468
vshReadlineCompletion(const char *text, int start,
                      int end ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
12469 12470
    char **matches = (char **) NULL;

12471
    if (start == 0)
K
Karel Zak 已提交
12472
        /* command name generator */
12473
        matches = rl_completion_matches(text, vshReadlineCommandGenerator);
K
Karel Zak 已提交
12474 12475
    else
        /* commands options */
12476
        matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
K
Karel Zak 已提交
12477 12478 12479 12480
    return matches;
}


12481 12482
static int
vshReadlineInit(vshControl *ctl)
12483
{
12484 12485
    char *userdir = NULL;

K
Karel Zak 已提交
12486 12487 12488 12489 12490
    /* 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;
12491 12492 12493

    /* Limit the total size of the history buffer */
    stifle_history(500);
12494 12495

    /* Prepare to read/write history from/to the ~/.virsh/history file */
12496
    userdir = virGetUserDirectory(getuid());
12497 12498 12499 12500 12501 12502

    if (userdir == NULL)
        return -1;

    if (virAsprintf(&ctl->historydir, "%s/.virsh", userdir) < 0) {
        vshError(ctl, "%s", _("Out of memory"));
12503
        VIR_FREE(userdir);
12504 12505 12506 12507 12508
        return -1;
    }

    if (virAsprintf(&ctl->historyfile, "%s/history", ctl->historydir) < 0) {
        vshError(ctl, "%s", _("Out of memory"));
12509
        VIR_FREE(userdir);
12510 12511 12512
        return -1;
    }

12513
    VIR_FREE(userdir);
12514 12515 12516 12517 12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531

    read_history(ctl->historyfile);

    return 0;
}

static void
vshReadlineDeinit (vshControl *ctl)
{
    if (ctl->historyfile != NULL) {
        if (mkdir(ctl->historydir, 0755) < 0 && errno != EEXIST) {
            char ebuf[1024];
            vshError(ctl, _("Failed to create '%s': %s"),
                     ctl->historydir, virStrerror(errno, ebuf, sizeof ebuf));
        } else
            write_history(ctl->historyfile);
    }

12532 12533
    VIR_FREE(ctl->historydir);
    VIR_FREE(ctl->historyfile);
K
Karel Zak 已提交
12534 12535
}

12536 12537 12538 12539 12540 12541
static char *
vshReadline (vshControl *ctl ATTRIBUTE_UNUSED, const char *prompt)
{
    return readline (prompt);
}

12542
#else /* !USE_READLINE */
12543

12544 12545 12546 12547 12548 12549 12550
static int
vshReadlineInit (vshControl *ctl ATTRIBUTE_UNUSED)
{
    /* empty */
    return 0;
}

12551
static void
12552
vshReadlineDeinit (vshControl *ctl ATTRIBUTE_UNUSED)
12553 12554 12555 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575
{
    /* empty */
}

static char *
vshReadline (vshControl *ctl, const char *prompt)
{
    char line[1024];
    char *r;
    int len;

    fputs (prompt, stdout);
    r = fgets (line, sizeof line, stdin);
    if (r == NULL) return NULL; /* EOF */

    /* Chomp trailing \n */
    len = strlen (r);
    if (len > 0 && r[len-1] == '\n')
        r[len-1] = '\0';

    return vshStrdup (ctl, r);
}

12576
#endif /* !USE_READLINE */
12577

K
Karel Zak 已提交
12578
/*
J
Jim Meyering 已提交
12579
 * Deinitialize virsh
K
Karel Zak 已提交
12580
 */
E
Eric Blake 已提交
12581
static bool
12582
vshDeinit(vshControl *ctl)
12583
{
12584
    vshReadlineDeinit(ctl);
12585
    vshCloseLogFile(ctl);
12586
    VIR_FREE(ctl->name);
K
Karel Zak 已提交
12587
    if (ctl->conn) {
12588 12589 12590
        int ret;
        if ((ret = virConnectClose(ctl->conn)) != 0) {
            vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret);
K
Karel Zak 已提交
12591 12592
        }
    }
D
Daniel P. Berrange 已提交
12593 12594
    virResetLastError();

E
Eric Blake 已提交
12595
    return true;
K
Karel Zak 已提交
12596
}
12597

K
Karel Zak 已提交
12598 12599 12600 12601
/*
 * Print usage
 */
static void
12602
vshUsage(void)
12603
{
12604
    const vshCmdGrp *grp;
12605
    const vshCmdDef *cmd;
12606

L
Lai Jiangshan 已提交
12607 12608
    fprintf(stdout, _("\n%s [options]... [<command_string>]"
                      "\n%s [options]... <command> [args...]\n\n"
12609 12610 12611 12612 12613 12614 12615 12616
                      "  options:\n"
                      "    -c | --connect <uri>    hypervisor connection URI\n"
                      "    -r | --readonly         connect readonly\n"
                      "    -d | --debug <num>      debug level [0-5]\n"
                      "    -h | --help             this help\n"
                      "    -q | --quiet            quiet mode\n"
                      "    -t | --timing           print timing information\n"
                      "    -l | --log <file>       output logging to file\n"
12617
                      "    -v | --version[=short]  program version\n"
E
Eric Blake 已提交
12618
                      "    -V | --version=long     version and full options\n\n"
12619
                      "  commands (non interactive mode):\n\n"), progname, progname);
12620

12621 12622
    for (grp = cmdGroups; grp->name; grp++) {
        fprintf(stdout, _(" %s (help keyword '%s')\n"), grp->name, grp->keyword);
12623

12624 12625 12626 12627 12628 12629 12630 12631 12632
        for (cmd = grp->commands; cmd->name; cmd++)
            fprintf(stdout,
                    "    %-30s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help")));

        fprintf(stdout, "\n");
    }

    fprintf(stdout, "%s",
            _("\n  (specify help <group> for details about the commands in the group)\n"));
12633 12634 12635
    fprintf(stdout, "%s",
            _("\n  (specify help <command> for details about the command)\n\n"));
    return;
K
Karel Zak 已提交
12636 12637
}

12638 12639 12640 12641 12642 12643 12644 12645 12646 12647
/*
 * Show version and options compiled in
 */
static void
vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED)
{
    /* FIXME - list a copyright blurb, as in GNU programs?  */
    vshPrint(ctl, _("Virsh command line tool of libvirt %s\n"), VERSION);
    vshPrint(ctl, _("See web site at %s\n\n"), "http://libvirt.org/");

L
Laine Stump 已提交
12648 12649
    vshPrint(ctl, "%s", _("Compiled with support for:\n"));
    vshPrint(ctl, "%s", _(" Hypervisors:"));
12650 12651 12652 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679 12680 12681 12682 12683 12684
#ifdef WITH_XEN
    vshPrint(ctl, " Xen");
#endif
#ifdef WITH_QEMU
    vshPrint(ctl, " QEmu/KVM");
#endif
#ifdef WITH_UML
    vshPrint(ctl, " UML");
#endif
#ifdef WITH_OPENVZ
    vshPrint(ctl, " OpenVZ");
#endif
#ifdef WITH_VBOX
    vshPrint(ctl, " VirtualBox");
#endif
#ifdef WITH_XENAPI
    vshPrint(ctl, " XenAPI");
#endif
#ifdef WITH_LXC
    vshPrint(ctl, " LXC");
#endif
#ifdef WITH_ESX
    vshPrint(ctl, " ESX");
#endif
#ifdef WITH_PHYP
    vshPrint(ctl, " PHYP");
#endif
#ifdef WITH_ONE
    vshPrint(ctl, " ONE");
#endif
#ifdef WITH_TEST
    vshPrint(ctl, " Test");
#endif
    vshPrint(ctl, "\n");

L
Laine Stump 已提交
12685
    vshPrint(ctl, "%s", _(" Networking:"));
12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705 12706 12707 12708 12709 12710 12711
#ifdef WITH_REMOTE
    vshPrint(ctl, " Remote");
#endif
#ifdef WITH_PROXY
    vshPrint(ctl, " Proxy");
#endif
#ifdef WITH_LIBVIRTD
    vshPrint(ctl, " Daemon");
#endif
#ifdef WITH_NETWORK
    vshPrint(ctl, " Network");
#endif
#ifdef WITH_BRIDGE
    vshPrint(ctl, " Bridging");
#endif
#ifdef WITH_NETCF
    vshPrint(ctl, " Netcf");
#endif
#ifdef WITH_NWFILTER
    vshPrint(ctl, " Nwfilter");
#endif
#ifdef WITH_VIRTUALPORT
    vshPrint(ctl, " VirtualPort");
#endif
    vshPrint(ctl, "\n");

L
Laine Stump 已提交
12712
    vshPrint(ctl, "%s", _(" Storage:"));
12713 12714 12715 12716 12717 12718 12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735
#ifdef WITH_STORAGE_DIR
    vshPrint(ctl, " Dir");
#endif
#ifdef WITH_STORAGE_DISK
    vshPrint(ctl, " Disk");
#endif
#ifdef WITH_STORAGE_FS
    vshPrint(ctl, " Filesystem");
#endif
#ifdef WITH_STORAGE_SCSI
    vshPrint(ctl, " SCSI");
#endif
#ifdef WITH_STORAGE_MPATH
    vshPrint(ctl, " Multipath");
#endif
#ifdef WITH_STORAGE_ISCSI
    vshPrint(ctl, " iSCSI");
#endif
#ifdef WITH_STORAGE_LVM
    vshPrint(ctl, " LVM");
#endif
    vshPrint(ctl, "\n");

L
Laine Stump 已提交
12736
    vshPrint(ctl, "%s", _(" Miscellaneous:"));
12737
#ifdef WITH_SECDRIVER_APPARMOR
12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759 12760
    vshPrint(ctl, " AppArmor");
#endif
#ifdef WITH_SECDRIVER_SELINUX
    vshPrint(ctl, " SELinux");
#endif
#ifdef WITH_SECRETS
    vshPrint(ctl, " Secrets");
#endif
#ifdef ENABLE_DEBUG
    vshPrint(ctl, " Debug");
#endif
#ifdef WITH_DTRACE
    vshPrint(ctl, " DTrace");
#endif
#ifdef USE_READLINE
    vshPrint(ctl, " Readline");
#endif
#ifdef WITH_DRIVER_MODULES
    vshPrint(ctl, " Modular");
#endif
    vshPrint(ctl, "\n");
}

K
Karel Zak 已提交
12761 12762 12763 12764
/*
 * argv[]:  virsh [options] [command]
 *
 */
E
Eric Blake 已提交
12765
static bool
12766
vshParseArgv(vshControl *ctl, int argc, char **argv)
12767
{
12768 12769
    bool help = false;
    int arg;
K
Karel Zak 已提交
12770
    struct option opt[] = {
E
Eric Blake 已提交
12771 12772 12773 12774 12775 12776 12777 12778 12779
        {"debug", required_argument, NULL, 'd'},
        {"help", no_argument, NULL, 'h'},
        {"quiet", no_argument, NULL, 'q'},
        {"timing", no_argument, NULL, 't'},
        {"version", optional_argument, NULL, 'v'},
        {"connect", required_argument, NULL, 'c'},
        {"readonly", no_argument, NULL, 'r'},
        {"log", required_argument, NULL, 'l'},
        {NULL, 0, NULL, 0}
12780 12781
    };

12782 12783 12784
    /* Standard (non-command) options. The leading + ensures that no
     * argument reordering takes place, so that command options are
     * not confused with top-level virsh options. */
12785
    while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:", opt, NULL)) != -1) {
12786
        switch (arg) {
12787
        case 'd':
D
Daniel Veillard 已提交
12788
            if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) {
L
Laine Stump 已提交
12789
                vshError(ctl, "%s", _("option -d takes a numeric argument"));
D
Daniel Veillard 已提交
12790 12791
                exit(EXIT_FAILURE);
            }
12792 12793
            break;
        case 'h':
12794
            help = true;
12795 12796
            break;
        case 'q':
E
Eric Blake 已提交
12797
            ctl->quiet = true;
12798 12799
            break;
        case 't':
E
Eric Blake 已提交
12800
            ctl->timing = true;
12801 12802 12803 12804
            break;
        case 'c':
            ctl->name = vshStrdup(ctl, optarg);
            break;
E
Eric Blake 已提交
12805 12806 12807 12808 12809 12810
        case 'v':
            if (STRNEQ_NULLABLE(optarg, "long")) {
                puts(VERSION);
                exit(EXIT_SUCCESS);
            }
            /* fall through */
12811 12812 12813
        case 'V':
            vshShowVersion(ctl);
            exit(EXIT_SUCCESS);
12814
        case 'r':
E
Eric Blake 已提交
12815
            ctl->readonly = true;
12816
            break;
12817 12818 12819
        case 'l':
            ctl->logfile = vshStrdup(ctl, optarg);
            break;
12820
        default:
12821 12822
            vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
            exit(EXIT_FAILURE);
K
Karel Zak 已提交
12823 12824 12825 12826
        }
    }

    if (help) {
12827 12828
        if (optind < argc) {
            vshError(ctl, _("extra argument '%s'. See --help."), argv[optind]);
12829 12830
            exit(EXIT_FAILURE);
        }
12831 12832 12833

        /* list all command */
        vshUsage();
K
Karel Zak 已提交
12834
        exit(EXIT_SUCCESS);
12835 12836
    }

12837
    if (argc > optind) {
K
Karel Zak 已提交
12838
        /* parse command */
E
Eric Blake 已提交
12839
        ctl->imode = false;
12840 12841 12842
        if (argc - optind == 1) {
            vshDebug(ctl, 2, "commands: \"%s\"\n", argv[optind]);
            return vshCommandStringParse(ctl, argv[optind]);
L
Lai Jiangshan 已提交
12843
        } else {
12844
            return vshCommandArgvParse(ctl, argc - optind, argv + optind);
K
Karel Zak 已提交
12845 12846
        }
    }
E
Eric Blake 已提交
12847
    return true;
K
Karel Zak 已提交
12848 12849
}

12850 12851 12852 12853
int
main(int argc, char **argv)
{
    vshControl _ctl, *ctl = &_ctl;
12854
    char *defaultConn;
E
Eric Blake 已提交
12855
    bool ret = true;
K
Karel Zak 已提交
12856

12857 12858
    if (!setlocale(LC_ALL, "")) {
        perror("setlocale");
12859
        /* failure to setup locale is not fatal */
12860
    }
12861
    if (!bindtextdomain(PACKAGE, LOCALEDIR)) {
12862
        perror("bindtextdomain");
E
Eric Blake 已提交
12863
        return EXIT_FAILURE;
12864
    }
12865
    if (!textdomain(PACKAGE)) {
12866
        perror("textdomain");
E
Eric Blake 已提交
12867
        return EXIT_FAILURE;
12868 12869
    }

12870
    if (!(progname = strrchr(argv[0], '/')))
K
Karel Zak 已提交
12871 12872 12873
        progname = argv[0];
    else
        progname++;
12874

K
Karel Zak 已提交
12875
    memset(ctl, 0, sizeof(vshControl));
E
Eric Blake 已提交
12876
    ctl->imode = true;          /* default is interactive mode */
12877
    ctl->log_fd = -1;           /* Initialize log file descriptor */
K
Karel Zak 已提交
12878

12879
    if ((defaultConn = getenv("VIRSH_DEFAULT_CONNECT_URI"))) {
E
Eric Blake 已提交
12880
        ctl->name = vshStrdup(ctl, defaultConn);
12881 12882
    }

D
Daniel P. Berrange 已提交
12883 12884
    if (!vshParseArgv(ctl, argc, argv)) {
        vshDeinit(ctl);
K
Karel Zak 已提交
12885
        exit(EXIT_FAILURE);
D
Daniel P. Berrange 已提交
12886
    }
12887

D
Daniel P. Berrange 已提交
12888 12889
    if (!vshInit(ctl)) {
        vshDeinit(ctl);
K
Karel Zak 已提交
12890
        exit(EXIT_FAILURE);
D
Daniel P. Berrange 已提交
12891
    }
12892

K
Karel Zak 已提交
12893
    if (!ctl->imode) {
12894
        ret = vshCommandRun(ctl, ctl->cmd);
12895
    } else {
K
Karel Zak 已提交
12896 12897
        /* interactive mode */
        if (!ctl->quiet) {
K
Karel Zak 已提交
12898
            vshPrint(ctl,
12899
                     _("Welcome to %s, the virtualization interactive terminal.\n\n"),
12900
                     progname);
J
Jim Meyering 已提交
12901
            vshPrint(ctl, "%s",
12902
                     _("Type:  'help' for help with commands\n"
12903
                       "       'quit' to quit\n\n"));
K
Karel Zak 已提交
12904
        }
12905 12906 12907 12908 12909 12910

        if (vshReadlineInit(ctl) < 0) {
            vshDeinit(ctl);
            exit(EXIT_FAILURE);
        }

K
Karel Zak 已提交
12911
        do {
12912
            const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW;
12913
            ctl->cmdstr =
12914
                vshReadline(ctl, prompt);
12915 12916
            if (ctl->cmdstr == NULL)
                break;          /* EOF */
K
Karel Zak 已提交
12917
            if (*ctl->cmdstr) {
12918
#if USE_READLINE
K
Karel Zak 已提交
12919
                add_history(ctl->cmdstr);
12920
#endif
12921
                if (vshCommandStringParse(ctl, ctl->cmdstr))
K
Karel Zak 已提交
12922 12923
                    vshCommandRun(ctl, ctl->cmd);
            }
12924
            VIR_FREE(ctl->cmdstr);
12925
        } while (ctl->imode);
K
Karel Zak 已提交
12926

12927 12928
        if (ctl->cmdstr == NULL)
            fputc('\n', stdout);        /* line break after alone prompt */
K
Karel Zak 已提交
12929
    }
12930

K
Karel Zak 已提交
12931 12932
    vshDeinit(ctl);
    exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
12933
}