virsh.c 253.1 KB
Newer Older
1
/*
2
 * virsh.c: a Xen shell used to exercise the libvirt API
3
 *
J
Jim Meyering 已提交
4
 * Copyright (C) 2005, 2007-2010 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>
J
Jim Meyering 已提交
24
#include "c-ctype.h"
25
#include <fcntl.h>
26
#include <locale.h>
27
#include <time.h>
28
#include <limits.h>
29
#include <assert.h>
30 31
#include <errno.h>
#include <sys/stat.h>
32
#include <inttypes.h>
33
#include <signal.h>
K
Karel Zak 已提交
34

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

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

45
#include "internal.h"
46
#include "virterror_internal.h"
47
#include "base64.h"
48
#include "buf.h"
49
#include "console.h"
50
#include "util.h"
51
#include "memory.h"
K
Karel Zak 已提交
52 53 54 55

static char *progname;

#ifndef TRUE
56 57
# define TRUE 1
# define FALSE 0
K
Karel Zak 已提交
58 59
#endif

60 61
#define VIRSH_MAX_XML_FILE 10*1024*1024

K
Karel Zak 已提交
62 63 64 65 66 67 68 69
#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)

70 71 72 73 74 75 76 77 78 79 80 81 82 83
/**
 * 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"

A
Atsushi SAKAI 已提交
84 85 86
#ifndef WEXITSTATUS
# define WEXITSTATUS(x) ((x) & 0xff)
#endif
87 88 89 90 91 92 93 94 95 96 97 98 99
/**
 * vshErrorLevel:
 *
 * Indicates the level of an log message
 */
typedef enum {
    VSH_ERR_DEBUG = 0,
    VSH_ERR_INFO,
    VSH_ERR_NOTICE,
    VSH_ERR_WARNING,
    VSH_ERR_ERROR
} vshErrorLevel;

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

/*
121
 * vshCmdOptType - command option type
122
 */
K
Karel Zak 已提交
123
typedef enum {
124 125 126 127 128
    VSH_OT_NONE = 0,            /* none */
    VSH_OT_BOOL,                /* boolean option */
    VSH_OT_STRING,              /* string option */
    VSH_OT_INT,                 /* int option */
    VSH_OT_DATA                 /* string data (as non-option) */
K
Karel Zak 已提交
129 130 131 132 133
} vshCmdOptType;

/*
 * Command Option Flags
 */
134 135
#define VSH_OFLAG_NONE    0     /* without flags */
#define VSH_OFLAG_REQ    (1 << 1)       /* option required */
K
Karel Zak 已提交
136 137 138 139 140 141 142 143

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

/*
 * vshCmdInfo -- information about command
 */
144 145 146
typedef struct {
    const char *name;           /* name of information */
    const char *data;           /* information */
K
Karel Zak 已提交
147 148 149 150 151
} vshCmdInfo;

/*
 * vshCmdOptDef - command option definition
 */
152 153 154 155 156
typedef struct {
    const char *name;           /* the name of option */
    vshCmdOptType type;         /* option type */
    int flag;                   /* flags */
    const char *help;           /* help string */
K
Karel Zak 已提交
157 158 159 160 161 162
} vshCmdOptDef;

/*
 * vshCmdOpt - command options
 */
typedef struct vshCmdOpt {
163
    const vshCmdOptDef *def;    /* pointer to relevant option */
164 165
    char *data;                 /* allocated data */
    struct vshCmdOpt *next;
K
Karel Zak 已提交
166 167 168 169 170
} vshCmdOpt;

/*
 * vshCmdDef - command definition
 */
171 172
typedef struct {
    const char *name;
173
    int (*handler) (vshControl *, const vshCmd *);    /* command handler */
174 175
    const vshCmdOptDef *opts;   /* definition of command options */
    const vshCmdInfo *info;     /* details about command */
K
Karel Zak 已提交
176 177 178 179 180 181
} vshCmdDef;

/*
 * vshCmd - parsed command
 */
typedef struct __vshCmd {
182
    const vshCmdDef *def;       /* command definition */
183 184
    vshCmdOpt *opts;            /* list of command arguments */
    struct __vshCmd *next;      /* next command */
K
Karel Zak 已提交
185 186 187 188 189 190
} __vshCmd;

/*
 * vshControl
 */
typedef struct __vshControl {
K
Karel Zak 已提交
191
    char *name;                 /* connection name */
192
    virConnectPtr conn;         /* connection to hypervisor (MAY BE NULL) */
193 194 195 196 197 198
    vshCmd *cmd;                /* the current command */
    char *cmdstr;               /* string with command */
    int imode;                  /* interactive mode? */
    int quiet;                  /* quiet mode */
    int debug;                  /* print debug messages? */
    int timing;                 /* print timing info? */
199 200 201
    int readonly;               /* connect readonly (first time only, not
                                 * during explicit connect command)
                                 */
202 203
    char *logfile;              /* log file name */
    int log_fd;                 /* log file descriptor */
204 205
    char *historydir;           /* readline history directory name */
    char *historyfile;          /* readline history file name */
K
Karel Zak 已提交
206
} __vshControl;
207

208

209
static const vshCmdDef commands[];
K
Karel Zak 已提交
210

211 212
static void vshError(vshControl *ctl, const char *format, ...)
    ATTRIBUTE_FMT_PRINTF(2, 3);
213 214
static int vshInit(vshControl *ctl);
static int vshDeinit(vshControl *ctl);
215
static void vshUsage(void);
216 217 218
static void vshOpenLogFile(vshControl *ctl);
static void vshOutputLogFile(vshControl *ctl, int log_level, const char *format, va_list ap);
static void vshCloseLogFile(vshControl *ctl);
K
Karel Zak 已提交
219

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

222
static const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info);
223
static const vshCmdDef *vshCmddefSearch(const char *cmdname);
224
static int vshCmddefHelp(vshControl *ctl, const char *name);
K
Karel Zak 已提交
225

226 227 228
static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found);
static char *vshCommandOptString(const vshCmd *cmd, const char *name,
229
                                 int *found);
230
#if 0
231
static int vshCommandOptStringList(const vshCmd *cmd, const char *name, char ***data);
232
#endif
233
static int vshCommandOptBool(const vshCmd *cmd, const char *name);
K
Karel Zak 已提交
234

235 236 237
#define VSH_BYID     (1 << 1)
#define VSH_BYUUID   (1 << 2)
#define VSH_BYNAME   (1 << 3)
238
#define VSH_BYMAC    (1 << 4)
K
Karel Zak 已提交
239

240
static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
J
Jim Meyering 已提交
241
                                          char **name, int flag);
K
Karel Zak 已提交
242 243

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

247
static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
J
Jim Meyering 已提交
248
                                            char **name, int flag);
249 250

/* default is lookup by Name and UUID */
J
Jim Meyering 已提交
251 252
#define vshCommandOptNetwork(_ctl, _cmd, _name)                    \
    vshCommandOptNetworkBy(_ctl, _cmd, _name,                      \
253 254
                           VSH_BYUUID|VSH_BYNAME)

255 256 257 258 259 260 261 262
static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
                                                char **name, int flag);

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

263
static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd,
264 265 266 267 268 269 270
                            const char *optname, char **name, int flag);

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

271
static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
272 273 274 275 276 277 278 279 280
                                           const char *optname,
                                           const char *pooloptname,
                                           char **name, int flag);

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

281 282 283
static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd,
                                        char **name);

284
static void vshPrintExtra(vshControl *ctl, const char *format, ...)
285
    ATTRIBUTE_FMT_PRINTF(2, 3);
286
static void vshDebug(vshControl *ctl, int level, const char *format, ...)
287
    ATTRIBUTE_FMT_PRINTF(3, 4);
K
Karel Zak 已提交
288 289

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

K
Karel Zak 已提交
292
static const char *vshDomainStateToString(int state);
293
static const char *vshDomainVcpuStateToString(int state);
294
static int vshConnectionUsability(vshControl *ctl, virConnectPtr conn,
295
                                  int showerror);
K
Karel Zak 已提交
296

297 298 299 300
static char *editWriteToTempFile (vshControl *ctl, const char *doc);
static int   editFile (vshControl *ctl, const char *filename);
static char *editReadBackFile (vshControl *ctl, const char *filename);

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

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

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

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

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330

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;

  return strcasecmp(*sa, *sb);
}

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
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 已提交
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
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)
{
378 379 380 381 382 383 384 385
    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)
386
            return;
387
    }
J
John Levon 已提交
388 389

    if (last_error->code == VIR_ERR_OK) {
390
        vshError(ctl, "%s", _("unknown error"));
J
John Levon 已提交
391 392 393
        goto out;
    }

394
    vshError(ctl, "%s", last_error->message);
J
John Levon 已提交
395 396 397 398 399 400

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

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
/*
 * Detection of disconnections and automatic reconnection support
 */
static int disconnected = 0; /* we may have been disconnected */

/*
 * 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
 */
static void vshCatchDisconnect(int sig, siginfo_t * siginfo,
                               void* context ATTRIBUTE_UNUSED) {
    if ((sig == SIGPIPE) || (siginfo->si_signo == SIGPIPE))
        disconnected++;
}

/*
 * vshSetupSignals:
 *
 * Catch SIGPIPE signals which may arise when disconnection
 * from libvirtd occurs
 */
L
Laine Stump 已提交
424
static void
425 426 427 428 429 430 431 432 433 434 435 436 437
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 已提交
438
 * Reconnect after a disconnect from libvirtd
439 440
 *
 */
L
Laine Stump 已提交
441
static void
442 443 444 445 446 447 448 449 450 451 452 453 454
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;
}
455

K
Karel Zak 已提交
456 457 458 459 460 461
/* ---------------
 * Commands
 * ---------------
 */

/*
462
 * "help" command
K
Karel Zak 已提交
463
 */
464
static const vshCmdInfo info_help[] = {
465 466
    {"help", N_("print help")},
    {"desc", N_("Prints global help or command specific help.")},
467

468
    {NULL, NULL}
K
Karel Zak 已提交
469 470
};

471
static const vshCmdOptDef opts_help[] = {
472
    {"command", VSH_OT_DATA, 0, N_("name of command")},
473
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
474 475 476
};

static int
477
cmdHelp(vshControl *ctl, const vshCmd *cmd)
478
{
K
Karel Zak 已提交
479
    const char *cmdname = vshCommandOptString(cmd, "command", NULL);
K
Karel Zak 已提交
480 481

    if (!cmdname) {
482
        const vshCmdDef *def;
483

J
Jim Meyering 已提交
484
        vshPrint(ctl, "%s", _("Commands:\n\n"));
485
        for (def = commands; def->name; def++)
K
Karel Zak 已提交
486
            vshPrint(ctl, "    %-15s %s\n", def->name,
E
Eric Blake 已提交
487
                     _(vshCmddefGetInfo(def, "help")));
K
Karel Zak 已提交
488 489
        return TRUE;
    }
490
    return vshCmddefHelp(ctl, cmdname);
K
Karel Zak 已提交
491 492
}

493 494 495
/*
 * "autostart" command
 */
496
static const vshCmdInfo info_autostart[] = {
497
    {"help", N_("autostart a domain")},
498
    {"desc",
499
     N_("Configure a domain to be automatically started at boot.")},
500 501 502
    {NULL, NULL}
};

503
static const vshCmdOptDef opts_autostart[] = {
504 505
    {"domain",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
506 507 508 509
    {NULL, 0, 0, NULL}
};

static int
510
cmdAutostart(vshControl *ctl, const vshCmd *cmd)
511 512 513 514 515 516 517 518
{
    virDomainPtr dom;
    char *name;
    int autostart;

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

J
Jim Meyering 已提交
519
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
520 521 522 523 524
        return FALSE;

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

    if (virDomainSetAutostart(dom, autostart) < 0) {
525
        if (autostart)
526
            vshError(ctl, _("Failed to mark domain %s as autostarted"), name);
527
        else
528
            vshError(ctl, _("Failed to unmark domain %s as autostarted"), name);
529 530 531 532
        virDomainFree(dom);
        return FALSE;
    }

533
    if (autostart)
534
        vshPrint(ctl, _("Domain %s marked as autostarted\n"), name);
535
    else
536
        vshPrint(ctl, _("Domain %s unmarked as autostarted\n"), name);
537

538
    virDomainFree(dom);
539 540 541
    return TRUE;
}

K
Karel Zak 已提交
542
/*
543
 * "connect" command
K
Karel Zak 已提交
544
 */
545
static const vshCmdInfo info_connect[] = {
546
    {"help", N_("(re)connect to hypervisor")},
547
    {"desc",
548
     N_("Connect to local hypervisor. This is built-in command after shell start up.")},
549
    {NULL, NULL}
K
Karel Zak 已提交
550 551
};

552
static const vshCmdOptDef opts_connect[] = {
553 554
    {"name",     VSH_OT_DATA, 0, N_("hypervisor connection URI")},
    {"readonly", VSH_OT_BOOL, 0, N_("read-only connection")},
555
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
556 557 558
};

static int
559
cmdConnect(vshControl *ctl, const vshCmd *cmd)
560
{
K
Karel Zak 已提交
561
    int ro = vshCommandOptBool(cmd, "readonly");
562

K
Karel Zak 已提交
563
    if (ctl->conn) {
564
        if (virConnectClose(ctl->conn) != 0) {
565
            vshError(ctl, "%s", _("Failed to disconnect from the hypervisor"));
K
Karel Zak 已提交
566 567 568 569
            return FALSE;
        }
        ctl->conn = NULL;
    }
570

571
    VIR_FREE(ctl->name);
572
    ctl->name = vshStrdup(ctl, vshCommandOptString(cmd, "name", NULL));
K
Karel Zak 已提交
573

574 575 576 577 578
    if (!ro) {
        ctl->readonly = 0;
    } else {
        ctl->readonly = 1;
    }
K
Karel Zak 已提交
579

580 581 582
    ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault,
                                   ctl->readonly ? VIR_CONNECT_RO : 0);

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

K
Karel Zak 已提交
586 587 588
    return ctl->conn ? TRUE : FALSE;
}

589 590
#ifndef WIN32

591
/*
592
 * "console" command
593
 */
594
static const vshCmdInfo info_console[] = {
595
    {"help", N_("connect to the guest console")},
596
    {"desc",
597
     N_("Connect the virtual serial console for the guest")},
598 599 600
    {NULL, NULL}
};

601
static const vshCmdOptDef opts_console[] = {
602
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
603 604 605 606
    {NULL, 0, 0, NULL}
};

static int
607
cmdRunConsole(vshControl *ctl, virDomainPtr dom)
608 609 610 611 612 613
{
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj = NULL;
    xmlXPathContextPtr ctxt = NULL;
    int ret = FALSE;
    char *doc;
614 615
    char *thatHost = NULL;
    char *thisHost = NULL;
616
    virDomainInfo dominfo;
617

618
    if (!(thisHost = virGetHostname(ctl->conn))) {
619
        vshError(ctl, "%s", _("Failed to get local hostname"));
620 621
        goto cleanup;
    }
622

623
    if (!(thatHost = virConnectGetHostname(ctl->conn))) {
624
        vshError(ctl, "%s", _("Failed to get connection hostname"));
625 626 627 628
        goto cleanup;
    }

    if (STRNEQ(thisHost, thatHost)) {
629
        vshError(ctl, "%s", _("Cannot connect to a remote console device"));
630 631
        goto cleanup;
    }
632

633 634 635 636 637 638 639 640 641 642
    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;
    }

643 644
    doc = virDomainGetXMLDesc(dom, 0);
    if (!doc)
645
        goto cleanup;
646 647

    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
648 649
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOWARNING);
650
    VIR_FREE(doc);
651 652 653 654 655 656 657 658
    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) &&
659
                          (obj->stringval != NULL) && (obj->stringval[0] != 0))) {
660 661
        vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom));
        vshPrintExtra(ctl, "%s", _("Escape character is ^]\n"));
662
        if (vshRunConsole((const char *)obj->stringval) == 0)
663 664
            ret = TRUE;
    } else {
J
Jim Meyering 已提交
665
        vshPrintExtra(ctl, "%s", _("No console available for domain\n"));
666 667 668 669
    }
    xmlXPathFreeObject(obj);

 cleanup:
670
    xmlXPathFreeContext(ctxt);
671 672
    if (xml)
        xmlFreeDoc(xml);
673 674
    VIR_FREE(thisHost);
    VIR_FREE(thatHost);
675

676 677 678
    return ret;
}

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
static int
cmdConsole(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
    int ret;

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

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

    ret = cmdRunConsole(ctl, dom);

    virDomainFree(dom);
    return ret;
}

697 698 699
#endif /* WIN32 */


K
Karel Zak 已提交
700 701 702
/*
 * "list" command
 */
703
static const vshCmdInfo info_list[] = {
704 705
    {"help", N_("list domains")},
    {"desc", N_("Returns list of domains.")},
706
    {NULL, NULL}
K
Karel Zak 已提交
707 708
};

709
static const vshCmdOptDef opts_list[] = {
710 711
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")},
712 713 714
    {NULL, 0, 0, NULL}
};

K
Karel Zak 已提交
715 716

static int
717
cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
718
{
719 720 721 722
    int inactive = vshCommandOptBool(cmd, "inactive");
    int all = vshCommandOptBool(cmd, "all");
    int active = !inactive || all ? 1 : 0;
    int *ids = NULL, maxid = 0, i;
723
    char **names = NULL;
724 725
    int maxname = 0;
    inactive |= all;
K
Karel Zak 已提交
726 727 728

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

730
    if (active) {
731 732
        maxid = virConnectNumOfDomains(ctl->conn);
        if (maxid < 0) {
733
            vshError(ctl, "%s", _("Failed to list active domains"));
734 735 736 737 738 739
            return FALSE;
        }
        if (maxid) {
            ids = vshMalloc(ctl, sizeof(int) * maxid);

            if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
740
                vshError(ctl, "%s", _("Failed to list active domains"));
741
                VIR_FREE(ids);
742 743 744
                return FALSE;
            }

745
            qsort(&ids[0], maxid, sizeof(int), idsorter);
746
        }
747 748
    }
    if (inactive) {
749 750
        maxname = virConnectNumOfDefinedDomains(ctl->conn);
        if (maxname < 0) {
751
            vshError(ctl, "%s", _("Failed to list inactive domains"));
752
            VIR_FREE(ids);
753
            return FALSE;
754
        }
755 756 757 758
        if (maxname) {
            names = vshMalloc(ctl, sizeof(char *) * maxname);

            if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
759
                vshError(ctl, "%s", _("Failed to list inactive domains"));
760 761
                VIR_FREE(ids);
                VIR_FREE(names);
762 763
                return FALSE;
            }
764

765
            qsort(&names[0], maxname, sizeof(char*), namesorter);
766
        }
767
    }
768
    vshPrintExtra(ctl, "%3s %-20s %s\n", _("Id"), _("Name"), _("State"));
K
Karel Zak 已提交
769
    vshPrintExtra(ctl, "----------------------------------\n");
770 771

    for (i = 0; i < maxid; i++) {
K
Karel Zak 已提交
772 773
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
774
        const char *state;
775 776

        /* this kind of work with domains is not atomic operation */
K
Karel Zak 已提交
777 778
        if (!dom)
            continue;
779 780 781 782

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

K
Karel Zak 已提交
785
        vshPrint(ctl, "%3d %-20s %s\n",
786 787
                 virDomainGetID(dom),
                 virDomainGetName(dom),
788
                 state);
789
        virDomainFree(dom);
K
Karel Zak 已提交
790
    }
791 792 793
    for (i = 0; i < maxname; i++) {
        virDomainInfo info;
        virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
794
        const char *state;
795 796

        /* this kind of work with domains is not atomic operation */
797
        if (!dom) {
798
            VIR_FREE(names[i]);
799
            continue;
800
        }
801 802 803 804

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

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

809
        virDomainFree(dom);
810
        VIR_FREE(names[i]);
811
    }
812 813
    VIR_FREE(ids);
    VIR_FREE(names);
K
Karel Zak 已提交
814 815 816 817
    return TRUE;
}

/*
K
Karel Zak 已提交
818
 * "domstate" command
K
Karel Zak 已提交
819
 */
820
static const vshCmdInfo info_domstate[] = {
821 822
    {"help", N_("domain state")},
    {"desc", N_("Returns state about a domain.")},
823
    {NULL, NULL}
K
Karel Zak 已提交
824 825
};

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

static int
832
cmdDomstate(vshControl *ctl, const vshCmd *cmd)
833
{
834
    virDomainInfo info;
K
Karel Zak 已提交
835
    virDomainPtr dom;
K
Karel Zak 已提交
836
    int ret = TRUE;
837

K
Karel Zak 已提交
838 839
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
840

J
Jim Meyering 已提交
841
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
K
Karel Zak 已提交
842
        return FALSE;
843 844

    if (virDomainGetInfo(dom, &info) == 0)
K
Karel Zak 已提交
845
        vshPrint(ctl, "%s\n",
E
Eric Blake 已提交
846
                 _(vshDomainStateToString(info.state)));
K
Karel Zak 已提交
847 848
    else
        ret = FALSE;
849

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

854 855
/* "domblkstat" command
 */
856
static const vshCmdInfo info_domblkstat[] = {
857 858
    {"help", N_("get device block stats for a domain")},
    {"desc", N_("Get device block stats for a running domain.")},
859 860 861
    {NULL,NULL}
};

862
static const vshCmdOptDef opts_domblkstat[] = {
863 864
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
865 866 867 868
    {NULL, 0, 0, NULL}
};

static int
869
cmdDomblkstat (vshControl *ctl, const vshCmd *cmd)
870 871 872 873 874 875 876 877
{
    virDomainPtr dom;
    char *name, *device;
    struct _virDomainBlockStats stats;

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

J
Jim Meyering 已提交
878
    if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
879 880
        return FALSE;

L
Laine Stump 已提交
881 882
    if (!(device = vshCommandOptString (cmd, "device", NULL))) {
        virDomainFree(dom);
883
        return FALSE;
L
Laine Stump 已提交
884
    }
885 886

    if (virDomainBlockStats (dom, device, &stats, sizeof stats) == -1) {
887
        vshError(ctl, _("Failed to get block stats %s %s"), name, device);
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
        virDomainFree(dom);
        return FALSE;
    }

    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);
    return TRUE;
}

/* "domifstat" command
 */
913
static const vshCmdInfo info_domifstat[] = {
914 915
    {"help", N_("get network interface stats for a domain")},
    {"desc", N_("Get network interface stats for a running domain.")},
916 917 918
    {NULL,NULL}
};

919
static const vshCmdOptDef opts_domifstat[] = {
920 921
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")},
922 923 924 925
    {NULL, 0, 0, NULL}
};

static int
926
cmdDomIfstat (vshControl *ctl, const vshCmd *cmd)
927 928 929 930 931 932 933 934
{
    virDomainPtr dom;
    char *name, *device;
    struct _virDomainInterfaceStats stats;

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

J
Jim Meyering 已提交
935
    if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
936 937
        return FALSE;

L
Laine Stump 已提交
938 939
    if (!(device = vshCommandOptString (cmd, "interface", NULL))) {
        virDomainFree(dom);
940
        return FALSE;
L
Laine Stump 已提交
941
    }
942 943

    if (virDomainInterfaceStats (dom, device, &stats, sizeof stats) == -1) {
944
        vshError(ctl, _("Failed to get interface stats %s %s"), name, device);
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
        virDomainFree(dom);
        return FALSE;
    }

    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);
    return TRUE;
}

977 978 979
/*
 * "dommemstats" command
 */
980
static const vshCmdInfo info_dommemstat[] = {
981 982
    {"help", N_("get memory statistics for a domain")},
    {"desc", N_("Get memory statistics for a runnng domain.")},
983 984 985
    {NULL,NULL}
};

986
static const vshCmdOptDef opts_dommemstat[] = {
987
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
988 989 990 991
    {NULL, 0, 0, NULL}
};

static int
992
cmdDomMemStat(vshControl *ctl, const vshCmd *cmd)
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
{
    virDomainPtr dom;
    char *name;
    struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR];
    unsigned int nr_stats, i;

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

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

    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);
        return FALSE;
    }

    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);
    return TRUE;
}

1031 1032 1033
/*
 * "suspend" command
 */
1034
static const vshCmdInfo info_suspend[] = {
1035 1036
    {"help", N_("suspend a domain")},
    {"desc", N_("Suspend a running domain.")},
1037
    {NULL, NULL}
1038 1039
};

1040
static const vshCmdOptDef opts_suspend[] = {
1041
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1042
    {NULL, 0, 0, NULL}
1043 1044 1045
};

static int
1046
cmdSuspend(vshControl *ctl, const vshCmd *cmd)
1047
{
1048
    virDomainPtr dom;
K
Karel Zak 已提交
1049 1050
    char *name;
    int ret = TRUE;
1051

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

J
Jim Meyering 已提交
1055
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1056
        return FALSE;
1057 1058

    if (virDomainSuspend(dom) == 0) {
1059
        vshPrint(ctl, _("Domain %s suspended\n"), name);
1060
    } else {
1061
        vshError(ctl, _("Failed to suspend domain %s"), name);
1062 1063
        ret = FALSE;
    }
1064

1065 1066 1067 1068
    virDomainFree(dom);
    return ret;
}

1069 1070 1071
/*
 * "create" command
 */
1072
static const vshCmdInfo info_create[] = {
1073 1074
    {"help", N_("create a domain from an XML file")},
    {"desc", N_("Create a domain.")},
1075 1076 1077
    {NULL, NULL}
};

1078
static const vshCmdOptDef opts_create[] = {
1079
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1080
#ifndef WIN32
1081
    {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1082
#endif
1083 1084 1085 1086
    {NULL, 0, 0, NULL}
};

static int
1087
cmdCreate(vshControl *ctl, const vshCmd *cmd)
1088 1089 1090 1091 1092
{
    virDomainPtr dom;
    char *from;
    int found;
    int ret = TRUE;
1093
    char *buffer;
1094
#ifndef WIN32
1095
    int console = vshCommandOptBool(cmd, "console");
1096
#endif
1097 1098 1099 1100 1101 1102 1103 1104

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

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

1105 1106
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;
1107

1108
    dom = virDomainCreateXML(ctl->conn, buffer, 0);
1109
    VIR_FREE(buffer);
1110

1111
    if (dom != NULL) {
1112
        vshPrint(ctl, _("Domain %s created from %s\n"),
1113
                 virDomainGetName(dom), from);
1114
#ifndef WIN32
1115 1116
        if (console)
            cmdRunConsole(ctl, dom);
1117
#endif
1118
        virDomainFree(dom);
1119
    } else {
1120
        vshError(ctl, _("Failed to create domain from %s"), from);
1121 1122 1123 1124 1125
        ret = FALSE;
    }
    return ret;
}

1126 1127 1128
/*
 * "define" command
 */
1129
static const vshCmdInfo info_define[] = {
1130 1131
    {"help", N_("define (but don't start) a domain from an XML file")},
    {"desc", N_("Define a domain.")},
1132 1133 1134
    {NULL, NULL}
};

1135
static const vshCmdOptDef opts_define[] = {
1136
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1137 1138 1139 1140
    {NULL, 0, 0, NULL}
};

static int
1141
cmdDefine(vshControl *ctl, const vshCmd *cmd)
1142 1143 1144 1145 1146
{
    virDomainPtr dom;
    char *from;
    int found;
    int ret = TRUE;
1147
    char *buffer;
1148 1149 1150 1151 1152 1153 1154 1155

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

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

1156 1157
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;
1158 1159

    dom = virDomainDefineXML(ctl->conn, buffer);
1160
    VIR_FREE(buffer);
1161

1162
    if (dom != NULL) {
1163
        vshPrint(ctl, _("Domain %s defined from %s\n"),
1164
                 virDomainGetName(dom), from);
1165
        virDomainFree(dom);
1166
    } else {
1167
        vshError(ctl, _("Failed to define domain from %s"), from);
1168 1169 1170 1171 1172 1173 1174 1175
        ret = FALSE;
    }
    return ret;
}

/*
 * "undefine" command
 */
1176
static const vshCmdInfo info_undefine[] = {
1177 1178
    {"help", N_("undefine an inactive domain")},
    {"desc", N_("Undefine the configuration for an inactive domain.")},
1179 1180 1181
    {NULL, NULL}
};

1182
static const vshCmdOptDef opts_undefine[] = {
1183
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
1184 1185 1186 1187
    {NULL, 0, 0, NULL}
};

static int
1188
cmdUndefine(vshControl *ctl, const vshCmd *cmd)
1189 1190 1191 1192
{
    virDomainPtr dom;
    int ret = TRUE;
    char *name;
1193 1194
    int found;
    int id;
1195 1196 1197 1198

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

1199 1200 1201 1202 1203 1204
    name = vshCommandOptString(cmd, "domain", &found);
    if (!found)
        return FALSE;

    if (name && virStrToLong_i(name, NULL, 10, &id) == 0
        && id >= 0 && (dom = virDomainLookupByID(ctl->conn, id))) {
1205 1206 1207 1208 1209
        vshError(ctl,
                 _("a running domain like %s cannot be undefined;\n"
                   "to undefine, first shutdown then undefine"
                   " using its name or UUID"),
                 name);
1210 1211 1212
        virDomainFree(dom);
        return FALSE;
    }
J
Jim Meyering 已提交
1213
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, &name,
1214
                                      VSH_BYNAME|VSH_BYUUID)))
1215 1216 1217
        return FALSE;

    if (virDomainUndefine(dom) == 0) {
1218
        vshPrint(ctl, _("Domain %s has been undefined\n"), name);
1219
    } else {
1220
        vshError(ctl, _("Failed to undefine domain %s"), name);
1221 1222 1223
        ret = FALSE;
    }

1224
    virDomainFree(dom);
1225 1226 1227 1228 1229 1230 1231
    return ret;
}


/*
 * "start" command
 */
1232
static const vshCmdInfo info_start[] = {
1233 1234
    {"help", N_("start a (previously defined) inactive domain")},
    {"desc", N_("Start a domain.")},
1235 1236 1237
    {NULL, NULL}
};

1238
static const vshCmdOptDef opts_start[] = {
1239
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive domain")},
1240
#ifndef WIN32
1241
    {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1242
#endif
1243 1244 1245 1246
    {NULL, 0, 0, NULL}
};

static int
1247
cmdStart(vshControl *ctl, const vshCmd *cmd)
1248 1249 1250
{
    virDomainPtr dom;
    int ret = TRUE;
1251
#ifndef WIN32
1252
    int console = vshCommandOptBool(cmd, "console");
1253
#endif
1254 1255 1256 1257

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

J
Jim Meyering 已提交
1258
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL, VSH_BYNAME)))
1259 1260 1261
        return FALSE;

    if (virDomainGetID(dom) != (unsigned int)-1) {
1262
        vshError(ctl, "%s", _("Domain is already active"));
1263
        virDomainFree(dom);
1264 1265 1266 1267
        return FALSE;
    }

    if (virDomainCreate(dom) == 0) {
1268
        vshPrint(ctl, _("Domain %s started\n"),
1269
                 virDomainGetName(dom));
1270
#ifndef WIN32
1271 1272
        if (console)
            cmdRunConsole(ctl, dom);
1273
#endif
1274
    } else {
1275
        vshError(ctl, _("Failed to start domain %s"), virDomainGetName(dom));
1276 1277
        ret = FALSE;
    }
1278
    virDomainFree(dom);
1279 1280 1281
    return ret;
}

1282 1283 1284
/*
 * "save" command
 */
1285
static const vshCmdInfo info_save[] = {
1286 1287
    {"help", N_("save a domain state to a file")},
    {"desc", N_("Save a running domain.")},
1288
    {NULL, NULL}
1289 1290
};

1291
static const vshCmdOptDef opts_save[] = {
1292 1293
    {"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")},
1294
    {NULL, 0, 0, NULL}
1295 1296 1297
};

static int
1298
cmdSave(vshControl *ctl, const vshCmd *cmd)
1299
{
1300 1301 1302 1303
    virDomainPtr dom;
    char *name;
    char *to;
    int ret = TRUE;
1304

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

1308
    if (!(to = vshCommandOptString(cmd, "file", NULL)))
1309
        return FALSE;
1310

J
Jim Meyering 已提交
1311
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1312
        return FALSE;
1313 1314

    if (virDomainSave(dom, to) == 0) {
1315
        vshPrint(ctl, _("Domain %s saved to %s\n"), name, to);
1316
    } else {
1317
        vshError(ctl, _("Failed to save domain %s to %s"), name, to);
1318 1319
        ret = FALSE;
    }
1320

1321 1322 1323 1324
    virDomainFree(dom);
    return ret;
}

1325 1326 1327
/*
 * "schedinfo" command
 */
1328
static const vshCmdInfo info_schedinfo[] = {
1329 1330
    {"help", N_("show/set scheduler parameters")},
    {"desc", N_("Show/Set scheduler parameters.")},
1331 1332 1333
    {NULL, NULL}
};

1334
static const vshCmdOptDef opts_schedinfo[] = {
1335 1336 1337 1338
    {"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")},
1339 1340 1341 1342
    {NULL, 0, 0, NULL}
};

static int
1343 1344
cmdSchedInfoUpdate(vshControl *ctl, const vshCmd *cmd,
                   virSchedParameterPtr param)
1345
{
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
    int found;
    char *data;

    /* Legacy 'weight' parameter */
    if (STREQ(param->field, "weight") &&
        param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
        vshCommandOptBool(cmd, "weight")) {
        int val;
        val = vshCommandOptInt(cmd, "weight", &found);
        if (!found) {
1356
            vshError(ctl, "%s", _("Invalid value of weight"));
1357
            return -1;
1358
        } else {
1359
            param->value.ui = val;
1360
        }
1361
        return 1;
1362 1363
    }

1364 1365 1366 1367 1368 1369 1370
    /* Legacy 'cap' parameter */
    if (STREQ(param->field, "cap") &&
        param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
        vshCommandOptBool(cmd, "cap")) {
        int val;
        val = vshCommandOptInt(cmd, "cap", &found);
        if (!found) {
1371
            vshError(ctl, "%s", _("Invalid value of cap"));
1372
            return -1;
1373
        } else {
1374
            param->value.ui = val;
1375
        }
1376
        return 1;
1377
    }
1378

1379 1380 1381 1382
    if ((data = vshCommandOptString(cmd, "set", NULL))) {
        char *val = strchr(data, '=');
        int match = 0;
        if (!val) {
1383
            vshError(ctl, "%s", _("Invalid syntax for --set, expecting name=value"));
1384
            return -1;
1385
        }
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
        *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) {
1397
                vshError(ctl, "%s",
1398 1399 1400 1401 1402 1403
                         _("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) {
1404
                vshError(ctl, "%s",
1405 1406 1407 1408 1409 1410
                         _("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) {
1411
                vshError(ctl, "%s",
1412 1413 1414 1415 1416 1417
                         _("Invalid value for parameter, expecting an long long"));
                return -1;
            }
            break;
        case VIR_DOMAIN_SCHED_FIELD_ULLONG:
            if (virStrToLong_ull(val, NULL, 10, &param->value.ul) < 0) {
1418
                vshError(ctl, "%s",
1419 1420 1421 1422 1423 1424
                         _("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) {
1425
                vshError(ctl, "%s", _("Invalid value for parameter, expecting a double"));
1426 1427 1428 1429 1430
                return -1;
            }
            break;
        case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
            param->value.b = STREQ(val, "0") ? 0 : 1;
1431
        }
1432
        return 1;
1433
    }
1434

1435 1436
    return 0;
}
1437

1438

1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
static int
cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
{
    char *schedulertype;
    virDomainPtr dom;
    virSchedParameterPtr params = NULL;
    int nparams = 0;
    int update = 0;
    int i, ret;
    int ret_val = FALSE;
1449

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

1453 1454
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
        return FALSE;
1455 1456 1457 1458

    /* Print SchedulerType */
    schedulertype = virDomainGetSchedulerType(dom, &nparams);
    if (schedulertype!= NULL){
1459
        vshPrint(ctl, "%-15s: %s\n", _("Scheduler"),
1460
             schedulertype);
1461
        VIR_FREE(schedulertype);
1462
    } else {
1463
        vshPrint(ctl, "%-15s: %s\n", _("Scheduler"), _("Unknown"));
1464
        goto cleanup;
1465 1466
    }

1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
    if (nparams) {
        params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams);
        if (params == NULL)
            goto cleanup;

        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;
        }

        ret_val = TRUE;
1499 1500 1501 1502 1503 1504 1505 1506 1507
        for (i = 0; i < nparams; i++){
            switch (params[i].type) {
            case VIR_DOMAIN_SCHED_FIELD_INT:
                 printf("%-15s: %d\n",  params[i].field, params[i].value.i);
                 break;
            case VIR_DOMAIN_SCHED_FIELD_UINT:
                 printf("%-15s: %u\n",  params[i].field, params[i].value.ui);
                 break;
            case VIR_DOMAIN_SCHED_FIELD_LLONG:
1508
                 printf("%-15s: %lld\n",  params[i].field, params[i].value.l);
1509 1510
                 break;
            case VIR_DOMAIN_SCHED_FIELD_ULLONG:
1511
                 printf("%-15s: %llu\n",  params[i].field, params[i].value.ul);
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523
                 break;
            case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
                 printf("%-15s: %f\n",  params[i].field, params[i].value.d);
                 break;
            case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
                 printf("%-15s: %d\n",  params[i].field, params[i].value.b);
                 break;
            default:
                 printf("not implemented scheduler parameter type\n");
            }
        }
    }
1524

1525
 cleanup:
1526
    VIR_FREE(params);
1527
    virDomainFree(dom);
1528
    return ret_val;
1529 1530
}

1531 1532 1533
/*
 * "restore" command
 */
1534
static const vshCmdInfo info_restore[] = {
1535 1536
    {"help", N_("restore a domain from a saved state in a file")},
    {"desc", N_("Restore a domain.")},
1537
    {NULL, NULL}
1538 1539
};

1540
static const vshCmdOptDef opts_restore[] = {
1541
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("the state to restore")},
1542
    {NULL, 0, 0, NULL}
1543 1544 1545
};

static int
1546
cmdRestore(vshControl *ctl, const vshCmd *cmd)
1547
{
1548 1549 1550
    char *from;
    int found;
    int ret = TRUE;
1551

1552 1553 1554 1555 1556 1557
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

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

    if (virDomainRestore(ctl->conn, from) == 0) {
1560
        vshPrint(ctl, _("Domain restored from %s\n"), from);
1561
    } else {
1562
        vshError(ctl, _("Failed to restore domain from %s"), from);
1563 1564 1565 1566 1567
        ret = FALSE;
    }
    return ret;
}

D
Daniel Veillard 已提交
1568 1569 1570
/*
 * "dump" command
 */
1571
static const vshCmdInfo info_dump[] = {
1572 1573
    {"help", N_("dump the core of a domain to a file for analysis")},
    {"desc", N_("Core dump a domain.")},
D
Daniel Veillard 已提交
1574 1575 1576
    {NULL, NULL}
};

1577
static const vshCmdOptDef opts_dump[] = {
1578 1579 1580 1581
    {"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 已提交
1582 1583 1584 1585
    {NULL, 0, 0, NULL}
};

static int
1586
cmdDump(vshControl *ctl, const vshCmd *cmd)
D
Daniel Veillard 已提交
1587 1588 1589 1590 1591
{
    virDomainPtr dom;
    char *name;
    char *to;
    int ret = TRUE;
1592
    int flags = 0;
D
Daniel Veillard 已提交
1593 1594 1595 1596 1597 1598 1599

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

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

J
Jim Meyering 已提交
1600
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
D
Daniel Veillard 已提交
1601 1602
        return FALSE;

P
Paolo Bonzini 已提交
1603 1604
    if (vshCommandOptBool (cmd, "live"))
        flags |= VIR_DUMP_LIVE;
1605 1606 1607 1608
    if (vshCommandOptBool (cmd, "crash"))
        flags |= VIR_DUMP_CRASH;

    if (virDomainCoreDump(dom, to, flags) == 0) {
1609
        vshPrint(ctl, _("Domain %s dumped to %s\n"), name, to);
D
Daniel Veillard 已提交
1610
    } else {
1611
        vshError(ctl, _("Failed to core dump domain %s to %s"), name, to);
D
Daniel Veillard 已提交
1612 1613 1614 1615 1616 1617 1618
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

1619 1620 1621
/*
 * "resume" command
 */
1622
static const vshCmdInfo info_resume[] = {
1623 1624
    {"help", N_("resume a domain")},
    {"desc", N_("Resume a previously suspended domain.")},
1625
    {NULL, NULL}
1626 1627
};

1628
static const vshCmdOptDef opts_resume[] = {
1629
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1630
    {NULL, 0, 0, NULL}
1631 1632 1633
};

static int
1634
cmdResume(vshControl *ctl, const vshCmd *cmd)
1635
{
1636
    virDomainPtr dom;
K
Karel Zak 已提交
1637 1638
    int ret = TRUE;
    char *name;
1639

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

J
Jim Meyering 已提交
1643
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1644
        return FALSE;
1645 1646

    if (virDomainResume(dom) == 0) {
1647
        vshPrint(ctl, _("Domain %s resumed\n"), name);
1648
    } else {
1649
        vshError(ctl, _("Failed to resume domain %s"), name);
1650 1651
        ret = FALSE;
    }
1652

1653 1654 1655 1656
    virDomainFree(dom);
    return ret;
}

1657 1658 1659
/*
 * "shutdown" command
 */
1660
static const vshCmdInfo info_shutdown[] = {
1661 1662
    {"help", N_("gracefully shutdown a domain")},
    {"desc", N_("Run shutdown in the target domain.")},
1663
    {NULL, NULL}
1664 1665
};

1666
static const vshCmdOptDef opts_shutdown[] = {
1667
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1668
    {NULL, 0, 0, NULL}
1669 1670 1671
};

static int
1672
cmdShutdown(vshControl *ctl, const vshCmd *cmd)
1673
{
1674 1675 1676
    virDomainPtr dom;
    int ret = TRUE;
    char *name;
1677

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

J
Jim Meyering 已提交
1681
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1682
        return FALSE;
1683 1684

    if (virDomainShutdown(dom) == 0) {
1685
        vshPrint(ctl, _("Domain %s is being shutdown\n"), name);
1686
    } else {
1687
        vshError(ctl, _("Failed to shutdown domain %s"), name);
1688 1689
        ret = FALSE;
    }
1690

1691 1692 1693 1694
    virDomainFree(dom);
    return ret;
}

1695 1696 1697
/*
 * "reboot" command
 */
1698
static const vshCmdInfo info_reboot[] = {
1699 1700
    {"help", N_("reboot a domain")},
    {"desc", N_("Run a reboot command in the target domain.")},
1701 1702 1703
    {NULL, NULL}
};

1704
static const vshCmdOptDef opts_reboot[] = {
1705
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1706 1707 1708 1709
    {NULL, 0, 0, NULL}
};

static int
1710
cmdReboot(vshControl *ctl, const vshCmd *cmd)
1711 1712 1713 1714 1715 1716 1717 1718
{
    virDomainPtr dom;
    int ret = TRUE;
    char *name;

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

J
Jim Meyering 已提交
1719
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1720 1721 1722
        return FALSE;

    if (virDomainReboot(dom, 0) == 0) {
1723
        vshPrint(ctl, _("Domain %s is being rebooted\n"), name);
1724
    } else {
1725
        vshError(ctl, _("Failed to reboot domain %s"), name);
1726 1727 1728 1729 1730 1731 1732
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

1733 1734 1735
/*
 * "destroy" command
 */
1736
static const vshCmdInfo info_destroy[] = {
1737 1738
    {"help", N_("destroy a domain")},
    {"desc", N_("Destroy a given domain.")},
1739
    {NULL, NULL}
1740 1741
};

1742
static const vshCmdOptDef opts_destroy[] = {
1743
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1744
    {NULL, 0, 0, NULL}
1745 1746 1747
};

static int
1748
cmdDestroy(vshControl *ctl, const vshCmd *cmd)
1749
{
1750
    virDomainPtr dom;
K
Karel Zak 已提交
1751 1752
    int ret = TRUE;
    char *name;
1753

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

J
Jim Meyering 已提交
1757
    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1758
        return FALSE;
1759 1760

    if (virDomainDestroy(dom) == 0) {
1761
        vshPrint(ctl, _("Domain %s destroyed\n"), name);
1762
    } else {
1763
        vshError(ctl, _("Failed to destroy domain %s"), name);
1764 1765
        ret = FALSE;
    }
1766

1767
    virDomainFree(dom);
K
Karel Zak 已提交
1768 1769 1770 1771
    return ret;
}

/*
1772
 * "dominfo" command
K
Karel Zak 已提交
1773
 */
1774
static const vshCmdInfo info_dominfo[] = {
1775 1776
    {"help", N_("domain information")},
    {"desc", N_("Returns basic information about the domain.")},
1777
    {NULL, NULL}
K
Karel Zak 已提交
1778 1779
};

1780
static const vshCmdOptDef opts_dominfo[] = {
1781
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1782
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
1783 1784 1785
};

static int
1786
cmdDominfo(vshControl *ctl, const vshCmd *cmd)
1787
{
K
Karel Zak 已提交
1788 1789
    virDomainInfo info;
    virDomainPtr dom;
1790 1791
    virSecurityModel secmodel;
    virSecurityLabel seclabel;
1792
    int ret = TRUE, autostart;
1793
    unsigned int id;
1794
    char *str, uuid[VIR_UUID_STRING_BUFLEN];
1795

K
Karel Zak 已提交
1796 1797 1798
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

J
Jim Meyering 已提交
1799
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
K
Karel Zak 已提交
1800
        return FALSE;
1801

1802 1803
    id = virDomainGetID(dom);
    if (id == ((unsigned int)-1))
1804
        vshPrint(ctl, "%-15s %s\n", _("Id:"), "-");
1805
    else
1806
        vshPrint(ctl, "%-15s %d\n", _("Id:"), id);
1807 1808
    vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom));

K
Karel Zak 已提交
1809
    if (virDomainGetUUIDString(dom, &uuid[0])==0)
1810
        vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
1811 1812

    if ((str = virDomainGetOSType(dom))) {
1813
        vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str);
1814
        VIR_FREE(str);
1815 1816 1817
    }

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

1821
        vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu);
1822 1823

        if (info.cpuTime != 0) {
1824
            double cpuUsed = info.cpuTime;
1825

1826
            cpuUsed /= 1000000000.0;
1827

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

1831 1832
        if (info.maxMem != UINT_MAX)
            vshPrint(ctl, "%-15s %lu kB\n", _("Max memory:"),
1833
                 info.maxMem);
1834
        else
1835
            vshPrint(ctl, "%-15s %s\n", _("Max memory:"),
1836 1837
                 _("no limit"));

1838
        vshPrint(ctl, "%-15s %lu kB\n", _("Used memory:"),
1839 1840
                 info.memory);

K
Karel Zak 已提交
1841 1842 1843
    } else {
        ret = FALSE;
    }
1844

1845
    if (!virDomainGetAutostart(dom, &autostart)) {
1846
        vshPrint(ctl, "%-15s %s\n", _("Autostart:"),
1847 1848 1849
                 autostart ? _("enable") : _("disable") );
    }

1850 1851 1852
    /* Security model and label information */
    memset(&secmodel, 0, sizeof secmodel);
    if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) {
1853 1854 1855 1856
        if (last_error->code != VIR_ERR_NO_SUPPORT) {
            virDomainFree(dom);
            return FALSE;
        }
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874
    } 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 */
            memset(&seclabel, 0, sizeof seclabel);
            if (virDomainGetSecurityLabel(dom, &seclabel) == -1) {
                virDomainFree(dom);
                return FALSE;
            } else {
                if (seclabel.label[0] != '\0')
                    vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"),
                             seclabel.label, seclabel.enforcing ? "enforcing" : "permissive");
            }
        }
    }
1875
    virDomainFree(dom);
K
Karel Zak 已提交
1876 1877 1878
    return ret;
}

1879 1880 1881 1882
/*
 * "domjobinfo" command
 */
static const vshCmdInfo info_domjobinfo[] = {
1883 1884
    {"help", N_("domain job information")},
    {"desc", N_("Returns information about jobs running on a domain.")},
1885 1886 1887 1888
    {NULL, NULL}
};

static const vshCmdOptDef opts_domjobinfo[] = {
1889
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1890 1891 1892 1893 1894 1895 1896 1897 1898
    {NULL, 0, 0, NULL}
};


static int
cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd)
{
    virDomainJobInfo info;
    virDomainPtr dom;
L
Laine Stump 已提交
1899
    int ret = TRUE;
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931

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

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

    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 已提交
1932
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data processed:"), val, unit);
1933
            val = prettyCapacity(info.dataRemaining, &unit);
E
Eric Blake 已提交
1934
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data remaining:"), val, unit);
1935
            val = prettyCapacity(info.dataTotal, &unit);
E
Eric Blake 已提交
1936
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data total:"), val, unit);
1937 1938 1939
        }
        if (info.memTotal || info.memRemaining || info.memProcessed) {
            val = prettyCapacity(info.memProcessed, &unit);
E
Eric Blake 已提交
1940
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory processed:"), val, unit);
1941
            val = prettyCapacity(info.memRemaining, &unit);
E
Eric Blake 已提交
1942
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory remaining:"), val, unit);
1943
            val = prettyCapacity(info.memTotal, &unit);
E
Eric Blake 已提交
1944
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory total:"), val, unit);
1945 1946 1947
        }
        if (info.fileTotal || info.fileRemaining || info.fileProcessed) {
            val = prettyCapacity(info.fileProcessed, &unit);
E
Eric Blake 已提交
1948
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("File processed:"), val, unit);
1949
            val = prettyCapacity(info.fileRemaining, &unit);
E
Eric Blake 已提交
1950
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("File remaining:"), val, unit);
1951
            val = prettyCapacity(info.fileTotal, &unit);
E
Eric Blake 已提交
1952
            vshPrint(ctl, "%-17s %-.3lf %s\n", _("File total:"), val, unit);
1953 1954 1955 1956 1957 1958 1959 1960 1961
        }
    } else {
        ret = FALSE;
    }
cleanup:
    virDomainFree(dom);
    return ret;
}

1962 1963 1964 1965
/*
 * "domjobabort" command
 */
static const vshCmdInfo info_domjobabort[] = {
1966 1967
    {"help", N_("abort active domain job")},
    {"desc", N_("Aborts the currently running domain job")},
1968 1969 1970 1971
    {NULL, NULL}
};

static const vshCmdOptDef opts_domjobabort[] = {
1972
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
    {NULL, 0, 0, NULL}
};

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

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

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

    if (virDomainAbortJob(dom) < 0)
        ret = FALSE;

    virDomainFree(dom);
    return ret;
}

1995 1996 1997
/*
 * "freecell" command
 */
1998
static const vshCmdInfo info_freecell[] = {
1999 2000
    {"help", N_("NUMA free memory")},
    {"desc", N_("display available free memory for the NUMA cell.")},
2001 2002 2003
    {NULL, NULL}
};

2004
static const vshCmdOptDef opts_freecell[] = {
2005
    {"cellno", VSH_OT_DATA, 0, N_("NUMA cell number")},
2006 2007 2008 2009
    {NULL, 0, 0, NULL}
};

static int
2010
cmdFreecell(vshControl *ctl, const vshCmd *cmd)
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020
{
    int ret;
    int cell, cell_given;
    unsigned long long memory;

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

    cell = vshCommandOptInt(cmd, "cellno", &cell_given);
    if (!cell_given) {
2021
        memory = virNodeGetFreeMemory(ctl->conn);
D
Daniel P. Berrange 已提交
2022 2023
        if (memory == 0)
            return FALSE;
2024
    } else {
2025 2026 2027
        ret = virNodeGetCellsFreeMemory(ctl->conn, &memory, cell, 1);
        if (ret != 1)
            return FALSE;
2028 2029 2030
    }

    if (cell == -1)
D
Daniel P. Berrange 已提交
2031
        vshPrint(ctl, "%s: %llu kB\n", _("Total"), (memory/1024));
2032
    else
D
Daniel P. Berrange 已提交
2033
        vshPrint(ctl, "%d: %llu kB\n", cell, (memory/1024));
2034 2035 2036 2037

    return TRUE;
}

2038 2039 2040
/*
 * "vcpuinfo" command
 */
2041
static const vshCmdInfo info_vcpuinfo[] = {
2042 2043
    {"help", N_("domain vcpu information")},
    {"desc", N_("Returns basic information about the domain virtual CPUs.")},
2044 2045 2046
    {NULL, NULL}
};

2047
static const vshCmdOptDef opts_vcpuinfo[] = {
2048
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2049 2050 2051 2052
    {NULL, 0, 0, NULL}
};

static int
2053
cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066
{
    virDomainInfo info;
    virDomainPtr dom;
    virNodeInfo nodeinfo;
    virVcpuInfoPtr cpuinfo;
    unsigned char *cpumap;
    int ncpus;
    size_t cpumaplen;
    int ret = TRUE;

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

J
Jim Meyering 已提交
2067
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2068 2069 2070 2071
        return FALSE;

    if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
        virDomainFree(dom);
2072
        return FALSE;
2073 2074 2075 2076 2077 2078 2079
    }

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

2080
    cpuinfo = vshMalloc(ctl, sizeof(virVcpuInfo)*info.nrVirtCpu);
2081
    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2082
    cpumap = vshMalloc(ctl, info.nrVirtCpu * cpumaplen);
2083

2084 2085 2086
    if ((ncpus = virDomainGetVcpus(dom,
                                   cpuinfo, info.nrVirtCpu,
                                   cpumap, cpumaplen)) >= 0) {
2087
        int n;
2088 2089 2090 2091 2092
        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 已提交
2093
                     _(vshDomainVcpuStateToString(cpuinfo[n].state)));
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109
            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");
            }
        }
2110
    } else {
2111
        if (info.state == VIR_DOMAIN_SHUTOFF) {
2112 2113
            vshError(ctl, "%s",
                     _("Domain shut off, virtual CPUs not present."));
2114
        }
2115 2116 2117
        ret = FALSE;
    }

2118 2119
    VIR_FREE(cpumap);
    VIR_FREE(cpuinfo);
2120 2121 2122 2123 2124 2125 2126
    virDomainFree(dom);
    return ret;
}

/*
 * "vcpupin" command
 */
2127
static const vshCmdInfo info_vcpupin[] = {
2128 2129
    {"help", N_("control domain vcpu affinity")},
    {"desc", N_("Pin domain VCPUs to host physical CPUs.")},
2130 2131 2132
    {NULL, NULL}
};

2133
static const vshCmdOptDef opts_vcpupin[] = {
2134 2135 2136
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"vcpu", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vcpu number")},
    {"cpulist", VSH_OT_DATA, VSH_OFLAG_REQ, N_("host cpu number(s) (comma separated)")},
2137 2138 2139 2140
    {NULL, 0, 0, NULL}
};

static int
2141
cmdVcpupin(vshControl *ctl, const vshCmd *cmd)
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151
{
    virDomainInfo info;
    virDomainPtr dom;
    virNodeInfo nodeinfo;
    int vcpu;
    char *cpulist;
    int ret = TRUE;
    int vcpufound = 0;
    unsigned char *cpumap;
    int cpumaplen;
2152 2153
    int i;
    enum { expect_num, expect_num_or_comma } state;
2154 2155 2156 2157

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

J
Jim Meyering 已提交
2158
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2159 2160 2161 2162
        return FALSE;

    vcpu = vshCommandOptInt(cmd, "vcpu", &vcpufound);
    if (!vcpufound) {
2163
        vshError(ctl, "%s", _("vcpupin: Invalid or missing vCPU number."));
2164 2165 2166 2167 2168
        virDomainFree(dom);
        return FALSE;
    }

    if (!(cpulist = vshCommandOptString(cmd, "cpulist", NULL))) {
2169
        vshError(ctl, "%s", _("vcpupin: Missing cpulist"));
2170 2171 2172
        virDomainFree(dom);
        return FALSE;
    }
2173

2174 2175 2176 2177 2178 2179
    if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
        virDomainFree(dom);
        return FALSE;
    }

    if (virDomainGetInfo(dom, &info) != 0) {
2180
        vshError(ctl, "%s", _("vcpupin: failed to get domain informations."));
2181 2182 2183 2184 2185
        virDomainFree(dom);
        return FALSE;
    }

    if (vcpu >= info.nrVirtCpu) {
2186
        vshError(ctl, "%s", _("vcpupin: Invalid vCPU number."));
2187 2188 2189 2190
        virDomainFree(dom);
        return FALSE;
    }

2191 2192 2193 2194
    /* Check that the cpulist parameter is a comma-separated list of
     * numbers and give an intelligent error message if not.
     */
    if (cpulist[0] == '\0') {
2195
        vshError(ctl, "%s", _("cpulist: Invalid format. Empty string."));
2196 2197 2198 2199 2200 2201 2202 2203
        virDomainFree (dom);
        return FALSE;
    }

    state = expect_num;
    for (i = 0; cpulist[i]; i++) {
        switch (state) {
        case expect_num:
2204
          if (!c_isdigit (cpulist[i])) {
2205 2206 2207
                vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
                                "digit at position %d (near '%c')."),
                         cpulist, i, cpulist[i]);
2208 2209 2210 2211 2212 2213 2214 2215
                virDomainFree (dom);
                return FALSE;
            }
            state = expect_num_or_comma;
            break;
        case expect_num_or_comma:
            if (cpulist[i] == ',')
                state = expect_num;
2216
            else if (!c_isdigit (cpulist[i])) {
2217 2218 2219
                vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
                                "digit or comma at position %d (near '%c')."),
                         cpulist, i, cpulist[i]);
2220 2221 2222 2223 2224 2225
                virDomainFree (dom);
                return FALSE;
            }
        }
    }
    if (state == expect_num) {
2226 2227 2228
        vshError(ctl, _("cpulist: %s: Invalid format. Trailing comma "
                        "at position %d."),
                 cpulist, i);
2229 2230 2231 2232
        virDomainFree (dom);
        return FALSE;
    }

2233
    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2234
    cpumap = vshCalloc(ctl, 1, cpumaplen);
2235 2236 2237 2238 2239 2240

    do {
        unsigned int cpu = atoi(cpulist);

        if (cpu < VIR_NODEINFO_MAXCPUS(nodeinfo)) {
            VIR_USE_CPU(cpumap, cpu);
2241
        } else {
2242
            vshError(ctl, _("Physical CPU %d doesn't exist."), cpu);
2243
            VIR_FREE(cpumap);
2244 2245
            virDomainFree(dom);
            return FALSE;
2246
        }
2247
        cpulist = strchr(cpulist, ',');
2248 2249 2250 2251 2252 2253 2254 2255
        if (cpulist)
            cpulist++;
    } while (cpulist);

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

2256
    VIR_FREE(cpumap);
2257 2258 2259 2260
    virDomainFree(dom);
    return ret;
}

2261 2262 2263
/*
 * "setvcpus" command
 */
2264
static const vshCmdInfo info_setvcpus[] = {
2265 2266
    {"help", N_("change number of virtual CPUs")},
    {"desc", N_("Change the number of virtual CPUs in the guest domain.")},
2267 2268 2269
    {NULL, NULL}
};

2270
static const vshCmdOptDef opts_setvcpus[] = {
2271 2272
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"count", VSH_OT_DATA, VSH_OFLAG_REQ, N_("number of virtual CPUs")},
2273 2274 2275 2276
    {NULL, 0, 0, NULL}
};

static int
2277
cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
2278 2279 2280
{
    virDomainPtr dom;
    int count;
2281
    int maxcpu;
2282 2283 2284 2285 2286
    int ret = TRUE;

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

J
Jim Meyering 已提交
2287
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2288 2289 2290
        return FALSE;

    count = vshCommandOptInt(cmd, "count", &count);
2291
    if (count <= 0) {
2292
        vshError(ctl, "%s", _("Invalid number of virtual CPUs."));
2293 2294 2295 2296
        virDomainFree(dom);
        return FALSE;
    }

2297
    maxcpu = virDomainGetMaxVcpus(dom);
2298
    if (maxcpu <= 0) {
2299 2300 2301 2302 2303
        virDomainFree(dom);
        return FALSE;
    }

    if (count > maxcpu) {
2304
        vshError(ctl, "%s", _("Too many virtual CPUs."));
2305 2306 2307 2308
        virDomainFree(dom);
        return FALSE;
    }

2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319
    if (virDomainSetVcpus(dom, count) != 0) {
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

/*
 * "setmemory" command
 */
2320
static const vshCmdInfo info_setmem[] = {
2321 2322
    {"help", N_("change memory allocation")},
    {"desc", N_("Change the current memory allocation in the guest domain.")},
2323 2324 2325
    {NULL, NULL}
};

2326
static const vshCmdOptDef opts_setmem[] = {
2327 2328
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"kilobytes", VSH_OT_DATA, VSH_OFLAG_REQ, N_("number of kilobytes of memory")},
2329 2330 2331 2332
    {NULL, 0, 0, NULL}
};

static int
2333
cmdSetmem(vshControl *ctl, const vshCmd *cmd)
2334 2335
{
    virDomainPtr dom;
2336
    virDomainInfo info;
2337
    int kilobytes;
2338 2339 2340 2341 2342
    int ret = TRUE;

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

J
Jim Meyering 已提交
2343
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2344 2345
        return FALSE;

2346 2347
    kilobytes = vshCommandOptInt(cmd, "kilobytes", &kilobytes);
    if (kilobytes <= 0) {
2348
        virDomainFree(dom);
2349
        vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
2350 2351 2352
        return FALSE;
    }

2353 2354
    if (virDomainGetInfo(dom, &info) != 0) {
        virDomainFree(dom);
2355
        vshError(ctl, "%s", _("Unable to verify MaxMemorySize"));
2356 2357 2358 2359 2360
        return FALSE;
    }

    if (kilobytes > info.maxMem) {
        virDomainFree(dom);
2361
        vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
2362 2363 2364
        return FALSE;
    }

2365
    if (virDomainSetMemory(dom, kilobytes) != 0) {
2366 2367 2368 2369 2370 2371 2372 2373 2374 2375
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

/*
 * "setmaxmem" command
 */
2376
static const vshCmdInfo info_setmaxmem[] = {
2377 2378
    {"help", N_("change maximum memory limit")},
    {"desc", N_("Change the maximum memory allocation limit in the guest domain.")},
2379 2380 2381
    {NULL, NULL}
};

2382
static const vshCmdOptDef opts_setmaxmem[] = {
2383 2384
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"kilobytes", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum memory limit in kilobytes")},
2385 2386 2387 2388
    {NULL, 0, 0, NULL}
};

static int
2389
cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
2390 2391
{
    virDomainPtr dom;
2392
    virDomainInfo info;
2393
    int kilobytes;
2394 2395 2396 2397 2398
    int ret = TRUE;

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

J
Jim Meyering 已提交
2399
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2400 2401
        return FALSE;

2402 2403
    kilobytes = vshCommandOptInt(cmd, "kilobytes", &kilobytes);
    if (kilobytes <= 0) {
2404
        virDomainFree(dom);
2405
        vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
2406 2407 2408
        return FALSE;
    }

2409 2410
    if (virDomainGetInfo(dom, &info) != 0) {
        virDomainFree(dom);
2411
        vshError(ctl, "%s", _("Unable to verify current MemorySize"));
2412 2413 2414 2415 2416 2417
        return FALSE;
    }

    if (kilobytes < info.memory) {
        if (virDomainSetMemory(dom, kilobytes) != 0) {
            virDomainFree(dom);
2418
            vshError(ctl, "%s", _("Unable to shrink current MemorySize"));
2419 2420 2421 2422
            return FALSE;
        }
    }

2423
    if (virDomainSetMaxMemory(dom, kilobytes) != 0) {
2424
        vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
2425 2426 2427 2428 2429 2430 2431
        ret = FALSE;
    }

    virDomainFree(dom);
    return ret;
}

2432 2433 2434
/*
 * "nodeinfo" command
 */
2435
static const vshCmdInfo info_nodeinfo[] = {
2436 2437
    {"help", N_("node information")},
    {"desc", N_("Returns basic information about the node.")},
2438 2439 2440 2441
    {NULL, NULL}
};

static int
2442
cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
2443 2444
{
    virNodeInfo info;
2445

2446 2447 2448 2449
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

    if (virNodeGetInfo(ctl->conn, &info) < 0) {
2450
        vshError(ctl, "%s", _("failed to get node information"));
2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461
        return FALSE;
    }
    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);

2462 2463 2464
    return TRUE;
}

2465 2466 2467
/*
 * "capabilities" command
 */
2468
static const vshCmdInfo info_capabilities[] = {
2469 2470
    {"help", N_("capabilities")},
    {"desc", N_("Returns capabilities of hypervisor/driver.")},
2471 2472 2473 2474
    {NULL, NULL}
};

static int
2475
cmdCapabilities (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
2476 2477 2478 2479 2480 2481 2482
{
    char *caps;

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

    if ((caps = virConnectGetCapabilities (ctl->conn)) == NULL) {
2483
        vshError(ctl, "%s", _("failed to get capabilities"));
2484 2485 2486
        return FALSE;
    }
    vshPrint (ctl, "%s\n", caps);
2487
    VIR_FREE(caps);
2488 2489 2490 2491

    return TRUE;
}

2492 2493 2494
/*
 * "dumpxml" command
 */
2495
static const vshCmdInfo info_dumpxml[] = {
2496 2497
    {"help", N_("domain information in XML")},
    {"desc", N_("Output the domain information as an XML dump to stdout.")},
2498
    {NULL, NULL}
2499 2500
};

2501
static const vshCmdOptDef opts_dumpxml[] = {
2502 2503 2504
    {"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")},
2505
    {NULL, 0, 0, NULL}
2506 2507 2508
};

static int
2509
cmdDumpXML(vshControl *ctl, const vshCmd *cmd)
2510
{
2511
    virDomainPtr dom;
K
Karel Zak 已提交
2512
    int ret = TRUE;
2513
    char *dump;
2514 2515 2516 2517 2518 2519 2520 2521
    int flags = 0;
    int inactive = vshCommandOptBool(cmd, "inactive");
    int secure = vshCommandOptBool(cmd, "security-info");

    if (inactive)
        flags |= VIR_DOMAIN_XML_INACTIVE;
    if (secure)
        flags |= VIR_DOMAIN_XML_SECURE;
2522

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

J
Jim Meyering 已提交
2526
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2527
        return FALSE;
2528

2529
    dump = virDomainGetXMLDesc(dom, flags);
2530 2531
    if (dump != NULL) {
        printf("%s", dump);
2532
        VIR_FREE(dump);
2533 2534 2535
    } else {
        ret = FALSE;
    }
2536

2537 2538 2539 2540
    virDomainFree(dom);
    return ret;
}

2541 2542 2543 2544
/*
 * "domxml-from-native" command
 */
static const vshCmdInfo info_domxmlfromnative[] = {
2545 2546
    {"help", N_("Convert native config to domain XML")},
    {"desc", N_("Convert native guest configuration format to domain XML format.")},
2547 2548 2549 2550
    {NULL, NULL}
};

static const vshCmdOptDef opts_domxmlfromnative[] = {
2551 2552
    {"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")},
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
    {NULL, 0, 0, NULL}
};

static int
cmdDomXMLFromNative(vshControl *ctl, const vshCmd *cmd)
{
    int ret = TRUE;
    char *format;
    char *configFile;
    char *configData;
    char *xmlData;
    int flags = 0;

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

    format = vshCommandOptString(cmd, "format", NULL);
    configFile = vshCommandOptString(cmd, "config", NULL);

    if (virFileReadAll(configFile, 1024*1024, &configData) < 0) {
        return FALSE;
    }

    xmlData = virConnectDomainXMLFromNative(ctl->conn, format, configData, flags);
    if (xmlData != NULL) {
        printf("%s", xmlData);
2579
        VIR_FREE(xmlData);
2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590
    } else {
        ret = FALSE;
    }

    return ret;
}

/*
 * "domxml-to-native" command
 */
static const vshCmdInfo info_domxmltonative[] = {
2591 2592
    {"help", N_("Convert domain XML to native config")},
    {"desc", N_("Convert domain XML config to a native guest configuration format.")},
2593 2594 2595 2596
    {NULL, NULL}
};

static const vshCmdOptDef opts_domxmltonative[] = {
2597 2598
    {"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")},
2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624
    {NULL, 0, 0, NULL}
};

static int
cmdDomXMLToNative(vshControl *ctl, const vshCmd *cmd)
{
    int ret = TRUE;
    char *format;
    char *xmlFile;
    char *configData;
    char *xmlData;
    int flags = 0;

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

    format = vshCommandOptString(cmd, "format", NULL);
    xmlFile = vshCommandOptString(cmd, "xml", NULL);

    if (virFileReadAll(xmlFile, 1024*1024, &xmlData) < 0) {
        return FALSE;
    }

    configData = virConnectDomainXMLToNative(ctl->conn, format, xmlData, flags);
    if (configData != NULL) {
        printf("%s", configData);
2625
        VIR_FREE(configData);
2626 2627 2628 2629 2630 2631 2632
    } else {
        ret = FALSE;
    }

    return ret;
}

K
Karel Zak 已提交
2633
/*
K
Karel Zak 已提交
2634
 * "domname" command
K
Karel Zak 已提交
2635
 */
2636
static const vshCmdInfo info_domname[] = {
2637
    {"help", N_("convert a domain id or UUID to domain name")},
2638
    {"desc", ""},
2639
    {NULL, NULL}
K
Karel Zak 已提交
2640 2641
};

2642
static const vshCmdOptDef opts_domname[] = {
2643
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or uuid")},
2644
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
2645 2646 2647
};

static int
2648
cmdDomname(vshControl *ctl, const vshCmd *cmd)
2649
{
K
Karel Zak 已提交
2650 2651 2652 2653
    virDomainPtr dom;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
J
Jim Meyering 已提交
2654
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
2655
                                      VSH_BYID|VSH_BYUUID)))
K
Karel Zak 已提交
2656
        return FALSE;
2657

K
Karel Zak 已提交
2658 2659
    vshPrint(ctl, "%s\n", virDomainGetName(dom));
    virDomainFree(dom);
K
Karel Zak 已提交
2660 2661 2662 2663
    return TRUE;
}

/*
K
Karel Zak 已提交
2664
 * "domid" command
K
Karel Zak 已提交
2665
 */
2666
static const vshCmdInfo info_domid[] = {
2667
    {"help", N_("convert a domain name or UUID to domain id")},
2668
    {"desc", ""},
2669
    {NULL, NULL}
K
Karel Zak 已提交
2670 2671
};

2672
static const vshCmdOptDef opts_domid[] = {
2673
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
2674
    {NULL, 0, 0, NULL}
K
Karel Zak 已提交
2675 2676 2677
};

static int
2678
cmdDomid(vshControl *ctl, const vshCmd *cmd)
2679
{
2680
    virDomainPtr dom;
2681
    unsigned int id;
K
Karel Zak 已提交
2682 2683 2684

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
J
Jim Meyering 已提交
2685
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
2686
                                      VSH_BYNAME|VSH_BYUUID)))
K
Karel Zak 已提交
2687
        return FALSE;
2688

2689 2690
    id = virDomainGetID(dom);
    if (id == ((unsigned int)-1))
2691
        vshPrint(ctl, "%s\n", "-");
2692
    else
2693
        vshPrint(ctl, "%d\n", id);
K
Karel Zak 已提交
2694 2695 2696
    virDomainFree(dom);
    return TRUE;
}
2697

K
Karel Zak 已提交
2698 2699 2700
/*
 * "domuuid" command
 */
2701
static const vshCmdInfo info_domuuid[] = {
2702
    {"help", N_("convert a domain name or id to domain UUID")},
2703
    {"desc", ""},
K
Karel Zak 已提交
2704 2705 2706
    {NULL, NULL}
};

2707
static const vshCmdOptDef opts_domuuid[] = {
2708
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or name")},
K
Karel Zak 已提交
2709 2710 2711 2712
    {NULL, 0, 0, NULL}
};

static int
2713
cmdDomuuid(vshControl *ctl, const vshCmd *cmd)
K
Karel Zak 已提交
2714 2715
{
    virDomainPtr dom;
2716
    char uuid[VIR_UUID_STRING_BUFLEN];
K
Karel Zak 已提交
2717 2718

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
K
Karel Zak 已提交
2719
        return FALSE;
J
Jim Meyering 已提交
2720
    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
2721
                                      VSH_BYNAME|VSH_BYID)))
K
Karel Zak 已提交
2722
        return FALSE;
2723

K
Karel Zak 已提交
2724 2725 2726
    if (virDomainGetUUIDString(dom, uuid) != -1)
        vshPrint(ctl, "%s\n", uuid);
    else
2727
        vshError(ctl, "%s", _("failed to get domain UUID"));
2728

2729
    virDomainFree(dom);
K
Karel Zak 已提交
2730 2731 2732
    return TRUE;
}

2733 2734 2735
/*
 * "migrate" command
 */
2736
static const vshCmdInfo info_migrate[] = {
2737 2738
    {"help", N_("migrate domain to another host")},
    {"desc", N_("Migrate domain to another host.  Add --live for live migration.")},
2739 2740 2741
    {NULL, NULL}
};

2742
static const vshCmdOptDef opts_migrate[] = {
2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753
    {"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")},
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, N_("connection URI of the destination host")},
    {"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)")},
2754 2755 2756 2757
    {NULL, 0, 0, NULL}
};

static int
2758
cmdMigrate (vshControl *ctl, const vshCmd *cmd)
2759 2760 2761 2762
{
    virDomainPtr dom = NULL;
    const char *desturi;
    const char *migrateuri;
D
Daniel Veillard 已提交
2763
    const char *dname;
2764 2765 2766 2767 2768
    int flags = 0, found, ret = FALSE;

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

J
Jim Meyering 已提交
2769
    if (!(dom = vshCommandOptDomain (ctl, cmd, NULL)))
2770 2771 2772 2773
        return FALSE;

    desturi = vshCommandOptString (cmd, "desturi", &found);
    if (!found) {
2774
        vshError(ctl, "%s", _("migrate: Missing desturi"));
2775 2776 2777
        goto done;
    }

2778
    migrateuri = vshCommandOptString (cmd, "migrateuri", NULL);
2779

2780
    dname = vshCommandOptString (cmd, "dname", NULL);
D
Daniel Veillard 已提交
2781

2782 2783
    if (vshCommandOptBool (cmd, "live"))
        flags |= VIR_MIGRATE_LIVE;
2784 2785
    if (vshCommandOptBool (cmd, "p2p"))
        flags |= VIR_MIGRATE_PEER2PEER;
C
Chris Lalancette 已提交
2786 2787 2788
    if (vshCommandOptBool (cmd, "tunnelled"))
        flags |= VIR_MIGRATE_TUNNELLED;

C
Chris Lalancette 已提交
2789 2790 2791 2792 2793
    if (vshCommandOptBool (cmd, "persistent"))
        flags |= VIR_MIGRATE_PERSIST_DEST;
    if (vshCommandOptBool (cmd, "undefinesource"))
        flags |= VIR_MIGRATE_UNDEFINE_SOURCE;

2794 2795 2796
    if (vshCommandOptBool (cmd, "suspend"))
        flags |= VIR_MIGRATE_PAUSED;

2797 2798 2799 2800
    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. */
2801

2802
        if (migrateuri != NULL) {
J
Jim Fehlig 已提交
2803
            vshError(ctl, "%s", _("migrate: Unexpected migrateuri for peer2peer/direct migration"));
2804 2805
            goto done;
        }
2806

2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823
        if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0)
            ret = TRUE;
    } else {
        /* For traditional live migration, connect to the destination host directly. */
        virConnectPtr dconn = NULL;
        virDomainPtr ddom = NULL;

        dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
        if (!dconn) goto done;

        ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
        if (ddom) {
            virDomainFree(ddom);
            ret = TRUE;
        }
        virConnectClose (dconn);
    }
2824 2825 2826 2827 2828 2829

 done:
    if (dom) virDomainFree (dom);
    return ret;
}

2830 2831 2832
/*
 * "net-autostart" command
 */
2833
static const vshCmdInfo info_network_autostart[] = {
2834
    {"help", N_("autostart a network")},
2835
    {"desc",
2836
     N_("Configure a network to be automatically started at boot.")},
2837 2838 2839
    {NULL, NULL}
};

2840
static const vshCmdOptDef opts_network_autostart[] = {
2841 2842
    {"network",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
    {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
2843 2844 2845 2846
    {NULL, 0, 0, NULL}
};

static int
2847
cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd)
2848 2849 2850 2851 2852 2853 2854 2855
{
    virNetworkPtr network;
    char *name;
    int autostart;

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

J
Jim Meyering 已提交
2856
    if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
2857 2858 2859 2860 2861
        return FALSE;

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

    if (virNetworkSetAutostart(network, autostart) < 0) {
2862
        if (autostart)
2863
            vshError(ctl, _("failed to mark network %s as autostarted"), name);
2864
        else
2865
            vshError(ctl, _("failed to unmark network %s as autostarted"), name);
2866 2867 2868 2869
        virNetworkFree(network);
        return FALSE;
    }

2870
    if (autostart)
2871
        vshPrint(ctl, _("Network %s marked as autostarted\n"), name);
2872
    else
2873
        vshPrint(ctl, _("Network %s unmarked as autostarted\n"), name);
2874

L
Laine Stump 已提交
2875
    virNetworkFree(network);
2876 2877
    return TRUE;
}
K
Karel Zak 已提交
2878

2879 2880 2881
/*
 * "net-create" command
 */
2882
static const vshCmdInfo info_network_create[] = {
2883 2884
    {"help", N_("create a network from an XML file")},
    {"desc", N_("Create a network.")},
2885 2886 2887
    {NULL, NULL}
};

2888
static const vshCmdOptDef opts_network_create[] = {
2889
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
2890 2891 2892 2893
    {NULL, 0, 0, NULL}
};

static int
2894
cmdNetworkCreate(vshControl *ctl, const vshCmd *cmd)
2895 2896 2897 2898 2899
{
    virNetworkPtr network;
    char *from;
    int found;
    int ret = TRUE;
2900
    char *buffer;
2901 2902 2903 2904 2905 2906 2907 2908

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

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

2909 2910
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;
2911 2912

    network = virNetworkCreateXML(ctl->conn, buffer);
2913
    VIR_FREE(buffer);
2914

2915 2916 2917
    if (network != NULL) {
        vshPrint(ctl, _("Network %s created from %s\n"),
                 virNetworkGetName(network), from);
L
Laine Stump 已提交
2918
        virNetworkFree(network);
2919
    } else {
2920
        vshError(ctl, _("Failed to create network from %s"), from);
2921 2922 2923 2924 2925 2926 2927 2928 2929
        ret = FALSE;
    }
    return ret;
}


/*
 * "net-define" command
 */
2930
static const vshCmdInfo info_network_define[] = {
2931 2932
    {"help", N_("define (but don't start) a network from an XML file")},
    {"desc", N_("Define a network.")},
2933 2934 2935
    {NULL, NULL}
};

2936
static const vshCmdOptDef opts_network_define[] = {
2937
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
2938 2939 2940 2941
    {NULL, 0, 0, NULL}
};

static int
2942
cmdNetworkDefine(vshControl *ctl, const vshCmd *cmd)
2943 2944 2945 2946 2947
{
    virNetworkPtr network;
    char *from;
    int found;
    int ret = TRUE;
2948
    char *buffer;
2949 2950 2951 2952 2953 2954 2955 2956

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

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

2957 2958
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;
2959 2960

    network = virNetworkDefineXML(ctl->conn, buffer);
2961
    VIR_FREE(buffer);
2962

2963 2964 2965
    if (network != NULL) {
        vshPrint(ctl, _("Network %s defined from %s\n"),
                 virNetworkGetName(network), from);
L
Laine Stump 已提交
2966
        virNetworkFree(network);
2967
    } else {
2968
        vshError(ctl, _("Failed to define network from %s"), from);
2969 2970 2971 2972 2973 2974 2975 2976 2977
        ret = FALSE;
    }
    return ret;
}


/*
 * "net-destroy" command
 */
2978
static const vshCmdInfo info_network_destroy[] = {
2979 2980
    {"help", N_("destroy a network")},
    {"desc", N_("Destroy a given network.")},
2981 2982 2983
    {NULL, NULL}
};

2984
static const vshCmdOptDef opts_network_destroy[] = {
2985
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name, id or uuid")},
2986 2987 2988 2989
    {NULL, 0, 0, NULL}
};

static int
2990
cmdNetworkDestroy(vshControl *ctl, const vshCmd *cmd)
2991 2992 2993 2994 2995 2996 2997 2998
{
    virNetworkPtr network;
    int ret = TRUE;
    char *name;

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

J
Jim Meyering 已提交
2999
    if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
3000 3001 3002 3003 3004
        return FALSE;

    if (virNetworkDestroy(network) == 0) {
        vshPrint(ctl, _("Network %s destroyed\n"), name);
    } else {
3005
        vshError(ctl, _("Failed to destroy network %s"), name);
3006 3007 3008
        ret = FALSE;
    }

3009
    virNetworkFree(network);
3010 3011 3012 3013 3014 3015 3016
    return ret;
}


/*
 * "net-dumpxml" command
 */
3017
static const vshCmdInfo info_network_dumpxml[] = {
3018 3019
    {"help", N_("network information in XML")},
    {"desc", N_("Output the network information as an XML dump to stdout.")},
3020 3021 3022
    {NULL, NULL}
};

3023
static const vshCmdOptDef opts_network_dumpxml[] = {
3024
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name, id or uuid")},
3025 3026 3027 3028
    {NULL, 0, 0, NULL}
};

static int
3029
cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd)
3030 3031 3032 3033 3034 3035 3036 3037
{
    virNetworkPtr network;
    int ret = TRUE;
    char *dump;

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

J
Jim Meyering 已提交
3038
    if (!(network = vshCommandOptNetwork(ctl, cmd, NULL)))
3039 3040 3041 3042 3043
        return FALSE;

    dump = virNetworkGetXMLDesc(network, 0);
    if (dump != NULL) {
        printf("%s", dump);
3044
        VIR_FREE(dump);
3045 3046 3047 3048 3049 3050 3051 3052 3053
    } else {
        ret = FALSE;
    }

    virNetworkFree(network);
    return ret;
}


3054 3055 3056 3057
/*
 * "iface-edit" command
 */
static const vshCmdInfo info_interface_edit[] = {
3058 3059
    {"help", N_("edit XML configuration for a physical host interface")},
    {"desc", N_("Edit the XML configuration for a physical host interface.")},
3060 3061 3062 3063
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_edit[] = {
3064
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceEdit (vshControl *ctl, const vshCmd *cmd)
{
    int ret = FALSE;
    virInterfacePtr iface = NULL;
    char *tmp = NULL;
    char *doc = NULL;
    char *doc_edited = NULL;
    char *doc_reread = NULL;
3077
    int flags = VIR_INTERFACE_XML_INACTIVE;
3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        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;

    unlink (tmp);
    tmp = NULL;

    /* 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));
        ret = TRUE;
        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)) {
3122 3123
        vshError(ctl, "%s",
                 _("ERROR: the XML configuration was changed by another user"));
3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141
        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));

    ret = TRUE;

cleanup:
    if (iface)
        virInterfaceFree (iface);

3142 3143 3144
    VIR_FREE(doc);
    VIR_FREE(doc_edited);
    VIR_FREE(doc_reread);
3145 3146 3147

    if (tmp) {
        unlink (tmp);
3148
        VIR_FREE(tmp);
3149 3150 3151 3152 3153
    }

    return ret;
}

3154 3155 3156
/*
 * "net-list" command
 */
3157
static const vshCmdInfo info_network_list[] = {
3158 3159
    {"help", N_("list networks")},
    {"desc", N_("Returns list of networks.")},
3160 3161 3162
    {NULL, NULL}
};

3163
static const vshCmdOptDef opts_network_list[] = {
3164 3165
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active networks")},
3166 3167 3168 3169
    {NULL, 0, 0, NULL}
};

static int
3170
cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3171 3172 3173 3174 3175
{
    int inactive = vshCommandOptBool(cmd, "inactive");
    int all = vshCommandOptBool(cmd, "all");
    int active = !inactive || all ? 1 : 0;
    int maxactive = 0, maxinactive = 0, i;
3176
    char **activeNames = NULL, **inactiveNames = NULL;
3177 3178 3179 3180 3181 3182
    inactive |= all;

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

    if (active) {
3183 3184
        maxactive = virConnectNumOfNetworks(ctl->conn);
        if (maxactive < 0) {
3185
            vshError(ctl, "%s", _("Failed to list active networks"));
3186
            return FALSE;
3187
        }
3188
        if (maxactive) {
3189
            activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
3190

3191
            if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
3192
                                                    maxactive)) < 0) {
3193
                vshError(ctl, "%s", _("Failed to list active networks"));
3194
                VIR_FREE(activeNames);
3195 3196
                return FALSE;
            }
3197

3198
            qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
3199
        }
3200 3201
    }
    if (inactive) {
3202 3203
        maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
        if (maxinactive < 0) {
3204
            vshError(ctl, "%s", _("Failed to list inactive networks"));
3205
            VIR_FREE(activeNames);
3206
            return FALSE;
3207
        }
3208 3209 3210
        if (maxinactive) {
            inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);

3211 3212 3213
            if ((maxinactive =
                     virConnectListDefinedNetworks(ctl->conn, inactiveNames,
                                                   maxinactive)) < 0) {
3214
                vshError(ctl, "%s", _("Failed to list inactive networks"));
3215 3216
                VIR_FREE(activeNames);
                VIR_FREE(inactiveNames);
3217 3218
                return FALSE;
            }
3219

3220 3221
            qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
        }
3222
    }
3223 3224
    vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
                  _("Autostart"));
3225
    vshPrintExtra(ctl, "-----------------------------------------\n");
3226 3227

    for (i = 0; i < maxactive; i++) {
3228 3229
        virNetworkPtr network =
            virNetworkLookupByName(ctl->conn, activeNames[i]);
3230 3231
        const char *autostartStr;
        int autostart = 0;
3232 3233 3234

        /* this kind of work with networks is not atomic operation */
        if (!network) {
3235
            VIR_FREE(activeNames[i]);
3236
            continue;
3237
        }
3238

3239 3240 3241 3242 3243 3244 3245 3246 3247
        if (virNetworkGetAutostart(network, &autostart) < 0)
            autostartStr = _("no autostart");
        else
            autostartStr = autostart ? "yes" : "no";

        vshPrint(ctl, "%-20s %-10s %-10s\n",
                 virNetworkGetName(network),
                 _("active"),
                 autostartStr);
3248
        virNetworkFree(network);
3249
        VIR_FREE(activeNames[i]);
3250 3251 3252
    }
    for (i = 0; i < maxinactive; i++) {
        virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
3253 3254
        const char *autostartStr;
        int autostart = 0;
3255 3256 3257

        /* this kind of work with networks is not atomic operation */
        if (!network) {
3258
            VIR_FREE(inactiveNames[i]);
3259
            continue;
3260
        }
3261

3262 3263 3264 3265 3266
        if (virNetworkGetAutostart(network, &autostart) < 0)
            autostartStr = _("no autostart");
        else
            autostartStr = autostart ? "yes" : "no";

3267
        vshPrint(ctl, "%-20s %-10s %-10s\n",
3268 3269 3270
                 inactiveNames[i],
                 _("inactive"),
                 autostartStr);
3271 3272

        virNetworkFree(network);
3273
        VIR_FREE(inactiveNames[i]);
3274
    }
3275 3276
    VIR_FREE(activeNames);
    VIR_FREE(inactiveNames);
3277 3278 3279 3280 3281 3282 3283
    return TRUE;
}


/*
 * "net-name" command
 */
3284
static const vshCmdInfo info_network_name[] = {
3285
    {"help", N_("convert a network UUID to network name")},
3286
    {"desc", ""},
3287 3288 3289
    {NULL, NULL}
};

3290
static const vshCmdOptDef opts_network_name[] = {
3291
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network uuid")},
3292 3293 3294 3295
    {NULL, 0, 0, NULL}
};

static int
3296
cmdNetworkName(vshControl *ctl, const vshCmd *cmd)
3297 3298 3299 3300 3301
{
    virNetworkPtr network;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
J
Jim Meyering 已提交
3302
    if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
3303
                                           VSH_BYUUID)))
3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314
        return FALSE;

    vshPrint(ctl, "%s\n", virNetworkGetName(network));
    virNetworkFree(network);
    return TRUE;
}


/*
 * "net-start" command
 */
3315
static const vshCmdInfo info_network_start[] = {
3316 3317
    {"help", N_("start a (previously defined) inactive network")},
    {"desc", N_("Start a network.")},
3318 3319 3320
    {NULL, NULL}
};

3321
static const vshCmdOptDef opts_network_start[] = {
3322
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive network")},
3323 3324 3325 3326
    {NULL, 0, 0, NULL}
};

static int
3327
cmdNetworkStart(vshControl *ctl, const vshCmd *cmd)
3328 3329 3330 3331 3332 3333 3334
{
    virNetworkPtr network;
    int ret = TRUE;

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

J
Jim Meyering 已提交
3335
    if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, VSH_BYNAME)))
3336
         return FALSE;
3337 3338 3339

    if (virNetworkCreate(network) == 0) {
        vshPrint(ctl, _("Network %s started\n"),
3340
                 virNetworkGetName(network));
3341
    } else {
3342
        vshError(ctl, _("Failed to start network %s"),
3343
                 virNetworkGetName(network));
3344 3345
        ret = FALSE;
    }
L
Laine Stump 已提交
3346
    virNetworkFree(network);
3347 3348 3349 3350 3351 3352 3353
    return ret;
}


/*
 * "net-undefine" command
 */
3354
static const vshCmdInfo info_network_undefine[] = {
3355 3356
    {"help", N_("undefine an inactive network")},
    {"desc", N_("Undefine the configuration for an inactive network.")},
3357 3358 3359
    {NULL, NULL}
};

3360
static const vshCmdOptDef opts_network_undefine[] = {
3361
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
3362 3363 3364 3365
    {NULL, 0, 0, NULL}
};

static int
3366
cmdNetworkUndefine(vshControl *ctl, const vshCmd *cmd)
3367 3368 3369 3370 3371 3372 3373 3374
{
    virNetworkPtr network;
    int ret = TRUE;
    char *name;

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

J
Jim Meyering 已提交
3375
    if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
3376 3377 3378 3379 3380
        return FALSE;

    if (virNetworkUndefine(network) == 0) {
        vshPrint(ctl, _("Network %s has been undefined\n"), name);
    } else {
3381
        vshError(ctl, _("Failed to undefine network %s"), name);
3382 3383 3384
        ret = FALSE;
    }

L
Laine Stump 已提交
3385
    virNetworkFree(network);
3386 3387 3388 3389 3390 3391 3392
    return ret;
}


/*
 * "net-uuid" command
 */
3393
static const vshCmdInfo info_network_uuid[] = {
3394
    {"help", N_("convert a network name to network UUID")},
3395
    {"desc", ""},
3396 3397 3398
    {NULL, NULL}
};

3399
static const vshCmdOptDef opts_network_uuid[] = {
3400
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")},
3401 3402 3403 3404
    {NULL, 0, 0, NULL}
};

static int
3405
cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd)
3406 3407 3408 3409 3410 3411 3412
{
    virNetworkPtr network;
    char uuid[VIR_UUID_STRING_BUFLEN];

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

J
Jim Meyering 已提交
3413
    if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
3414
                                           VSH_BYNAME)))
3415 3416 3417 3418 3419
        return FALSE;

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

L
Laine Stump 已提交
3422
    virNetworkFree(network);
3423 3424 3425 3426
    return TRUE;
}


3427 3428 3429 3430 3431
/**************************************************************************/
/*
 * "iface-list" command
 */
static const vshCmdInfo info_interface_list[] = {
3432 3433
    {"help", N_("list physical host interfaces")},
    {"desc", N_("Returns list of physical host interfaces.")},
3434 3435 3436 3437
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_list[] = {
3438 3439
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive interfaces")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active interfaces")},
3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457
    {NULL, 0, 0, NULL}
};
static int
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;

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

    if (active) {
        maxactive = virConnectNumOfInterfaces(ctl->conn);
        if (maxactive < 0) {
3458
            vshError(ctl, "%s", _("Failed to list active interfaces"));
3459 3460 3461 3462 3463 3464 3465
            return FALSE;
        }
        if (maxactive) {
            activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);

            if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames,
                                                    maxactive)) < 0) {
3466
                vshError(ctl, "%s", _("Failed to list active interfaces"));
3467
                VIR_FREE(activeNames);
3468 3469 3470 3471 3472 3473 3474 3475 3476
                return FALSE;
            }

            qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
        }
    }
    if (inactive) {
        maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn);
        if (maxinactive < 0) {
3477
            vshError(ctl, "%s", _("Failed to list inactive interfaces"));
3478
            VIR_FREE(activeNames);
3479 3480 3481 3482 3483
            return FALSE;
        }
        if (maxinactive) {
            inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);

3484 3485 3486
            if ((maxinactive =
                     virConnectListDefinedInterfaces(ctl->conn, inactiveNames,
                                                     maxinactive)) < 0) {
3487
                vshError(ctl, "%s", _("Failed to list inactive interfaces"));
3488 3489
                VIR_FREE(activeNames);
                VIR_FREE(inactiveNames);
3490 3491 3492 3493 3494 3495
                return FALSE;
            }

            qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
        }
    }
3496 3497
    vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
                  _("MAC Address"));
3498 3499 3500
    vshPrintExtra(ctl, "--------------------------------------------\n");

    for (i = 0; i < maxactive; i++) {
3501 3502
        virInterfacePtr iface =
            virInterfaceLookupByName(ctl->conn, activeNames[i]);
3503 3504 3505

        /* this kind of work with interfaces is not atomic */
        if (!iface) {
3506
            VIR_FREE(activeNames[i]);
3507 3508 3509 3510 3511 3512 3513 3514
            continue;
        }

        vshPrint(ctl, "%-20s %-10s %s\n",
                 virInterfaceGetName(iface),
                 _("active"),
                 virInterfaceGetMACString(iface));
        virInterfaceFree(iface);
3515
        VIR_FREE(activeNames[i]);
3516 3517
    }
    for (i = 0; i < maxinactive; i++) {
3518 3519
        virInterfacePtr iface =
            virInterfaceLookupByName(ctl->conn, inactiveNames[i]);
3520 3521 3522

        /* this kind of work with interfaces is not atomic */
        if (!iface) {
3523
            VIR_FREE(inactiveNames[i]);
3524 3525 3526 3527 3528 3529 3530 3531
            continue;
        }

        vshPrint(ctl, "%-20s %-10s %s\n",
                 virInterfaceGetName(iface),
                 _("inactive"),
                 virInterfaceGetMACString(iface));
        virInterfaceFree(iface);
3532
        VIR_FREE(inactiveNames[i]);
3533
    }
3534 3535
    VIR_FREE(activeNames);
    VIR_FREE(inactiveNames);
3536 3537 3538 3539 3540 3541 3542 3543
    return TRUE;

}

/*
 * "iface-name" command
 */
static const vshCmdInfo info_interface_name[] = {
3544
    {"help", N_("convert an interface MAC address to interface name")},
3545 3546 3547 3548 3549
    {"desc", ""},
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_name[] = {
3550
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface mac")},
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceName(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
                                           VSH_BYMAC)))
        return FALSE;

    vshPrint(ctl, "%s\n", virInterfaceGetName(iface));
    virInterfaceFree(iface);
    return TRUE;
}

/*
 * "iface-mac" command
 */
static const vshCmdInfo info_interface_mac[] = {
3574
    {"help", N_("convert an interface name to interface MAC address")},
3575 3576 3577 3578 3579
    {"desc", ""},
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_mac[] = {
3580
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name")},
3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
                                           VSH_BYNAME)))
        return FALSE;

    vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface));
    virInterfaceFree(iface);
    return TRUE;
}

/*
 * "iface-dumpxml" command
 */
static const vshCmdInfo info_interface_dumpxml[] = {
3604 3605
    {"help", N_("interface information in XML")},
    {"desc", N_("Output the physical host interface information as an XML dump to stdout.")},
3606 3607 3608 3609
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_dumpxml[] = {
3610 3611
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
    {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")},
3612 3613 3614 3615 3616 3617 3618 3619 3620
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
    int ret = TRUE;
    char *dump;
3621 3622 3623 3624 3625
    int flags = 0;
    int inactive = vshCommandOptBool(cmd, "inactive");

    if (inactive)
        flags |= VIR_INTERFACE_XML_INACTIVE;
3626 3627 3628 3629 3630 3631 3632

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

    if (!(iface = vshCommandOptInterface(ctl, cmd, NULL)))
        return FALSE;

3633
    dump = virInterfaceGetXMLDesc(iface, flags);
3634 3635
    if (dump != NULL) {
        printf("%s", dump);
3636
        VIR_FREE(dump);
3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
    } else {
        ret = FALSE;
    }

    virInterfaceFree(iface);
    return ret;
}

/*
 * "iface-define" command
 */
static const vshCmdInfo info_interface_define[] = {
3649 3650
    {"help", N_("define (but don't start) a physical host interface from an XML file")},
    {"desc", N_("Define a physical host interface.")},
3651 3652 3653 3654
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_define[] = {
3655
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML interface description")},
3656 3657 3658 3659 3660 3661
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd)
{
3662
    virInterfacePtr iface;
3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677
    char *from;
    int found;
    int ret = TRUE;
    char *buffer;

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

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

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;

3678
    iface = virInterfaceDefineXML(ctl->conn, buffer, 0);
3679
    VIR_FREE(buffer);
3680

3681
    if (iface != NULL) {
3682
        vshPrint(ctl, _("Interface %s defined from %s\n"),
3683
                 virInterfaceGetName(iface), from);
L
Laine Stump 已提交
3684
        virInterfaceFree (iface);
3685
    } else {
3686
        vshError(ctl, _("Failed to define interface from %s"), from);
3687 3688 3689 3690 3691 3692 3693 3694 3695
        ret = FALSE;
    }
    return ret;
}

/*
 * "iface-undefine" command
 */
static const vshCmdInfo info_interface_undefine[] = {
3696 3697
    {"help", N_("undefine a physical host interface (remove it from configuration)")},
    {"desc", N_("undefine an interface.")},
3698 3699 3700 3701
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_undefine[] = {
3702
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
    int ret = TRUE;
    char *name;

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

    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
        return FALSE;

    if (virInterfaceUndefine(iface) == 0) {
        vshPrint(ctl, _("Interface %s undefined\n"), name);
    } else {
3722
        vshError(ctl, _("Failed to undefine interface %s"), name);
3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733
        ret = FALSE;
    }

    virInterfaceFree(iface);
    return ret;
}

/*
 * "iface-start" command
 */
static const vshCmdInfo info_interface_start[] = {
3734 3735
    {"help", N_("start a physical host interface (enable it / \"if-up\")")},
    {"desc", N_("start a physical host interface.")},
3736 3737 3738 3739
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_start[] = {
3740
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceStart(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
    int ret = TRUE;
    char *name;

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

    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
        return FALSE;

    if (virInterfaceCreate(iface, 0) == 0) {
        vshPrint(ctl, _("Interface %s started\n"), name);
    } else {
3760
        vshError(ctl, _("Failed to start interface %s"), name);
3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771
        ret = FALSE;
    }

    virInterfaceFree(iface);
    return ret;
}

/*
 * "iface-destroy" command
 */
static const vshCmdInfo info_interface_destroy[] = {
3772 3773
    {"help", N_("destroy a physical host interface (disable it / \"if-down\")")},
    {"desc", N_("destroy a physical host interface.")},
3774 3775 3776 3777
    {NULL, NULL}
};

static const vshCmdOptDef opts_interface_destroy[] = {
3778
    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797
    {NULL, 0, 0, NULL}
};

static int
cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd)
{
    virInterfacePtr iface;
    int ret = TRUE;
    char *name;

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

    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
        return FALSE;

    if (virInterfaceDestroy(iface, 0) == 0) {
        vshPrint(ctl, _("Interface %s destroyed\n"), name);
    } else {
3798
        vshError(ctl, _("Failed to destroy interface %s"), name);
3799 3800 3801 3802 3803 3804 3805 3806
        ret = FALSE;
    }

    virInterfaceFree(iface);
    return ret;
}

/**************************************************************************/
3807
/*
3808
 * "pool-autostart" command
3809
 */
3810
static const vshCmdInfo info_pool_autostart[] = {
3811
    {"help", N_("autostart a pool")},
3812
    {"desc",
3813
     N_("Configure a pool to be automatically started at boot.")},
3814
    {NULL, NULL}
3815 3816
};

3817
static const vshCmdOptDef opts_pool_autostart[] = {
3818 3819
    {"pool",  VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
    {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
3820 3821
    {NULL, 0, 0, NULL}
};
3822 3823

static int
3824
cmdPoolAutostart(vshControl *ctl, const vshCmd *cmd)
3825
{
3826 3827 3828
    virStoragePoolPtr pool;
    char *name;
    int autostart;
3829 3830 3831

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

3833
    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
3834 3835
        return FALSE;

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

3838 3839
    if (virStoragePoolSetAutostart(pool, autostart) < 0) {
        if (autostart)
3840
            vshError(ctl, _("failed to mark pool %s as autostarted"), name);
3841
        else
3842
            vshError(ctl, _("failed to unmark pool %s as autostarted"), name);
3843
        virStoragePoolFree(pool);
3844 3845 3846
        return FALSE;
    }

3847
    if (autostart)
3848
        vshPrint(ctl, _("Pool %s marked as autostarted\n"), name);
3849
    else
3850
        vshPrint(ctl, _("Pool %s unmarked as autostarted\n"), name);
3851

L
Laine Stump 已提交
3852
    virStoragePoolFree(pool);
3853 3854 3855
    return TRUE;
}

3856
/*
3857
 * "pool-create" command
3858
 */
3859
static const vshCmdInfo info_pool_create[] = {
3860 3861
    {"help", N_("create a pool from an XML file")},
    {"desc", N_("Create a pool.")},
3862 3863 3864
    {NULL, NULL}
};

3865
static const vshCmdOptDef opts_pool_create[] = {
J
Jim Meyering 已提交
3866
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
3867
     N_("file containing an XML pool description")},
3868 3869 3870
    {NULL, 0, 0, NULL}
};

3871
static int
3872
cmdPoolCreate(vshControl *ctl, const vshCmd *cmd)
3873
{
3874 3875 3876 3877 3878
    virStoragePoolPtr pool;
    char *from;
    int found;
    int ret = TRUE;
    char *buffer;
3879 3880 3881 3882

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

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

3887 3888
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;
3889

3890
    pool = virStoragePoolCreateXML(ctl->conn, buffer, 0);
3891
    VIR_FREE(buffer);
3892 3893 3894 3895

    if (pool != NULL) {
        vshPrint(ctl, _("Pool %s created from %s\n"),
                 virStoragePoolGetName(pool), from);
L
Laine Stump 已提交
3896
        virStoragePoolFree(pool);
3897
    } else {
3898
        vshError(ctl, _("Failed to create pool from %s"), from);
3899 3900 3901
        ret = FALSE;
    }
    return ret;
3902 3903
}

3904

3905 3906 3907 3908
/*
 * "nodedev-create" command
 */
static const vshCmdInfo info_node_device_create[] = {
3909
    {"help", N_("create a device defined "
3910
                          "by an XML file on the node")},
3911
    {"desc", N_("Create a device on the node.  Note that this "
3912 3913 3914 3915 3916 3917 3918
                          "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,
3919
     N_("file containing an XML description of the device")},
3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944
    {NULL, 0, 0, NULL}
};

static int
cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
{
    virNodeDevicePtr dev = NULL;
    char *from;
    int found = 0;
    int ret = TRUE;
    char *buffer;

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

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

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
        return FALSE;
    }

    dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0);
3945
    VIR_FREE(buffer);
3946 3947 3948 3949

    if (dev != NULL) {
        vshPrint(ctl, _("Node device %s created from %s\n"),
                 virNodeDeviceGetName(dev), from);
L
Laine Stump 已提交
3950
        virNodeDeviceFree(dev);
3951
    } else {
3952
        vshError(ctl, _("Failed to create node device from %s"), from);
3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963
        ret = FALSE;
    }

    return ret;
}


/*
 * "nodedev-destroy" command
 */
static const vshCmdInfo info_node_device_destroy[] = {
3964 3965
    {"help", N_("destroy a device on the node")},
    {"desc", N_("Destroy a device on the node.  Note that this "
3966 3967 3968 3969 3970 3971
                          "command destroys devices on the physical host ")},
    {NULL, NULL}
};

static const vshCmdOptDef opts_node_device_destroy[] = {
    {"name", VSH_OT_DATA, VSH_OFLAG_REQ,
3972
     N_("name of the device to be destroyed")},
3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997
    {NULL, 0, 0, NULL}
};

static int
cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
{
    virNodeDevicePtr dev = NULL;
    int ret = TRUE;
    int found = 0;
    char *name;

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

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

    dev = virNodeDeviceLookupByName(ctl->conn, name);

    if (virNodeDeviceDestroy(dev) == 0) {
        vshPrint(ctl, _("Destroyed node device '%s'\n"), name);
    } else {
3998
        vshError(ctl, _("Failed to destroy node device '%s'"), name);
3999 4000 4001 4002 4003 4004 4005 4006
        ret = FALSE;
    }

    virNodeDeviceFree(dev);
    return ret;
}


4007
/*
4008
 * XML Building helper for pool-define-as and pool-create-as
4009
 */
4010
static const vshCmdOptDef opts_pool_X_as[] = {
4011 4012 4013 4014 4015 4016 4017 4018
    {"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")},
4019 4020 4021
    {NULL, 0, 0, NULL}
};

4022
static int buildPoolXML(const vshCmd *cmd, char **retname, char **xml) {
4023 4024

    int found;
4025
    char *name, *type, *srcHost, *srcPath, *srcDev, *srcName, *target;
4026
    virBuffer buf = VIR_BUFFER_INITIALIZER;
4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037

    name = vshCommandOptString(cmd, "name", &found);
    if (!found)
        goto cleanup;
    type = vshCommandOptString(cmd, "type", &found);
    if (!found)
        goto cleanup;

    srcHost = vshCommandOptString(cmd, "source-host", &found);
    srcPath = vshCommandOptString(cmd, "source-path", &found);
    srcDev = vshCommandOptString(cmd, "source-dev", &found);
4038
    srcName = vshCommandOptString(cmd, "source-name", &found);
4039 4040
    target = vshCommandOptString(cmd, "target", &found);

4041 4042
    virBufferVSprintf(&buf, "<pool type='%s'>\n", type);
    virBufferVSprintf(&buf, "  <name>%s</name>\n", name);
4043
    if (srcHost || srcPath || srcDev) {
4044
        virBufferAddLit(&buf, "  <source>\n");
4045

4046 4047
        if (srcHost)
            virBufferVSprintf(&buf, "    <host name='%s'/>\n", srcHost);
4048 4049 4050 4051
        if (srcPath)
            virBufferVSprintf(&buf, "    <dir path='%s'/>\n", srcPath);
        if (srcDev)
            virBufferVSprintf(&buf, "    <device path='%s'/>\n", srcDev);
4052 4053
        if (srcName)
            virBufferVSprintf(&buf, "    <name>%s</name>\n", srcName);
4054 4055

        virBufferAddLit(&buf, "  </source>\n");
4056 4057
    }
    if (target) {
4058 4059 4060
        virBufferAddLit(&buf, "  <target>\n");
        virBufferVSprintf(&buf, "    <path>%s</path>\n", target);
        virBufferAddLit(&buf, "  </target>\n");
4061
    }
4062 4063 4064 4065 4066 4067
    virBufferAddLit(&buf, "</pool>\n");

    if (virBufferError(&buf)) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
        return FALSE;
    }
4068 4069 4070 4071 4072 4073

    *xml = virBufferContentAndReset(&buf);
    *retname = name;
    return TRUE;

cleanup:
4074
    virBufferFreeAndReset(&buf);
4075 4076 4077 4078 4079 4080 4081
    return FALSE;
}

/*
 * "pool-create-as" command
 */
static const vshCmdInfo info_pool_create_as[] = {
4082 4083
    {"help", N_("create a pool from a set of args")},
    {"desc", N_("Create a pool.")},
4084 4085 4086 4087 4088 4089 4090 4091
    {NULL, NULL}
};

static int
cmdPoolCreateAs(vshControl *ctl, const vshCmd *cmd)
{
    virStoragePoolPtr pool;
    char *xml, *name;
4092
    int printXML = vshCommandOptBool(cmd, "print-xml");
4093 4094 4095 4096 4097 4098

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

    if (!buildPoolXML(cmd, &name, &xml))
        return FALSE;
4099

4100 4101
    if (printXML) {
        printf("%s", xml);
4102
        VIR_FREE(xml);
4103
    } else {
4104
        pool = virStoragePoolCreateXML(ctl->conn, xml, 0);
4105
        VIR_FREE(xml);
4106

4107 4108 4109 4110
        if (pool != NULL) {
            vshPrint(ctl, _("Pool %s created\n"), name);
            virStoragePoolFree(pool);
        } else {
4111
            vshError(ctl, _("Failed to create pool %s"), name);
4112 4113 4114 4115
            return FALSE;
        }
    }
    return TRUE;
4116 4117
}

4118

4119
/*
4120
 * "pool-define" command
4121
 */
4122
static const vshCmdInfo info_pool_define[] = {
4123 4124
    {"help", N_("define (but don't start) a pool from an XML file")},
    {"desc", N_("Define a pool.")},
4125 4126 4127
    {NULL, NULL}
};

4128
static const vshCmdOptDef opts_pool_define[] = {
4129
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML pool description")},
4130 4131 4132
    {NULL, 0, 0, NULL}
};

4133
static int
4134
cmdPoolDefine(vshControl *ctl, const vshCmd *cmd)
4135
{
4136 4137 4138 4139 4140
    virStoragePoolPtr pool;
    char *from;
    int found;
    int ret = TRUE;
    char *buffer;
4141 4142 4143 4144

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

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

4149 4150
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;
4151

4152
    pool = virStoragePoolDefineXML(ctl->conn, buffer, 0);
4153
    VIR_FREE(buffer);
4154 4155 4156 4157

    if (pool != NULL) {
        vshPrint(ctl, _("Pool %s defined from %s\n"),
                 virStoragePoolGetName(pool), from);
L
Laine Stump 已提交
4158
        virStoragePoolFree(pool);
4159
    } else {
4160
        vshError(ctl, _("Failed to define pool from %s"), from);
4161 4162 4163
        ret = FALSE;
    }
    return ret;
4164 4165
}

4166

4167 4168 4169
/*
 * "pool-define-as" command
 */
4170
static const vshCmdInfo info_pool_define_as[] = {
4171 4172
    {"help", N_("define a pool from a set of args")},
    {"desc", N_("Define a pool.")},
4173 4174 4175 4176
    {NULL, NULL}
};

static int
4177
cmdPoolDefineAs(vshControl *ctl, const vshCmd *cmd)
4178 4179
{
    virStoragePoolPtr pool;
4180
    char *xml, *name;
4181
    int printXML = vshCommandOptBool(cmd, "print-xml");
4182 4183 4184 4185

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

4186
    if (!buildPoolXML(cmd, &name, &xml))
4187 4188
        return FALSE;

4189 4190
    if (printXML) {
        printf("%s", xml);
4191
        VIR_FREE(xml);
4192
    } else {
4193
        pool = virStoragePoolDefineXML(ctl->conn, xml, 0);
4194
        VIR_FREE(xml);
4195

4196 4197 4198 4199
        if (pool != NULL) {
            vshPrint(ctl, _("Pool %s defined\n"), name);
            virStoragePoolFree(pool);
        } else {
4200
            vshError(ctl, _("Failed to define pool %s"), name);
4201 4202 4203 4204
            return FALSE;
        }
    }
    return TRUE;
4205 4206 4207
}


4208
/*
4209
 * "pool-build" command
4210
 */
4211
static const vshCmdInfo info_pool_build[] = {
4212 4213
    {"help", N_("build a pool")},
    {"desc", N_("Build a given pool.")},
4214 4215 4216
    {NULL, NULL}
};

4217
static const vshCmdOptDef opts_pool_build[] = {
4218
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4219 4220 4221 4222
    {NULL, 0, 0, NULL}
};

static int
4223
cmdPoolBuild(vshControl *ctl, const vshCmd *cmd)
4224
{
4225 4226 4227
    virStoragePoolPtr pool;
    int ret = TRUE;
    char *name;
4228 4229 4230 4231

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

4232
    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
4233 4234
        return FALSE;

4235
    if (virStoragePoolBuild(pool, 0) == 0) {
4236
        vshPrint(ctl, _("Pool %s built\n"), name);
4237
    } else {
4238
        vshError(ctl, _("Failed to build pool %s"), name);
4239
        ret = FALSE;
4240 4241
    }

4242 4243
    virStoragePoolFree(pool);

4244 4245 4246
    return ret;
}

4247

4248
/*
4249
 * "pool-destroy" command
4250
 */
4251
static const vshCmdInfo info_pool_destroy[] = {
4252 4253
    {"help", N_("destroy a pool")},
    {"desc", N_("Destroy a given pool.")},
4254 4255 4256
    {NULL, NULL}
};

4257
static const vshCmdOptDef opts_pool_destroy[] = {
4258
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4259 4260 4261 4262
    {NULL, 0, 0, NULL}
};

static int
4263
cmdPoolDestroy(vshControl *ctl, const vshCmd *cmd)
4264
{
4265 4266 4267
    virStoragePoolPtr pool;
    int ret = TRUE;
    char *name;
4268 4269 4270 4271

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

4272
    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
4273 4274
        return FALSE;

4275 4276 4277
    if (virStoragePoolDestroy(pool) == 0) {
        vshPrint(ctl, _("Pool %s destroyed\n"), name);
    } else {
4278
        vshError(ctl, _("Failed to destroy pool %s"), name);
4279
        ret = FALSE;
4280 4281
    }

4282
    virStoragePoolFree(pool);
4283 4284 4285
    return ret;
}

4286

4287
/*
4288 4289
 * "pool-delete" command
 */
4290
static const vshCmdInfo info_pool_delete[] = {
4291 4292
    {"help", N_("delete a pool")},
    {"desc", N_("Delete a given pool.")},
4293 4294 4295
    {NULL, NULL}
};

4296
static const vshCmdOptDef opts_pool_delete[] = {
4297
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4298 4299 4300 4301
    {NULL, 0, 0, NULL}
};

static int
4302
cmdPoolDelete(vshControl *ctl, const vshCmd *cmd)
4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314
{
    virStoragePoolPtr pool;
    int ret = TRUE;
    char *name;

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

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
        return FALSE;

    if (virStoragePoolDelete(pool, 0) == 0) {
D
Daniel Veillard 已提交
4315
        vshPrint(ctl, _("Pool %s deleted\n"), name);
4316
    } else {
4317
        vshError(ctl, _("Failed to delete pool %s"), name);
4318 4319 4320
        ret = FALSE;
    }

L
Laine Stump 已提交
4321
    virStoragePoolFree(pool);
4322 4323 4324 4325 4326 4327 4328
    return ret;
}


/*
 * "pool-refresh" command
 */
4329
static const vshCmdInfo info_pool_refresh[] = {
4330 4331
    {"help", N_("refresh a pool")},
    {"desc", N_("Refresh a given pool.")},
4332 4333 4334
    {NULL, NULL}
};

4335
static const vshCmdOptDef opts_pool_refresh[] = {
4336
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4337 4338 4339 4340
    {NULL, 0, 0, NULL}
};

static int
4341
cmdPoolRefresh(vshControl *ctl, const vshCmd *cmd)
4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355
{
    virStoragePoolPtr pool;
    int ret = TRUE;
    char *name;

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

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
        return FALSE;

    if (virStoragePoolRefresh(pool, 0) == 0) {
        vshPrint(ctl, _("Pool %s refreshed\n"), name);
    } else {
4356
        vshError(ctl, _("Failed to refresh pool %s"), name);
4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367
        ret = FALSE;
    }
    virStoragePoolFree(pool);

    return ret;
}


/*
 * "pool-dumpxml" command
 */
4368
static const vshCmdInfo info_pool_dumpxml[] = {
4369 4370
    {"help", N_("pool information in XML")},
    {"desc", N_("Output the pool information as an XML dump to stdout.")},
4371 4372 4373
    {NULL, NULL}
};

4374
static const vshCmdOptDef opts_pool_dumpxml[] = {
4375
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4376 4377 4378 4379
    {NULL, 0, 0, NULL}
};

static int
4380
cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd)
4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394
{
    virStoragePoolPtr pool;
    int ret = TRUE;
    char *dump;

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

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
        return FALSE;

    dump = virStoragePoolGetXMLDesc(pool, 0);
    if (dump != NULL) {
        printf("%s", dump);
4395
        VIR_FREE(dump);
4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407
    } else {
        ret = FALSE;
    }

    virStoragePoolFree(pool);
    return ret;
}


/*
 * "pool-list" command
 */
4408
static const vshCmdInfo info_pool_list[] = {
4409 4410
    {"help", N_("list pools")},
    {"desc", N_("Returns list of pools.")},
4411 4412 4413
    {NULL, NULL}
};

4414
static const vshCmdOptDef opts_pool_list[] = {
4415 4416
    {"inactive", VSH_OT_BOOL, 0, N_("list inactive pools")},
    {"all", VSH_OT_BOOL, 0, N_("list inactive & active pools")},
4417 4418 4419 4420
    {NULL, 0, 0, NULL}
};

static int
4421
cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435
{
    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;

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

    if (active) {
        maxactive = virConnectNumOfStoragePools(ctl->conn);
        if (maxactive < 0) {
4436
            vshError(ctl, "%s", _("Failed to list active pools"));
4437 4438 4439 4440 4441 4442 4443
            return FALSE;
        }
        if (maxactive) {
            activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);

            if ((maxactive = virConnectListStoragePools(ctl->conn, activeNames,
                                                        maxactive)) < 0) {
4444
                vshError(ctl, "%s", _("Failed to list active pools"));
4445
                VIR_FREE(activeNames);
4446 4447 4448 4449 4450 4451 4452 4453 4454
                return FALSE;
            }

            qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
        }
    }
    if (inactive) {
        maxinactive = virConnectNumOfDefinedStoragePools(ctl->conn);
        if (maxinactive < 0) {
4455
            vshError(ctl, "%s", _("Failed to list inactive pools"));
4456
            VIR_FREE(activeNames);
4457 4458 4459 4460 4461 4462
            return FALSE;
        }
        if (maxinactive) {
            inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);

            if ((maxinactive = virConnectListDefinedStoragePools(ctl->conn, inactiveNames, maxinactive)) < 0) {
4463
                vshError(ctl, "%s", _("Failed to list inactive pools"));
4464 4465
                VIR_FREE(activeNames);
                VIR_FREE(inactiveNames);
4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481
                return FALSE;
            }

            qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
        }
    }
    vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("State"), _("Autostart"));
    vshPrintExtra(ctl, "-----------------------------------------\n");

    for (i = 0; i < maxactive; i++) {
        virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, activeNames[i]);
        const char *autostartStr;
        int autostart = 0;

        /* this kind of work with pools is not atomic operation */
        if (!pool) {
4482
            VIR_FREE(activeNames[i]);
4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495
            continue;
        }

        if (virStoragePoolGetAutostart(pool, &autostart) < 0)
            autostartStr = _("no autostart");
        else
            autostartStr = autostart ? "yes" : "no";

        vshPrint(ctl, "%-20s %-10s %-10s\n",
                 virStoragePoolGetName(pool),
                 _("active"),
                 autostartStr);
        virStoragePoolFree(pool);
4496
        VIR_FREE(activeNames[i]);
4497 4498 4499 4500 4501 4502 4503 4504
    }
    for (i = 0; i < maxinactive; i++) {
        virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, inactiveNames[i]);
        const char *autostartStr;
        int autostart = 0;

        /* this kind of work with pools is not atomic operation */
        if (!pool) {
4505
            VIR_FREE(inactiveNames[i]);
4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519
            continue;
        }

        if (virStoragePoolGetAutostart(pool, &autostart) < 0)
            autostartStr = _("no autostart");
        else
            autostartStr = autostart ? "yes" : "no";

        vshPrint(ctl, "%-20s %-10s %-10s\n",
                 inactiveNames[i],
                 _("inactive"),
                 autostartStr);

        virStoragePoolFree(pool);
4520
        VIR_FREE(inactiveNames[i]);
4521
    }
4522 4523
    VIR_FREE(activeNames);
    VIR_FREE(inactiveNames);
4524 4525 4526
    return TRUE;
}

4527 4528 4529 4530
/*
 * "find-storage-pool-sources-as" command
 */
static const vshCmdInfo info_find_storage_pool_sources_as[] = {
4531 4532
    {"help", N_("find potential storage pool sources")},
    {"desc", N_("Returns XML <sources> document.")},
4533 4534 4535 4536 4537
    {NULL, NULL}
};

static const vshCmdOptDef opts_find_storage_pool_sources_as[] = {
    {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
4538 4539 4540
     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")},
4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575
    {NULL, 0, 0, NULL}
};

static int
cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
{
    char *type, *host;
    char *srcSpec = NULL;
    char *srcList;
    int found;

    type = vshCommandOptString(cmd, "type", &found);
    if (!found)
        return FALSE;
    host = vshCommandOptString(cmd, "host", &found);
    if (!found)
        host = NULL;

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

    if (host) {
        size_t hostlen = strlen(host);
        char *port = vshCommandOptString(cmd, "port", &found);
        int ret;
        if (!found) {
            port = strrchr(host, ':');
            if (port) {
                if (*(++port))
                    hostlen = port - host - 1;
                else
                    port = NULL;
            }
        }
        ret = port ?
4576 4577 4578 4579 4580 4581
            virAsprintf(&srcSpec,
                        "<source><host name='%.*s' port='%s'/></source>",
                        (int)hostlen, host, port) :
            virAsprintf(&srcSpec,
                        "<source><host name='%.*s'/></source>",
                        (int)hostlen, host);
4582 4583 4584
        if (ret < 0) {
            switch (errno) {
            case ENOMEM:
4585
                vshError(ctl, "%s", _("Out of memory"));
4586 4587
                break;
            default:
4588
                vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
4589 4590 4591 4592 4593 4594
            }
            return FALSE;
        }
    }

    srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
4595
    VIR_FREE(srcSpec);
4596
    if (srcList == NULL) {
4597
        vshError(ctl, _("Failed to find any %s pool sources"), type);
4598 4599 4600
        return FALSE;
    }
    vshPrint(ctl, "%s", srcList);
4601
    VIR_FREE(srcList);
4602 4603 4604 4605 4606 4607 4608 4609 4610

    return TRUE;
}


/*
 * "find-storage-pool-sources" command
 */
static const vshCmdInfo info_find_storage_pool_sources[] = {
4611 4612
    {"help", N_("discover potential storage pool sources")},
    {"desc", N_("Returns XML <sources> document.")},
4613 4614 4615 4616 4617
    {NULL, NULL}
};

static const vshCmdOptDef opts_find_storage_pool_sources[] = {
    {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
4618
     N_("type of storage pool sources to discover")},
4619
    {"srcSpec", VSH_OT_DATA, VSH_OFLAG_NONE,
4620
     N_("optional file of source xml to query for pools")},
4621 4622 4623 4624 4625 4626
    {NULL, 0, 0, NULL}
};

static int
cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
{
4627 4628
    char *type, *srcSpecFile, *srcList;
    char *srcSpec = NULL;
4629 4630 4631 4632 4633 4634
    int found;

    type = vshCommandOptString(cmd, "type", &found);
    if (!found)
        return FALSE;
    srcSpecFile = vshCommandOptString(cmd, "srcSpec", &found);
4635
    if (!found)
4636 4637 4638 4639 4640 4641 4642 4643 4644
        srcSpecFile = NULL;

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

    if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0)
        return FALSE;

    srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
4645
    VIR_FREE(srcSpec);
4646
    if (srcList == NULL) {
4647
        vshError(ctl, _("Failed to find any %s pool sources"), type);
4648 4649 4650
        return FALSE;
    }
    vshPrint(ctl, "%s", srcList);
4651
    VIR_FREE(srcList);
4652 4653 4654 4655 4656

    return TRUE;
}


4657 4658 4659
/*
 * "pool-info" command
 */
4660
static const vshCmdInfo info_pool_info[] = {
4661 4662
    {"help", N_("storage pool information")},
    {"desc", N_("Returns basic information about the storage pool.")},
4663 4664 4665
    {NULL, NULL}
};

4666
static const vshCmdOptDef opts_pool_info[] = {
4667
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4668 4669 4670 4671
    {NULL, 0, 0, NULL}
};

static int
4672
cmdPoolInfo(vshControl *ctl, const vshCmd *cmd)
4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734
{
    virStoragePoolInfo info;
    virStoragePoolPtr pool;
    int ret = TRUE;
    char uuid[VIR_UUID_STRING_BUFLEN];

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

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
        return FALSE;

    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;
        }

        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 {
        ret = FALSE;
    }

    virStoragePoolFree(pool);
    return ret;
}


/*
 * "pool-name" command
 */
4735
static const vshCmdInfo info_pool_name[] = {
4736
    {"help", N_("convert a pool UUID to pool name")},
4737
    {"desc", ""},
4738 4739 4740
    {NULL, NULL}
};

4741
static const vshCmdOptDef opts_pool_name[] = {
4742
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")},
4743 4744 4745 4746
    {NULL, 0, 0, NULL}
};

static int
4747
cmdPoolName(vshControl *ctl, const vshCmd *cmd)
4748 4749 4750 4751 4752 4753
{
    virStoragePoolPtr pool;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
4754
                                           VSH_BYUUID)))
4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765
        return FALSE;

    vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
    virStoragePoolFree(pool);
    return TRUE;
}


/*
 * "pool-start" command
 */
4766
static const vshCmdInfo info_pool_start[] = {
4767 4768
    {"help", N_("start a (previously defined) inactive pool")},
    {"desc", N_("Start a pool.")},
4769 4770 4771
    {NULL, NULL}
};

4772
static const vshCmdOptDef opts_pool_start[] = {
4773
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive pool")},
4774 4775 4776 4777
    {NULL, 0, 0, NULL}
};

static int
4778
cmdPoolStart(vshControl *ctl, const vshCmd *cmd)
4779 4780 4781 4782 4783 4784 4785
{
    virStoragePoolPtr pool;
    int ret = TRUE;

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

4786
    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
4787 4788 4789 4790 4791 4792
         return FALSE;

    if (virStoragePoolCreate(pool, 0) == 0) {
        vshPrint(ctl, _("Pool %s started\n"),
                 virStoragePoolGetName(pool));
    } else {
4793
        vshError(ctl, _("Failed to start pool %s"), virStoragePoolGetName(pool));
4794 4795
        ret = FALSE;
    }
L
Laine Stump 已提交
4796 4797

    virStoragePoolFree(pool);
4798 4799 4800 4801
    return ret;
}


4802 4803 4804
/*
 * "vol-create-as" command
 */
4805
static const vshCmdInfo info_vol_create_as[] = {
4806 4807
    {"help", N_("create a volume from a set of args")},
    {"desc", N_("Create a vol.")},
4808 4809 4810
    {NULL, NULL}
};

4811
static const vshCmdOptDef opts_vol_create_as[] = {
4812 4813 4814 4815 4816
    {"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")},
4817 4818 4819 4820 4821 4822 4823 4824 4825 4826
    {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 已提交
4827
        /* Deliberate fallthrough cases here :-) */
4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848
        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;
}

static int
4849
cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd)
4850 4851 4852 4853
{
    virStoragePoolPtr pool;
    virStorageVolPtr vol;
    int found;
4854
    char *xml;
4855 4856
    char *name, *capacityStr, *allocationStr, *format;
    unsigned long long capacity, allocation = 0;
4857
    virBuffer buf = VIR_BUFFER_INITIALIZER;
4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873

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

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
                                     VSH_BYNAME)))
        return FALSE;

    name = vshCommandOptString(cmd, "name", &found);
    if (!found)
        goto cleanup;

    capacityStr = vshCommandOptString(cmd, "capacity", &found);
    if (!found)
        goto cleanup;
    if (cmdVolSize(capacityStr, &capacity) < 0)
4874
        vshError(ctl, _("Malformed size %s"), capacityStr);
4875 4876 4877 4878

    allocationStr = vshCommandOptString(cmd, "allocation", &found);
    if (allocationStr &&
        cmdVolSize(allocationStr, &allocation) < 0)
4879
        vshError(ctl, _("Malformed size %s"), allocationStr);
4880 4881 4882

    format = vshCommandOptString(cmd, "format", &found);

4883 4884 4885 4886 4887
    virBufferAddLit(&buf, "<volume>\n");
    virBufferVSprintf(&buf, "  <name>%s</name>\n", name);
    virBufferVSprintf(&buf, "  <capacity>%llu</capacity>\n", capacity);
    if (allocationStr)
        virBufferVSprintf(&buf, "  <allocation>%llu</allocation>\n", allocation);
4888 4889

    if (format) {
4890
        virBufferAddLit(&buf, "  <target>\n");
4891
        virBufferVSprintf(&buf, "    <format type='%s'/>\n",format);
4892
        virBufferAddLit(&buf, "  </target>\n");
4893
    }
4894 4895
    virBufferAddLit(&buf, "</volume>\n");

4896

4897 4898 4899 4900 4901 4902
    if (virBufferError(&buf)) {
        vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
        return FALSE;
    }
    xml = virBufferContentAndReset(&buf);
    vol = virStorageVolCreateXML(pool, xml, 0);
4903
    VIR_FREE(xml);
4904 4905 4906 4907 4908 4909 4910
    virStoragePoolFree(pool);

    if (vol != NULL) {
        vshPrint(ctl, _("Vol %s created\n"), name);
        virStorageVolFree(vol);
        return TRUE;
    } else {
4911
        vshError(ctl, _("Failed to create vol %s"), name);
4912 4913 4914 4915
        return FALSE;
    }

 cleanup:
4916
    virBufferFreeAndReset(&buf);
4917 4918 4919 4920 4921
    virStoragePoolFree(pool);
    return FALSE;
}


4922 4923 4924
/*
 * "pool-undefine" command
 */
4925
static const vshCmdInfo info_pool_undefine[] = {
4926 4927
    {"help", N_("undefine an inactive pool")},
    {"desc", N_("Undefine the configuration for an inactive pool.")},
4928 4929 4930
    {NULL, NULL}
};

4931
static const vshCmdOptDef opts_pool_undefine[] = {
4932
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4933 4934 4935 4936
    {NULL, 0, 0, NULL}
};

static int
4937
cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd)
4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951
{
    virStoragePoolPtr pool;
    int ret = TRUE;
    char *name;

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

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
        return FALSE;

    if (virStoragePoolUndefine(pool) == 0) {
        vshPrint(ctl, _("Pool %s has been undefined\n"), name);
    } else {
4952
        vshError(ctl, _("Failed to undefine pool %s"), name);
4953 4954 4955
        ret = FALSE;
    }

L
Laine Stump 已提交
4956
    virStoragePoolFree(pool);
4957 4958 4959 4960 4961 4962 4963
    return ret;
}


/*
 * "pool-uuid" command
 */
4964
static const vshCmdInfo info_pool_uuid[] = {
4965
    {"help", N_("convert a pool name to pool UUID")},
4966
    {"desc", ""},
4967 4968 4969
    {NULL, NULL}
};

4970
static const vshCmdOptDef opts_pool_uuid[] = {
4971
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
4972 4973 4974 4975
    {NULL, 0, 0, NULL}
};

static int
4976
cmdPoolUuid(vshControl *ctl, const vshCmd *cmd)
4977 4978 4979 4980 4981 4982 4983 4984
{
    virStoragePoolPtr pool;
    char uuid[VIR_UUID_STRING_BUFLEN];

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

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
4985
                                           VSH_BYNAME)))
4986 4987 4988 4989 4990
        return FALSE;

    if (virStoragePoolGetUUIDString(pool, uuid) != -1)
        vshPrint(ctl, "%s\n", uuid);
    else
4991
        vshError(ctl, "%s", _("failed to get pool UUID"));
4992

L
Laine Stump 已提交
4993
    virStoragePoolFree(pool);
4994 4995 4996 4997 4998 4999 5000
    return TRUE;
}


/*
 * "vol-create" command
 */
5001
static const vshCmdInfo info_vol_create[] = {
5002 5003
    {"help", N_("create a vol from an XML file")},
    {"desc", N_("Create a vol.")},
5004 5005 5006
    {NULL, NULL}
};

5007
static const vshCmdOptDef opts_vol_create[] = {
5008 5009
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
5010 5011 5012 5013
    {NULL, 0, 0, NULL}
};

static int
5014
cmdVolCreate(vshControl *ctl, const vshCmd *cmd)
5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026
{
    virStoragePoolPtr pool;
    virStorageVolPtr vol;
    char *from;
    int found;
    int ret = TRUE;
    char *buffer;

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

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
5027
                                           VSH_BYNAME)))
5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041
        return FALSE;

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

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
        virStoragePoolFree(pool);
        return FALSE;
    }

    vol = virStorageVolCreateXML(pool, buffer, 0);
5042
    VIR_FREE(buffer);
5043 5044 5045 5046 5047 5048 5049
    virStoragePoolFree(pool);

    if (vol != NULL) {
        vshPrint(ctl, _("Vol %s created from %s\n"),
                 virStorageVolGetName(vol), from);
        virStorageVolFree(vol);
    } else {
5050
        vshError(ctl, _("Failed to create vol from %s"), from);
5051 5052 5053 5054 5055
        ret = FALSE;
    }
    return ret;
}

5056 5057 5058 5059
/*
 * "vol-create-from" command
 */
static const vshCmdInfo info_vol_create_from[] = {
5060 5061
    {"help", N_("create a vol, using another volume as input")},
    {"desc", N_("Create a vol from an existing volume.")},
5062 5063 5064 5065
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_create_from[] = {
5066 5067 5068 5069
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
    {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")},
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")},
5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106
    {NULL, 0, 0, NULL}
};

static int
cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd)
{
    virStoragePoolPtr pool = NULL;
    virStorageVolPtr newvol = NULL, inputvol = NULL;
    char *from;
    int found;
    int ret = FALSE;
    char *buffer = NULL;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        goto cleanup;

    if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
        goto cleanup;

    from = vshCommandOptString(cmd, "file", &found);
    if (!found) {
        goto cleanup;
    }

    if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL)))
        goto cleanup;

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
        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 {
5107
        vshError(ctl, _("Failed to create vol from %s"), from);
5108 5109 5110 5111 5112
        goto cleanup;
    }

    ret = TRUE;
cleanup:
5113
    VIR_FREE(buffer);
5114 5115 5116 5117
    if (pool)
        virStoragePoolFree(pool);
    if (inputvol)
        virStorageVolFree(inputvol);
L
Laine Stump 已提交
5118 5119
    if (newvol)
        virStorageVolFree(newvol);
5120 5121 5122 5123 5124 5125
    return ret;
}

static xmlChar *
makeCloneXML(char *origxml, char *newname) {

5126 5127 5128
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlXPathObjectPtr obj = NULL;
5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158
    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[] = {
5159 5160
    {"help", N_("clone a volume.")},
    {"desc", N_("Clone an existing volume.")},
5161 5162 5163 5164
    {NULL, NULL}
};

static const vshCmdOptDef opts_vol_clone[] = {
5165 5166 5167
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")},
    {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")},
5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188
    {NULL, 0, 0, NULL}
};

static int
cmdVolClone(vshControl *ctl, const vshCmd *cmd)
{
    virStoragePoolPtr origpool = NULL;
    virStorageVolPtr origvol = NULL, newvol = NULL;
    char *name, *origxml = NULL;
    xmlChar *newxml = NULL;
    int found;
    int ret = FALSE;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        goto cleanup;

    if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
        goto cleanup;

    origpool = virStoragePoolLookupByVolume(origvol);
    if (!origpool) {
5189
        vshError(ctl, "%s", _("failed to get parent pool"));
5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212
        goto cleanup;
    }

    name = vshCommandOptString(cmd, "newname", &found);
    if (!found)
        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 {
5213
        vshError(ctl, _("Failed to clone vol from %s"),
5214 5215 5216 5217 5218 5219 5220
                 virStorageVolGetName(origvol));
        goto cleanup;
    }

    ret = TRUE;

cleanup:
5221
    VIR_FREE(origxml);
5222 5223 5224
    xmlFree(newxml);
    if (origvol)
        virStorageVolFree(origvol);
L
Laine Stump 已提交
5225 5226
    if (newvol)
        virStorageVolFree(newvol);
5227 5228 5229 5230 5231
    if (origpool)
        virStoragePoolFree(origpool);
    return ret;
}

5232 5233 5234
/*
 * "vol-delete" command
 */
5235
static const vshCmdInfo info_vol_delete[] = {
5236 5237
    {"help", N_("delete a vol")},
    {"desc", N_("Delete a given vol.")},
5238 5239 5240
    {NULL, NULL}
};

5241
static const vshCmdOptDef opts_vol_delete[] = {
5242 5243
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
5244 5245 5246 5247
    {NULL, 0, 0, NULL}
};

static int
5248
cmdVolDelete(vshControl *ctl, const vshCmd *cmd)
5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261
{
    virStorageVolPtr vol;
    int ret = TRUE;
    char *name;

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

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
        return FALSE;
    }

    if (virStorageVolDelete(vol, 0) == 0) {
D
Daniel Veillard 已提交
5262
        vshPrint(ctl, _("Vol %s deleted\n"), name);
5263
    } else {
5264
        vshError(ctl, _("Failed to delete vol %s"), name);
5265 5266 5267
        ret = FALSE;
    }

L
Laine Stump 已提交
5268
    virStorageVolFree(vol);
5269 5270 5271 5272 5273 5274 5275
    return ret;
}


/*
 * "vol-info" command
 */
5276
static const vshCmdInfo info_vol_info[] = {
5277 5278
    {"help", N_("storage vol information")},
    {"desc", N_("Returns basic information about the storage vol.")},
5279 5280 5281
    {NULL, NULL}
};

5282
static const vshCmdOptDef opts_vol_info[] = {
5283 5284
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
5285 5286 5287 5288
    {NULL, 0, 0, NULL}
};

static int
5289
cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 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
{
    virStorageVolInfo info;
    virStorageVolPtr vol;
    int ret = TRUE;

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

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
        return FALSE;

    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 {
        ret = FALSE;
    }

    virStorageVolFree(vol);
    return ret;
}


/*
 * "vol-dumpxml" command
 */
5327
static const vshCmdInfo info_vol_dumpxml[] = {
5328 5329
    {"help", N_("vol information in XML")},
    {"desc", N_("Output the vol information as an XML dump to stdout.")},
5330 5331 5332
    {NULL, NULL}
};

5333
static const vshCmdOptDef opts_vol_dumpxml[] = {
5334 5335
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
5336 5337 5338 5339
    {NULL, 0, 0, NULL}
};

static int
5340
cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd)
5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354
{
    virStorageVolPtr vol;
    int ret = TRUE;
    char *dump;

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

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
        return FALSE;

    dump = virStorageVolGetXMLDesc(vol, 0);
    if (dump != NULL) {
        printf("%s", dump);
5355
        VIR_FREE(dump);
5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367
    } else {
        ret = FALSE;
    }

    virStorageVolFree(vol);
    return ret;
}


/*
 * "vol-list" command
 */
5368
static const vshCmdInfo info_vol_list[] = {
5369 5370
    {"help", N_("list vols")},
    {"desc", N_("Returns list of vols by pool.")},
5371 5372 5373
    {NULL, NULL}
};

5374
static const vshCmdOptDef opts_vol_list[] = {
5375
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5376 5377 5378 5379
    {NULL, 0, 0, NULL}
};

static int
5380
cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394
{
    virStoragePoolPtr pool;
    int maxactive = 0, i;
    char **activeNames = NULL;

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

    if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
        return FALSE;

    maxactive = virStoragePoolNumOfVolumes(pool);
    if (maxactive < 0) {
        virStoragePoolFree(pool);
5395
        vshError(ctl, "%s", _("Failed to list active vols"));
5396 5397 5398 5399 5400 5401 5402
        return FALSE;
    }
    if (maxactive) {
        activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);

        if ((maxactive = virStoragePoolListVolumes(pool, activeNames,
                                                   maxactive)) < 0) {
5403
            vshError(ctl, "%s", _("Failed to list active vols"));
5404
            VIR_FREE(activeNames);
5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419
            virStoragePoolFree(pool);
            return FALSE;
        }

        qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
    }
    vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path"));
    vshPrintExtra(ctl, "-----------------------------------------\n");

    for (i = 0; i < maxactive; i++) {
        virStorageVolPtr vol = virStorageVolLookupByName(pool, activeNames[i]);
        char *path;

        /* this kind of work with vols is not atomic operation */
        if (!vol) {
5420
            VIR_FREE(activeNames[i]);
5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432
            continue;
        }

        if ((path = virStorageVolGetPath(vol)) == NULL) {
            virStorageVolFree(vol);
            continue;
        }


        vshPrint(ctl, "%-20s %-40s\n",
                 virStorageVolGetName(vol),
                 path);
5433
        VIR_FREE(path);
5434
        virStorageVolFree(vol);
5435
        VIR_FREE(activeNames[i]);
5436
    }
5437
    VIR_FREE(activeNames);
5438 5439 5440 5441 5442 5443 5444 5445
    virStoragePoolFree(pool);
    return TRUE;
}


/*
 * "vol-name" command
 */
5446
static const vshCmdInfo info_vol_name[] = {
5447
    {"help", N_("convert a vol UUID to vol name")},
5448
    {"desc", ""},
5449 5450 5451
    {NULL, NULL}
};

5452
static const vshCmdOptDef opts_vol_name[] = {
5453
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol key or path")},
5454 5455 5456 5457
    {NULL, 0, 0, NULL}
};

static int
5458
cmdVolName(vshControl *ctl, const vshCmd *cmd)
5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478
{
    virStorageVolPtr vol;

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

    if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
                                   VSH_BYUUID)))
        return FALSE;

    vshPrint(ctl, "%s\n", virStorageVolGetName(vol));
    virStorageVolFree(vol);
    return TRUE;
}



/*
 * "vol-key" command
 */
5479
static const vshCmdInfo info_vol_key[] = {
5480
    {"help", N_("convert a vol UUID to vol key")},
5481
    {"desc", ""},
5482 5483 5484
    {NULL, NULL}
};

5485
static const vshCmdOptDef opts_vol_key[] = {
5486
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol uuid")},
5487 5488 5489 5490
    {NULL, 0, 0, NULL}
};

static int
5491
cmdVolKey(vshControl *ctl, const vshCmd *cmd)
5492 5493 5494 5495 5496 5497
{
    virStorageVolPtr vol;

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

5498
    if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511
                                   VSH_BYUUID)))
        return FALSE;

    vshPrint(ctl, "%s\n", virStorageVolGetKey(vol));
    virStorageVolFree(vol);
    return TRUE;
}



/*
 * "vol-path" command
 */
5512
static const vshCmdInfo info_vol_path[] = {
5513
    {"help", N_("convert a vol UUID to vol path")},
5514
    {"desc", ""},
5515 5516 5517
    {NULL, NULL}
};

5518
static const vshCmdOptDef opts_vol_path[] = {
5519 5520
    {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
    {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name or key")},
5521 5522 5523 5524
    {NULL, 0, 0, NULL}
};

static int
5525
cmdVolPath(vshControl *ctl, const vshCmd *cmd)
5526 5527
{
    virStorageVolPtr vol;
5528
    char *name = NULL;
5529 5530 5531

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

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
5534
        return FALSE;
5535
    }
5536 5537 5538 5539 5540 5541 5542

    vshPrint(ctl, "%s\n", virStorageVolGetPath(vol));
    virStorageVolFree(vol);
    return TRUE;
}


5543 5544 5545 5546
/*
 * "secret-define" command
 */
static const vshCmdInfo info_secret_define[] = {
5547 5548
    {"help", N_("define or modify a secret from an XML file")},
    {"desc", N_("Define or modify a secret.")},
5549 5550
    {NULL, NULL}
};
5551

5552
static const vshCmdOptDef opts_secret_define[] = {
5553
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")},
5554 5555
    {NULL, 0, 0, NULL}
};
5556

5557 5558 5559
static int
cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
{
5560
    char *from, *buffer;
5561
    virSecretPtr res;
5562
    char uuid[VIR_UUID_STRING_BUFLEN];
5563

5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574
    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;

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

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;

    res = virSecretDefineXML(ctl->conn, buffer, 0);
5575
    VIR_FREE(buffer);
5576 5577

    if (res == NULL) {
5578
        vshError(ctl, _("Failed to set attributes from %s"), from);
5579 5580
        return FALSE;
    }
5581
    if (virSecretGetUUIDString(res, &(uuid[0])) < 0) {
5582
        vshError(ctl, "%s", _("Failed to get UUID of created secret"));
5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594
        virSecretFree(res);
        return FALSE;
    }
    vshPrint(ctl, _("Secret %s created\n"), uuid);
    virSecretFree(res);
    return TRUE;
}

/*
 * "secret-dumpxml" command
 */
static const vshCmdInfo info_secret_dumpxml[] = {
5595 5596
    {"help", N_("secret attributes in XML")},
    {"desc", N_("Output attributes of a secret as an XML dump to stdout.")},
5597 5598 5599 5600
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_dumpxml[] = {
5601
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622
    {NULL, 0, 0, NULL}
};

static int
cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
    int ret = FALSE;
    char *xml;

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

    secret = vshCommandOptSecret(ctl, cmd, NULL);
    if (secret == NULL)
        return FALSE;

    xml = virSecretGetXMLDesc(secret, 0);
    if (xml == NULL)
        goto cleanup;
    printf("%s", xml);
5623
    VIR_FREE(xml);
5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634
    ret = TRUE;

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-set-value" command
 */
static const vshCmdInfo info_secret_set_value[] = {
5635 5636
    {"help", N_("set a secret value")},
    {"desc", N_("Set a secret value.")},
5637 5638 5639 5640
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_set_value[] = {
5641 5642
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
    {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")},
5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665
    {NULL, 0, 0, NULL}
};

static int
cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
    size_t value_size;
    char *base64, *value;
    int found, res, ret = FALSE;

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

    secret = vshCommandOptSecret(ctl, cmd, NULL);
    if (secret == NULL)
        return FALSE;

    base64 = vshCommandOptString(cmd, "base64", &found);
    if (!base64)
        goto cleanup;

    if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
J
Jim Meyering 已提交
5666
        vshError(ctl, "%s", _("Invalid base64 data"));
5667 5668 5669
        goto cleanup;
    }
    if (value == NULL) {
5670
        vshError(ctl, "%s", _("Failed to allocate memory"));
5671 5672 5673 5674 5675
        return FALSE;
    }

    res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
    memset(value, 0, value_size);
5676
    VIR_FREE(value);
5677 5678

    if (res != 0) {
5679
        vshError(ctl, "%s", _("Failed to set secret value"));
5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693
        goto cleanup;
    }
    vshPrint(ctl, "%s", _("Secret value set\n"));
    ret = TRUE;

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-get-value" command
 */
static const vshCmdInfo info_secret_get_value[] = {
5694 5695
    {"help", N_("Output a secret value")},
    {"desc", N_("Output a secret value to stdout.")},
5696 5697 5698 5699
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_get_value[] = {
5700
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725
    {NULL, 0, 0, NULL}
};

static int
cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
    char *base64;
    unsigned char *value;
    size_t value_size;
    int ret = FALSE;

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

    secret = vshCommandOptSecret(ctl, cmd, NULL);
    if (secret == NULL)
        return FALSE;

    value = virSecretGetValue(secret, &value_size, 0);
    if (value == NULL)
        goto cleanup;

    base64_encode_alloc((char *)value, value_size, &base64);
    memset(value, 0, value_size);
5726
    VIR_FREE(value);
5727 5728

    if (base64 == NULL) {
5729
        vshError(ctl, "%s", _("Failed to allocate memory"));
5730 5731 5732 5733
        goto cleanup;
    }
    printf("%s", base64);
    memset(base64, 0, strlen(base64));
5734
    VIR_FREE(base64);
5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745
    ret = TRUE;

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-undefine" command
 */
static const vshCmdInfo info_secret_undefine[] = {
5746 5747
    {"help", N_("undefine a secret")},
    {"desc", N_("Undefine a secret.")},
5748 5749 5750 5751
    {NULL, NULL}
};

static const vshCmdOptDef opts_secret_undefine[] = {
5752
    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770
    {NULL, 0, 0, NULL}
};

static int
cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
{
    virSecretPtr secret;
    int ret = FALSE;
    char *uuid;

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

    secret = vshCommandOptSecret(ctl, cmd, &uuid);
    if (secret == NULL)
        return FALSE;

    if (virSecretUndefine(secret) < 0) {
5771
        vshError(ctl, _("Failed to delete secret %s"), uuid);
5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785
        goto cleanup;
    }
    vshPrint(ctl, _("Secret %s deleted\n"), uuid);
    ret = TRUE;

cleanup:
    virSecretFree(secret);
    return ret;
}

/*
 * "secret-list" command
 */
static const vshCmdInfo info_secret_list[] = {
5786 5787
    {"help", N_("list secrets")},
    {"desc", N_("Returns a list of secrets")},
5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801
    {NULL, NULL}
};

static int
cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    int maxuuids = 0, i;
    char **uuids = NULL;

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

    maxuuids = virConnectNumOfSecrets(ctl->conn);
    if (maxuuids < 0) {
5802
        vshError(ctl, "%s", _("Failed to list secrets"));
5803 5804 5805 5806 5807 5808
        return FALSE;
    }
    uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);

    maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
    if (maxuuids < 0) {
5809
        vshError(ctl, "%s", _("Failed to list secrets"));
5810
        VIR_FREE(uuids);
5811 5812 5813 5814 5815
        return FALSE;
    }

    qsort(uuids, maxuuids, sizeof(char *), namesorter);

5816 5817
    vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage"));
    vshPrintExtra(ctl, "-----------------------------------------------------------\n");
5818 5819

    for (i = 0; i < maxuuids; i++) {
5820 5821 5822 5823
        virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]);
        const char *usageType = NULL;

        if (!sec) {
5824
            VIR_FREE(uuids[i]);
5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842
            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);
5843
        VIR_FREE(uuids[i]);
5844
    }
5845
    VIR_FREE(uuids);
5846 5847
    return TRUE;
}
5848 5849 5850 5851 5852


/*
 * "version" command
 */
5853
static const vshCmdInfo info_version[] = {
5854 5855
    {"help", N_("show version")},
    {"desc", N_("Display the system version information.")},
5856 5857 5858 5859 5860
    {NULL, NULL}
};


static int
5861
cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877
{
    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;

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

    hvType = virConnectGetType(ctl->conn);
    if (hvType == NULL) {
5878
        vshError(ctl, "%s", _("failed to get hypervisor type"));
5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891
        return FALSE;
    }

    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) {
5892
        vshError(ctl, "%s", _("failed to get the library version"));
5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910
        return FALSE;
    }
    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) {
5911
        vshError(ctl, "%s", _("failed to get the hypervisor version"));
5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928
        return FALSE;
    }
    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);
    }
    return TRUE;
}

5929 5930 5931 5932
/*
 * "nodedev-list" command
 */
static const vshCmdInfo info_node_list_devices[] = {
5933
    {"help", N_("enumerate devices on this host")},
5934
    {"desc", ""},
5935 5936 5937 5938
    {NULL, NULL}
};

static const vshCmdOptDef opts_node_list_devices[] = {
5939 5940
    {"tree", VSH_OT_BOOL, 0, N_("list devices in a tree")},
    {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability name")},
5941 5942 5943
    {NULL, 0, 0, NULL}
};

5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965
#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] = '-';
5966 5967
        indentBuf[indentIdx+2] = ' ';
        indentBuf[indentIdx+3] = '\0';
5968 5969 5970
    }

    /* Print this device */
5971
    vshPrint(ctl, "%s", indentBuf);
5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994
    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) {
5995
        vshPrint(ctl, "%s", indentBuf);
5996
        vshPrint(ctl, " |\n");
5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018
    }

    /* 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) {
6019
        vshPrint(ctl, "%s", indentBuf);
6020 6021 6022 6023
        vshPrint(ctl, "\n");
    }
}

6024 6025 6026 6027 6028 6029
static int
cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    char *cap;
    char **devices;
    int found, num_devices, i;
6030
    int tree = vshCommandOptBool(cmd, "tree");
6031 6032 6033 6034 6035 6036 6037 6038 6039 6040

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

    cap = vshCommandOptString(cmd, "cap", &found);
    if (!found)
        cap = NULL;

    num_devices = virNodeNumOfDevices(ctl->conn, cap, 0);
    if (num_devices < 0) {
6041
        vshError(ctl, "%s", _("Failed to count node devices"));
6042 6043 6044 6045 6046 6047 6048 6049 6050
        return FALSE;
    } else if (num_devices == 0) {
        return TRUE;
    }

    devices = vshMalloc(ctl, sizeof(char *) * num_devices);
    num_devices =
        virNodeListDevices(ctl->conn, cap, devices, num_devices, 0);
    if (num_devices < 0) {
6051
        vshError(ctl, "%s", _("Failed to list node devices"));
6052
        VIR_FREE(devices);
6053 6054
        return FALSE;
    }
6055
    qsort(&devices[0], num_devices, sizeof(char*), namesorter);
6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082
    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);
                parents[i] = parent ? strdup(parent) : NULL;
            } 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++) {
6083 6084
            VIR_FREE(devices[i]);
            VIR_FREE(parents[i]);
6085
        }
6086
        VIR_FREE(parents);
6087 6088 6089
    } else {
        for (i = 0; i < num_devices; i++) {
            vshPrint(ctl, "%s\n", devices[i]);
6090
            VIR_FREE(devices[i]);
6091
        }
6092
    }
6093
    VIR_FREE(devices);
6094 6095 6096 6097 6098 6099 6100
    return TRUE;
}

/*
 * "nodedev-dumpxml" command
 */
static const vshCmdInfo info_node_device_dumpxml[] = {
6101 6102
    {"help", N_("node device details in XML")},
    {"desc", N_("Output the node device details as an XML dump to stdout.")},
6103 6104 6105 6106 6107
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_dumpxml[] = {
6108
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
6109 6110 6111 6112 6113 6114 6115 6116
    {NULL, 0, 0, NULL}
};

static int
cmdNodeDeviceDumpXML (vshControl *ctl, const vshCmd *cmd)
{
    const char *name;
    virNodeDevicePtr device;
L
Laine Stump 已提交
6117
    char *xml;
6118 6119 6120 6121 6122 6123

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!(name = vshCommandOptString(cmd, "device", NULL)))
        return FALSE;
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
6124
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
6125 6126 6127
        return FALSE;
    }

L
Laine Stump 已提交
6128 6129 6130 6131 6132 6133 6134
    xml = virNodeDeviceGetXMLDesc(device, 0);
    if (!xml) {
        virNodeDeviceFree(device);
        return FALSE;
    }

    vshPrint(ctl, "%s\n", xml);
6135
    VIR_FREE(xml);
6136 6137 6138 6139
    virNodeDeviceFree(device);
    return TRUE;
}

6140 6141 6142 6143
/*
 * "nodedev-dettach" command
 */
static const vshCmdInfo info_node_device_dettach[] = {
6144 6145
    {"help", N_("dettach node device from its device driver")},
    {"desc", N_("Dettach node device from its device driver before assigning to a domain.")},
6146 6147 6148 6149 6150
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_dettach[] = {
6151
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166
    {NULL, 0, 0, NULL}
};

static int
cmdNodeDeviceDettach (vshControl *ctl, const vshCmd *cmd)
{
    const char *name;
    virNodeDevicePtr device;
    int ret = TRUE;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!(name = vshCommandOptString(cmd, "device", NULL)))
        return FALSE;
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
6167
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
6168 6169 6170 6171 6172 6173
        return FALSE;
    }

    if (virNodeDeviceDettach(device) == 0) {
        vshPrint(ctl, _("Device %s dettached\n"), name);
    } else {
6174
        vshError(ctl, _("Failed to dettach device %s"), name);
6175 6176 6177 6178 6179 6180 6181 6182 6183 6184
        ret = FALSE;
    }
    virNodeDeviceFree(device);
    return ret;
}

/*
 * "nodedev-reattach" command
 */
static const vshCmdInfo info_node_device_reattach[] = {
6185 6186
    {"help", N_("reattach node device to its device driver")},
    {"desc", N_("Reattach node device to its device driver once released by the domain.")},
6187 6188 6189 6190 6191
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_reattach[] = {
6192
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207
    {NULL, 0, 0, NULL}
};

static int
cmdNodeDeviceReAttach (vshControl *ctl, const vshCmd *cmd)
{
    const char *name;
    virNodeDevicePtr device;
    int ret = TRUE;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!(name = vshCommandOptString(cmd, "device", NULL)))
        return FALSE;
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
6208
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
6209 6210 6211 6212 6213 6214
        return FALSE;
    }

    if (virNodeDeviceReAttach(device) == 0) {
        vshPrint(ctl, _("Device %s re-attached\n"), name);
    } else {
6215
        vshError(ctl, _("Failed to re-attach device %s"), name);
6216 6217 6218 6219 6220 6221 6222 6223 6224 6225
        ret = FALSE;
    }
    virNodeDeviceFree(device);
    return ret;
}

/*
 * "nodedev-reset" command
 */
static const vshCmdInfo info_node_device_reset[] = {
6226 6227
    {"help", N_("reset node device")},
    {"desc", N_("Reset node device before or after assigning to a domain.")},
6228 6229 6230 6231 6232
    {NULL, NULL}
};


static const vshCmdOptDef opts_node_device_reset[] = {
6233
    {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248
    {NULL, 0, 0, NULL}
};

static int
cmdNodeDeviceReset (vshControl *ctl, const vshCmd *cmd)
{
    const char *name;
    virNodeDevicePtr device;
    int ret = TRUE;

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        return FALSE;
    if (!(name = vshCommandOptString(cmd, "device", NULL)))
        return FALSE;
    if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
6249
        vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
6250 6251 6252 6253 6254 6255
        return FALSE;
    }

    if (virNodeDeviceReset(device) == 0) {
        vshPrint(ctl, _("Device %s reset\n"), name);
    } else {
6256
        vshError(ctl, _("Failed to reset device %s"), name);
6257 6258 6259 6260 6261 6262
        ret = FALSE;
    }
    virNodeDeviceFree(device);
    return ret;
}

6263 6264 6265
/*
 * "hostkey" command
 */
6266
static const vshCmdInfo info_hostname[] = {
6267
    {"help", N_("print the hypervisor hostname")},
6268
    {"desc", ""},
6269 6270 6271 6272
    {NULL, NULL}
};

static int
6273
cmdHostname (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
6274 6275 6276 6277 6278 6279 6280 6281
{
    char *hostname;

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

    hostname = virConnectGetHostname (ctl->conn);
    if (hostname == NULL) {
6282
        vshError(ctl, "%s", _("failed to get hostname"));
6283 6284 6285 6286
        return FALSE;
    }

    vshPrint (ctl, "%s\n", hostname);
6287
    VIR_FREE(hostname);
6288 6289 6290 6291 6292 6293 6294

    return TRUE;
}

/*
 * "uri" command
 */
6295
static const vshCmdInfo info_uri[] = {
6296
    {"help", N_("print the hypervisor canonical URI")},
6297
    {"desc", ""},
6298 6299 6300 6301
    {NULL, NULL}
};

static int
6302
cmdURI (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
6303 6304 6305 6306 6307 6308 6309 6310
{
    char *uri;

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

    uri = virConnectGetURI (ctl->conn);
    if (uri == NULL) {
6311
        vshError(ctl, "%s", _("failed to get URI"));
6312 6313 6314 6315
        return FALSE;
    }

    vshPrint (ctl, "%s\n", uri);
6316
    VIR_FREE(uri);
6317 6318 6319 6320 6321 6322 6323

    return TRUE;
}

/*
 * "vncdisplay" command
 */
6324
static const vshCmdInfo info_vncdisplay[] = {
6325 6326
    {"help", N_("vnc display")},
    {"desc", N_("Output the IP address and port number for the VNC display.")},
6327 6328 6329
    {NULL, NULL}
};

6330
static const vshCmdOptDef opts_vncdisplay[] = {
6331
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
6332 6333 6334 6335
    {NULL, 0, 0, NULL}
};

static int
6336
cmdVNCDisplay(vshControl *ctl, const vshCmd *cmd)
6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348
{
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj = NULL;
    xmlXPathContextPtr ctxt = NULL;
    virDomainPtr dom;
    int ret = FALSE;
    int port = 0;
    char *doc;

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

J
Jim Meyering 已提交
6349
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
6350 6351 6352 6353 6354 6355 6356 6357 6358
        return FALSE;

    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);
6359
    VIR_FREE(doc);
6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377
    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) ||
6378
        STREQ((const char*)obj->stringval, "0.0.0.0")) {
6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398
        vshPrint(ctl, ":%d\n", port-5900);
    } else {
        vshPrint(ctl, "%s:%d\n", (const char *)obj->stringval, port-5900);
    }
    xmlXPathFreeObject(obj);
    obj = NULL;
    ret = TRUE;

 cleanup:
    xmlXPathFreeObject(obj);
    xmlXPathFreeContext(ctxt);
    if (xml)
        xmlFreeDoc(xml);
    virDomainFree(dom);
    return ret;
}

/*
 * "ttyconsole" command
 */
6399
static const vshCmdInfo info_ttyconsole[] = {
6400 6401
    {"help", N_("tty console")},
    {"desc", N_("Output the device for the TTY console.")},
6402 6403 6404
    {NULL, NULL}
};

6405
static const vshCmdOptDef opts_ttyconsole[] = {
6406
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
6407 6408 6409 6410
    {NULL, 0, 0, NULL}
};

static int
6411
cmdTTYConsole(vshControl *ctl, const vshCmd *cmd)
6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422
{
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj = NULL;
    xmlXPathContextPtr ctxt = NULL;
    virDomainPtr dom;
    int ret = FALSE;
    char *doc;

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

J
Jim Meyering 已提交
6423
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
6424 6425 6426 6427 6428 6429 6430 6431 6432
        return FALSE;

    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);
6433
    VIR_FREE(doc);
6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445
    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);
6446
    ret = TRUE;
6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458

 cleanup:
    xmlXPathFreeObject(obj);
    xmlXPathFreeContext(ctxt);
    if (xml)
        xmlFreeDoc(xml);
    virDomainFree(dom);
    return ret;
}

/*
 * "attach-device" command
6459
 */
6460
static const vshCmdInfo info_attach_device[] = {
6461 6462
    {"help", N_("attach device from an XML file")},
    {"desc", N_("Attach device from an XML <file>.")},
6463 6464 6465
    {NULL, NULL}
};

6466
static const vshCmdOptDef opts_attach_device[] = {
6467 6468 6469
    {"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")},
6470 6471 6472 6473
    {NULL, 0, 0, NULL}
};

static int
6474
cmdAttachDevice(vshControl *ctl, const vshCmd *cmd)
6475 6476 6477 6478 6479 6480
{
    virDomainPtr dom;
    char *from;
    char *buffer;
    int ret = TRUE;
    int found;
J
Jim Fehlig 已提交
6481
    unsigned int flags;
6482 6483 6484 6485

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

J
Jim Meyering 已提交
6486
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
6487 6488 6489 6490
        return FALSE;

    from = vshCommandOptString(cmd, "file", &found);
    if (!found) {
6491
        vshError(ctl, "%s", _("attach-device: Missing <file> option"));
6492 6493 6494 6495
        virDomainFree(dom);
        return FALSE;
    }

6496 6497
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
        virDomainFree(dom);
6498
        return FALSE;
6499
    }
6500

J
Jim Fehlig 已提交
6501 6502 6503 6504 6505 6506 6507 6508
    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);
    }
6509
    VIR_FREE(buffer);
6510 6511

    if (ret < 0) {
6512
        vshError(ctl, _("Failed to attach device from %s"), from);
6513 6514
        virDomainFree(dom);
        return FALSE;
6515
    } else {
J
Jim Meyering 已提交
6516
        vshPrint(ctl, "%s", _("Device attached successfully\n"));
6517 6518 6519 6520 6521 6522 6523 6524 6525 6526
    }

    virDomainFree(dom);
    return TRUE;
}


/*
 * "detach-device" command
 */
6527
static const vshCmdInfo info_detach_device[] = {
6528 6529
    {"help", N_("detach device from an XML file")},
    {"desc", N_("Detach device from an XML <file>")},
6530 6531 6532
    {NULL, NULL}
};

6533
static const vshCmdOptDef opts_detach_device[] = {
6534 6535 6536
    {"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")},
6537 6538 6539 6540
    {NULL, 0, 0, NULL}
};

static int
6541
cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
6542 6543 6544 6545 6546 6547
{
    virDomainPtr dom;
    char *from;
    char *buffer;
    int ret = TRUE;
    int found;
J
Jim Fehlig 已提交
6548
    unsigned int flags;
6549 6550 6551 6552

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

J
Jim Meyering 已提交
6553
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
6554 6555 6556 6557
        return FALSE;

    from = vshCommandOptString(cmd, "file", &found);
    if (!found) {
6558
        vshError(ctl, "%s", _("detach-device: Missing <file> option"));
6559 6560 6561 6562
        virDomainFree(dom);
        return FALSE;
    }

6563 6564
    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
        virDomainFree(dom);
6565
        return FALSE;
6566
    }
6567

J
Jim Fehlig 已提交
6568 6569 6570 6571 6572 6573 6574 6575
    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);
    }
6576
    VIR_FREE(buffer);
6577 6578

    if (ret < 0) {
6579
        vshError(ctl, _("Failed to detach device from %s"), from);
6580 6581
        virDomainFree(dom);
        return FALSE;
6582
    } else {
J
Jim Meyering 已提交
6583
        vshPrint(ctl, "%s", _("Device detached successfully\n"));
6584 6585 6586 6587 6588 6589
    }

    virDomainFree(dom);
    return TRUE;
}

6590

6591 6592 6593
/*
 * "attach-interface" command
 */
6594
static const vshCmdInfo info_attach_interface[] = {
6595 6596
    {"help", N_("attach network interface")},
    {"desc", N_("Attach new network interface.")},
6597 6598 6599
    {NULL, NULL}
};

6600
static const vshCmdOptDef opts_attach_interface[] = {
6601 6602 6603 6604 6605 6606 6607
    {"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")},
    {"persistent", VSH_OT_BOOL, 0, N_("persist interface attachment")},
6608 6609 6610 6611
    {NULL, 0, 0, NULL}
};

static int
6612
cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
6613 6614 6615 6616 6617
{
    virDomainPtr dom = NULL;
    char *mac, *target, *script, *type, *source;
    int typ, ret = FALSE;
    char *buf = NULL, *tmp = NULL;
J
Jim Fehlig 已提交
6618
    unsigned int flags;
6619 6620 6621 6622

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        goto cleanup;

J
Jim Meyering 已提交
6623
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634
        goto cleanup;

    if (!(type = vshCommandOptString(cmd, "type", NULL)))
        goto cleanup;

    source = vshCommandOptString(cmd, "source", NULL);
    target = vshCommandOptString(cmd, "target", NULL);
    mac = vshCommandOptString(cmd, "mac", NULL);
    script = vshCommandOptString(cmd, "script", NULL);

    /* check interface type */
6635
    if (STREQ(type, "network")) {
6636
        typ = 1;
6637
    } else if (STREQ(type, "bridge")) {
6638 6639
        typ = 2;
    } else {
6640
        vshError(ctl, _("No support %s in command 'attach-interface'"), type);
6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692
        goto cleanup;
    }

    /* Make XML of interface */
    tmp = vshMalloc(ctl, 1);
    if (!tmp) goto cleanup;
    buf = vshMalloc(ctl, strlen(type) + 25);
    if (!buf) goto cleanup;
    sprintf(buf, "    <interface type='%s'>\n" , type);

    tmp = vshRealloc(ctl, tmp, strlen(source) + 28);
    if (!tmp) goto cleanup;
    if (typ == 1) {
        sprintf(tmp, "      <source network='%s'/>\n", source);
    } else if (typ == 2) {
        sprintf(tmp, "      <source bridge='%s'/>\n", source);
    }
    buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
    if (!buf) goto cleanup;
    strcat(buf, tmp);

    if (target != NULL) {
        tmp = vshRealloc(ctl, tmp, strlen(target) + 24);
        if (!tmp) goto cleanup;
        sprintf(tmp, "      <target dev='%s'/>\n", target);
        buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
        if (!buf) goto cleanup;
        strcat(buf, tmp);
    }

    if (mac != NULL) {
        tmp = vshRealloc(ctl, tmp, strlen(mac) + 25);
        if (!tmp) goto cleanup;
        sprintf(tmp, "      <mac address='%s'/>\n", mac);
        buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
        if (!buf) goto cleanup;
        strcat(buf, tmp);
    }

    if (script != NULL) {
        tmp = vshRealloc(ctl, tmp, strlen(script) + 25);
        if (!tmp) goto cleanup;
        sprintf(tmp, "      <script path='%s'/>\n", script);
        buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
        if (!buf) goto cleanup;
        strcat(buf, tmp);
    }

    buf = vshRealloc(ctl, buf, strlen(buf) + 19);
    if (!buf) goto cleanup;
    strcat(buf, "    </interface>\n");

J
Jim Fehlig 已提交
6693 6694 6695 6696 6697
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
        ret = virDomainAttachDeviceFlags(dom, buf, flags);
6698
    } else {
J
Jim Fehlig 已提交
6699
        ret = virDomainAttachDevice(dom, buf);
6700
    }
6701

J
Jim Fehlig 已提交
6702
    if (ret != 0) {
L
Laine Stump 已提交
6703
        vshError(ctl, "%s", _("Failed to attach interface"));
J
Jim Fehlig 已提交
6704 6705 6706 6707 6708
        ret = FALSE;
    } else {
        vshPrint(ctl, "%s", _("Interface attached successfully\n"));
        ret = TRUE;
    }
6709 6710 6711 6712

 cleanup:
    if (dom)
        virDomainFree(dom);
6713 6714
    VIR_FREE(buf);
    VIR_FREE(tmp);
6715 6716 6717 6718 6719 6720
    return ret;
}

/*
 * "detach-interface" command
 */
6721
static const vshCmdInfo info_detach_interface[] = {
6722 6723
    {"help", N_("detach network interface")},
    {"desc", N_("Detach network interface.")},
6724 6725 6726
    {NULL, NULL}
};

6727
static const vshCmdOptDef opts_detach_interface[] = {
6728 6729 6730 6731
    {"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")},
6732 6733 6734 6735
    {NULL, 0, 0, NULL}
};

static int
6736
cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747
{
    virDomainPtr dom = NULL;
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj=NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr cur = NULL;
    xmlChar *tmp_mac = NULL;
    xmlBufferPtr xml_buf = NULL;
    char *doc, *mac =NULL, *type;
    char buf[64];
    int i = 0, diff_mac, ret = FALSE;
J
Jim Fehlig 已提交
6748
    unsigned int flags;
6749 6750 6751 6752

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        goto cleanup;

J
Jim Meyering 已提交
6753
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767
        goto cleanup;

    if (!(type = vshCommandOptString(cmd, "type", NULL)))
        goto cleanup;

    mac = vshCommandOptString(cmd, "mac", NULL);

    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);
6768
    VIR_FREE(doc);
6769
    if (!xml) {
6770
        vshError(ctl, "%s", _("Failed to get interface information"));
6771 6772 6773 6774
        goto cleanup;
    }
    ctxt = xmlXPathNewContext(xml);
    if (!ctxt) {
6775
        vshError(ctl, "%s", _("Failed to get interface information"));
6776 6777 6778 6779 6780 6781 6782
        goto cleanup;
    }

    sprintf(buf, "/domain/devices/interface[@type='%s']", type);
    obj = xmlXPathEval(BAD_CAST buf, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
6783
        vshError(ctl, _("No found interface whose type is %s"), type);
6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795
        goto cleanup;
    }

    if (!mac)
        goto hit;

    /* search mac */
    for (; i < obj->nodesetval->nodeNr; i++) {
        cur = obj->nodesetval->nodeTab[i]->children;
        while (cur != NULL) {
            if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, BAD_CAST "mac")) {
                tmp_mac = xmlGetProp(cur, BAD_CAST "address");
6796
                diff_mac = virMacAddrCompare ((char *) tmp_mac, mac);
6797 6798 6799 6800 6801 6802 6803 6804
                xmlFree(tmp_mac);
                if (!diff_mac) {
                    goto hit;
                }
            }
            cur = cur->next;
        }
    }
6805
    vshError(ctl, _("No found interface whose MAC address is %s"), mac);
6806 6807 6808 6809 6810
    goto cleanup;

 hit:
    xml_buf = xmlBufferCreate();
    if (!xml_buf) {
6811
        vshError(ctl, "%s", _("Failed to allocate memory"));
6812 6813 6814 6815
        goto cleanup;
    }

    if(xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0){
6816
        vshError(ctl, "%s", _("Failed to create XML"));
6817 6818 6819
        goto cleanup;
    }

J
Jim Fehlig 已提交
6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831
    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 已提交
6832
        vshError(ctl, "%s", _("Failed to detach interface"));
6833
        ret = FALSE;
J
Jim Fehlig 已提交
6834
    } else {
J
Jim Meyering 已提交
6835
        vshPrint(ctl, "%s", _("Interface detached successfully\n"));
6836
        ret = TRUE;
6837
    }
6838 6839 6840 6841

 cleanup:
    if (dom)
        virDomainFree(dom);
6842
    xmlXPathFreeObject(obj);
6843
    xmlXPathFreeContext(ctxt);
6844 6845 6846 6847 6848 6849 6850 6851 6852 6853
    if (xml)
        xmlFreeDoc(xml);
    if (xml_buf)
        xmlBufferFree(xml_buf);
    return ret;
}

/*
 * "attach-disk" command
 */
6854
static const vshCmdInfo info_attach_disk[] = {
6855 6856
    {"help", N_("attach disk device")},
    {"desc", N_("Attach new disk device.")},
6857 6858 6859
    {NULL, NULL}
};

6860
static const vshCmdOptDef opts_attach_disk[] = {
6861 6862 6863 6864 6865 6866 6867 6868
    {"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")},
6869 6870 6871 6872
    {NULL, 0, 0, NULL}
};

static int
6873
cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
6874 6875 6876 6877 6878
{
    virDomainPtr dom = NULL;
    char *source, *target, *driver, *subdriver, *type, *mode;
    int isFile = 0, ret = FALSE;
    char *buf = NULL, *tmp = NULL;
J
Jim Fehlig 已提交
6879
    unsigned int flags;
6880 6881 6882 6883

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        goto cleanup;

J
Jim Meyering 已提交
6884
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898
        goto cleanup;

    if (!(source = vshCommandOptString(cmd, "source", NULL)))
        goto cleanup;

    if (!(target = vshCommandOptString(cmd, "target", NULL)))
        goto cleanup;

    driver = vshCommandOptString(cmd, "driver", NULL);
    subdriver = vshCommandOptString(cmd, "subdriver", NULL);
    type = vshCommandOptString(cmd, "type", NULL);
    mode = vshCommandOptString(cmd, "mode", NULL);

    if (driver) {
6899
        if (STREQ(driver, "file") || STREQ(driver, "tap")) {
6900
            isFile = 1;
6901
        } else if (STRNEQ(driver, "phy")) {
6902
            vshError(ctl, _("No support %s in command 'attach-disk'"), driver);
6903 6904 6905 6906 6907
            goto cleanup;
        }
    }

    if (mode) {
6908
        if (STRNEQ(mode, "readonly") && STRNEQ(mode, "shareable")) {
6909
            vshError(ctl, _("No support %s in command 'attach-disk'"), mode);
6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994
            goto cleanup;
        }
    }

    /* Make XML of disk */
    tmp = vshMalloc(ctl, 1);
    if (!tmp) goto cleanup;
    buf = vshMalloc(ctl, 23);
    if (!buf) goto cleanup;
    if (isFile) {
        sprintf(buf, "    <disk type='file'");
    } else {
        sprintf(buf, "    <disk type='block'");
    }

    if (type) {
        tmp = vshRealloc(ctl, tmp, strlen(type) + 13);
        if (!tmp) goto cleanup;
        sprintf(tmp, " device='%s'>\n", type);
    } else {
        tmp = vshRealloc(ctl, tmp, 3);
        if (!tmp) goto cleanup;
        sprintf(tmp, ">\n");
    }
    buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
    if (!buf) goto cleanup;
    strcat(buf, tmp);

    if (driver) {
        tmp = vshRealloc(ctl, tmp, strlen(driver) + 22);
        if (!tmp) goto cleanup;
        sprintf(tmp, "      <driver name='%s'", driver);
    } else {
        tmp = vshRealloc(ctl, tmp, 25);
        if (!tmp) goto cleanup;
        sprintf(tmp, "      <driver name='phy'");
    }
    buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
    if (!buf) goto cleanup;
    strcat(buf, tmp);

    if (subdriver) {
        tmp = vshRealloc(ctl, tmp, strlen(subdriver) + 12);
        if (!tmp) goto cleanup;
        sprintf(tmp, " type='%s'/>\n", subdriver);
    } else {
        tmp = vshRealloc(ctl, tmp, 4);
        if (!tmp) goto cleanup;
        sprintf(tmp, "/>\n");
    }
    buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
    if (!buf) goto cleanup;
    strcat(buf, tmp);

    tmp = vshRealloc(ctl, tmp, strlen(source) + 25);
    if (!tmp) goto cleanup;
    if (isFile) {
        sprintf(tmp, "      <source file='%s'/>\n", source);
    } else {
        sprintf(tmp, "      <source dev='%s'/>\n", source);
    }
    buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
    if (!buf) goto cleanup;
    strcat(buf, tmp);

    tmp = vshRealloc(ctl, tmp, strlen(target) + 24);
    if (!tmp) goto cleanup;
    sprintf(tmp, "      <target dev='%s'/>\n", target);
    buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
    if (!buf) goto cleanup;
    strcat(buf, tmp);

    if (mode != NULL) {
        tmp = vshRealloc(ctl, tmp, strlen(mode) + 11);
        if (!tmp) goto cleanup;
        sprintf(tmp, "      <%s/>\n", mode);
        buf = vshRealloc(ctl, buf, strlen(buf) + strlen(tmp) + 1);
        if (!buf) goto cleanup;
        strcat(buf, tmp);
    }

    buf = vshRealloc(ctl, buf, strlen(buf) + 13);
    if (!buf) goto cleanup;
    strcat(buf, "    </disk>\n");

J
Jim Fehlig 已提交
6995 6996 6997 6998 6999 7000 7001 7002
    if (vshCommandOptBool(cmd, "persistent")) {
        flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        if (virDomainIsActive(dom) == 1)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
        ret = virDomainAttachDeviceFlags(dom, buf, flags);
    } else {
        ret = virDomainAttachDevice(dom, buf);
    }
7003

J
Jim Fehlig 已提交
7004
    if (ret != 0) {
L
Laine Stump 已提交
7005
        vshError(ctl, "%s", _("Failed to attach disk"));
J
Jim Fehlig 已提交
7006 7007 7008 7009 7010
        ret = FALSE;
    } else {
        vshPrint(ctl, "%s", _("Disk attached successfully\n"));
        ret = TRUE;
    }
7011 7012 7013 7014

 cleanup:
    if (dom)
        virDomainFree(dom);
7015 7016
    VIR_FREE(buf);
    VIR_FREE(tmp);
7017 7018 7019 7020 7021 7022
    return ret;
}

/*
 * "detach-disk" command
 */
7023
static const vshCmdInfo info_detach_disk[] = {
7024 7025
    {"help", N_("detach disk device")},
    {"desc", N_("Detach disk device.")},
7026 7027 7028
    {NULL, NULL}
};

7029
static const vshCmdOptDef opts_detach_disk[] = {
7030 7031 7032
    {"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")},
7033 7034 7035 7036
    {NULL, 0, 0, NULL}
};

static int
7037
cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
7038 7039 7040 7041 7042 7043 7044 7045 7046 7047
{
    xmlDocPtr xml = NULL;
    xmlXPathObjectPtr obj=NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr cur = NULL;
    xmlChar *tmp_tgt = NULL;
    xmlBufferPtr xml_buf = NULL;
    virDomainPtr dom = NULL;
    char *doc, *target;
    int i = 0, diff_tgt, ret = FALSE;
J
Jim Fehlig 已提交
7048
    unsigned int flags;
7049 7050 7051 7052

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        goto cleanup;

J
Jim Meyering 已提交
7053
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065
        goto cleanup;

    if (!(target = vshCommandOptString(cmd, "target", NULL)))
        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);
7066
    VIR_FREE(doc);
7067
    if (!xml) {
7068
        vshError(ctl, "%s", _("Failed to get disk information"));
7069 7070 7071 7072
        goto cleanup;
    }
    ctxt = xmlXPathNewContext(xml);
    if (!ctxt) {
7073
        vshError(ctl, "%s", _("Failed to get disk information"));
7074 7075 7076 7077 7078 7079
        goto cleanup;
    }

    obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
7080
        vshError(ctl, "%s", _("Failed to get disk information"));
7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098
        goto cleanup;
    }

    /* search target */
    for (; i < obj->nodesetval->nodeNr; i++) {
        cur = obj->nodesetval->nodeTab[i]->children;
        while (cur != NULL) {
            if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, BAD_CAST "target")) {
                tmp_tgt = xmlGetProp(cur, BAD_CAST "dev");
                diff_tgt = xmlStrEqual(tmp_tgt, BAD_CAST target);
                xmlFree(tmp_tgt);
                if (diff_tgt) {
                    goto hit;
                }
            }
            cur = cur->next;
        }
    }
7099
    vshError(ctl, _("No found disk whose target is %s"), target);
7100 7101 7102 7103 7104
    goto cleanup;

 hit:
    xml_buf = xmlBufferCreate();
    if (!xml_buf) {
7105
        vshError(ctl, "%s", _("Failed to allocate memory"));
7106 7107 7108 7109
        goto cleanup;
    }

    if(xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0){
7110
        vshError(ctl, "%s", _("Failed to create XML"));
7111 7112 7113
        goto cleanup;
    }

J
Jim Fehlig 已提交
7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125
    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 已提交
7126
        vshError(ctl, "%s", _("Failed to detach disk"));
7127
        ret = FALSE;
J
Jim Fehlig 已提交
7128
    } else {
J
Jim Meyering 已提交
7129
        vshPrint(ctl, "%s", _("Disk detached successfully\n"));
7130
        ret = TRUE;
7131
    }
7132 7133

 cleanup:
7134
    xmlXPathFreeObject(obj);
7135
    xmlXPathFreeContext(ctxt);
7136 7137 7138 7139 7140 7141 7142 7143 7144
    if (xml)
        xmlFreeDoc(xml);
    if (xml_buf)
        xmlBufferFree(xml_buf);
    if (dom)
        virDomainFree(dom);
    return ret;
}

7145 7146 7147 7148
/*
 * "cpu-compare" command
 */
static const vshCmdInfo info_cpu_compare[] = {
7149 7150
    {"help", N_("compare host CPU with a CPU described by an XML file")},
    {"desc", N_("compare CPU with host CPU")},
7151 7152 7153 7154
    {NULL, NULL}
};

static const vshCmdOptDef opts_cpu_compare[] = {
7155
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML CPU description")},
7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178
    {NULL, 0, 0, NULL}
};

static int
cmdCPUCompare(vshControl *ctl, const vshCmd *cmd)
{
    char *from;
    int found;
    int ret = TRUE;
    char *buffer;
    int result;

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

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

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;

    result = virConnectCompareCPU(ctl->conn, buffer, 0);
7179
    VIR_FREE(buffer);
7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208

    switch (result) {
    case VIR_CPU_COMPARE_INCOMPATIBLE:
        vshPrint(ctl, _("CPU described in %s is incompatible with host CPU\n"),
                 from);
        ret = FALSE;
        break;

    case VIR_CPU_COMPARE_IDENTICAL:
        vshPrint(ctl, _("CPU described in %s is identical to host CPU\n"),
                 from);
        ret = TRUE;
        break;

    case VIR_CPU_COMPARE_SUPERSET:
        vshPrint(ctl, _("Host CPU is a superset of CPU described in %s\n"),
                 from);
        ret = TRUE;
        break;

    case VIR_CPU_COMPARE_ERROR:
    default:
        vshError(ctl, _("Failed to compare host CPU with %s"), from);
        ret = FALSE;
    }

    return ret;
}

7209 7210 7211 7212
/*
 * "cpu-baseline" command
 */
static const vshCmdInfo info_cpu_baseline[] = {
7213 7214
    {"help", N_("compute baseline CPU")},
    {"desc", N_("Compute baseline CPU for a set of given CPUs.")},
7215 7216 7217 7218
    {NULL, NULL}
};

static const vshCmdOptDef opts_cpu_baseline[] = {
7219
    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing XML CPU descriptions")},
7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233
    {NULL, 0, 0, NULL}
};

static int
cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
{
    char *from;
    int found;
    int ret = TRUE;
    char *buffer;
    char *result = NULL;
    const char **list = NULL;
    unsigned int count = 0;
    xmlDocPtr doc = NULL;
7234
    xmlNodePtr node_list;
7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254
    xmlXPathContextPtr ctxt = NULL;
    xmlSaveCtxtPtr sctxt = NULL;
    xmlBufferPtr buf = NULL;
    xmlXPathObjectPtr obj = NULL;
    int res, i;

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

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

    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
        return FALSE;

    doc = xmlNewDoc(NULL);
    if (doc == NULL)
        goto no_memory;

L
Laine Stump 已提交
7255 7256
    res = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
                                      (const xmlChar *)buffer, &node_list);
7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323
    if (res != 0) {
        vshError(ctl, _("Failed to parse XML fragment %s"), from);
        ret = FALSE;
        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);
        ret = FALSE;
        goto cleanup;
    }

    result = virConnectBaselineCPU(ctl->conn, list, count, 0);

    if (result)
        vshPrint(ctl, "%s", result);
    else
        ret = FALSE;

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"));
    ret = FALSE;
7324
    goto cleanup;
7325 7326
}

7327 7328 7329 7330 7331 7332 7333 7334 7335 7336
/* 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;

    ret = malloc (PATH_MAX);
    if (!ret) {
7337 7338
        vshError(ctl, _("malloc: failed to allocate temporary file name: %s"),
                 strerror(errno));
7339 7340 7341 7342 7343 7344 7345 7346
        return NULL;
    }

    tmpdir = getenv ("TMPDIR");
    if (!tmpdir) tmpdir = "/tmp";
    snprintf (ret, PATH_MAX, "%s/virshXXXXXX", tmpdir);
    fd = mkstemp (ret);
    if (fd == -1) {
7347 7348
        vshError(ctl, _("mkstemp: failed to create temporary file: %s"),
                 strerror(errno));
7349
        VIR_FREE(ret);
7350 7351 7352 7353
        return NULL;
    }

    if (safewrite (fd, doc, strlen (doc)) == -1) {
7354 7355
        vshError(ctl, _("write: %s: failed to write to temporary file: %s"),
                 ret, strerror(errno));
7356 7357
        close (fd);
        unlink (ret);
7358
        VIR_FREE(ret);
7359 7360 7361
        return NULL;
    }
    if (close (fd) == -1) {
7362 7363
        vshError(ctl, _("close: %s: failed to write or close temporary file: %s"),
                 ret, strerror(errno));
7364
        unlink (ret);
7365
        VIR_FREE(ret);
7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390
        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;
    char *command;
    int command_ret;

    editor = getenv ("EDITOR");
    if (!editor) editor = "vi"; /* could be cruel & default to ed(1) here */

    /* Check the editor doesn't contain shell meta-characters, and if
     * it does, refuse to run.
     */
    if (strspn (editor, ACCEPTED_CHARS) != strlen (editor)) {
7391 7392 7393
        vshError(ctl,
                 _("%s: $EDITOR environment variable contains shell meta or "
                   "other unacceptable characters"),
7394 7395 7396 7397 7398
                 editor);
        return -1;
    }
    /* Same for the filename. */
    if (strspn (filename, ACCEPTED_CHARS) != strlen (filename)) {
7399 7400 7401
        vshError(ctl,
                 _("%s: temporary filename contains shell meta or other "
                   "unacceptable characters (is $TMPDIR wrong?)"),
7402 7403 7404 7405
                 filename);
        return -1;
    }

7406
    if (virAsprintf(&command, "%s %s", editor, filename) == -1) {
7407
        vshError(ctl,
7408
                 _("virAsprintf: could not create editing command: %s"),
7409
                 strerror(errno));
7410 7411 7412 7413 7414
        return -1;
    }

    command_ret = system (command);
    if (command_ret == -1) {
7415 7416
        vshError(ctl,
                 _("%s: edit command failed: %s"), command, strerror(errno));
7417
        VIR_FREE(command);
7418 7419 7420
        return -1;
    }
    if (command_ret != WEXITSTATUS (0)) {
7421
        vshError(ctl,
7422
                 _("%s: command exited with non-zero status"), command);
7423
        VIR_FREE(command);
7424 7425
        return -1;
    }
7426
    VIR_FREE(command);
7427 7428 7429 7430 7431 7432 7433 7434 7435
    return 0;
}

static char *
editReadBackFile (vshControl *ctl, const char *filename)
{
    char *ret;

    if (virFileReadAll (filename, VIRSH_MAX_XML_FILE, &ret) == -1) {
7436
        vshError(ctl,
7437
                 _("%s: failed to read temporary file: %s"),
7438
                 filename, strerror(errno));
7439 7440 7441 7442 7443
        return NULL;
    }
    return ret;
}

7444 7445

#ifndef WIN32
P
Paolo Bonzini 已提交
7446 7447 7448 7449
/*
 * "cd" command
 */
static const vshCmdInfo info_cd[] = {
7450 7451
    {"help", N_("change the current directory")},
    {"desc", N_("Change the current directory.")},
P
Paolo Bonzini 已提交
7452 7453 7454 7455
    {NULL, NULL}
};

static const vshCmdOptDef opts_cd[] = {
7456
    {"dir", VSH_OT_DATA, 0, N_("directory to switch to (default: home or else root)")},
P
Paolo Bonzini 已提交
7457 7458 7459 7460 7461 7462 7463 7464 7465 7466
    {NULL, 0, 0, NULL}
};

static int
cmdCd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    const char *dir;
    int found;

    if (!ctl->imode) {
7467
        vshError(ctl, "%s", _("cd: command valid only in interactive mode"));
P
Paolo Bonzini 已提交
7468 7469 7470 7471 7472 7473
        return -1;
    }

    dir = vshCommandOptString(cmd, "dir", &found);
    if (!found) {
        uid_t uid = geteuid();
7474
        dir = virGetUserDirectory(uid);
P
Paolo Bonzini 已提交
7475 7476 7477 7478 7479
    }
    if (!dir)
        dir = "/";

    if (chdir (dir) == -1) {
7480
        vshError(ctl, _("cd: %s: %s"), strerror(errno), dir);
P
Paolo Bonzini 已提交
7481 7482 7483 7484 7485 7486
        return -1;
    }

    return 0;
}

7487 7488 7489
#endif

#ifndef WIN32
P
Paolo Bonzini 已提交
7490 7491 7492 7493
/*
 * "pwd" command
 */
static const vshCmdInfo info_pwd[] = {
7494 7495
    {"help", N_("print the current directory")},
    {"desc", N_("Print the current directory.")},
P
Paolo Bonzini 已提交
7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517
    {NULL, NULL}
};

static int
cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
    char *cwd;
    size_t path_max;
    int err = TRUE;

    path_max = (size_t) PATH_MAX + 2;
    cwd = vshMalloc (ctl, path_max);
    while (cwd) {
        err = getcwd (cwd, path_max) == NULL;
        if (!err || errno != ERANGE)
            break;

        path_max *= 2;
        cwd = vshRealloc (ctl, cwd, path_max);
    }

    if (err)
7518 7519
        vshError(ctl, _("pwd: cannot get current directory: %s"),
                 strerror(errno));
P
Paolo Bonzini 已提交
7520 7521 7522
    else
        vshPrint (ctl, _("%s\n"), cwd);

7523
    VIR_FREE(cwd);
P
Paolo Bonzini 已提交
7524 7525
    return !err;
}
7526
#endif
P
Paolo Bonzini 已提交
7527

7528 7529 7530 7531
/*
 * "edit" command
 */
static const vshCmdInfo info_edit[] = {
7532 7533
    {"help", N_("edit XML configuration for a domain")},
    {"desc", N_("Edit the XML configuration for a domain.")},
7534 7535 7536 7537
    {NULL, NULL}
};

static const vshCmdOptDef opts_edit[] = {
7538
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553
    {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.
 */
static int
cmdEdit (vshControl *ctl, const vshCmd *cmd)
{
    int ret = FALSE;
    virDomainPtr dom = NULL;
    char *tmp = NULL;
    char *doc = NULL;
    char *doc_edited = NULL;
    char *doc_reread = NULL;
7554
    int flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_INACTIVE;
7555 7556 7557 7558

    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
        goto cleanup;

J
Jim Meyering 已提交
7559
    dom = vshCommandOptDomain (ctl, cmd, NULL);
7560 7561 7562 7563
    if (dom == NULL)
        goto cleanup;

    /* Get the XML configuration of the domain. */
7564
    doc = virDomainGetXMLDesc (dom, flags);
7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593
    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;

    unlink (tmp);
    tmp = NULL;

    /* 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));
        ret = TRUE;
        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.
     */
7594
    doc_reread = virDomainGetXMLDesc (dom, flags);
7595 7596 7597 7598
    if (!doc_reread)
        goto cleanup;

    if (STRNEQ (doc, doc_reread)) {
7599 7600
        vshError(ctl,
                 "%s", _("ERROR: the XML configuration was changed by another user"));
7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618
        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));

    ret = TRUE;

 cleanup:
    if (dom)
        virDomainFree (dom);

7619 7620 7621
    VIR_FREE(doc);
    VIR_FREE(doc_edited);
    VIR_FREE(doc_reread);
7622 7623 7624

    if (tmp) {
        unlink (tmp);
7625
        VIR_FREE(tmp);
7626 7627 7628 7629 7630 7631 7632 7633 7634
    }

    return ret;
}

/*
 * "net-edit" command
 */
static const vshCmdInfo info_network_edit[] = {
7635 7636
    {"help", N_("edit XML configuration for a network")},
    {"desc", N_("Edit the XML configuration for a network.")},
7637 7638 7639 7640
    {NULL, NULL}
};

static const vshCmdOptDef opts_network_edit[] = {
7641
    {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name, id or uuid")},
7642 7643 7644 7645 7646 7647 7648 7649 7650 7651
    {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[] = {
7652 7653
    {"help", N_("edit XML configuration for a storage pool")},
    {"desc", N_("Edit the XML configuration for a storage pool.")},
7654 7655 7656 7657
    {NULL, NULL}
};

static const vshCmdOptDef opts_pool_edit[] = {
7658
    {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
7659 7660 7661 7662 7663 7664
    {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 已提交
7665 7666 7667
/*
 * "quit" command
 */
7668
static const vshCmdInfo info_quit[] = {
7669
    {"help", N_("quit this interactive terminal")},
7670
    {"desc", ""},
7671
    {NULL, NULL}
K
Karel Zak 已提交
7672 7673 7674
};

static int
7675
cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7676
{
K
Karel Zak 已提交
7677 7678 7679 7680 7681 7682 7683
    ctl->imode = FALSE;
    return TRUE;
}

/*
 * Commands
 */
7684
static const vshCmdDef commands[] = {
7685 7686 7687 7688
    {"help", cmdHelp, opts_help, info_help},
    {"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},
7689
    {"autostart", cmdAutostart, opts_autostart, info_autostart},
7690
    {"capabilities", cmdCapabilities, NULL, info_capabilities},
7691
#ifndef WIN32
P
Paolo Bonzini 已提交
7692
    {"cd", cmdCd, opts_cd, info_cd},
7693
#endif
7694
    {"connect", cmdConnect, opts_connect, info_connect},
7695
#ifndef WIN32
7696
    {"console", cmdConsole, opts_console, info_console},
7697
#endif
7698
    {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline},
7699
    {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare},
7700
    {"create", cmdCreate, opts_create, info_create},
7701
    {"start", cmdStart, opts_start, info_start},
K
Karel Zak 已提交
7702
    {"destroy", cmdDestroy, opts_destroy, info_destroy},
7703 7704 7705
    {"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},
7706
    {"define", cmdDefine, opts_define, info_define},
K
Karel Zak 已提交
7707
    {"domid", cmdDomid, opts_domid, info_domid},
K
Karel Zak 已提交
7708
    {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
7709
    {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
7710
    {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo},
7711
    {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort},
K
Karel Zak 已提交
7712 7713
    {"domname", cmdDomname, opts_domname, info_domname},
    {"domstate", cmdDomstate, opts_domstate, info_domstate},
7714 7715
    {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
    {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat},
7716
    {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat},
7717 7718
    {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, info_domxmlfromnative},
    {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, info_domxmltonative},
7719
    {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
7720
    {"edit", cmdEdit, opts_edit, info_edit},
7721 7722 7723 7724
    {"find-storage-pool-sources", cmdPoolDiscoverSources,
     opts_find_storage_pool_sources, info_find_storage_pool_sources},
    {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs,
     opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as},
7725
    {"freecell", cmdFreecell, opts_freecell, info_freecell},
7726
    {"hostname", cmdHostname, NULL, info_hostname},
7727
    {"list", cmdList, opts_list, info_list},
7728
    {"migrate", cmdMigrate, opts_migrate, info_migrate},
7729

7730
    {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart},
7731 7732 7733 7734
    {"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},
7735
    {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit},
7736 7737 7738 7739 7740
    {"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},
7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751

    {"iface-list", cmdInterfaceList, opts_interface_list, info_interface_list},
    {"iface-name", cmdInterfaceName, opts_interface_name, info_interface_name},
    {"iface-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac},
    {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, info_interface_dumpxml},
    {"iface-define", cmdInterfaceDefine, opts_interface_define, info_interface_define},
    {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, info_interface_undefine},
    {"iface-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit},
    {"iface-start", cmdInterfaceStart, opts_interface_start, info_interface_start},
    {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, info_interface_destroy},

K
Karel Zak 已提交
7752
    {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
7753

7754 7755
    {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices},
    {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml},
7756 7757 7758
    {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach},
    {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach},
    {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset},
7759 7760
    {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
    {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},
7761

7762 7763 7764
    {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
    {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
    {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create},
7765
    {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as},
7766
    {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define},
7767
    {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as},
7768 7769 7770
    {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy},
    {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete},
    {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml},
7771
    {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit},
7772 7773 7774 7775 7776 7777 7778 7779
    {"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},

7780 7781 7782 7783 7784 7785 7786 7787
    {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define},
    {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml},
    {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value},
    {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value},
    {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine},
    {"secret-list", cmdSecretList, NULL, info_secret_list},


7788
#ifndef WIN32
P
Paolo Bonzini 已提交
7789
    {"pwd", cmdPwd, NULL, info_pwd},
7790
#endif
K
Karel Zak 已提交
7791 7792 7793
    {"quit", cmdQuit, NULL, info_quit},
    {"reboot", cmdReboot, opts_reboot, info_reboot},
    {"restore", cmdRestore, opts_restore, info_restore},
7794 7795
    {"resume", cmdResume, opts_resume, info_resume},
    {"save", cmdSave, opts_save, info_save},
7796
    {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo},
D
Daniel Veillard 已提交
7797
    {"dump", cmdDump, opts_dump, info_dump},
7798
    {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
7799 7800 7801
    {"setmem", cmdSetmem, opts_setmem, info_setmem},
    {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
    {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
K
Karel Zak 已提交
7802
    {"suspend", cmdSuspend, opts_suspend, info_suspend},
7803
    {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},
7804
    {"undefine", cmdUndefine, opts_undefine, info_undefine},
7805
    {"uri", cmdURI, NULL, info_uri},
7806 7807

    {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
7808
    {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from},
7809
    {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
7810
    {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone},
7811 7812 7813 7814 7815 7816 7817 7818
    {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete},
    {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml},
    {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info},
    {"vol-list", cmdVolList, opts_vol_list, info_vol_list},
    {"vol-path", cmdVolPath, opts_vol_path, info_vol_path},
    {"vol-name", cmdVolName, opts_vol_name, info_vol_name},
    {"vol-key", cmdVolKey, opts_vol_key, info_vol_key},

7819 7820
    {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
    {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
7821
    {"version", cmdVersion, NULL, info_version},
7822
    {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
7823
    {NULL, NULL, NULL, NULL}
K
Karel Zak 已提交
7824 7825 7826 7827 7828 7829
};

/* ---------------
 * Utils for work with command definition
 * ---------------
 */
K
Karel Zak 已提交
7830
static const char *
7831
vshCmddefGetInfo(const vshCmdDef * cmd, const char *name)
7832
{
7833
    const vshCmdInfo *info;
7834

K
Karel Zak 已提交
7835
    for (info = cmd->info; info && info->name; info++) {
7836
        if (STREQ(info->name, name))
K
Karel Zak 已提交
7837 7838 7839 7840 7841
            return info->data;
    }
    return NULL;
}

7842 7843
static const vshCmdOptDef *
vshCmddefGetOption(const vshCmdDef * cmd, const char *name)
7844
{
7845
    const vshCmdOptDef *opt;
7846

K
Karel Zak 已提交
7847
    for (opt = cmd->opts; opt && opt->name; opt++)
7848
        if (STREQ(opt->name, name))
K
Karel Zak 已提交
7849 7850 7851 7852
            return opt;
    return NULL;
}

7853 7854
static const vshCmdOptDef *
vshCmddefGetData(const vshCmdDef * cmd, int data_ct)
7855
{
7856
    const vshCmdOptDef *opt;
K
Karel Zak 已提交
7857

7858
    for (opt = cmd->opts; opt && opt->name; opt++) {
7859 7860
        if (opt->type == VSH_OT_DATA) {
            if (data_ct == 0)
7861 7862 7863 7864 7865
                return opt;
            else
                data_ct--;
        }
    }
K
Karel Zak 已提交
7866 7867 7868
    return NULL;
}

7869 7870 7871
/*
 * Checks for required options
 */
7872
static int
7873
vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd)
7874
{
7875 7876
    const vshCmdDef *def = cmd->def;
    const vshCmdOptDef *d;
7877
    int err = 0;
7878 7879 7880 7881

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

            while (o && ok == 0) {
7885
                if (o->def == d)
7886
                    ok = 1;
7887 7888 7889
                o = o->next;
            }
            if (!ok) {
7890
                vshError(ctl,
7891
                         d->type == VSH_OT_DATA ?
7892
                         _("command '%s' requires <%s> option") :
7893
                         _("command '%s' requires --%s option"),
7894
                         def->name, d->name);
7895 7896
                err = 1;
            }
7897

7898 7899 7900 7901 7902
        }
    }
    return !err;
}

7903
static const vshCmdDef *
7904 7905
vshCmddefSearch(const char *cmdname)
{
7906
    const vshCmdDef *c;
7907

K
Karel Zak 已提交
7908
    for (c = commands; c->name; c++)
7909
        if (STREQ(c->name, cmdname))
K
Karel Zak 已提交
7910 7911 7912 7913 7914
            return c;
    return NULL;
}

static int
7915
vshCmddefHelp(vshControl *ctl, const char *cmdname)
7916
{
7917
    const vshCmdDef *def = vshCmddefSearch(cmdname);
7918

K
Karel Zak 已提交
7919
    if (!def) {
7920
        vshError(ctl, _("command '%s' doesn't exist"), cmdname);
7921 7922
        return FALSE;
    } else {
E
Eric Blake 已提交
7923 7924
        const char *desc = _(vshCmddefGetInfo(def, "desc"));
        const char *help = _(vshCmddefGetInfo(def, "help"));
7925
        char buf[256];
K
Karel Zak 已提交
7926

7927
        fputs(_("  NAME\n"), stdout);
7928 7929
        fprintf(stdout, "    %s - %s\n", def->name, help);

7930 7931 7932 7933 7934 7935 7936 7937 7938
        fputs(_("\n  SYNOPSIS\n"), stdout);
        fprintf(stdout, "    %s", def->name);
        if (def->opts) {
            const vshCmdOptDef *opt;
            for (opt = def->opts; opt->name; opt++) {
                const char *fmt;
                if (opt->type == VSH_OT_BOOL)
                    fmt = "[--%s]";
                else if (opt->type == VSH_OT_INT)
E
Eric Blake 已提交
7939 7940
                    /* xgettext:c-format */
                    fmt = _("[--%s <number>]");
7941
                else if (opt->type == VSH_OT_STRING)
E
Eric Blake 已提交
7942 7943
                    /* xgettext:c-format */
                    fmt = _("[--%s <string>]");
7944 7945 7946 7947 7948
                else if (opt->type == VSH_OT_DATA)
                    fmt = ((opt->flag & VSH_OFLAG_REQ) ? "<%s>" : "[<%s>]");
                else
                    assert(0);
                fputc(' ', stdout);
E
Eric Blake 已提交
7949
                fprintf(stdout, fmt, opt->name);
7950
            }
K
Karel Zak 已提交
7951
        }
7952 7953 7954
        fputc('\n', stdout);

        if (desc[0]) {
7955
            /* Print the description only if it's not empty.  */
7956
            fputs(_("\n  DESCRIPTION\n"), stdout);
K
Karel Zak 已提交
7957 7958
            fprintf(stdout, "    %s\n", desc);
        }
7959

K
Karel Zak 已提交
7960
        if (def->opts) {
7961
            const vshCmdOptDef *opt;
7962
            fputs(_("\n  OPTIONS\n"), stdout);
7963 7964
            for (opt = def->opts; opt->name; opt++) {
                if (opt->type == VSH_OT_BOOL)
K
Karel Zak 已提交
7965
                    snprintf(buf, sizeof(buf), "--%s", opt->name);
7966
                else if (opt->type == VSH_OT_INT)
7967
                    snprintf(buf, sizeof(buf), _("--%s <number>"), opt->name);
7968
                else if (opt->type == VSH_OT_STRING)
7969
                    snprintf(buf, sizeof(buf), _("--%s <string>"), opt->name);
7970
                else if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
7971
                    snprintf(buf, sizeof(buf), "<%s>", opt->name);
7972

E
Eric Blake 已提交
7973
                fprintf(stdout, "    %-15s  %s\n", buf, _(opt->help));
7974
            }
K
Karel Zak 已提交
7975 7976 7977 7978 7979 7980 7981 7982 7983 7984
        }
        fputc('\n', stdout);
    }
    return TRUE;
}

/* ---------------
 * Utils for work with runtime commands data
 * ---------------
 */
7985 7986 7987
static void
vshCommandOptFree(vshCmdOpt * arg)
{
K
Karel Zak 已提交
7988 7989
    vshCmdOpt *a = arg;

7990
    while (a) {
K
Karel Zak 已提交
7991
        vshCmdOpt *tmp = a;
7992

K
Karel Zak 已提交
7993 7994
        a = a->next;

7995 7996
        VIR_FREE(tmp->data);
        VIR_FREE(tmp);
K
Karel Zak 已提交
7997 7998 7999 8000
    }
}

static void
8001
vshCommandFree(vshCmd *cmd)
8002
{
K
Karel Zak 已提交
8003 8004
    vshCmd *c = cmd;

8005
    while (c) {
K
Karel Zak 已提交
8006
        vshCmd *tmp = c;
8007

K
Karel Zak 已提交
8008 8009 8010 8011
        c = c->next;

        if (tmp->opts)
            vshCommandOptFree(tmp->opts);
8012
        VIR_FREE(tmp);
K
Karel Zak 已提交
8013 8014 8015 8016 8017 8018 8019
    }
}

/*
 * Returns option by name
 */
static vshCmdOpt *
8020
vshCommandOpt(const vshCmd *cmd, const char *name)
8021
{
K
Karel Zak 已提交
8022
    vshCmdOpt *opt = cmd->opts;
8023 8024

    while (opt) {
8025
        if (opt->def && STREQ(opt->def->name, name))
K
Karel Zak 已提交
8026 8027 8028 8029 8030 8031 8032 8033 8034 8035
            return opt;
        opt = opt->next;
    }
    return NULL;
}

/*
 * Returns option as INT
 */
static int
8036
vshCommandOptInt(const vshCmd *cmd, const char *name, int *found)
8037
{
K
Karel Zak 已提交
8038
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
8039 8040
    int res = 0, num_found = FALSE;
    char *end_p = NULL;
8041

8042 8043
    if ((arg != NULL) && (arg->data != NULL)) {
        res = strtol(arg->data, &end_p, 10);
8044 8045 8046 8047
        if ((arg->data == end_p) || (*end_p!= 0))
            num_found = FALSE;
        else
            num_found = TRUE;
8048
    }
K
Karel Zak 已提交
8049
    if (found)
8050
        *found = num_found;
K
Karel Zak 已提交
8051 8052 8053 8054 8055 8056 8057
    return res;
}

/*
 * Returns option as STRING
 */
static char *
8058
vshCommandOptString(const vshCmd *cmd, const char *name, int *found)
8059
{
K
Karel Zak 已提交
8060
    vshCmdOpt *arg = vshCommandOpt(cmd, name);
8061

K
Karel Zak 已提交
8062 8063
    if (found)
        *found = arg ? TRUE : FALSE;
8064 8065

    return arg && arg->data && *arg->data ? arg->data : NULL;
K
Karel Zak 已提交
8066 8067
}

8068 8069
#if 0
static int
8070
vshCommandOptStringList(const vshCmd *cmd, const char *name, char ***data)
8071 8072 8073 8074 8075 8076 8077 8078 8079
{
    vshCmdOpt *arg = cmd->opts;
    char **val = NULL;
    int nval = 0;

    while (arg) {
        if (arg->def && STREQ(arg->def->name, name)) {
            char **tmp = realloc(val, sizeof(*tmp) * (nval+1));
            if (!tmp) {
8080
                VIR_FREE(val);
8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093
                return -1;
            }
            val = tmp;
            val[nval++] = arg->data;
        }
        arg = arg->next;
    }

    *data = val;
    return nval;
}
#endif

K
Karel Zak 已提交
8094 8095 8096 8097
/*
 * Returns TRUE/FALSE if the option exists
 */
static int
8098
vshCommandOptBool(const vshCmd *cmd, const char *name)
8099
{
K
Karel Zak 已提交
8100 8101 8102
    return vshCommandOpt(cmd, name) ? TRUE : FALSE;
}

J
Jim Meyering 已提交
8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120
/* 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)
8121
        vshError(ctl, _("internal error: virsh %s: no %s VSH_OT_DATA option"),
J
Jim Meyering 已提交
8122 8123 8124
                 cmd->def->name, optname);
    return found;
}
8125

K
Karel Zak 已提交
8126
static virDomainPtr
J
Jim Meyering 已提交
8127
vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
8128
                      char **name, int flag)
8129
{
K
Karel Zak 已提交
8130
    virDomainPtr dom = NULL;
8131
    char *n;
K
Karel Zak 已提交
8132
    int id;
J
Jim Meyering 已提交
8133 8134 8135
    const char *optname = "domain";
    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;
8136

K
Karel Zak 已提交
8137
    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
8138
        vshError(ctl, "%s", _("undefined domain name or id"));
8139
        return NULL;
K
Karel Zak 已提交
8140
    }
8141

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

K
Karel Zak 已提交
8145 8146
    if (name)
        *name = n;
8147

K
Karel Zak 已提交
8148
    /* try it by ID */
8149
    if (flag & VSH_BYID) {
8150
        if (virStrToLong_i(n, NULL, 10, &id) == 0 && id >= 0) {
K
Karel Zak 已提交
8151 8152 8153 8154
            vshDebug(ctl, 5, "%s: <%s> seems like domain ID\n",
                     cmd->def->name, optname);
            dom = virDomainLookupByID(ctl->conn, id);
        }
8155
    }
K
Karel Zak 已提交
8156
    /* try it by UUID */
8157
    if (dom==NULL && (flag & VSH_BYUUID) && strlen(n)==VIR_UUID_STRING_BUFLEN-1) {
D
Daniel Veillard 已提交
8158
        vshDebug(ctl, 5, "%s: <%s> trying as domain UUID\n",
8159
                 cmd->def->name, optname);
K
Karel Zak 已提交
8160
        dom = virDomainLookupByUUIDString(ctl->conn, n);
K
Karel Zak 已提交
8161
    }
K
Karel Zak 已提交
8162
    /* try it by NAME */
8163
    if (dom==NULL && (flag & VSH_BYNAME)) {
D
Daniel Veillard 已提交
8164
        vshDebug(ctl, 5, "%s: <%s> trying as domain NAME\n",
8165
                 cmd->def->name, optname);
K
Karel Zak 已提交
8166
        dom = virDomainLookupByName(ctl->conn, n);
8167
    }
K
Karel Zak 已提交
8168

8169
    if (!dom)
8170
        vshError(ctl, _("failed to get domain '%s'"), n);
8171

K
Karel Zak 已提交
8172 8173 8174
    return dom;
}

8175
static virNetworkPtr
J
Jim Meyering 已提交
8176
vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
8177
                       char **name, int flag)
8178 8179 8180
{
    virNetworkPtr network = NULL;
    char *n;
J
Jim Meyering 已提交
8181 8182 8183
    const char *optname = "network";
    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;
8184 8185

    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
8186
        vshError(ctl, "%s", _("undefined network name"));
8187 8188 8189 8190 8191 8192 8193 8194 8195 8196
        return NULL;
    }

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

    if (name)
        *name = n;

    /* try it by UUID */
8197
    if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
D
Daniel Veillard 已提交
8198
        vshDebug(ctl, 5, "%s: <%s> trying as network UUID\n",
8199
                 cmd->def->name, optname);
8200 8201 8202 8203
        network = virNetworkLookupByUUIDString(ctl->conn, n);
    }
    /* try it by NAME */
    if (network==NULL && (flag & VSH_BYNAME)) {
D
Daniel Veillard 已提交
8204
        vshDebug(ctl, 5, "%s: <%s> trying as network NAME\n",
8205 8206 8207 8208 8209
                 cmd->def->name, optname);
        network = virNetworkLookupByName(ctl->conn, n);
    }

    if (!network)
8210
        vshError(ctl, _("failed to get network '%s'"), n);
8211 8212 8213 8214

    return network;
}

8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225
static virInterfacePtr
vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
                         char **name, int flag)
{
    virInterfacePtr iface = NULL;
    char *n;
    const char *optname = "interface";
    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;

    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
8226
        vshError(ctl, "%s", _("undefined interface identifier"));
8227 8228 8229 8230 8231 8232 8233 8234 8235 8236
        return NULL;
    }

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

    if (name)
        *name = n;

    /* try it by NAME */
8237
    if ((flag & VSH_BYNAME)) {
8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249
        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)
8250
        vshError(ctl, _("failed to get interface '%s'"), n);
8251 8252 8253 8254

    return iface;
}

8255
static virStoragePoolPtr
8256
vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
8257 8258 8259 8260 8261 8262
                    char **name, int flag)
{
    virStoragePoolPtr pool = NULL;
    char *n;

    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
8263
        vshError(ctl, "%s", _("undefined pool name"));
8264 8265 8266 8267 8268 8269 8270 8271 8272 8273
        return NULL;
    }

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

    if (name)
        *name = n;

    /* try it by UUID */
8274
    if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
8275
        vshDebug(ctl, 5, "%s: <%s> trying as pool UUID\n",
8276
                 cmd->def->name, optname);
8277 8278 8279
        pool = virStoragePoolLookupByUUIDString(ctl->conn, n);
    }
    /* try it by NAME */
8280
    if (pool == NULL && (flag & VSH_BYNAME)) {
8281 8282 8283 8284 8285 8286
        vshDebug(ctl, 5, "%s: <%s> trying as pool NAME\n",
                 cmd->def->name, optname);
        pool = virStoragePoolLookupByName(ctl->conn, n);
    }

    if (!pool)
8287
        vshError(ctl, _("failed to get pool '%s'"), n);
8288 8289 8290 8291 8292

    return pool;
}

static virStorageVolPtr
8293
vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
8294 8295 8296 8297 8298 8299 8300 8301 8302 8303
                   const char *optname,
                   const char *pooloptname,
                   char **name, int flag)
{
    virStorageVolPtr vol = NULL;
    virStoragePoolPtr pool = NULL;
    char *n, *p;
    int found;

    if (!(n = vshCommandOptString(cmd, optname, NULL))) {
8304
        vshError(ctl, "%s", _("undefined vol name"));
8305 8306 8307 8308
        return NULL;
    }

    if (!(p = vshCommandOptString(cmd, pooloptname, &found)) && found) {
8309
        vshError(ctl, "%s", _("undefined pool name"));
8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339
        return NULL;
    }

    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;

    /* try it by PATH */
    if (pool && (flag & VSH_BYNAME)) {
        vshDebug(ctl, 5, "%s: <%s> trying as vol UUID\n",
                 cmd->def->name, optname);
        vol = virStorageVolLookupByName(pool, n);
    }
    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);
    }
    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)
8340
        vshError(ctl, _("failed to get vol '%s'"), n);
8341 8342 8343 8344 8345 8346 8347

    if (pool)
        virStoragePoolFree(pool);

    return vol;
}

8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359
static virSecretPtr
vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, char **name)
{
    virSecretPtr secret = NULL;
    char *n;
    const char *optname = "secret";

    if (!cmd_has_option (ctl, cmd, optname))
        return NULL;

    n = vshCommandOptString(cmd, optname, NULL);
    if (n == NULL) {
8360
        vshError(ctl, "%s", _("undefined secret UUID"));
8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371
        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)
8372
        vshError(ctl, _("failed to get secret '%s'"), n);
8373 8374 8375 8376

    return secret;
}

K
Karel Zak 已提交
8377 8378 8379 8380
/*
 * Executes command(s) and returns return code from last command
 */
static int
8381
vshCommandRun(vshControl *ctl, const vshCmd *cmd)
8382
{
K
Karel Zak 已提交
8383
    int ret = TRUE;
8384 8385

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

8388 8389 8390
        if ((ctl->conn == NULL) || (disconnected != 0))
            vshReconnect(ctl);

K
Karel Zak 已提交
8391 8392
        if (ctl->timing)
            GETTIMEOFDAY(&before);
8393

K
Karel Zak 已提交
8394 8395 8396 8397
        ret = cmd->def->handler(ctl, cmd);

        if (ctl->timing)
            GETTIMEOFDAY(&after);
8398

J
John Levon 已提交
8399 8400 8401
        if (ret == FALSE)
            virshReportError(ctl);

8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412
        /* try to automatically catch disconnections */
        if ((ret == FALSE) &&
            ((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);

8413
        if (STREQ(cmd->def->name, "quit"))        /* hack ... */
K
Karel Zak 已提交
8414 8415 8416
            return ret;

        if (ctl->timing)
8417
            vshPrint(ctl, _("\n(Time: %.3f ms)\n\n"),
8418 8419
                     DIFF_MSEC(&after, &before));
        else
K
Karel Zak 已提交
8420
            vshPrintExtra(ctl, "\n");
K
Karel Zak 已提交
8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435
        cmd = cmd->next;
    }
    return ret;
}

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

8436
static int
8437
vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
8438
{
K
Karel Zak 已提交
8439 8440 8441 8442 8443
    int tk = VSH_TK_NONE;
    int quote = FALSE;
    int sz = 0;
    char *p = str;
    char *tkstr = NULL;
8444

K
Karel Zak 已提交
8445
    *end = NULL;
8446

8447
    while (p && *p && (*p == ' ' || *p == '\t'))
K
Karel Zak 已提交
8448
        p++;
8449 8450

    if (p == NULL || *p == '\0')
K
Karel Zak 已提交
8451
        return VSH_TK_END;
8452
    if (*p == ';') {
D
Daniel Veillard 已提交
8453
        *end = ++p;             /* = \0 or begin of next command */
K
Karel Zak 已提交
8454 8455
        return VSH_TK_END;
    }
8456
    while (*p) {
K
Karel Zak 已提交
8457
        /* end of token is blank space or ';' */
8458
        if ((quote == FALSE && (*p == ' ' || *p == '\t')) || *p == ';')
K
Karel Zak 已提交
8459
            break;
8460

8461
        /* end of option name could be '=' */
8462 8463
        if (tk == VSH_TK_OPTION && *p == '=') {
            p++;                /* skip '=' */
8464 8465
            break;
        }
8466 8467 8468

        if (tk == VSH_TK_NONE) {
            if (*p == '-' && *(p + 1) == '-' && *(p + 2)
8469
                && c_isalnum(*(p + 2))) {
K
Karel Zak 已提交
8470
                tk = VSH_TK_OPTION;
8471
                p += 2;
K
Karel Zak 已提交
8472 8473
            } else {
                tk = VSH_TK_DATA;
8474 8475
                if (*p == '"') {
                    quote = TRUE;
K
Karel Zak 已提交
8476 8477 8478 8479 8480
                    p++;
                } else {
                    quote = FALSE;
                }
            }
8481 8482
            tkstr = p;          /* begin of token */
        } else if (quote && *p == '"') {
K
Karel Zak 已提交
8483 8484
            quote = FALSE;
            p++;
8485
            break;              /* end of "..." token */
K
Karel Zak 已提交
8486 8487 8488 8489 8490
        }
        p++;
        sz++;
    }
    if (quote) {
8491
        vshError(ctl, "%s", _("missing \""));
K
Karel Zak 已提交
8492 8493
        return VSH_TK_ERROR;
    }
8494
    if (tkstr == NULL || *tkstr == '\0' || p == NULL)
K
Karel Zak 已提交
8495
        return VSH_TK_END;
8496
    if (sz == 0)
K
Karel Zak 已提交
8497
        return VSH_TK_END;
8498

8499
    *res = vshMalloc(ctl, sz + 1);
K
Karel Zak 已提交
8500
    memcpy(*res, tkstr, sz);
8501
    *(*res + sz) = '\0';
K
Karel Zak 已提交
8502 8503 8504 8505 8506 8507

    *end = p;
    return tk;
}

static int
8508
vshCommandParse(vshControl *ctl, char *cmdstr)
8509
{
K
Karel Zak 已提交
8510 8511 8512 8513
    char *str;
    char *tkdata = NULL;
    vshCmd *clast = NULL;
    vshCmdOpt *first = NULL;
8514

K
Karel Zak 已提交
8515 8516 8517 8518
    if (ctl->cmd) {
        vshCommandFree(ctl->cmd);
        ctl->cmd = NULL;
    }
8519 8520

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

K
Karel Zak 已提交
8523
    str = cmdstr;
8524
    while (str && *str) {
K
Karel Zak 已提交
8525
        vshCmdOpt *last = NULL;
8526
        const vshCmdDef *cmd = NULL;
K
Karel Zak 已提交
8527
        int tk = VSH_TK_NONE;
8528
        int data_ct = 0;
8529

K
Karel Zak 已提交
8530
        first = NULL;
8531 8532

        while (tk != VSH_TK_END) {
K
Karel Zak 已提交
8533
            char *end = NULL;
8534
            const vshCmdOptDef *opt = NULL;
8535

K
Karel Zak 已提交
8536
            tkdata = NULL;
8537

K
Karel Zak 已提交
8538 8539
            /* get token */
            tk = vshCommandGetToken(ctl, str, &end, &tkdata);
8540

K
Karel Zak 已提交
8541
            str = end;
8542

J
Jim Meyering 已提交
8543 8544
            if (tk == VSH_TK_END) {
                VIR_FREE(tkdata);
K
Karel Zak 已提交
8545
                break;
J
Jim Meyering 已提交
8546
            }
8547
            if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
8548
                goto syntaxError;
8549 8550

            if (cmd == NULL) {
K
Karel Zak 已提交
8551
                /* first token must be command name */
8552
                if (tk != VSH_TK_DATA) {
8553
                    vshError(ctl,
8554
                             _("unexpected token (command name): '%s'"),
8555
                             tkdata);
K
Karel Zak 已提交
8556 8557 8558
                    goto syntaxError;
                }
                if (!(cmd = vshCmddefSearch(tkdata))) {
8559
                    vshError(ctl, _("unknown command: '%s'"), tkdata);
8560
                    goto syntaxError;   /* ... or ignore this command only? */
K
Karel Zak 已提交
8561
                }
8562
                VIR_FREE(tkdata);
8563
            } else if (tk == VSH_TK_OPTION) {
K
Karel Zak 已提交
8564
                if (!(opt = vshCmddefGetOption(cmd, tkdata))) {
8565
                    vshError(ctl,
8566
                             _("command '%s' doesn't support option --%s"),
8567
                             cmd->name, tkdata);
K
Karel Zak 已提交
8568 8569
                    goto syntaxError;
                }
8570
                VIR_FREE(tkdata);   /* option name */
K
Karel Zak 已提交
8571 8572 8573 8574

                if (opt->type != VSH_OT_BOOL) {
                    /* option data */
                    tk = vshCommandGetToken(ctl, str, &end, &tkdata);
8575 8576
                    str = end;
                    if (tk == VSH_TK_ERROR)
K
Karel Zak 已提交
8577
                        goto syntaxError;
8578
                    if (tk != VSH_TK_DATA) {
8579
                        vshError(ctl,
8580
                                 _("expected syntax: --%s <%s>"),
8581 8582
                                 opt->name,
                                 opt->type ==
8583
                                 VSH_OT_INT ? _("number") : _("string"));
K
Karel Zak 已提交
8584 8585 8586
                        goto syntaxError;
                    }
                }
8587
            } else if (tk == VSH_TK_DATA) {
8588
                if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
8589
                    vshError(ctl, _("unexpected data '%s'"), tkdata);
K
Karel Zak 已提交
8590 8591 8592 8593 8594
                    goto syntaxError;
                }
            }
            if (opt) {
                /* save option */
8595
                vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
8596

K
Karel Zak 已提交
8597 8598 8599 8600
                arg->def = opt;
                arg->data = tkdata;
                arg->next = NULL;
                tkdata = NULL;
8601

K
Karel Zak 已提交
8602 8603 8604 8605 8606
                if (!first)
                    first = arg;
                if (last)
                    last->next = arg;
                last = arg;
8607

K
Karel Zak 已提交
8608
                vshDebug(ctl, 4, "%s: %s(%s): %s\n",
8609 8610
                         cmd->name,
                         opt->name,
8611
                         tk == VSH_TK_OPTION ? _("OPTION") : _("DATA"),
8612
                         arg->data);
K
Karel Zak 已提交
8613 8614 8615 8616
            }
            if (!str)
                break;
        }
8617

D
Daniel Veillard 已提交
8618
        /* command parsed -- allocate new struct for the command */
K
Karel Zak 已提交
8619
        if (cmd) {
8620
            vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
8621

K
Karel Zak 已提交
8622 8623 8624 8625
            c->opts = first;
            c->def = cmd;
            c->next = NULL;

8626
            if (!vshCommandCheckOpts(ctl, c)) {
8627
                VIR_FREE(c);
8628
                goto syntaxError;
8629
            }
8630

K
Karel Zak 已提交
8631 8632 8633 8634 8635 8636 8637
            if (!ctl->cmd)
                ctl->cmd = c;
            if (clast)
                clast->next = c;
            clast = c;
        }
    }
8638

K
Karel Zak 已提交
8639 8640
    return TRUE;

8641
 syntaxError:
K
Karel Zak 已提交
8642 8643 8644 8645
    if (ctl->cmd)
        vshCommandFree(ctl->cmd);
    if (first)
        vshCommandOptFree(first);
8646
    VIR_FREE(tkdata);
8647
    return FALSE;
K
Karel Zak 已提交
8648 8649 8650 8651
}


/* ---------------
8652
 * Misc utils
K
Karel Zak 已提交
8653 8654
 * ---------------
 */
K
Karel Zak 已提交
8655
static const char *
8656 8657
vshDomainStateToString(int state)
{
K
Karel Zak 已提交
8658
    switch (state) {
8659
    case VIR_DOMAIN_RUNNING:
8660
        return N_("running");
8661
    case VIR_DOMAIN_BLOCKED:
8662
        return N_("idle");
8663
    case VIR_DOMAIN_PAUSED:
8664
        return N_("paused");
8665
    case VIR_DOMAIN_SHUTDOWN:
8666
        return N_("in shutdown");
8667
    case VIR_DOMAIN_SHUTOFF:
8668
        return N_("shut off");
8669
    case VIR_DOMAIN_CRASHED:
8670
        return N_("crashed");
8671
    default:
8672
        ;/*FALLTHROUGH*/
K
Karel Zak 已提交
8673
    }
8674
    return N_("no state");  /* = dom0 state */
K
Karel Zak 已提交
8675 8676
}

8677 8678 8679 8680
static const char *
vshDomainVcpuStateToString(int state)
{
    switch (state) {
8681
    case VIR_VCPU_OFFLINE:
8682
        return N_("offline");
8683
    case VIR_VCPU_BLOCKED:
8684
        return N_("idle");
8685
    case VIR_VCPU_RUNNING:
8686
        return N_("running");
8687
    default:
8688
        ;/*FALLTHROUGH*/
8689
    }
8690
    return N_("no state");
8691 8692
}

K
Karel Zak 已提交
8693
static int
8694
vshConnectionUsability(vshControl *ctl, virConnectPtr conn, int showerror)
8695
{
8696 8697
    /* TODO: use something like virConnectionState() to
     *       check usability of the connection
K
Karel Zak 已提交
8698 8699 8700
     */
    if (!conn) {
        if (showerror)
8701
            vshError(ctl, "%s", _("no valid connection"));
K
Karel Zak 已提交
8702 8703 8704 8705 8706
        return FALSE;
    }
    return TRUE;
}

K
Karel Zak 已提交
8707
static void
8708
vshDebug(vshControl *ctl, int level, const char *format, ...)
8709
{
K
Karel Zak 已提交
8710 8711
    va_list ap;

8712 8713 8714 8715
    va_start(ap, format);
    vshOutputLogFile(ctl, VSH_ERR_DEBUG, format, ap);
    va_end(ap);

K
Karel Zak 已提交
8716 8717 8718 8719 8720 8721
    if (level > ctl->debug)
        return;

    va_start(ap, format);
    vfprintf(stdout, format, ap);
    va_end(ap);
K
Karel Zak 已提交
8722 8723 8724
}

static void
8725
vshPrintExtra(vshControl *ctl, const char *format, ...)
8726
{
K
Karel Zak 已提交
8727
    va_list ap;
8728

K
Karel Zak 已提交
8729
    if (ctl->quiet == TRUE)
K
Karel Zak 已提交
8730
        return;
8731

K
Karel Zak 已提交
8732
    va_start(ap, format);
8733
    vfprintf(stdout, format, ap);
K
Karel Zak 已提交
8734 8735 8736
    va_end(ap);
}

K
Karel Zak 已提交
8737

K
Karel Zak 已提交
8738
static void
8739
vshError(vshControl *ctl, const char *format, ...)
8740
{
K
Karel Zak 已提交
8741
    va_list ap;
8742

8743 8744 8745 8746 8747
    if (ctl != NULL) {
        va_start(ap, format);
        vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
        va_end(ap);
    }
8748

8749
    fputs(_("error: "), stderr);
8750

K
Karel Zak 已提交
8751 8752 8753 8754 8755 8756 8757
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);

    fputc('\n', stderr);
}

8758
static void *
8759
_vshMalloc(vshControl *ctl, size_t size, const char *filename, int line)
8760 8761 8762 8763 8764
{
    void *x;

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

static void *
8771
_vshCalloc(vshControl *ctl, size_t nmemb, size_t size, const char *filename, int line)
8772 8773 8774 8775 8776
{
    void *x;

    if ((x = calloc(nmemb, size)))
        return x;
8777
    vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
8778
             filename, line, (int) (size*nmemb));
8779
    exit(EXIT_FAILURE);
8780 8781
}

8782
static void *
8783
_vshRealloc(vshControl *ctl, void *ptr, size_t size, const char *filename, int line)
8784 8785 8786 8787 8788
{
    void *x;

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

8795
static char *
8796
_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line)
8797 8798 8799
{
    char *x;

8800 8801
    if (s == NULL)
        return(NULL);
8802 8803
    if ((x = strdup(s)))
        return x;
8804
    vshError(ctl, _("%s: %d: failed to allocate %lu bytes"),
8805
             filename, line, (unsigned long)strlen(s));
8806
    exit(EXIT_FAILURE);
8807 8808
}

K
Karel Zak 已提交
8809
/*
8810
 * Initialize connection.
K
Karel Zak 已提交
8811 8812
 */
static int
8813
vshInit(vshControl *ctl)
8814
{
K
Karel Zak 已提交
8815 8816 8817
    if (ctl->conn)
        return FALSE;

8818 8819
    vshOpenLogFile(ctl);

8820 8821
    /* set up the library error handler */
    virSetErrorFunc(NULL, virshErrorHandler);
8822

8823 8824 8825
    /* set up the signals handlers to catch disconnections */
    vshSetupSignals();

8826 8827 8828 8829
    ctl->conn = virConnectOpenAuth(ctl->name,
                                   virConnectAuthPtrDefault,
                                   ctl->readonly ? VIR_CONNECT_RO : 0);

8830

8831 8832 8833 8834
    /* This is not necessarily fatal.  All the individual commands check
     * vshConnectionUsability, except ones which don't need a connection
     * such as "help".
     */
8835
    if (!ctl->conn) {
8836
        virshReportError(ctl);
8837
        vshError(ctl, "%s", _("failed to connect to the hypervisor"));
8838 8839
        return FALSE;
    }
K
Karel Zak 已提交
8840 8841 8842 8843

    return TRUE;
}

8844
#ifndef O_SYNC
8845
# define O_SYNC 0
8846 8847 8848
#endif
#define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT | O_SYNC)

8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867
/**
 * 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:
8868
                vshError(ctl, "%s",
J
Jim Meyering 已提交
8869
                         _("failed to get the log file information"));
8870
                exit(EXIT_FAILURE);
8871 8872 8873
        }
    } else {
        if (!S_ISREG(st.st_mode)) {
8874 8875
            vshError(ctl, "%s", _("the log path is not a file"));
            exit(EXIT_FAILURE);
8876 8877 8878 8879
        }
    }

    /* log file open */
8880
    if ((ctl->log_fd = open(ctl->logfile, LOGFILE_FLAGS, FILE_MODE)) < 0) {
8881
        vshError(ctl, "%s",
J
Jim Meyering 已提交
8882
                 _("failed to open the log file. check the log file path"));
8883
        exit(EXIT_FAILURE);
8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948
    }
}

/**
 * vshOutputLogFile:
 *
 * Outputting an error to log file.
 */
static void
vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format, va_list ap)
{
    char msg_buf[MSG_BUFFER];
    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);
    snprintf(msg_buf, sizeof(msg_buf),
             "[%d.%02d.%02d %02d:%02d:%02d ",
             (1900 + stTm->tm_year),
             (1 + stTm->tm_mon),
             (stTm->tm_mday),
             (stTm->tm_hour),
             (stTm->tm_min),
             (stTm->tm_sec));
    snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
             "%s] ", SIGN_NAME);
    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;
    }
    snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
             "%s ", lvl);
    vsnprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
              msg_format, ap);

    if (msg_buf[strlen(msg_buf) - 1] != '\n')
        snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf), "\n");

    /* write log */
8949
    if (safewrite(ctl->log_fd, msg_buf, strlen(msg_buf)) < 0) {
8950
        vshCloseLogFile(ctl);
8951
        vshError(ctl, "%s", _("failed to write the log file"));
8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964
    }
}

/**
 * vshCloseLogFile:
 *
 * Close log file.
 */
static void
vshCloseLogFile(vshControl *ctl)
{
    /* log file close */
    if (ctl->log_fd >= 0) {
8965
        if (close(ctl->log_fd) < 0)
8966
            vshError(ctl, _("%s: failed to write log file: %s"),
8967
                     ctl->logfile ? ctl->logfile : "?", strerror (errno));
8968 8969 8970 8971
        ctl->log_fd = -1;
    }

    if (ctl->logfile) {
8972
        VIR_FREE(ctl->logfile);
8973 8974 8975 8976
        ctl->logfile = NULL;
    }
}

8977
#ifdef USE_READLINE
8978

K
Karel Zak 已提交
8979 8980 8981 8982 8983
/* -----------------
 * Readline stuff
 * -----------------
 */

8984
/*
K
Karel Zak 已提交
8985 8986
 * Generator function for command completion.  STATE lets us
 * know whether to start from scratch; without any state
8987
 * (i.e. STATE == 0), then we start at the top of the list.
K
Karel Zak 已提交
8988 8989
 */
static char *
8990 8991
vshReadlineCommandGenerator(const char *text, int state)
{
K
Karel Zak 已提交
8992
    static int list_index, len;
K
Karel Zak 已提交
8993
    const char *name;
K
Karel Zak 已提交
8994 8995 8996

    /* If this is a new word to complete, initialize now.  This
     * includes saving the length of TEXT for efficiency, and
8997
     * initializing the index variable to 0.
K
Karel Zak 已提交
8998 8999 9000
     */
    if (!state) {
        list_index = 0;
9001
        len = strlen(text);
K
Karel Zak 已提交
9002 9003 9004
    }

    /* Return the next name which partially matches from the
9005
     * command list.
K
Karel Zak 已提交
9006
     */
K
Karel Zak 已提交
9007
    while ((name = commands[list_index].name)) {
K
Karel Zak 已提交
9008
        list_index++;
9009
        if (STREQLEN(name, text, len))
9010
            return vshStrdup(NULL, name);
K
Karel Zak 已提交
9011 9012 9013 9014 9015 9016 9017
    }

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

static char *
9018 9019
vshReadlineOptionsGenerator(const char *text, int state)
{
K
Karel Zak 已提交
9020
    static int list_index, len;
9021
    static const vshCmdDef *cmd = NULL;
K
Karel Zak 已提交
9022
    const char *name;
K
Karel Zak 已提交
9023 9024 9025 9026 9027 9028 9029 9030 9031

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

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

9032
        cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
9033
        memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
K
Karel Zak 已提交
9034 9035 9036

        cmd = vshCmddefSearch(cmdname);
        list_index = 0;
9037
        len = strlen(text);
9038
        VIR_FREE(cmdname);
K
Karel Zak 已提交
9039 9040 9041 9042
    }

    if (!cmd)
        return NULL;
9043

9044 9045 9046
    if (!cmd->opts)
        return NULL;

K
Karel Zak 已提交
9047
    while ((name = cmd->opts[list_index].name)) {
9048
        const vshCmdOptDef *opt = &cmd->opts[list_index];
K
Karel Zak 已提交
9049
        char *res;
9050

K
Karel Zak 已提交
9051
        list_index++;
9052

K
Karel Zak 已提交
9053
        if (opt->type == VSH_OT_DATA)
K
Karel Zak 已提交
9054 9055
            /* ignore non --option */
            continue;
9056

K
Karel Zak 已提交
9057
        if (len > 2) {
9058
            if (STRNEQLEN(name, text + 2, len - 2))
K
Karel Zak 已提交
9059 9060
                continue;
        }
9061
        res = vshMalloc(NULL, strlen(name) + 3);
9062
        snprintf(res, strlen(name) + 3,  "--%s", name);
K
Karel Zak 已提交
9063 9064 9065 9066 9067 9068 9069 9070
        return res;
    }

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

static char **
9071 9072 9073
vshReadlineCompletion(const char *text, int start,
                      int end ATTRIBUTE_UNUSED)
{
K
Karel Zak 已提交
9074 9075
    char **matches = (char **) NULL;

9076
    if (start == 0)
K
Karel Zak 已提交
9077
        /* command name generator */
9078
        matches = rl_completion_matches(text, vshReadlineCommandGenerator);
K
Karel Zak 已提交
9079 9080
    else
        /* commands options */
9081
        matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
K
Karel Zak 已提交
9082 9083 9084 9085
    return matches;
}


9086 9087
static int
vshReadlineInit(vshControl *ctl)
9088
{
9089 9090
    char *userdir = NULL;

K
Karel Zak 已提交
9091 9092 9093 9094 9095
    /* 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;
9096 9097 9098

    /* Limit the total size of the history buffer */
    stifle_history(500);
9099 9100

    /* Prepare to read/write history from/to the ~/.virsh/history file */
9101
    userdir = virGetUserDirectory(getuid());
9102 9103 9104 9105 9106 9107

    if (userdir == NULL)
        return -1;

    if (virAsprintf(&ctl->historydir, "%s/.virsh", userdir) < 0) {
        vshError(ctl, "%s", _("Out of memory"));
9108
        VIR_FREE(userdir);
9109 9110 9111 9112 9113
        return -1;
    }

    if (virAsprintf(&ctl->historyfile, "%s/history", ctl->historydir) < 0) {
        vshError(ctl, "%s", _("Out of memory"));
9114
        VIR_FREE(userdir);
9115 9116 9117
        return -1;
    }

9118
    VIR_FREE(userdir);
9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136

    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);
    }

9137 9138
    VIR_FREE(ctl->historydir);
    VIR_FREE(ctl->historyfile);
K
Karel Zak 已提交
9139 9140
}

9141 9142 9143 9144 9145 9146
static char *
vshReadline (vshControl *ctl ATTRIBUTE_UNUSED, const char *prompt)
{
    return readline (prompt);
}

9147
#else /* !USE_READLINE */
9148

9149 9150 9151 9152 9153 9154 9155
static int
vshReadlineInit (vshControl *ctl ATTRIBUTE_UNUSED)
{
    /* empty */
    return 0;
}

9156
static void
9157
vshReadlineDeinit (vshControl *ctl ATTRIBUTE_UNUSED)
9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180
{
    /* 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);
}

9181
#endif /* !USE_READLINE */
9182

K
Karel Zak 已提交
9183
/*
J
Jim Meyering 已提交
9184
 * Deinitialize virsh
K
Karel Zak 已提交
9185 9186
 */
static int
9187
vshDeinit(vshControl *ctl)
9188
{
9189
    vshReadlineDeinit(ctl);
9190
    vshCloseLogFile(ctl);
9191
    VIR_FREE(ctl->name);
K
Karel Zak 已提交
9192
    if (ctl->conn) {
9193
        if (virConnectClose(ctl->conn) != 0) {
9194
            vshError(ctl, "%s", _("failed to disconnect from the hypervisor"));
K
Karel Zak 已提交
9195 9196
        }
    }
D
Daniel P. Berrange 已提交
9197 9198
    virResetLastError();

K
Karel Zak 已提交
9199 9200
    return TRUE;
}
9201

K
Karel Zak 已提交
9202 9203 9204 9205
/*
 * Print usage
 */
static void
9206
vshUsage(void)
9207
{
9208
    const vshCmdDef *cmd;
9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222
    fprintf(stdout, _("\n%s [options] [commands]\n\n"
                      "  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"
                      "    -v | --version          program version\n\n"
                      "  commands (non interactive mode):\n"), progname);

    for (cmd = commands; cmd->name; cmd++)
        fprintf(stdout,
E
Eric Blake 已提交
9223
                "    %-15s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help")));
9224 9225 9226 9227

    fprintf(stdout, "%s",
            _("\n  (specify help <command> for details about the command)\n\n"));
    return;
K
Karel Zak 已提交
9228 9229 9230 9231 9232 9233 9234
}

/*
 * argv[]:  virsh [options] [command]
 *
 */
static int
9235
vshParseArgv(vshControl *ctl, int argc, char **argv)
9236
{
K
Karel Zak 已提交
9237 9238
    char *last = NULL;
    int i, end = 0, help = 0;
9239
    int arg, idx = 0;
K
Karel Zak 已提交
9240
    struct option opt[] = {
9241 9242 9243 9244 9245
        {"debug", 1, 0, 'd'},
        {"help", 0, 0, 'h'},
        {"quiet", 0, 0, 'q'},
        {"timing", 0, 0, 't'},
        {"version", 0, 0, 'v'},
K
Karel Zak 已提交
9246
        {"connect", 1, 0, 'c'},
9247
        {"readonly", 0, 0, 'r'},
9248
        {"log", 1, 0, 'l'},
K
Karel Zak 已提交
9249
        {0, 0, 0, 0}
9250 9251
    };

K
Karel Zak 已提交
9252 9253

    if (argc < 2)
K
Karel Zak 已提交
9254
        return TRUE;
9255

9256
    /* look for begin of the command, for example:
K
Karel Zak 已提交
9257 9258 9259 9260
     *   ./virsh --debug 5 -q command --cmdoption
     *                  <--- ^ --->
     *        getopt() stuff | command suff
     */
9261
    for (i = 1; i < argc; i++) {
K
Karel Zak 已提交
9262 9263
        if (*argv[i] != '-') {
            int valid = FALSE;
9264

K
Karel Zak 已提交
9265 9266 9267 9268
            /* non "--option" argv, is it command? */
            if (last) {
                struct option *o;
                int sz = strlen(last);
9269 9270

                for (o = opt; o->name; o++) {
9271 9272 9273 9274
                    if (o->has_arg == 1){
                        if (sz == 2 && *(last + 1) == o->val)
                            /* valid virsh short option */
                            valid = TRUE;
9275
                        else if (sz > 2 && STREQ(o->name, last + 2))
9276 9277 9278
                            /* valid virsh long option */
                            valid = TRUE;
                    }
K
Karel Zak 已提交
9279 9280 9281 9282 9283 9284 9285 9286 9287
                }
            }
            if (!valid) {
                end = i;
                break;
            }
        }
        last = argv[i];
    }
9288
    end = end ? end : argc;
9289

K
Karel Zak 已提交
9290
    /* standard (non-command) options */
9291
    while ((arg = getopt_long(end, argv, "d:hqtc:vrl:", opt, &idx)) != -1) {
9292
        switch (arg) {
9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310
        case 'd':
            ctl->debug = atoi(optarg);
            break;
        case 'h':
            help = 1;
            break;
        case 'q':
            ctl->quiet = TRUE;
            break;
        case 't':
            ctl->timing = TRUE;
            break;
        case 'c':
            ctl->name = vshStrdup(ctl, optarg);
            break;
        case 'v':
            fprintf(stdout, "%s\n", VERSION);
            exit(EXIT_SUCCESS);
9311 9312 9313
        case 'r':
            ctl->readonly = TRUE;
            break;
9314 9315 9316
        case 'l':
            ctl->logfile = vshStrdup(ctl, optarg);
            break;
9317
        default:
9318 9319
            vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
            exit(EXIT_FAILURE);
K
Karel Zak 已提交
9320 9321 9322 9323
        }
    }

    if (help) {
9324 9325 9326 9327
        if (end < argc) {
            vshError(ctl, _("extra argument '%s'. See --help."), argv[end]);
            exit(EXIT_FAILURE);
        }
9328 9329 9330

        /* list all command */
        vshUsage();
K
Karel Zak 已提交
9331
        exit(EXIT_SUCCESS);
9332 9333
    }

K
Karel Zak 已提交
9334 9335 9336
    if (argc > end) {
        /* parse command */
        char *cmdstr;
9337 9338
        int sz = 0, ret;

K
Karel Zak 已提交
9339 9340
        ctl->imode = FALSE;

9341 9342 9343
        for (i = end; i < argc; i++)
            sz += strlen(argv[i]) + 1;  /* +1 is for blank space between items */

9344
        cmdstr = vshCalloc(ctl, sz + 1, 1);
9345 9346

        for (i = end; i < argc; i++) {
K
Karel Zak 已提交
9347 9348 9349 9350
            strncat(cmdstr, argv[i], sz);
            sz -= strlen(argv[i]);
            strncat(cmdstr, " ", sz--);
        }
K
Karel Zak 已提交
9351
        vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
K
Karel Zak 已提交
9352
        ret = vshCommandParse(ctl, cmdstr);
9353

9354
        VIR_FREE(cmdstr);
K
Karel Zak 已提交
9355 9356 9357 9358 9359
        return ret;
    }
    return TRUE;
}

9360 9361 9362 9363
int
main(int argc, char **argv)
{
    vshControl _ctl, *ctl = &_ctl;
9364
    char *defaultConn;
K
Karel Zak 已提交
9365 9366
    int ret = TRUE;

9367 9368
    if (!setlocale(LC_ALL, "")) {
        perror("setlocale");
9369
        /* failure to setup locale is not fatal */
9370 9371 9372
    }
    if (!bindtextdomain(GETTEXT_PACKAGE, LOCALEBASEDIR)) {
        perror("bindtextdomain");
9373
        return -1;
9374 9375 9376
    }
    if (!textdomain(GETTEXT_PACKAGE)) {
        perror("textdomain");
9377
        return -1;
9378 9379
    }

9380
    if (!(progname = strrchr(argv[0], '/')))
K
Karel Zak 已提交
9381 9382 9383
        progname = argv[0];
    else
        progname++;
9384

K
Karel Zak 已提交
9385
    memset(ctl, 0, sizeof(vshControl));
9386
    ctl->imode = TRUE;          /* default is interactive mode */
9387
    ctl->log_fd = -1;           /* Initialize log file descriptor */
K
Karel Zak 已提交
9388

9389
    if ((defaultConn = getenv("VIRSH_DEFAULT_CONNECT_URI"))) {
9390
        ctl->name = strdup(defaultConn);
9391 9392
    }

D
Daniel P. Berrange 已提交
9393 9394
    if (!vshParseArgv(ctl, argc, argv)) {
        vshDeinit(ctl);
K
Karel Zak 已提交
9395
        exit(EXIT_FAILURE);
D
Daniel P. Berrange 已提交
9396
    }
9397

D
Daniel P. Berrange 已提交
9398 9399
    if (!vshInit(ctl)) {
        vshDeinit(ctl);
K
Karel Zak 已提交
9400
        exit(EXIT_FAILURE);
D
Daniel P. Berrange 已提交
9401
    }
9402

K
Karel Zak 已提交
9403
    if (!ctl->imode) {
9404
        ret = vshCommandRun(ctl, ctl->cmd);
9405
    } else {
K
Karel Zak 已提交
9406 9407
        /* interactive mode */
        if (!ctl->quiet) {
K
Karel Zak 已提交
9408
            vshPrint(ctl,
9409
                     _("Welcome to %s, the virtualization interactive terminal.\n\n"),
9410
                     progname);
J
Jim Meyering 已提交
9411
            vshPrint(ctl, "%s",
9412
                     _("Type:  'help' for help with commands\n"
9413
                       "       'quit' to quit\n\n"));
K
Karel Zak 已提交
9414
        }
9415 9416 9417 9418 9419 9420

        if (vshReadlineInit(ctl) < 0) {
            vshDeinit(ctl);
            exit(EXIT_FAILURE);
        }

K
Karel Zak 已提交
9421
        do {
9422
            const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW;
9423
            ctl->cmdstr =
9424
                vshReadline(ctl, prompt);
9425 9426
            if (ctl->cmdstr == NULL)
                break;          /* EOF */
K
Karel Zak 已提交
9427
            if (*ctl->cmdstr) {
9428
#if USE_READLINE
K
Karel Zak 已提交
9429
                add_history(ctl->cmdstr);
9430
#endif
K
Karel Zak 已提交
9431 9432 9433
                if (vshCommandParse(ctl, ctl->cmdstr))
                    vshCommandRun(ctl, ctl->cmd);
            }
9434
            VIR_FREE(ctl->cmdstr);
9435
        } while (ctl->imode);
K
Karel Zak 已提交
9436

9437 9438
        if (ctl->cmdstr == NULL)
            fputc('\n', stdout);        /* line break after alone prompt */
K
Karel Zak 已提交
9439
    }
9440

K
Karel Zak 已提交
9441 9442
    vshDeinit(ctl);
    exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
9443
}