man pages: update the description for the virsh help command
[libvirt/aglitke.git] / tools / virsh.c
blob31de80f94fe94155a406dbf549e8a735c697c159
1 /*
2 * virsh.c: a shell to exercise the libvirt API
4 * Copyright (C) 2005, 2007-2010 Red Hat, Inc.
6 * See COPYING.LIB for the License of this software
8 * Daniel Veillard <veillard@redhat.com>
9 * Karel Zak <kzak@redhat.com>
10 * Daniel P. Berrange <berrange@redhat.com>
13 #include <config.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdarg.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <getopt.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/wait.h>
25 #include "c-ctype.h"
26 #include <fcntl.h>
27 #include <locale.h>
28 #include <time.h>
29 #include <limits.h>
30 #include <assert.h>
31 #include <sys/stat.h>
32 #include <inttypes.h>
33 #include <signal.h>
35 #include <libxml/parser.h>
36 #include <libxml/tree.h>
37 #include <libxml/xpath.h>
38 #include <libxml/xmlsave.h>
40 #ifdef HAVE_READLINE_READLINE_H
41 # include <readline/readline.h>
42 # include <readline/history.h>
43 #endif
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"
52 #include "xml.h"
53 #include "libvirt/libvirt-qemu.h"
54 #include "files.h"
55 #include "../daemon/event.h"
56 #include "configmake.h"
58 static char *progname;
60 #ifndef TRUE
61 # define TRUE 1
62 # define FALSE 0
63 #endif
65 #define VIRSH_MAX_XML_FILE 10*1024*1024
67 #define VSH_PROMPT_RW "virsh # "
68 #define VSH_PROMPT_RO "virsh > "
70 #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
71 #define DIFF_MSEC(T, U) \
72 ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
73 ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
75 /**
76 * The log configuration
78 #define MSG_BUFFER 4096
79 #define SIGN_NAME "virsh"
80 #define DIR_MODE (S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) /* 0755 */
81 #define FILE_MODE (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) /* 0644 */
82 #define LOCK_MODE (S_IWUSR | S_IRUSR) /* 0600 */
83 #define LVL_DEBUG "DEBUG"
84 #define LVL_INFO "INFO"
85 #define LVL_NOTICE "NOTICE"
86 #define LVL_WARNING "WARNING"
87 #define LVL_ERROR "ERROR"
89 /**
90 * vshErrorLevel:
92 * Indicates the level of a log message
94 typedef enum {
95 VSH_ERR_DEBUG = 0,
96 VSH_ERR_INFO,
97 VSH_ERR_NOTICE,
98 VSH_ERR_WARNING,
99 VSH_ERR_ERROR
100 } vshErrorLevel;
103 * virsh command line grammar:
105 * command_line = <command>\n | <command>; <command>; ...
107 * command = <keyword> <option> [--] <data>
109 * option = <bool_option> | <int_option> | <string_option>
110 * data = <string>
112 * bool_option = --optionname
113 * int_option = --optionname <number> | --optionname=<number>
114 * string_option = --optionname <string> | --optionname=<string>
116 * keyword = [a-zA-Z][a-zA-Z-]*
117 * number = [0-9]+
118 * string = ('[^']*'|"([^\\"]|\\.)*"|([^ \t\n\\'"]|\\.))+
123 * vshCmdOptType - command option type
125 typedef enum {
126 VSH_OT_BOOL, /* optional boolean option */
127 VSH_OT_STRING, /* optional string option */
128 VSH_OT_INT, /* optional or mandatory int option */
129 VSH_OT_DATA, /* string data (as non-option) */
130 VSH_OT_ARGV /* remaining arguments, opt->name should be "" */
131 } vshCmdOptType;
134 * Command group types
136 #define VSH_CMD_GRP_DOM_MANAGEMENT "Domain Management"
137 #define VSH_CMD_GRP_DOM_MONITORING "Domain Monitoring"
138 #define VSH_CMD_GRP_STORAGE_POOL "Storage Pool"
139 #define VSH_CMD_GRP_STORAGE_VOL "Storage Volume"
140 #define VSH_CMD_GRP_NETWORK "Networking"
141 #define VSH_CMD_GRP_NODEDEV "Node Device"
142 #define VSH_CMD_GRP_IFACE "Interface"
143 #define VSH_CMD_GRP_NWFILTER "Network Filter"
144 #define VSH_CMD_GRP_SECRET "Secret"
145 #define VSH_CMD_GRP_SNAPSHOT "Snapshot"
146 #define VSH_CMD_GRP_HOST_AND_HV "Host and Hypervisor"
147 #define VSH_CMD_GRP_VIRSH "Virsh itself"
150 * Command Option Flags
152 #define VSH_OFLAG_NONE 0 /* without flags */
153 #define VSH_OFLAG_REQ (1 << 1) /* option required */
155 /* dummy */
156 typedef struct __vshControl vshControl;
157 typedef struct __vshCmd vshCmd;
160 * vshCmdInfo -- information about command
162 typedef struct {
163 const char *name; /* name of information */
164 const char *data; /* information */
165 } vshCmdInfo;
168 * vshCmdOptDef - command option definition
170 typedef struct {
171 const char *name; /* the name of option */
172 vshCmdOptType type; /* option type */
173 int flag; /* flags */
174 const char *help; /* help string */
175 } vshCmdOptDef;
178 * vshCmdOpt - command options
180 typedef struct vshCmdOpt {
181 const vshCmdOptDef *def; /* pointer to relevant option */
182 char *data; /* allocated data */
183 struct vshCmdOpt *next;
184 } vshCmdOpt;
187 * vshCmdDef - command definition
189 typedef struct {
190 const char *name;
191 int (*handler) (vshControl *, const vshCmd *); /* command handler */
192 const vshCmdOptDef *opts; /* definition of command options */
193 const vshCmdInfo *info; /* details about command */
194 } vshCmdDef;
197 * vshCmd - parsed command
199 typedef struct __vshCmd {
200 const vshCmdDef *def; /* command definition */
201 vshCmdOpt *opts; /* list of command arguments */
202 struct __vshCmd *next; /* next command */
203 } __vshCmd;
206 * vshControl
208 typedef struct __vshControl {
209 char *name; /* connection name */
210 virConnectPtr conn; /* connection to hypervisor (MAY BE NULL) */
211 vshCmd *cmd; /* the current command */
212 char *cmdstr; /* string with command */
213 int imode; /* interactive mode? */
214 int quiet; /* quiet mode */
215 int debug; /* print debug messages? */
216 int timing; /* print timing info? */
217 int readonly; /* connect readonly (first time only, not
218 * during explicit connect command)
220 char *logfile; /* log file name */
221 int log_fd; /* log file descriptor */
222 char *historydir; /* readline history directory name */
223 char *historyfile; /* readline history file name */
224 } __vshControl;
226 typedef struct vshCmdGrp {
227 const char *name;
228 const char *keyword; /* help keyword */
229 const vshCmdDef *commands;
230 } vshCmdGrp;
232 static const vshCmdGrp cmdGroups[];
234 static void vshError(vshControl *ctl, const char *format, ...)
235 ATTRIBUTE_FMT_PRINTF(2, 3);
236 static int vshInit(vshControl *ctl);
237 static int vshDeinit(vshControl *ctl);
238 static void vshUsage(void);
239 static void vshOpenLogFile(vshControl *ctl);
240 static void vshOutputLogFile(vshControl *ctl, int log_level, const char *format, va_list ap);
241 static void vshCloseLogFile(vshControl *ctl);
243 static int vshParseArgv(vshControl *ctl, int argc, char **argv);
245 static const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info);
246 static const vshCmdDef *vshCmddefSearch(const char *cmdname);
247 static int vshCmddefHelp(vshControl *ctl, const char *name);
248 static const vshCmdGrp *vshCmdGrpSearch(const char *grpname);
249 static int vshCmdGrpHelp(vshControl *ctl, const char *name);
251 static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
252 static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found);
253 static unsigned long vshCommandOptUL(const vshCmd *cmd, const char *name,
254 int *found);
255 static char *vshCommandOptString(const vshCmd *cmd, const char *name,
256 int *found);
257 static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name,
258 int *found);
259 static int vshCommandOptBool(const vshCmd *cmd, const char *name);
260 static char *vshCommandOptArgv(const vshCmd *cmd, int count);
262 #define VSH_BYID (1 << 1)
263 #define VSH_BYUUID (1 << 2)
264 #define VSH_BYNAME (1 << 3)
265 #define VSH_BYMAC (1 << 4)
267 static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
268 char **name, int flag);
270 /* default is lookup by Id, Name and UUID */
271 #define vshCommandOptDomain(_ctl, _cmd, _name) \
272 vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME)
274 static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
275 char **name, int flag);
277 /* default is lookup by Name and UUID */
278 #define vshCommandOptNetwork(_ctl, _cmd, _name) \
279 vshCommandOptNetworkBy(_ctl, _cmd, _name, \
280 VSH_BYUUID|VSH_BYNAME)
282 static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
283 char **name, int flag);
285 /* default is lookup by Name and UUID */
286 #define vshCommandOptNWFilter(_ctl, _cmd, _name) \
287 vshCommandOptNWFilterBy(_ctl, _cmd, _name, \
288 VSH_BYUUID|VSH_BYNAME)
290 static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
291 char **name, int flag);
293 /* default is lookup by Name and MAC */
294 #define vshCommandOptInterface(_ctl, _cmd, _name) \
295 vshCommandOptInterfaceBy(_ctl, _cmd, _name, \
296 VSH_BYMAC|VSH_BYNAME)
298 static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd,
299 const char *optname, char **name, int flag);
301 /* default is lookup by Name and UUID */
302 #define vshCommandOptPool(_ctl, _cmd, _optname, _name) \
303 vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \
304 VSH_BYUUID|VSH_BYNAME)
306 static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
307 const char *optname,
308 const char *pooloptname,
309 char **name, int flag);
311 /* default is lookup by Name and UUID */
312 #define vshCommandOptVol(_ctl, _cmd,_optname, _pooloptname, _name) \
313 vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \
314 VSH_BYUUID|VSH_BYNAME)
316 static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd,
317 char **name);
319 static void vshPrintExtra(vshControl *ctl, const char *format, ...)
320 ATTRIBUTE_FMT_PRINTF(2, 3);
321 static void vshDebug(vshControl *ctl, int level, const char *format, ...)
322 ATTRIBUTE_FMT_PRINTF(3, 4);
324 /* XXX: add batch support */
325 #define vshPrint(_ctl, ...) fprintf(stdout, __VA_ARGS__)
327 static const char *vshDomainStateToString(int state);
328 static const char *vshDomainVcpuStateToString(int state);
329 static int vshConnectionUsability(vshControl *ctl, virConnectPtr conn);
331 static char *editWriteToTempFile (vshControl *ctl, const char *doc);
332 static int editFile (vshControl *ctl, const char *filename);
333 static char *editReadBackFile (vshControl *ctl, const char *filename);
335 static void *_vshMalloc(vshControl *ctl, size_t sz, const char *filename, int line);
336 #define vshMalloc(_ctl, _sz) _vshMalloc(_ctl, _sz, __FILE__, __LINE__)
338 static void *_vshCalloc(vshControl *ctl, size_t nmemb, size_t sz, const char *filename, int line);
339 #define vshCalloc(_ctl, _nmemb, _sz) _vshCalloc(_ctl, _nmemb, _sz, __FILE__, __LINE__)
341 static void *_vshRealloc(vshControl *ctl, void *ptr, size_t sz, const char *filename, int line);
342 #define vshRealloc(_ctl, _ptr, _sz) _vshRealloc(_ctl, _ptr, _sz, __FILE__, __LINE__)
344 static char *_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line);
345 #define vshStrdup(_ctl, _s) _vshStrdup(_ctl, _s, __FILE__, __LINE__)
347 static void *
348 _vshMalloc(vshControl *ctl, size_t size, const char *filename, int line)
350 void *x;
352 if ((x = malloc(size)))
353 return x;
354 vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
355 filename, line, (int) size);
356 exit(EXIT_FAILURE);
359 static void *
360 _vshCalloc(vshControl *ctl, size_t nmemb, size_t size, const char *filename, int line)
362 void *x;
364 if ((x = calloc(nmemb, size)))
365 return x;
366 vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
367 filename, line, (int) (size*nmemb));
368 exit(EXIT_FAILURE);
371 static void *
372 _vshRealloc(vshControl *ctl, void *ptr, size_t size, const char *filename, int line)
374 void *x;
376 if ((x = realloc(ptr, size)))
377 return x;
378 VIR_FREE(ptr);
379 vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
380 filename, line, (int) size);
381 exit(EXIT_FAILURE);
384 static char *
385 _vshStrdup(vshControl *ctl, const char *s, const char *filename, int line)
387 char *x;
389 if (s == NULL)
390 return(NULL);
391 if ((x = strdup(s)))
392 return x;
393 vshError(ctl, _("%s: %d: failed to allocate %lu bytes"),
394 filename, line, (unsigned long)strlen(s));
395 exit(EXIT_FAILURE);
398 /* Poison the raw allocating identifiers in favor of our vsh variants. */
399 #undef malloc
400 #undef calloc
401 #undef realloc
402 #undef strdup
403 #define malloc use_vshMalloc_instead_of_malloc
404 #define calloc use_vshCalloc_instead_of_calloc
405 #define realloc use_vshRealloc_instead_of_realloc
406 #define strdup use_vshStrdup_instead_of_strdup
408 static int idsorter(const void *a, const void *b) {
409 const int *ia = (const int *)a;
410 const int *ib = (const int *)b;
412 if (*ia > *ib)
413 return 1;
414 else if (*ia < *ib)
415 return -1;
416 return 0;
418 static int namesorter(const void *a, const void *b) {
419 const char **sa = (const char**)a;
420 const char **sb = (const char**)b;
422 return strcasecmp(*sa, *sb);
425 static double
426 prettyCapacity(unsigned long long val,
427 const char **unit) {
428 if (val < 1024) {
429 *unit = "";
430 return (double)val;
431 } else if (val < (1024.0l * 1024.0l)) {
432 *unit = "KB";
433 return (((double)val / 1024.0l));
434 } else if (val < (1024.0l * 1024.0l * 1024.0l)) {
435 *unit = "MB";
436 return ((double)val / (1024.0l * 1024.0l));
437 } else if (val < (1024.0l * 1024.0l * 1024.0l * 1024.0l)) {
438 *unit = "GB";
439 return ((double)val / (1024.0l * 1024.0l * 1024.0l));
440 } else {
441 *unit = "TB";
442 return ((double)val / (1024.0l * 1024.0l * 1024.0l * 1024.0l));
447 static virErrorPtr last_error;
450 * Quieten libvirt until we're done with the command.
452 static void
453 virshErrorHandler(void *unused ATTRIBUTE_UNUSED, virErrorPtr error)
455 virFreeError(last_error);
456 last_error = virSaveLastError();
457 if (getenv("VIRSH_DEBUG") != NULL)
458 virDefaultErrorFunc(error);
462 * Report an error when a command finishes. This is better than before
463 * (when correct operation would report errors), but it has some
464 * problems: we lose the smarter formatting of virDefaultErrorFunc(),
465 * and it can become harder to debug problems, if errors get reported
466 * twice during one command. This case shouldn't really happen anyway,
467 * and it's IMHO a bug that libvirt does that sometimes.
469 static void
470 virshReportError(vshControl *ctl)
472 if (last_error == NULL) {
473 /* Calling directly into libvirt util functions won't trigger the
474 * error callback (which sets last_error), so check it ourselves.
476 * If the returned error has CODE_OK, this most likely means that
477 * no error was ever raised, so just ignore */
478 last_error = virSaveLastError();
479 if (!last_error || last_error->code == VIR_ERR_OK)
480 goto out;
483 if (last_error->code == VIR_ERR_OK) {
484 vshError(ctl, "%s", _("unknown error"));
485 goto out;
488 vshError(ctl, "%s", last_error->message);
490 out:
491 virFreeError(last_error);
492 last_error = NULL;
496 * Detection of disconnections and automatic reconnection support
498 static int disconnected = 0; /* we may have been disconnected */
500 #ifdef SIGPIPE
502 * vshCatchDisconnect:
504 * We get here when a SIGPIPE is being raised, we can't do much in the
505 * handler, just save the fact it was raised
507 static void vshCatchDisconnect(int sig, siginfo_t * siginfo,
508 void* context ATTRIBUTE_UNUSED) {
509 if ((sig == SIGPIPE) || (siginfo->si_signo == SIGPIPE))
510 disconnected++;
514 * vshSetupSignals:
516 * Catch SIGPIPE signals which may arise when disconnection
517 * from libvirtd occurs
519 static void
520 vshSetupSignals(void) {
521 struct sigaction sig_action;
523 sig_action.sa_sigaction = vshCatchDisconnect;
524 sig_action.sa_flags = SA_SIGINFO;
525 sigemptyset(&sig_action.sa_mask);
527 sigaction(SIGPIPE, &sig_action, NULL);
529 #else
530 static void
531 vshSetupSignals(void) {}
532 #endif
535 * vshReconnect:
537 * Reconnect after a disconnect from libvirtd
540 static void
541 vshReconnect(vshControl *ctl) {
542 if (ctl->conn != NULL)
543 virConnectClose(ctl->conn);
545 ctl->conn = virConnectOpenAuth(ctl->name,
546 virConnectAuthPtrDefault,
547 ctl->readonly ? VIR_CONNECT_RO : 0);
548 if (!ctl->conn)
549 vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
550 else
551 vshError(ctl, "%s", _("Reconnected to the hypervisor"));
552 disconnected = 0;
555 /* ---------------
556 * Commands
557 * ---------------
561 * "help" command
563 static const vshCmdInfo info_help[] = {
564 {"help", N_("print help")},
565 {"desc", N_("Prints global help, command specific help, or help for a\n"
566 " group of related commands")},
568 {NULL, NULL}
571 static const vshCmdOptDef opts_help[] = {
572 {"command", VSH_OT_DATA, 0, N_("Prints global help or command specific help.")},
573 {"group", VSH_OT_DATA, 0, N_("Prints global help or help for a group of related commands.")},
574 {NULL, 0, 0, NULL}
577 static int
578 cmdHelp(vshControl *ctl, const vshCmd *cmd)
580 const vshCmdDef *c;
581 const vshCmdGrp *g;
582 const char *name;
584 name = vshCommandOptString(cmd, "command", NULL);
586 if (!name)
587 name = vshCommandOptString(cmd, "group", NULL);
589 if (!name) {
590 const vshCmdGrp *grp;
591 const vshCmdDef *def;
593 vshPrint(ctl, "%s", _("Grouped commands:\n\n"));
595 for (grp = cmdGroups; grp->name; grp++) {
596 vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
597 grp->keyword);
599 for (def = grp->commands; def->name; def++)
600 vshPrint(ctl, " %-30s %s\n", def->name,
601 _(vshCmddefGetInfo(def, "help")));
603 vshPrint(ctl, "\n");
606 return TRUE;
609 if ((c = vshCmddefSearch(name))) {
610 return vshCmddefHelp(ctl, name);
611 } else if ((g = vshCmdGrpSearch(name))) {
612 return vshCmdGrpHelp(ctl, name);
613 } else {
614 vshError(ctl, _("command or command group '%s' doesn't exist"), name);
615 return FALSE;
620 * "autostart" command
622 static const vshCmdInfo info_autostart[] = {
623 {"help", N_("autostart a domain")},
624 {"desc",
625 N_("Configure a domain to be automatically started at boot.")},
626 {NULL, NULL}
629 static const vshCmdOptDef opts_autostart[] = {
630 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
631 {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
632 {NULL, 0, 0, NULL}
635 static int
636 cmdAutostart(vshControl *ctl, const vshCmd *cmd)
638 virDomainPtr dom;
639 char *name;
640 int autostart;
642 if (!vshConnectionUsability(ctl, ctl->conn))
643 return FALSE;
645 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
646 return FALSE;
648 autostart = !vshCommandOptBool(cmd, "disable");
650 if (virDomainSetAutostart(dom, autostart) < 0) {
651 if (autostart)
652 vshError(ctl, _("Failed to mark domain %s as autostarted"), name);
653 else
654 vshError(ctl, _("Failed to unmark domain %s as autostarted"), name);
655 virDomainFree(dom);
656 return FALSE;
659 if (autostart)
660 vshPrint(ctl, _("Domain %s marked as autostarted\n"), name);
661 else
662 vshPrint(ctl, _("Domain %s unmarked as autostarted\n"), name);
664 virDomainFree(dom);
665 return TRUE;
669 * "connect" command
671 static const vshCmdInfo info_connect[] = {
672 {"help", N_("(re)connect to hypervisor")},
673 {"desc",
674 N_("Connect to local hypervisor. This is built-in command after shell start up.")},
675 {NULL, NULL}
678 static const vshCmdOptDef opts_connect[] = {
679 {"name", VSH_OT_DATA, 0, N_("hypervisor connection URI")},
680 {"readonly", VSH_OT_BOOL, 0, N_("read-only connection")},
681 {NULL, 0, 0, NULL}
684 static int
685 cmdConnect(vshControl *ctl, const vshCmd *cmd)
687 int ro = vshCommandOptBool(cmd, "readonly");
688 char *name;
690 if (ctl->conn) {
691 int ret;
692 if ((ret = virConnectClose(ctl->conn)) != 0) {
693 vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret);
694 return FALSE;
696 ctl->conn = NULL;
699 VIR_FREE(ctl->name);
700 name = vshCommandOptString(cmd, "name", NULL);
701 if (!name)
702 return FALSE;
703 ctl->name = vshStrdup(ctl, name);
705 if (!ro) {
706 ctl->readonly = 0;
707 } else {
708 ctl->readonly = 1;
711 ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault,
712 ctl->readonly ? VIR_CONNECT_RO : 0);
714 if (!ctl->conn)
715 vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
717 return ctl->conn ? TRUE : FALSE;
720 #ifndef WIN32
723 * "console" command
725 static const vshCmdInfo info_console[] = {
726 {"help", N_("connect to the guest console")},
727 {"desc",
728 N_("Connect the virtual serial console for the guest")},
729 {NULL, NULL}
732 static const vshCmdOptDef opts_console[] = {
733 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
734 {"devname", VSH_OT_STRING, 0, N_("character device name")},
735 {NULL, 0, 0, NULL}
738 static int
739 cmdRunConsole(vshControl *ctl, virDomainPtr dom, const char *devname)
741 int ret = FALSE;
742 virDomainInfo dominfo;
744 if (virDomainGetInfo(dom, &dominfo) < 0) {
745 vshError(ctl, "%s", _("Unable to get domain status"));
746 goto cleanup;
749 if (dominfo.state == VIR_DOMAIN_SHUTOFF) {
750 vshError(ctl, "%s", _("The domain is not running"));
751 goto cleanup;
754 vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom));
755 vshPrintExtra(ctl, "%s", _("Escape character is ^]\n"));
756 if (vshRunConsole(dom, devname) == 0)
757 ret = TRUE;
759 cleanup:
761 return ret;
764 static int
765 cmdConsole(vshControl *ctl, const vshCmd *cmd)
767 virDomainPtr dom;
768 int ret;
769 const char *devname;
771 if (!vshConnectionUsability(ctl, ctl->conn))
772 return FALSE;
774 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
775 return FALSE;
777 devname = vshCommandOptString(cmd, "devname", NULL);
779 ret = cmdRunConsole(ctl, dom, devname);
781 virDomainFree(dom);
782 return ret;
785 #endif /* WIN32 */
789 * "list" command
791 static const vshCmdInfo info_list[] = {
792 {"help", N_("list domains")},
793 {"desc", N_("Returns list of domains.")},
794 {NULL, NULL}
797 static const vshCmdOptDef opts_list[] = {
798 {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")},
799 {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")},
800 {NULL, 0, 0, NULL}
804 static int
805 cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
807 int inactive = vshCommandOptBool(cmd, "inactive");
808 int all = vshCommandOptBool(cmd, "all");
809 int active = !inactive || all ? 1 : 0;
810 int *ids = NULL, maxid = 0, i;
811 char **names = NULL;
812 int maxname = 0;
813 inactive |= all;
815 if (!vshConnectionUsability(ctl, ctl->conn))
816 return FALSE;
818 if (active) {
819 maxid = virConnectNumOfDomains(ctl->conn);
820 if (maxid < 0) {
821 vshError(ctl, "%s", _("Failed to list active domains"));
822 return FALSE;
824 if (maxid) {
825 ids = vshMalloc(ctl, sizeof(int) * maxid);
827 if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
828 vshError(ctl, "%s", _("Failed to list active domains"));
829 VIR_FREE(ids);
830 return FALSE;
833 qsort(&ids[0], maxid, sizeof(int), idsorter);
836 if (inactive) {
837 maxname = virConnectNumOfDefinedDomains(ctl->conn);
838 if (maxname < 0) {
839 vshError(ctl, "%s", _("Failed to list inactive domains"));
840 VIR_FREE(ids);
841 return FALSE;
843 if (maxname) {
844 names = vshMalloc(ctl, sizeof(char *) * maxname);
846 if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
847 vshError(ctl, "%s", _("Failed to list inactive domains"));
848 VIR_FREE(ids);
849 VIR_FREE(names);
850 return FALSE;
853 qsort(&names[0], maxname, sizeof(char*), namesorter);
856 vshPrintExtra(ctl, "%3s %-20s %s\n", _("Id"), _("Name"), _("State"));
857 vshPrintExtra(ctl, "----------------------------------\n");
859 for (i = 0; i < maxid; i++) {
860 virDomainInfo info;
861 virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
862 const char *state;
864 /* this kind of work with domains is not atomic operation */
865 if (!dom)
866 continue;
868 if (virDomainGetInfo(dom, &info) < 0)
869 state = _("no state");
870 else
871 state = _(vshDomainStateToString(info.state));
873 vshPrint(ctl, "%3d %-20s %s\n",
874 virDomainGetID(dom),
875 virDomainGetName(dom),
876 state);
877 virDomainFree(dom);
879 for (i = 0; i < maxname; i++) {
880 virDomainInfo info;
881 virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
882 const char *state;
884 /* this kind of work with domains is not atomic operation */
885 if (!dom) {
886 VIR_FREE(names[i]);
887 continue;
890 if (virDomainGetInfo(dom, &info) < 0)
891 state = _("no state");
892 else
893 state = _(vshDomainStateToString(info.state));
895 vshPrint(ctl, "%3s %-20s %s\n", "-", names[i], state);
897 virDomainFree(dom);
898 VIR_FREE(names[i]);
900 VIR_FREE(ids);
901 VIR_FREE(names);
902 return TRUE;
906 * "domstate" command
908 static const vshCmdInfo info_domstate[] = {
909 {"help", N_("domain state")},
910 {"desc", N_("Returns state about a domain.")},
911 {NULL, NULL}
914 static const vshCmdOptDef opts_domstate[] = {
915 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
916 {NULL, 0, 0, NULL}
919 static int
920 cmdDomstate(vshControl *ctl, const vshCmd *cmd)
922 virDomainInfo info;
923 virDomainPtr dom;
924 int ret = TRUE;
926 if (!vshConnectionUsability(ctl, ctl->conn))
927 return FALSE;
929 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
930 return FALSE;
932 if (virDomainGetInfo(dom, &info) == 0)
933 vshPrint(ctl, "%s\n",
934 _(vshDomainStateToString(info.state)));
935 else
936 ret = FALSE;
938 virDomainFree(dom);
939 return ret;
942 /* "domblkstat" command
944 static const vshCmdInfo info_domblkstat[] = {
945 {"help", N_("get device block stats for a domain")},
946 {"desc", N_("Get device block stats for a running domain.")},
947 {NULL,NULL}
950 static const vshCmdOptDef opts_domblkstat[] = {
951 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
952 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
953 {NULL, 0, 0, NULL}
956 static int
957 cmdDomblkstat (vshControl *ctl, const vshCmd *cmd)
959 virDomainPtr dom;
960 char *name, *device;
961 struct _virDomainBlockStats stats;
963 if (!vshConnectionUsability (ctl, ctl->conn))
964 return FALSE;
966 if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
967 return FALSE;
969 if (!(device = vshCommandOptString (cmd, "device", NULL))) {
970 virDomainFree(dom);
971 return FALSE;
974 if (virDomainBlockStats (dom, device, &stats, sizeof stats) == -1) {
975 vshError(ctl, _("Failed to get block stats %s %s"), name, device);
976 virDomainFree(dom);
977 return FALSE;
980 if (stats.rd_req >= 0)
981 vshPrint (ctl, "%s rd_req %lld\n", device, stats.rd_req);
983 if (stats.rd_bytes >= 0)
984 vshPrint (ctl, "%s rd_bytes %lld\n", device, stats.rd_bytes);
986 if (stats.wr_req >= 0)
987 vshPrint (ctl, "%s wr_req %lld\n", device, stats.wr_req);
989 if (stats.wr_bytes >= 0)
990 vshPrint (ctl, "%s wr_bytes %lld\n", device, stats.wr_bytes);
992 if (stats.errs >= 0)
993 vshPrint (ctl, "%s errs %lld\n", device, stats.errs);
995 virDomainFree(dom);
996 return TRUE;
999 /* "domifstat" command
1001 static const vshCmdInfo info_domifstat[] = {
1002 {"help", N_("get network interface stats for a domain")},
1003 {"desc", N_("Get network interface stats for a running domain.")},
1004 {NULL,NULL}
1007 static const vshCmdOptDef opts_domifstat[] = {
1008 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1009 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")},
1010 {NULL, 0, 0, NULL}
1013 static int
1014 cmdDomIfstat (vshControl *ctl, const vshCmd *cmd)
1016 virDomainPtr dom;
1017 char *name, *device;
1018 struct _virDomainInterfaceStats stats;
1020 if (!vshConnectionUsability (ctl, ctl->conn))
1021 return FALSE;
1023 if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
1024 return FALSE;
1026 if (!(device = vshCommandOptString (cmd, "interface", NULL))) {
1027 virDomainFree(dom);
1028 return FALSE;
1031 if (virDomainInterfaceStats (dom, device, &stats, sizeof stats) == -1) {
1032 vshError(ctl, _("Failed to get interface stats %s %s"), name, device);
1033 virDomainFree(dom);
1034 return FALSE;
1037 if (stats.rx_bytes >= 0)
1038 vshPrint (ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes);
1040 if (stats.rx_packets >= 0)
1041 vshPrint (ctl, "%s rx_packets %lld\n", device, stats.rx_packets);
1043 if (stats.rx_errs >= 0)
1044 vshPrint (ctl, "%s rx_errs %lld\n", device, stats.rx_errs);
1046 if (stats.rx_drop >= 0)
1047 vshPrint (ctl, "%s rx_drop %lld\n", device, stats.rx_drop);
1049 if (stats.tx_bytes >= 0)
1050 vshPrint (ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes);
1052 if (stats.tx_packets >= 0)
1053 vshPrint (ctl, "%s tx_packets %lld\n", device, stats.tx_packets);
1055 if (stats.tx_errs >= 0)
1056 vshPrint (ctl, "%s tx_errs %lld\n", device, stats.tx_errs);
1058 if (stats.tx_drop >= 0)
1059 vshPrint (ctl, "%s tx_drop %lld\n", device, stats.tx_drop);
1061 virDomainFree(dom);
1062 return TRUE;
1066 * "dommemstats" command
1068 static const vshCmdInfo info_dommemstat[] = {
1069 {"help", N_("get memory statistics for a domain")},
1070 {"desc", N_("Get memory statistics for a runnng domain.")},
1071 {NULL,NULL}
1074 static const vshCmdOptDef opts_dommemstat[] = {
1075 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1076 {NULL, 0, 0, NULL}
1079 static int
1080 cmdDomMemStat(vshControl *ctl, const vshCmd *cmd)
1082 virDomainPtr dom;
1083 char *name;
1084 struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR];
1085 unsigned int nr_stats, i;
1087 if (!vshConnectionUsability(ctl, ctl->conn))
1088 return FALSE;
1090 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1091 return FALSE;
1093 nr_stats = virDomainMemoryStats (dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0);
1094 if (nr_stats == -1) {
1095 vshError(ctl, _("Failed to get memory statistics for domain %s"), name);
1096 virDomainFree(dom);
1097 return FALSE;
1100 for (i = 0; i < nr_stats; i++) {
1101 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
1102 vshPrint (ctl, "swap_in %llu\n", stats[i].val);
1103 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
1104 vshPrint (ctl, "swap_out %llu\n", stats[i].val);
1105 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
1106 vshPrint (ctl, "major_fault %llu\n", stats[i].val);
1107 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
1108 vshPrint (ctl, "minor_fault %llu\n", stats[i].val);
1109 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED)
1110 vshPrint (ctl, "unused %llu\n", stats[i].val);
1111 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE)
1112 vshPrint (ctl, "available %llu\n", stats[i].val);
1115 virDomainFree(dom);
1116 return TRUE;
1120 * "domblkinfo" command
1122 static const vshCmdInfo info_domblkinfo[] = {
1123 {"help", N_("domain block device size information")},
1124 {"desc", N_("Get block device size info for a domain.")},
1125 {NULL, NULL}
1128 static const vshCmdOptDef opts_domblkinfo[] = {
1129 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1130 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
1131 {NULL, 0, 0, NULL}
1134 static int
1135 cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd)
1137 virDomainBlockInfo info;
1138 virDomainPtr dom;
1139 int ret = TRUE;
1140 const char *device;
1142 if (!vshConnectionUsability(ctl, ctl->conn))
1143 return FALSE;
1145 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
1146 return FALSE;
1148 if (!(device = vshCommandOptString (cmd, "device", NULL))) {
1149 virDomainFree(dom);
1150 return FALSE;
1153 if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) {
1154 virDomainFree(dom);
1155 return FALSE;
1158 vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity);
1159 vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation);
1160 vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical);
1162 virDomainFree(dom);
1163 return ret;
1167 * "suspend" command
1169 static const vshCmdInfo info_suspend[] = {
1170 {"help", N_("suspend a domain")},
1171 {"desc", N_("Suspend a running domain.")},
1172 {NULL, NULL}
1175 static const vshCmdOptDef opts_suspend[] = {
1176 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1177 {NULL, 0, 0, NULL}
1180 static int
1181 cmdSuspend(vshControl *ctl, const vshCmd *cmd)
1183 virDomainPtr dom;
1184 char *name;
1185 int ret = TRUE;
1187 if (!vshConnectionUsability(ctl, ctl->conn))
1188 return FALSE;
1190 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1191 return FALSE;
1193 if (virDomainSuspend(dom) == 0) {
1194 vshPrint(ctl, _("Domain %s suspended\n"), name);
1195 } else {
1196 vshError(ctl, _("Failed to suspend domain %s"), name);
1197 ret = FALSE;
1200 virDomainFree(dom);
1201 return ret;
1205 * "create" command
1207 static const vshCmdInfo info_create[] = {
1208 {"help", N_("create a domain from an XML file")},
1209 {"desc", N_("Create a domain.")},
1210 {NULL, NULL}
1213 static const vshCmdOptDef opts_create[] = {
1214 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1215 #ifndef WIN32
1216 {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1217 #endif
1218 {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
1219 {NULL, 0, 0, NULL}
1222 static int
1223 cmdCreate(vshControl *ctl, const vshCmd *cmd)
1225 virDomainPtr dom;
1226 char *from;
1227 int found;
1228 int ret = TRUE;
1229 char *buffer;
1230 #ifndef WIN32
1231 int console = vshCommandOptBool(cmd, "console");
1232 #endif
1233 unsigned int flags = VIR_DOMAIN_NONE;
1235 if (!vshConnectionUsability(ctl, ctl->conn))
1236 return FALSE;
1238 from = vshCommandOptString(cmd, "file", &found);
1239 if (!found)
1240 return FALSE;
1242 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
1243 return FALSE;
1245 if (vshCommandOptBool(cmd, "paused"))
1246 flags |= VIR_DOMAIN_START_PAUSED;
1248 dom = virDomainCreateXML(ctl->conn, buffer, flags);
1249 VIR_FREE(buffer);
1251 if (dom != NULL) {
1252 vshPrint(ctl, _("Domain %s created from %s\n"),
1253 virDomainGetName(dom), from);
1254 #ifndef WIN32
1255 if (console)
1256 cmdRunConsole(ctl, dom, NULL);
1257 #endif
1258 virDomainFree(dom);
1259 } else {
1260 vshError(ctl, _("Failed to create domain from %s"), from);
1261 ret = FALSE;
1263 return ret;
1267 * "define" command
1269 static const vshCmdInfo info_define[] = {
1270 {"help", N_("define (but don't start) a domain from an XML file")},
1271 {"desc", N_("Define a domain.")},
1272 {NULL, NULL}
1275 static const vshCmdOptDef opts_define[] = {
1276 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1277 {NULL, 0, 0, NULL}
1280 static int
1281 cmdDefine(vshControl *ctl, const vshCmd *cmd)
1283 virDomainPtr dom;
1284 char *from;
1285 int found;
1286 int ret = TRUE;
1287 char *buffer;
1289 if (!vshConnectionUsability(ctl, ctl->conn))
1290 return FALSE;
1292 from = vshCommandOptString(cmd, "file", &found);
1293 if (!found)
1294 return FALSE;
1296 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
1297 return FALSE;
1299 dom = virDomainDefineXML(ctl->conn, buffer);
1300 VIR_FREE(buffer);
1302 if (dom != NULL) {
1303 vshPrint(ctl, _("Domain %s defined from %s\n"),
1304 virDomainGetName(dom), from);
1305 virDomainFree(dom);
1306 } else {
1307 vshError(ctl, _("Failed to define domain from %s"), from);
1308 ret = FALSE;
1310 return ret;
1314 * "undefine" command
1316 static const vshCmdInfo info_undefine[] = {
1317 {"help", N_("undefine an inactive domain")},
1318 {"desc", N_("Undefine the configuration for an inactive domain.")},
1319 {NULL, NULL}
1322 static const vshCmdOptDef opts_undefine[] = {
1323 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
1324 {NULL, 0, 0, NULL}
1327 static int
1328 cmdUndefine(vshControl *ctl, const vshCmd *cmd)
1330 virDomainPtr dom;
1331 int ret = TRUE;
1332 char *name;
1333 int found;
1334 int id;
1336 if (!vshConnectionUsability(ctl, ctl->conn))
1337 return FALSE;
1339 name = vshCommandOptString(cmd, "domain", &found);
1340 if (!found)
1341 return FALSE;
1343 if (name && virStrToLong_i(name, NULL, 10, &id) == 0
1344 && id >= 0 && (dom = virDomainLookupByID(ctl->conn, id))) {
1345 vshError(ctl,
1346 _("a running domain like %s cannot be undefined;\n"
1347 "to undefine, first shutdown then undefine"
1348 " using its name or UUID"),
1349 name);
1350 virDomainFree(dom);
1351 return FALSE;
1353 if (!(dom = vshCommandOptDomainBy(ctl, cmd, &name,
1354 VSH_BYNAME|VSH_BYUUID)))
1355 return FALSE;
1357 if (virDomainUndefine(dom) == 0) {
1358 vshPrint(ctl, _("Domain %s has been undefined\n"), name);
1359 } else {
1360 vshError(ctl, _("Failed to undefine domain %s"), name);
1361 ret = FALSE;
1364 virDomainFree(dom);
1365 return ret;
1370 * "start" command
1372 static const vshCmdInfo info_start[] = {
1373 {"help", N_("start a (previously defined) inactive domain")},
1374 {"desc", N_("Start a domain, either from the last managedsave\n"
1375 " state, or via a fresh boot if no managedsave state\n"
1376 " is present.")},
1377 {NULL, NULL}
1380 static const vshCmdOptDef opts_start[] = {
1381 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive domain")},
1382 #ifndef WIN32
1383 {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1384 #endif
1385 {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
1386 {NULL, 0, 0, NULL}
1389 static int
1390 cmdStart(vshControl *ctl, const vshCmd *cmd)
1392 virDomainPtr dom;
1393 int ret = TRUE;
1394 #ifndef WIN32
1395 int console = vshCommandOptBool(cmd, "console");
1396 #endif
1397 unsigned int flags = VIR_DOMAIN_NONE;
1399 if (!vshConnectionUsability(ctl, ctl->conn))
1400 return FALSE;
1402 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL, VSH_BYNAME)))
1403 return FALSE;
1405 if (virDomainGetID(dom) != (unsigned int)-1) {
1406 vshError(ctl, "%s", _("Domain is already active"));
1407 virDomainFree(dom);
1408 return FALSE;
1411 if (vshCommandOptBool(cmd, "paused"))
1412 flags |= VIR_DOMAIN_START_PAUSED;
1414 /* Prefer older API unless we have to pass a flag. */
1415 if ((flags ? virDomainCreateWithFlags(dom, flags)
1416 : virDomainCreate(dom)) == 0) {
1417 vshPrint(ctl, _("Domain %s started\n"),
1418 virDomainGetName(dom));
1419 #ifndef WIN32
1420 if (console)
1421 cmdRunConsole(ctl, dom, NULL);
1422 #endif
1423 } else {
1424 vshError(ctl, _("Failed to start domain %s"), virDomainGetName(dom));
1425 ret = FALSE;
1427 virDomainFree(dom);
1428 return ret;
1432 * "save" command
1434 static const vshCmdInfo info_save[] = {
1435 {"help", N_("save a domain state to a file")},
1436 {"desc", N_("Save a running domain.")},
1437 {NULL, NULL}
1440 static const vshCmdOptDef opts_save[] = {
1441 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1442 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to save the data")},
1443 {NULL, 0, 0, NULL}
1446 static int
1447 cmdSave(vshControl *ctl, const vshCmd *cmd)
1449 virDomainPtr dom;
1450 char *name;
1451 char *to;
1452 int ret = TRUE;
1454 if (!vshConnectionUsability(ctl, ctl->conn))
1455 return FALSE;
1457 if (!(to = vshCommandOptString(cmd, "file", NULL)))
1458 return FALSE;
1460 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1461 return FALSE;
1463 if (virDomainSave(dom, to) == 0) {
1464 vshPrint(ctl, _("Domain %s saved to %s\n"), name, to);
1465 } else {
1466 vshError(ctl, _("Failed to save domain %s to %s"), name, to);
1467 ret = FALSE;
1470 virDomainFree(dom);
1471 return ret;
1475 * "managedsave" command
1477 static const vshCmdInfo info_managedsave[] = {
1478 {"help", N_("managed save of a domain state")},
1479 {"desc", N_("Save and destroy a running domain, so it can be restarted from\n"
1480 " the same state at a later time. When the virsh 'start'\n"
1481 " command is next run for the domain, it will automatically\n"
1482 " be started from this saved state.")},
1483 {NULL, NULL}
1486 static const vshCmdOptDef opts_managedsave[] = {
1487 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1488 {NULL, 0, 0, NULL}
1491 static int
1492 cmdManagedSave(vshControl *ctl, const vshCmd *cmd)
1494 virDomainPtr dom;
1495 char *name;
1496 int ret = TRUE;
1498 if (!vshConnectionUsability(ctl, ctl->conn))
1499 return FALSE;
1501 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1502 return FALSE;
1504 if (virDomainManagedSave(dom, 0) == 0) {
1505 vshPrint(ctl, _("Domain %s state saved by libvirt\n"), name);
1506 } else {
1507 vshError(ctl, _("Failed to save domain %s state"), name);
1508 ret = FALSE;
1511 virDomainFree(dom);
1512 return ret;
1516 * "managedsave-remove" command
1518 static const vshCmdInfo info_managedsaveremove[] = {
1519 {"help", N_("Remove managed save of a domain")},
1520 {"desc", N_("Remove an existing managed save state file from a domain")},
1521 {NULL, NULL}
1524 static const vshCmdOptDef opts_managedsaveremove[] = {
1525 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1526 {NULL, 0, 0, NULL}
1529 static int
1530 cmdManagedSaveRemove(vshControl *ctl, const vshCmd *cmd)
1532 virDomainPtr dom;
1533 char *name;
1534 int ret = FALSE;
1535 int hassave;
1537 if (!vshConnectionUsability(ctl, ctl->conn))
1538 return FALSE;
1540 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1541 return FALSE;
1543 hassave = virDomainHasManagedSaveImage(dom, 0);
1544 if (hassave < 0) {
1545 vshError(ctl, "%s", _("Failed to check for domain managed save image"));
1546 goto cleanup;
1549 if (hassave) {
1550 if (virDomainManagedSaveRemove(dom, 0) < 0) {
1551 vshError(ctl, _("Failed to remove managed save image for domain %s"),
1552 name);
1553 goto cleanup;
1555 else
1556 vshPrint(ctl, _("Removed managedsave image for domain %s"), name);
1558 else
1559 vshPrint(ctl, _("Domain %s has no manage save image; removal skipped"),
1560 name);
1562 ret = TRUE;
1564 cleanup:
1565 virDomainFree(dom);
1566 return ret;
1570 * "schedinfo" command
1572 static const vshCmdInfo info_schedinfo[] = {
1573 {"help", N_("show/set scheduler parameters")},
1574 {"desc", N_("Show/Set scheduler parameters.")},
1575 {NULL, NULL}
1578 static const vshCmdOptDef opts_schedinfo[] = {
1579 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1580 {"set", VSH_OT_STRING, VSH_OFLAG_NONE, N_("parameter=value")},
1581 {"weight", VSH_OT_INT, VSH_OFLAG_NONE, N_("weight for XEN_CREDIT")},
1582 {"cap", VSH_OT_INT, VSH_OFLAG_NONE, N_("cap for XEN_CREDIT")},
1583 {NULL, 0, 0, NULL}
1586 static int
1587 cmdSchedInfoUpdate(vshControl *ctl, const vshCmd *cmd,
1588 virSchedParameterPtr param)
1590 int found;
1591 char *data;
1593 /* Legacy 'weight' parameter */
1594 if (STREQ(param->field, "weight") &&
1595 param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
1596 vshCommandOptBool(cmd, "weight")) {
1597 int val;
1598 val = vshCommandOptInt(cmd, "weight", &found);
1599 if (!found) {
1600 vshError(ctl, "%s", _("Invalid value of weight"));
1601 return -1;
1602 } else {
1603 param->value.ui = val;
1605 return 1;
1608 /* Legacy 'cap' parameter */
1609 if (STREQ(param->field, "cap") &&
1610 param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
1611 vshCommandOptBool(cmd, "cap")) {
1612 int val;
1613 val = vshCommandOptInt(cmd, "cap", &found);
1614 if (!found) {
1615 vshError(ctl, "%s", _("Invalid value of cap"));
1616 return -1;
1617 } else {
1618 param->value.ui = val;
1620 return 1;
1623 if ((data = vshCommandOptString(cmd, "set", NULL))) {
1624 char *val = strchr(data, '=');
1625 int match = 0;
1626 if (!val) {
1627 vshError(ctl, "%s", _("Invalid syntax for --set, expecting name=value"));
1628 return -1;
1630 *val = '\0';
1631 match = STREQ(data, param->field);
1632 *val = '=';
1633 val++;
1635 if (!match)
1636 return 0;
1638 switch (param->type) {
1639 case VIR_DOMAIN_SCHED_FIELD_INT:
1640 if (virStrToLong_i(val, NULL, 10, &param->value.i) < 0) {
1641 vshError(ctl, "%s",
1642 _("Invalid value for parameter, expecting an int"));
1643 return -1;
1645 break;
1646 case VIR_DOMAIN_SCHED_FIELD_UINT:
1647 if (virStrToLong_ui(val, NULL, 10, &param->value.ui) < 0) {
1648 vshError(ctl, "%s",
1649 _("Invalid value for parameter, expecting an unsigned int"));
1650 return -1;
1652 break;
1653 case VIR_DOMAIN_SCHED_FIELD_LLONG:
1654 if (virStrToLong_ll(val, NULL, 10, &param->value.l) < 0) {
1655 vshError(ctl, "%s",
1656 _("Invalid value for parameter, expecting a long long"));
1657 return -1;
1659 break;
1660 case VIR_DOMAIN_SCHED_FIELD_ULLONG:
1661 if (virStrToLong_ull(val, NULL, 10, &param->value.ul) < 0) {
1662 vshError(ctl, "%s",
1663 _("Invalid value for parameter, expecting an unsigned long long"));
1664 return -1;
1666 break;
1667 case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
1668 if (virStrToDouble(val, NULL, &param->value.d) < 0) {
1669 vshError(ctl, "%s", _("Invalid value for parameter, expecting a double"));
1670 return -1;
1672 break;
1673 case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
1674 param->value.b = STREQ(val, "0") ? 0 : 1;
1676 return 1;
1679 return 0;
1683 static int
1684 cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
1686 char *schedulertype;
1687 virDomainPtr dom;
1688 virSchedParameterPtr params = NULL;
1689 int nparams = 0;
1690 int update = 0;
1691 int i, ret;
1692 int ret_val = FALSE;
1694 if (!vshConnectionUsability(ctl, ctl->conn))
1695 return FALSE;
1697 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
1698 return FALSE;
1700 /* Print SchedulerType */
1701 schedulertype = virDomainGetSchedulerType(dom, &nparams);
1702 if (schedulertype!= NULL){
1703 vshPrint(ctl, "%-15s: %s\n", _("Scheduler"),
1704 schedulertype);
1705 VIR_FREE(schedulertype);
1706 } else {
1707 vshPrint(ctl, "%-15s: %s\n", _("Scheduler"), _("Unknown"));
1708 goto cleanup;
1711 if (nparams) {
1712 params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams);
1714 memset(params, 0, sizeof(virSchedParameter)* nparams);
1715 ret = virDomainGetSchedulerParameters(dom, params, &nparams);
1716 if (ret == -1)
1717 goto cleanup;
1719 /* See if any params are being set */
1720 for (i = 0; i < nparams; i++){
1721 ret = cmdSchedInfoUpdate(ctl, cmd, &(params[i]));
1722 if (ret == -1)
1723 goto cleanup;
1725 if (ret == 1)
1726 update = 1;
1729 /* Update parameters & refresh data */
1730 if (update) {
1731 ret = virDomainSetSchedulerParameters(dom, params, nparams);
1732 if (ret == -1)
1733 goto cleanup;
1735 ret = virDomainGetSchedulerParameters(dom, params, &nparams);
1736 if (ret == -1)
1737 goto cleanup;
1738 } else {
1739 /* See if we've tried to --set var=val. If so, the fact that
1740 we reach this point (with update == 0) means that "var" did
1741 not match any of the settable parameters. Report the error. */
1742 char *var_value_pair = vshCommandOptString(cmd, "set", NULL);
1743 if (var_value_pair) {
1744 vshError(ctl, _("invalid scheduler option: %s"),
1745 var_value_pair);
1746 goto cleanup;
1750 ret_val = TRUE;
1751 for (i = 0; i < nparams; i++){
1752 switch (params[i].type) {
1753 case VIR_DOMAIN_SCHED_FIELD_INT:
1754 vshPrint(ctl, "%-15s: %d\n", params[i].field, params[i].value.i);
1755 break;
1756 case VIR_DOMAIN_SCHED_FIELD_UINT:
1757 vshPrint(ctl, "%-15s: %u\n", params[i].field, params[i].value.ui);
1758 break;
1759 case VIR_DOMAIN_SCHED_FIELD_LLONG:
1760 vshPrint(ctl, "%-15s: %lld\n", params[i].field, params[i].value.l);
1761 break;
1762 case VIR_DOMAIN_SCHED_FIELD_ULLONG:
1763 vshPrint(ctl, "%-15s: %llu\n", params[i].field, params[i].value.ul);
1764 break;
1765 case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
1766 vshPrint(ctl, "%-15s: %f\n", params[i].field, params[i].value.d);
1767 break;
1768 case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
1769 vshPrint(ctl, "%-15s: %d\n", params[i].field, params[i].value.b);
1770 break;
1771 default:
1772 vshPrint(ctl, "not implemented scheduler parameter type\n");
1777 cleanup:
1778 VIR_FREE(params);
1779 virDomainFree(dom);
1780 return ret_val;
1784 * "restore" command
1786 static const vshCmdInfo info_restore[] = {
1787 {"help", N_("restore a domain from a saved state in a file")},
1788 {"desc", N_("Restore a domain.")},
1789 {NULL, NULL}
1792 static const vshCmdOptDef opts_restore[] = {
1793 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("the state to restore")},
1794 {NULL, 0, 0, NULL}
1797 static int
1798 cmdRestore(vshControl *ctl, const vshCmd *cmd)
1800 char *from;
1801 int found;
1802 int ret = TRUE;
1804 if (!vshConnectionUsability(ctl, ctl->conn))
1805 return FALSE;
1807 from = vshCommandOptString(cmd, "file", &found);
1808 if (!found)
1809 return FALSE;
1811 if (virDomainRestore(ctl->conn, from) == 0) {
1812 vshPrint(ctl, _("Domain restored from %s\n"), from);
1813 } else {
1814 vshError(ctl, _("Failed to restore domain from %s"), from);
1815 ret = FALSE;
1817 return ret;
1821 * "dump" command
1823 static const vshCmdInfo info_dump[] = {
1824 {"help", N_("dump the core of a domain to a file for analysis")},
1825 {"desc", N_("Core dump a domain.")},
1826 {NULL, NULL}
1829 static const vshCmdOptDef opts_dump[] = {
1830 {"live", VSH_OT_BOOL, 0, N_("perform a live core dump if supported")},
1831 {"crash", VSH_OT_BOOL, 0, N_("crash the domain after core dump")},
1832 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1833 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to dump the core")},
1834 {NULL, 0, 0, NULL}
1837 static int
1838 cmdDump(vshControl *ctl, const vshCmd *cmd)
1840 virDomainPtr dom;
1841 char *name;
1842 char *to;
1843 int ret = TRUE;
1844 int flags = 0;
1846 if (!vshConnectionUsability(ctl, ctl->conn))
1847 return FALSE;
1849 if (!(to = vshCommandOptString(cmd, "file", NULL)))
1850 return FALSE;
1852 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1853 return FALSE;
1855 if (vshCommandOptBool (cmd, "live"))
1856 flags |= VIR_DUMP_LIVE;
1857 if (vshCommandOptBool (cmd, "crash"))
1858 flags |= VIR_DUMP_CRASH;
1860 if (virDomainCoreDump(dom, to, flags) == 0) {
1861 vshPrint(ctl, _("Domain %s dumped to %s\n"), name, to);
1862 } else {
1863 vshError(ctl, _("Failed to core dump domain %s to %s"), name, to);
1864 ret = FALSE;
1867 virDomainFree(dom);
1868 return ret;
1872 * "resume" command
1874 static const vshCmdInfo info_resume[] = {
1875 {"help", N_("resume a domain")},
1876 {"desc", N_("Resume a previously suspended domain.")},
1877 {NULL, NULL}
1880 static const vshCmdOptDef opts_resume[] = {
1881 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1882 {NULL, 0, 0, NULL}
1885 static int
1886 cmdResume(vshControl *ctl, const vshCmd *cmd)
1888 virDomainPtr dom;
1889 int ret = TRUE;
1890 char *name;
1892 if (!vshConnectionUsability(ctl, ctl->conn))
1893 return FALSE;
1895 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1896 return FALSE;
1898 if (virDomainResume(dom) == 0) {
1899 vshPrint(ctl, _("Domain %s resumed\n"), name);
1900 } else {
1901 vshError(ctl, _("Failed to resume domain %s"), name);
1902 ret = FALSE;
1905 virDomainFree(dom);
1906 return ret;
1910 * "shutdown" command
1912 static const vshCmdInfo info_shutdown[] = {
1913 {"help", N_("gracefully shutdown a domain")},
1914 {"desc", N_("Run shutdown in the target domain.")},
1915 {NULL, NULL}
1918 static const vshCmdOptDef opts_shutdown[] = {
1919 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1920 {NULL, 0, 0, NULL}
1923 static int
1924 cmdShutdown(vshControl *ctl, const vshCmd *cmd)
1926 virDomainPtr dom;
1927 int ret = TRUE;
1928 char *name;
1930 if (!vshConnectionUsability(ctl, ctl->conn))
1931 return FALSE;
1933 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1934 return FALSE;
1936 if (virDomainShutdown(dom) == 0) {
1937 vshPrint(ctl, _("Domain %s is being shutdown\n"), name);
1938 } else {
1939 vshError(ctl, _("Failed to shutdown domain %s"), name);
1940 ret = FALSE;
1943 virDomainFree(dom);
1944 return ret;
1948 * "reboot" command
1950 static const vshCmdInfo info_reboot[] = {
1951 {"help", N_("reboot a domain")},
1952 {"desc", N_("Run a reboot command in the target domain.")},
1953 {NULL, NULL}
1956 static const vshCmdOptDef opts_reboot[] = {
1957 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1958 {NULL, 0, 0, NULL}
1961 static int
1962 cmdReboot(vshControl *ctl, const vshCmd *cmd)
1964 virDomainPtr dom;
1965 int ret = TRUE;
1966 char *name;
1968 if (!vshConnectionUsability(ctl, ctl->conn))
1969 return FALSE;
1971 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1972 return FALSE;
1974 if (virDomainReboot(dom, 0) == 0) {
1975 vshPrint(ctl, _("Domain %s is being rebooted\n"), name);
1976 } else {
1977 vshError(ctl, _("Failed to reboot domain %s"), name);
1978 ret = FALSE;
1981 virDomainFree(dom);
1982 return ret;
1986 * "destroy" command
1988 static const vshCmdInfo info_destroy[] = {
1989 {"help", N_("destroy a domain")},
1990 {"desc", N_("Destroy a given domain.")},
1991 {NULL, NULL}
1994 static const vshCmdOptDef opts_destroy[] = {
1995 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1996 {NULL, 0, 0, NULL}
1999 static int
2000 cmdDestroy(vshControl *ctl, const vshCmd *cmd)
2002 virDomainPtr dom;
2003 int ret = TRUE;
2004 char *name;
2006 if (!vshConnectionUsability(ctl, ctl->conn))
2007 return FALSE;
2009 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
2010 return FALSE;
2012 if (virDomainDestroy(dom) == 0) {
2013 vshPrint(ctl, _("Domain %s destroyed\n"), name);
2014 } else {
2015 vshError(ctl, _("Failed to destroy domain %s"), name);
2016 ret = FALSE;
2019 virDomainFree(dom);
2020 return ret;
2024 * "dominfo" command
2026 static const vshCmdInfo info_dominfo[] = {
2027 {"help", N_("domain information")},
2028 {"desc", N_("Returns basic information about the domain.")},
2029 {NULL, NULL}
2032 static const vshCmdOptDef opts_dominfo[] = {
2033 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2034 {NULL, 0, 0, NULL}
2037 static int
2038 cmdDominfo(vshControl *ctl, const vshCmd *cmd)
2040 virDomainInfo info;
2041 virDomainPtr dom;
2042 virSecurityModel secmodel;
2043 virSecurityLabel seclabel;
2044 int persistent = 0;
2045 int ret = TRUE, autostart;
2046 unsigned int id;
2047 char *str, uuid[VIR_UUID_STRING_BUFLEN];
2049 if (!vshConnectionUsability(ctl, ctl->conn))
2050 return FALSE;
2052 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2053 return FALSE;
2055 id = virDomainGetID(dom);
2056 if (id == ((unsigned int)-1))
2057 vshPrint(ctl, "%-15s %s\n", _("Id:"), "-");
2058 else
2059 vshPrint(ctl, "%-15s %d\n", _("Id:"), id);
2060 vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom));
2062 if (virDomainGetUUIDString(dom, &uuid[0])==0)
2063 vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
2065 if ((str = virDomainGetOSType(dom))) {
2066 vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str);
2067 VIR_FREE(str);
2070 if (virDomainGetInfo(dom, &info) == 0) {
2071 vshPrint(ctl, "%-15s %s\n", _("State:"),
2072 _(vshDomainStateToString(info.state)));
2074 vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu);
2076 if (info.cpuTime != 0) {
2077 double cpuUsed = info.cpuTime;
2079 cpuUsed /= 1000000000.0;
2081 vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed);
2084 if (info.maxMem != UINT_MAX)
2085 vshPrint(ctl, "%-15s %lu kB\n", _("Max memory:"),
2086 info.maxMem);
2087 else
2088 vshPrint(ctl, "%-15s %s\n", _("Max memory:"),
2089 _("no limit"));
2091 vshPrint(ctl, "%-15s %lu kB\n", _("Used memory:"),
2092 info.memory);
2094 } else {
2095 ret = FALSE;
2098 /* Check and display whether the domain is persistent or not */
2099 persistent = virDomainIsPersistent(dom);
2100 vshDebug(ctl, 5, "Domain persistent flag value: %d\n", persistent);
2101 if (persistent < 0)
2102 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
2103 else
2104 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));
2106 /* Check and display whether the domain autostarts or not */
2107 if (!virDomainGetAutostart(dom, &autostart)) {
2108 vshPrint(ctl, "%-15s %s\n", _("Autostart:"),
2109 autostart ? _("enable") : _("disable") );
2112 /* Security model and label information */
2113 memset(&secmodel, 0, sizeof secmodel);
2114 if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) {
2115 if (last_error->code != VIR_ERR_NO_SUPPORT) {
2116 virDomainFree(dom);
2117 return FALSE;
2119 } else {
2120 /* Only print something if a security model is active */
2121 if (secmodel.model[0] != '\0') {
2122 vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model);
2123 vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi);
2125 /* Security labels are only valid for active domains */
2126 memset(&seclabel, 0, sizeof seclabel);
2127 if (virDomainGetSecurityLabel(dom, &seclabel) == -1) {
2128 virDomainFree(dom);
2129 return FALSE;
2130 } else {
2131 if (seclabel.label[0] != '\0')
2132 vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"),
2133 seclabel.label, seclabel.enforcing ? "enforcing" : "permissive");
2137 virDomainFree(dom);
2138 return ret;
2142 * "domjobinfo" command
2144 static const vshCmdInfo info_domjobinfo[] = {
2145 {"help", N_("domain job information")},
2146 {"desc", N_("Returns information about jobs running on a domain.")},
2147 {NULL, NULL}
2150 static const vshCmdOptDef opts_domjobinfo[] = {
2151 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2152 {NULL, 0, 0, NULL}
2156 static int
2157 cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd)
2159 virDomainJobInfo info;
2160 virDomainPtr dom;
2161 int ret = TRUE;
2163 if (!vshConnectionUsability(ctl, ctl->conn))
2164 return FALSE;
2166 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2167 return FALSE;
2169 if (virDomainGetJobInfo(dom, &info) == 0) {
2170 const char *unit;
2171 double val;
2173 vshPrint(ctl, "%-17s ", _("Job type:"));
2174 switch (info.type) {
2175 case VIR_DOMAIN_JOB_BOUNDED:
2176 vshPrint(ctl, "%-12s\n", _("Bounded"));
2177 break;
2179 case VIR_DOMAIN_JOB_UNBOUNDED:
2180 vshPrint(ctl, "%-12s\n", _("Unbounded"));
2181 break;
2183 case VIR_DOMAIN_JOB_NONE:
2184 default:
2185 vshPrint(ctl, "%-12s\n", _("None"));
2186 goto cleanup;
2189 vshPrint(ctl, "%-17s %-12llu ms\n", _("Time elapsed:"), info.timeElapsed);
2190 if (info.type == VIR_DOMAIN_JOB_BOUNDED)
2191 vshPrint(ctl, "%-17s %-12llu ms\n", _("Time remaining:"), info.timeRemaining);
2192 if (info.dataTotal || info.dataRemaining || info.dataProcessed) {
2193 val = prettyCapacity(info.dataProcessed, &unit);
2194 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data processed:"), val, unit);
2195 val = prettyCapacity(info.dataRemaining, &unit);
2196 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data remaining:"), val, unit);
2197 val = prettyCapacity(info.dataTotal, &unit);
2198 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data total:"), val, unit);
2200 if (info.memTotal || info.memRemaining || info.memProcessed) {
2201 val = prettyCapacity(info.memProcessed, &unit);
2202 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory processed:"), val, unit);
2203 val = prettyCapacity(info.memRemaining, &unit);
2204 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory remaining:"), val, unit);
2205 val = prettyCapacity(info.memTotal, &unit);
2206 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory total:"), val, unit);
2208 if (info.fileTotal || info.fileRemaining || info.fileProcessed) {
2209 val = prettyCapacity(info.fileProcessed, &unit);
2210 vshPrint(ctl, "%-17s %-.3lf %s\n", _("File processed:"), val, unit);
2211 val = prettyCapacity(info.fileRemaining, &unit);
2212 vshPrint(ctl, "%-17s %-.3lf %s\n", _("File remaining:"), val, unit);
2213 val = prettyCapacity(info.fileTotal, &unit);
2214 vshPrint(ctl, "%-17s %-.3lf %s\n", _("File total:"), val, unit);
2216 } else {
2217 ret = FALSE;
2219 cleanup:
2220 virDomainFree(dom);
2221 return ret;
2225 * "domjobabort" command
2227 static const vshCmdInfo info_domjobabort[] = {
2228 {"help", N_("abort active domain job")},
2229 {"desc", N_("Aborts the currently running domain job")},
2230 {NULL, NULL}
2233 static const vshCmdOptDef opts_domjobabort[] = {
2234 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2235 {NULL, 0, 0, NULL}
2238 static int
2239 cmdDomjobabort(vshControl *ctl, const vshCmd *cmd)
2241 virDomainPtr dom;
2242 int ret = TRUE;
2244 if (!vshConnectionUsability(ctl, ctl->conn))
2245 return FALSE;
2247 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2248 return FALSE;
2250 if (virDomainAbortJob(dom) < 0)
2251 ret = FALSE;
2253 virDomainFree(dom);
2254 return ret;
2258 * "freecell" command
2260 static const vshCmdInfo info_freecell[] = {
2261 {"help", N_("NUMA free memory")},
2262 {"desc", N_("display available free memory for the NUMA cell.")},
2263 {NULL, NULL}
2266 static const vshCmdOptDef opts_freecell[] = {
2267 {"cellno", VSH_OT_INT, 0, N_("NUMA cell number")},
2268 {NULL, 0, 0, NULL}
2271 static int
2272 cmdFreecell(vshControl *ctl, const vshCmd *cmd)
2274 int ret;
2275 int cell, cell_given;
2276 unsigned long long memory;
2278 if (!vshConnectionUsability(ctl, ctl->conn))
2279 return FALSE;
2281 cell = vshCommandOptInt(cmd, "cellno", &cell_given);
2282 if (!cell_given) {
2283 memory = virNodeGetFreeMemory(ctl->conn);
2284 if (memory == 0)
2285 return FALSE;
2286 } else {
2287 ret = virNodeGetCellsFreeMemory(ctl->conn, &memory, cell, 1);
2288 if (ret != 1)
2289 return FALSE;
2292 if (cell == -1)
2293 vshPrint(ctl, "%s: %llu kB\n", _("Total"), (memory/1024));
2294 else
2295 vshPrint(ctl, "%d: %llu kB\n", cell, (memory/1024));
2297 return TRUE;
2301 * "maxvcpus" command
2303 static const vshCmdInfo info_maxvcpus[] = {
2304 {"help", N_("connection vcpu maximum")},
2305 {"desc", N_("Show maximum number of virtual CPUs for guests on this connection.")},
2306 {NULL, NULL}
2309 static const vshCmdOptDef opts_maxvcpus[] = {
2310 {"type", VSH_OT_STRING, 0, N_("domain type")},
2311 {NULL, 0, 0, NULL}
2314 static int
2315 cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd)
2317 char *type;
2318 int vcpus;
2320 type = vshCommandOptString(cmd, "type", NULL);
2322 if (!vshConnectionUsability(ctl, ctl->conn))
2323 return FALSE;
2325 vcpus = virConnectGetMaxVcpus(ctl->conn, type);
2326 if (vcpus < 0)
2327 return FALSE;
2328 vshPrint(ctl, "%d\n", vcpus);
2330 return TRUE;
2334 * "vcpucount" command
2336 static const vshCmdInfo info_vcpucount[] = {
2337 {"help", N_("domain vcpu counts")},
2338 {"desc", N_("Returns the number of virtual CPUs used by the domain.")},
2339 {NULL, NULL}
2342 static const vshCmdOptDef opts_vcpucount[] = {
2343 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2344 {"maximum", VSH_OT_BOOL, 0, N_("get maximum cap on vcpus")},
2345 {"current", VSH_OT_BOOL, 0, N_("get current vcpu usage")},
2346 {"config", VSH_OT_BOOL, 0, N_("get value to be used on next boot")},
2347 {"live", VSH_OT_BOOL, 0, N_("get value from running domain")},
2348 {NULL, 0, 0, NULL}
2351 static int
2352 cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
2354 virDomainPtr dom;
2355 int ret = TRUE;
2356 int maximum = vshCommandOptBool(cmd, "maximum");
2357 int current = vshCommandOptBool(cmd, "current");
2358 int config = vshCommandOptBool(cmd, "config");
2359 int live = vshCommandOptBool(cmd, "live");
2360 bool all = maximum + current + config + live == 0;
2361 int count;
2363 if (maximum && current) {
2364 vshError(ctl, "%s",
2365 _("--maximum and --current cannot both be specified"));
2366 return FALSE;
2368 if (config && live) {
2369 vshError(ctl, "%s",
2370 _("--config and --live cannot both be specified"));
2371 return FALSE;
2373 /* We want one of each pair of mutually exclusive options; that
2374 * is, use of flags requires exactly two options. */
2375 if (maximum + current + config + live == 1) {
2376 vshError(ctl,
2377 _("when using --%s, either --%s or --%s must be specified"),
2378 (maximum ? "maximum" : current ? "current"
2379 : config ? "config" : "live"),
2380 maximum + current ? "config" : "maximum",
2381 maximum + current ? "live" : "current");
2382 return FALSE;
2385 if (!vshConnectionUsability(ctl, ctl->conn))
2386 return FALSE;
2388 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2389 return FALSE;
2391 /* In all cases, try the new API first; if it fails because we are
2392 * talking to an older client, try a fallback API before giving
2393 * up. */
2394 if (all || (maximum && config)) {
2395 count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
2396 VIR_DOMAIN_VCPU_CONFIG));
2397 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2398 || last_error->code == VIR_ERR_INVALID_ARG)) {
2399 char *tmp;
2400 char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
2401 if (xml && (tmp = strstr(xml, "<vcpu"))) {
2402 tmp = strchr(tmp, '>');
2403 if (!tmp || virStrToLong_i(tmp + 1, &tmp, 10, &count) < 0)
2404 count = -1;
2406 VIR_FREE(xml);
2409 if (count < 0) {
2410 virshReportError(ctl);
2411 ret = FALSE;
2412 } else if (all) {
2413 vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("config"),
2414 count);
2415 } else {
2416 vshPrint(ctl, "%d\n", count);
2418 virFreeError(last_error);
2419 last_error = NULL;
2422 if (all || (maximum && live)) {
2423 count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
2424 VIR_DOMAIN_VCPU_LIVE));
2425 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2426 || last_error->code == VIR_ERR_INVALID_ARG)) {
2427 count = virDomainGetMaxVcpus(dom);
2430 if (count < 0) {
2431 virshReportError(ctl);
2432 ret = FALSE;
2433 } else if (all) {
2434 vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("live"),
2435 count);
2436 } else {
2437 vshPrint(ctl, "%d\n", count);
2439 virFreeError(last_error);
2440 last_error = NULL;
2443 if (all || (current && config)) {
2444 count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_CONFIG);
2445 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2446 || last_error->code == VIR_ERR_INVALID_ARG)) {
2447 char *tmp, *end;
2448 char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
2449 if (xml && (tmp = strstr(xml, "<vcpu"))) {
2450 end = strchr(tmp, '>');
2451 if (end) {
2452 *end = '\0';
2453 tmp = strstr(tmp, "current=");
2454 if (!tmp)
2455 tmp = end + 1;
2456 else {
2457 tmp += strlen("current=");
2458 tmp += *tmp == '\'' || *tmp == '"';
2461 if (!tmp || virStrToLong_i(tmp, &tmp, 10, &count) < 0)
2462 count = -1;
2464 VIR_FREE(xml);
2467 if (count < 0) {
2468 virshReportError(ctl);
2469 ret = FALSE;
2470 } else if (all) {
2471 vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("config"),
2472 count);
2473 } else {
2474 vshPrint(ctl, "%d\n", count);
2476 virFreeError(last_error);
2477 last_error = NULL;
2480 if (all || (current && live)) {
2481 count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_LIVE);
2482 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2483 || last_error->code == VIR_ERR_INVALID_ARG)) {
2484 virDomainInfo info;
2485 if (virDomainGetInfo(dom, &info) == 0)
2486 count = info.nrVirtCpu;
2489 if (count < 0) {
2490 virshReportError(ctl);
2491 ret = FALSE;
2492 } else if (all) {
2493 vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("live"),
2494 count);
2495 } else {
2496 vshPrint(ctl, "%d\n", count);
2498 virFreeError(last_error);
2499 last_error = NULL;
2502 virDomainFree(dom);
2503 return ret;
2507 * "vcpuinfo" command
2509 static const vshCmdInfo info_vcpuinfo[] = {
2510 {"help", N_("detailed domain vcpu information")},
2511 {"desc", N_("Returns basic information about the domain virtual CPUs.")},
2512 {NULL, NULL}
2515 static const vshCmdOptDef opts_vcpuinfo[] = {
2516 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2517 {NULL, 0, 0, NULL}
2520 static int
2521 cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
2523 virDomainInfo info;
2524 virDomainPtr dom;
2525 virNodeInfo nodeinfo;
2526 virVcpuInfoPtr cpuinfo;
2527 unsigned char *cpumap;
2528 int ncpus;
2529 size_t cpumaplen;
2530 int ret = TRUE;
2532 if (!vshConnectionUsability(ctl, ctl->conn))
2533 return FALSE;
2535 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2536 return FALSE;
2538 if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
2539 virDomainFree(dom);
2540 return FALSE;
2543 if (virDomainGetInfo(dom, &info) != 0) {
2544 virDomainFree(dom);
2545 return FALSE;
2548 cpuinfo = vshMalloc(ctl, sizeof(virVcpuInfo)*info.nrVirtCpu);
2549 cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2550 cpumap = vshMalloc(ctl, info.nrVirtCpu * cpumaplen);
2552 if ((ncpus = virDomainGetVcpus(dom,
2553 cpuinfo, info.nrVirtCpu,
2554 cpumap, cpumaplen)) >= 0) {
2555 int n;
2556 for (n = 0 ; n < ncpus ; n++) {
2557 unsigned int m;
2558 vshPrint(ctl, "%-15s %d\n", _("VCPU:"), n);
2559 vshPrint(ctl, "%-15s %d\n", _("CPU:"), cpuinfo[n].cpu);
2560 vshPrint(ctl, "%-15s %s\n", _("State:"),
2561 _(vshDomainVcpuStateToString(cpuinfo[n].state)));
2562 if (cpuinfo[n].cpuTime != 0) {
2563 double cpuUsed = cpuinfo[n].cpuTime;
2565 cpuUsed /= 1000000000.0;
2567 vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed);
2569 vshPrint(ctl, "%-15s ", _("CPU Affinity:"));
2570 for (m = 0 ; m < VIR_NODEINFO_MAXCPUS(nodeinfo) ; m++) {
2571 vshPrint(ctl, "%c", VIR_CPU_USABLE(cpumap, cpumaplen, n, m) ? 'y' : '-');
2573 vshPrint(ctl, "\n");
2574 if (n < (ncpus - 1)) {
2575 vshPrint(ctl, "\n");
2578 } else {
2579 if (info.state == VIR_DOMAIN_SHUTOFF) {
2580 vshError(ctl, "%s",
2581 _("Domain shut off, virtual CPUs not present."));
2583 ret = FALSE;
2586 VIR_FREE(cpumap);
2587 VIR_FREE(cpuinfo);
2588 virDomainFree(dom);
2589 return ret;
2593 * "vcpupin" command
2595 static const vshCmdInfo info_vcpupin[] = {
2596 {"help", N_("control domain vcpu affinity")},
2597 {"desc", N_("Pin domain VCPUs to host physical CPUs.")},
2598 {NULL, NULL}
2601 static const vshCmdOptDef opts_vcpupin[] = {
2602 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2603 {"vcpu", VSH_OT_INT, VSH_OFLAG_REQ, N_("vcpu number")},
2604 {"cpulist", VSH_OT_DATA, VSH_OFLAG_REQ, N_("host cpu number(s) (comma separated)")},
2605 {NULL, 0, 0, NULL}
2608 static int
2609 cmdVcpupin(vshControl *ctl, const vshCmd *cmd)
2611 virDomainInfo info;
2612 virDomainPtr dom;
2613 virNodeInfo nodeinfo;
2614 int vcpu;
2615 char *cpulist;
2616 int ret = TRUE;
2617 int vcpufound = 0;
2618 unsigned char *cpumap;
2619 int cpumaplen;
2620 int i;
2621 enum { expect_num, expect_num_or_comma } state;
2623 if (!vshConnectionUsability(ctl, ctl->conn))
2624 return FALSE;
2626 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2627 return FALSE;
2629 vcpu = vshCommandOptInt(cmd, "vcpu", &vcpufound);
2630 if (!vcpufound) {
2631 vshError(ctl, "%s", _("vcpupin: Invalid or missing vCPU number."));
2632 virDomainFree(dom);
2633 return FALSE;
2636 if (!(cpulist = vshCommandOptString(cmd, "cpulist", NULL))) {
2637 virDomainFree(dom);
2638 return FALSE;
2641 if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
2642 virDomainFree(dom);
2643 return FALSE;
2646 if (virDomainGetInfo(dom, &info) != 0) {
2647 vshError(ctl, "%s", _("vcpupin: failed to get domain informations."));
2648 virDomainFree(dom);
2649 return FALSE;
2652 if (vcpu >= info.nrVirtCpu) {
2653 vshError(ctl, "%s", _("vcpupin: Invalid vCPU number."));
2654 virDomainFree(dom);
2655 return FALSE;
2658 /* Check that the cpulist parameter is a comma-separated list of
2659 * numbers and give an intelligent error message if not.
2661 if (cpulist[0] == '\0') {
2662 vshError(ctl, "%s", _("cpulist: Invalid format. Empty string."));
2663 virDomainFree (dom);
2664 return FALSE;
2667 state = expect_num;
2668 for (i = 0; cpulist[i]; i++) {
2669 switch (state) {
2670 case expect_num:
2671 if (!c_isdigit (cpulist[i])) {
2672 vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
2673 "digit at position %d (near '%c')."),
2674 cpulist, i, cpulist[i]);
2675 virDomainFree (dom);
2676 return FALSE;
2678 state = expect_num_or_comma;
2679 break;
2680 case expect_num_or_comma:
2681 if (cpulist[i] == ',')
2682 state = expect_num;
2683 else if (!c_isdigit (cpulist[i])) {
2684 vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
2685 "digit or comma at position %d (near '%c')."),
2686 cpulist, i, cpulist[i]);
2687 virDomainFree (dom);
2688 return FALSE;
2692 if (state == expect_num) {
2693 vshError(ctl, _("cpulist: %s: Invalid format. Trailing comma "
2694 "at position %d."),
2695 cpulist, i);
2696 virDomainFree (dom);
2697 return FALSE;
2700 cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2701 cpumap = vshCalloc(ctl, 1, cpumaplen);
2703 do {
2704 unsigned int cpu = atoi(cpulist);
2706 if (cpu < VIR_NODEINFO_MAXCPUS(nodeinfo)) {
2707 VIR_USE_CPU(cpumap, cpu);
2708 } else {
2709 vshError(ctl, _("Physical CPU %d doesn't exist."), cpu);
2710 VIR_FREE(cpumap);
2711 virDomainFree(dom);
2712 return FALSE;
2714 cpulist = strchr(cpulist, ',');
2715 if (cpulist)
2716 cpulist++;
2717 } while (cpulist);
2719 if (virDomainPinVcpu(dom, vcpu, cpumap, cpumaplen) != 0) {
2720 ret = FALSE;
2723 VIR_FREE(cpumap);
2724 virDomainFree(dom);
2725 return ret;
2729 * "setvcpus" command
2731 static const vshCmdInfo info_setvcpus[] = {
2732 {"help", N_("change number of virtual CPUs")},
2733 {"desc", N_("Change the number of virtual CPUs in the guest domain.")},
2734 {NULL, NULL}
2737 static const vshCmdOptDef opts_setvcpus[] = {
2738 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2739 {"count", VSH_OT_INT, VSH_OFLAG_REQ, N_("number of virtual CPUs")},
2740 {"maximum", VSH_OT_BOOL, 0, N_("set maximum limit on next boot")},
2741 {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
2742 {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
2743 {NULL, 0, 0, NULL}
2746 static int
2747 cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
2749 virDomainPtr dom;
2750 int count;
2751 int ret = TRUE;
2752 int maximum = vshCommandOptBool(cmd, "maximum");
2753 int config = vshCommandOptBool(cmd, "config");
2754 int live = vshCommandOptBool(cmd, "live");
2755 int flags = ((maximum ? VIR_DOMAIN_VCPU_MAXIMUM : 0) |
2756 (config ? VIR_DOMAIN_VCPU_CONFIG : 0) |
2757 (live ? VIR_DOMAIN_VCPU_LIVE : 0));
2759 if (!vshConnectionUsability(ctl, ctl->conn))
2760 return FALSE;
2762 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2763 return FALSE;
2765 count = vshCommandOptInt(cmd, "count", &count);
2767 if (!flags) {
2768 if (virDomainSetVcpus(dom, count) != 0) {
2769 ret = FALSE;
2771 } else {
2772 if (virDomainSetVcpusFlags(dom, count, flags) < 0) {
2773 ret = FALSE;
2777 virDomainFree(dom);
2778 return ret;
2782 * "setmemory" command
2784 static const vshCmdInfo info_setmem[] = {
2785 {"help", N_("change memory allocation")},
2786 {"desc", N_("Change the current memory allocation in the guest domain.")},
2787 {NULL, NULL}
2790 static const vshCmdOptDef opts_setmem[] = {
2791 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2792 {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("number of kilobytes of memory")},
2793 {NULL, 0, 0, NULL}
2796 static int
2797 cmdSetmem(vshControl *ctl, const vshCmd *cmd)
2799 virDomainPtr dom;
2800 virDomainInfo info;
2801 unsigned long kilobytes;
2802 int ret = TRUE;
2804 if (!vshConnectionUsability(ctl, ctl->conn))
2805 return FALSE;
2807 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2808 return FALSE;
2810 kilobytes = vshCommandOptUL(cmd, "kilobytes", NULL);
2811 if (kilobytes <= 0) {
2812 virDomainFree(dom);
2813 vshError(ctl, _("Invalid value of %lu for memory size"), kilobytes);
2814 return FALSE;
2817 if (virDomainGetInfo(dom, &info) != 0) {
2818 virDomainFree(dom);
2819 vshError(ctl, "%s", _("Unable to verify MaxMemorySize"));
2820 return FALSE;
2823 if (kilobytes > info.maxMem) {
2824 virDomainFree(dom);
2825 vshError(ctl, _("Requested memory size %lu kb is larger than maximum of %lu kb"),
2826 kilobytes, info.maxMem);
2827 return FALSE;
2830 if (virDomainSetMemory(dom, kilobytes) != 0) {
2831 ret = FALSE;
2834 virDomainFree(dom);
2835 return ret;
2839 * "setmaxmem" command
2841 static const vshCmdInfo info_setmaxmem[] = {
2842 {"help", N_("change maximum memory limit")},
2843 {"desc", N_("Change the maximum memory allocation limit in the guest domain.")},
2844 {NULL, NULL}
2847 static const vshCmdOptDef opts_setmaxmem[] = {
2848 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2849 {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("maximum memory limit in kilobytes")},
2850 {NULL, 0, 0, NULL}
2853 static int
2854 cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
2856 virDomainPtr dom;
2857 virDomainInfo info;
2858 int kilobytes;
2859 int ret = TRUE;
2861 if (!vshConnectionUsability(ctl, ctl->conn))
2862 return FALSE;
2864 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2865 return FALSE;
2867 kilobytes = vshCommandOptInt(cmd, "kilobytes", &kilobytes);
2868 if (kilobytes <= 0) {
2869 virDomainFree(dom);
2870 vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
2871 return FALSE;
2874 if (virDomainGetInfo(dom, &info) != 0) {
2875 virDomainFree(dom);
2876 vshError(ctl, "%s", _("Unable to verify current MemorySize"));
2877 return FALSE;
2880 if (virDomainSetMaxMemory(dom, kilobytes) != 0) {
2881 vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
2882 virDomainFree(dom);
2883 return FALSE;
2886 if (kilobytes < info.memory) {
2887 if (virDomainSetMemory(dom, kilobytes) != 0) {
2888 vshError(ctl, "%s", _("Unable to shrink current MemorySize"));
2889 ret = FALSE;
2893 virDomainFree(dom);
2894 return ret;
2898 * "memtune" command
2900 static const vshCmdInfo info_memtune[] = {
2901 {"help", N_("Get/Set memory paramters")},
2902 {"desc", N_("Get/Set the current memory paramters for the guest domain.\n" \
2903 " To get the memory parameters use following command: \n\n" \
2904 " virsh # memtune <domain>")},
2905 {NULL, NULL}
2908 static const vshCmdOptDef opts_memtune[] = {
2909 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2910 {"hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
2911 N_("Max memory in kilobytes")},
2912 {"soft-limit", VSH_OT_INT, VSH_OFLAG_NONE,
2913 N_("Memory during contention in kilobytes")},
2914 {"swap-hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
2915 N_("Max swap in kilobytes")},
2916 {"min-guarantee", VSH_OT_INT, VSH_OFLAG_NONE,
2917 N_("Min guaranteed memory in kilobytes")},
2918 {NULL, 0, 0, NULL}
2921 static int
2922 cmdMemtune(vshControl * ctl, const vshCmd * cmd)
2924 virDomainPtr dom;
2925 long long hard_limit, soft_limit, swap_hard_limit, min_guarantee;
2926 int nparams = 0;
2927 unsigned int i = 0;
2928 virMemoryParameterPtr params = NULL, temp = NULL;
2929 int ret = FALSE;
2931 if (!vshConnectionUsability(ctl, ctl->conn))
2932 return FALSE;
2934 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2935 return FALSE;
2937 hard_limit =
2938 vshCommandOptLongLong(cmd, "hard-limit", NULL);
2939 if (hard_limit)
2940 nparams++;
2942 soft_limit =
2943 vshCommandOptLongLong(cmd, "soft-limit", NULL);
2944 if (soft_limit)
2945 nparams++;
2947 swap_hard_limit =
2948 vshCommandOptLongLong(cmd, "swap-hard-limit", NULL);
2949 if (swap_hard_limit)
2950 nparams++;
2952 min_guarantee =
2953 vshCommandOptLongLong(cmd, "min-guarantee", NULL);
2954 if (min_guarantee)
2955 nparams++;
2957 if (nparams == 0) {
2958 /* get the number of memory parameters */
2959 if (virDomainGetMemoryParameters(dom, NULL, &nparams, 0) != 0) {
2960 vshError(ctl, "%s",
2961 _("Unable to get number of memory parameters"));
2962 goto cleanup;
2965 if (nparams == 0) {
2966 /* nothing to output */
2967 ret = TRUE;
2968 goto cleanup;
2971 /* now go get all the memory parameters */
2972 params = vshCalloc(ctl, nparams, sizeof(*params));
2973 if (virDomainGetMemoryParameters(dom, params, &nparams, 0) != 0) {
2974 vshError(ctl, "%s", _("Unable to get memory parameters"));
2975 goto cleanup;
2978 for (i = 0; i < nparams; i++) {
2979 switch (params[i].type) {
2980 case VIR_DOMAIN_MEMORY_PARAM_INT:
2981 vshPrint(ctl, "%-15s: %d\n", params[i].field,
2982 params[i].value.i);
2983 break;
2984 case VIR_DOMAIN_MEMORY_PARAM_UINT:
2985 vshPrint(ctl, "%-15s: %u\n", params[i].field,
2986 params[i].value.ui);
2987 break;
2988 case VIR_DOMAIN_MEMORY_PARAM_LLONG:
2989 vshPrint(ctl, "%-15s: %lld\n", params[i].field,
2990 params[i].value.l);
2991 break;
2992 case VIR_DOMAIN_MEMORY_PARAM_ULLONG:
2993 vshPrint(ctl, "%-15s: %llu\n", params[i].field,
2994 params[i].value.ul);
2995 break;
2996 case VIR_DOMAIN_MEMORY_PARAM_DOUBLE:
2997 vshPrint(ctl, "%-15s: %f\n", params[i].field,
2998 params[i].value.d);
2999 break;
3000 case VIR_DOMAIN_MEMORY_PARAM_BOOLEAN:
3001 vshPrint(ctl, "%-15s: %d\n", params[i].field,
3002 params[i].value.b);
3003 break;
3004 default:
3005 vshPrint(ctl, "unimplemented memory parameter type\n");
3009 ret = TRUE;
3010 } else {
3011 /* set the memory parameters */
3012 params = vshCalloc(ctl, nparams, sizeof(*params));
3014 for (i = 0; i < nparams; i++) {
3015 temp = &params[i];
3016 temp->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG;
3019 * Some magic here, this is used to fill the params structure with
3020 * the valid arguments passed, after filling the particular
3021 * argument we purposely make them 0, so on the next pass it goes
3022 * to the next valid argument and so on.
3024 if (soft_limit) {
3025 temp->value.ul = soft_limit;
3026 strncpy(temp->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
3027 sizeof(temp->field));
3028 soft_limit = 0;
3029 } else if (hard_limit) {
3030 temp->value.ul = hard_limit;
3031 strncpy(temp->field, VIR_DOMAIN_MEMORY_HARD_LIMIT,
3032 sizeof(temp->field));
3033 hard_limit = 0;
3034 } else if (swap_hard_limit) {
3035 temp->value.ul = swap_hard_limit;
3036 strncpy(temp->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
3037 sizeof(temp->field));
3038 swap_hard_limit = 0;
3039 } else if (min_guarantee) {
3040 temp->value.ul = min_guarantee;
3041 strncpy(temp->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
3042 sizeof(temp->field));
3043 min_guarantee = 0;
3046 if (virDomainSetMemoryParameters(dom, params, nparams, 0) != 0)
3047 vshError(ctl, "%s", _("Unable to change memory parameters"));
3048 else
3049 ret = TRUE;
3052 cleanup:
3053 VIR_FREE(params);
3054 virDomainFree(dom);
3055 return ret;
3059 * "nodeinfo" command
3061 static const vshCmdInfo info_nodeinfo[] = {
3062 {"help", N_("node information")},
3063 {"desc", N_("Returns basic information about the node.")},
3064 {NULL, NULL}
3067 static int
3068 cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3070 virNodeInfo info;
3072 if (!vshConnectionUsability(ctl, ctl->conn))
3073 return FALSE;
3075 if (virNodeGetInfo(ctl->conn, &info) < 0) {
3076 vshError(ctl, "%s", _("failed to get node information"));
3077 return FALSE;
3079 vshPrint(ctl, "%-20s %s\n", _("CPU model:"), info.model);
3080 vshPrint(ctl, "%-20s %d\n", _("CPU(s):"), info.cpus);
3081 vshPrint(ctl, "%-20s %d MHz\n", _("CPU frequency:"), info.mhz);
3082 vshPrint(ctl, "%-20s %d\n", _("CPU socket(s):"), info.sockets);
3083 vshPrint(ctl, "%-20s %d\n", _("Core(s) per socket:"), info.cores);
3084 vshPrint(ctl, "%-20s %d\n", _("Thread(s) per core:"), info.threads);
3085 vshPrint(ctl, "%-20s %d\n", _("NUMA cell(s):"), info.nodes);
3086 vshPrint(ctl, "%-20s %lu kB\n", _("Memory size:"), info.memory);
3088 return TRUE;
3092 * "capabilities" command
3094 static const vshCmdInfo info_capabilities[] = {
3095 {"help", N_("capabilities")},
3096 {"desc", N_("Returns capabilities of hypervisor/driver.")},
3097 {NULL, NULL}
3100 static int
3101 cmdCapabilities (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3103 char *caps;
3105 if (!vshConnectionUsability(ctl, ctl->conn))
3106 return FALSE;
3108 if ((caps = virConnectGetCapabilities (ctl->conn)) == NULL) {
3109 vshError(ctl, "%s", _("failed to get capabilities"));
3110 return FALSE;
3112 vshPrint (ctl, "%s\n", caps);
3113 VIR_FREE(caps);
3115 return TRUE;
3119 * "dumpxml" command
3121 static const vshCmdInfo info_dumpxml[] = {
3122 {"help", N_("domain information in XML")},
3123 {"desc", N_("Output the domain information as an XML dump to stdout.")},
3124 {NULL, NULL}
3127 static const vshCmdOptDef opts_dumpxml[] = {
3128 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3129 {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")},
3130 {"security-info", VSH_OT_BOOL, 0, N_("include security sensitive information in XML dump")},
3131 {"update-cpu", VSH_OT_BOOL, 0, N_("update guest CPU according to host CPU")},
3132 {NULL, 0, 0, NULL}
3135 static int
3136 cmdDumpXML(vshControl *ctl, const vshCmd *cmd)
3138 virDomainPtr dom;
3139 int ret = TRUE;
3140 char *dump;
3141 int flags = 0;
3142 int inactive = vshCommandOptBool(cmd, "inactive");
3143 int secure = vshCommandOptBool(cmd, "security-info");
3144 int update = vshCommandOptBool(cmd, "update-cpu");
3146 if (inactive)
3147 flags |= VIR_DOMAIN_XML_INACTIVE;
3148 if (secure)
3149 flags |= VIR_DOMAIN_XML_SECURE;
3150 if (update)
3151 flags |= VIR_DOMAIN_XML_UPDATE_CPU;
3153 if (!vshConnectionUsability(ctl, ctl->conn))
3154 return FALSE;
3156 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
3157 return FALSE;
3159 dump = virDomainGetXMLDesc(dom, flags);
3160 if (dump != NULL) {
3161 vshPrint(ctl, "%s", dump);
3162 VIR_FREE(dump);
3163 } else {
3164 ret = FALSE;
3167 virDomainFree(dom);
3168 return ret;
3172 * "domxml-from-native" command
3174 static const vshCmdInfo info_domxmlfromnative[] = {
3175 {"help", N_("Convert native config to domain XML")},
3176 {"desc", N_("Convert native guest configuration format to domain XML format.")},
3177 {NULL, NULL}
3180 static const vshCmdOptDef opts_domxmlfromnative[] = {
3181 {"format", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source config data format")},
3182 {"config", VSH_OT_DATA, VSH_OFLAG_REQ, N_("config data file to import from")},
3183 {NULL, 0, 0, NULL}
3186 static int
3187 cmdDomXMLFromNative(vshControl *ctl, const vshCmd *cmd)
3189 int ret = TRUE;
3190 char *format;
3191 char *configFile;
3192 char *configData;
3193 char *xmlData;
3194 int flags = 0;
3196 if (!vshConnectionUsability(ctl, ctl->conn))
3197 return FALSE;
3199 format = vshCommandOptString(cmd, "format", NULL);
3200 configFile = vshCommandOptString(cmd, "config", NULL);
3202 if (virFileReadAll(configFile, 1024*1024, &configData) < 0)
3203 return FALSE;
3205 xmlData = virConnectDomainXMLFromNative(ctl->conn, format, configData, flags);
3206 if (xmlData != NULL) {
3207 vshPrint(ctl, "%s", xmlData);
3208 VIR_FREE(xmlData);
3209 } else {
3210 ret = FALSE;
3213 return ret;
3217 * "domxml-to-native" command
3219 static const vshCmdInfo info_domxmltonative[] = {
3220 {"help", N_("Convert domain XML to native config")},
3221 {"desc", N_("Convert domain XML config to a native guest configuration format.")},
3222 {NULL, NULL}
3225 static const vshCmdOptDef opts_domxmltonative[] = {
3226 {"format", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target config data type format")},
3227 {"xml", VSH_OT_DATA, VSH_OFLAG_REQ, N_("xml data file to export from")},
3228 {NULL, 0, 0, NULL}
3231 static int
3232 cmdDomXMLToNative(vshControl *ctl, const vshCmd *cmd)
3234 int ret = TRUE;
3235 char *format;
3236 char *xmlFile;
3237 char *configData;
3238 char *xmlData;
3239 int flags = 0;
3241 if (!vshConnectionUsability(ctl, ctl->conn))
3242 return FALSE;
3244 format = vshCommandOptString(cmd, "format", NULL);
3245 xmlFile = vshCommandOptString(cmd, "xml", NULL);
3247 if (virFileReadAll(xmlFile, 1024*1024, &xmlData) < 0)
3248 return FALSE;
3250 configData = virConnectDomainXMLToNative(ctl->conn, format, xmlData, flags);
3251 if (configData != NULL) {
3252 vshPrint(ctl, "%s", configData);
3253 VIR_FREE(configData);
3254 } else {
3255 ret = FALSE;
3258 return ret;
3262 * "domname" command
3264 static const vshCmdInfo info_domname[] = {
3265 {"help", N_("convert a domain id or UUID to domain name")},
3266 {"desc", ""},
3267 {NULL, NULL}
3270 static const vshCmdOptDef opts_domname[] = {
3271 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or uuid")},
3272 {NULL, 0, 0, NULL}
3275 static int
3276 cmdDomname(vshControl *ctl, const vshCmd *cmd)
3278 virDomainPtr dom;
3280 if (!vshConnectionUsability(ctl, ctl->conn))
3281 return FALSE;
3282 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3283 VSH_BYID|VSH_BYUUID)))
3284 return FALSE;
3286 vshPrint(ctl, "%s\n", virDomainGetName(dom));
3287 virDomainFree(dom);
3288 return TRUE;
3292 * "domid" command
3294 static const vshCmdInfo info_domid[] = {
3295 {"help", N_("convert a domain name or UUID to domain id")},
3296 {"desc", ""},
3297 {NULL, NULL}
3300 static const vshCmdOptDef opts_domid[] = {
3301 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
3302 {NULL, 0, 0, NULL}
3305 static int
3306 cmdDomid(vshControl *ctl, const vshCmd *cmd)
3308 virDomainPtr dom;
3309 unsigned int id;
3311 if (!vshConnectionUsability(ctl, ctl->conn))
3312 return FALSE;
3313 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3314 VSH_BYNAME|VSH_BYUUID)))
3315 return FALSE;
3317 id = virDomainGetID(dom);
3318 if (id == ((unsigned int)-1))
3319 vshPrint(ctl, "%s\n", "-");
3320 else
3321 vshPrint(ctl, "%d\n", id);
3322 virDomainFree(dom);
3323 return TRUE;
3327 * "domuuid" command
3329 static const vshCmdInfo info_domuuid[] = {
3330 {"help", N_("convert a domain name or id to domain UUID")},
3331 {"desc", ""},
3332 {NULL, NULL}
3335 static const vshCmdOptDef opts_domuuid[] = {
3336 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or name")},
3337 {NULL, 0, 0, NULL}
3340 static int
3341 cmdDomuuid(vshControl *ctl, const vshCmd *cmd)
3343 virDomainPtr dom;
3344 char uuid[VIR_UUID_STRING_BUFLEN];
3346 if (!vshConnectionUsability(ctl, ctl->conn))
3347 return FALSE;
3348 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3349 VSH_BYNAME|VSH_BYID)))
3350 return FALSE;
3352 if (virDomainGetUUIDString(dom, uuid) != -1)
3353 vshPrint(ctl, "%s\n", uuid);
3354 else
3355 vshError(ctl, "%s", _("failed to get domain UUID"));
3357 virDomainFree(dom);
3358 return TRUE;
3362 * "migrate" command
3364 static const vshCmdInfo info_migrate[] = {
3365 {"help", N_("migrate domain to another host")},
3366 {"desc", N_("Migrate domain to another host. Add --live for live migration.")},
3367 {NULL, NULL}
3370 static const vshCmdOptDef opts_migrate[] = {
3371 {"live", VSH_OT_BOOL, 0, N_("live migration")},
3372 {"p2p", VSH_OT_BOOL, 0, N_("peer-2-peer migration")},
3373 {"direct", VSH_OT_BOOL, 0, N_("direct migration")},
3374 {"tunnelled", VSH_OT_BOOL, 0, N_("tunnelled migration")},
3375 {"persistent", VSH_OT_BOOL, 0, N_("persist VM on destination")},
3376 {"undefinesource", VSH_OT_BOOL, 0, N_("undefine VM on source")},
3377 {"suspend", VSH_OT_BOOL, 0, N_("do not restart the domain on the destination host")},
3378 {"copy-storage-all", VSH_OT_BOOL, 0, N_("migration with non-shared storage with full disk copy")},
3379 {"copy-storage-inc", VSH_OT_BOOL, 0, N_("migration with non-shared storage with incremental copy (same base image shared between source and destination)")},
3380 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3381 {"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, N_("connection URI of the destination host")},
3382 {"migrateuri", VSH_OT_DATA, 0, N_("migration URI, usually can be omitted")},
3383 {"dname", VSH_OT_DATA, 0, N_("rename to new name during migration (if supported)")},
3384 {NULL, 0, 0, NULL}
3387 static int
3388 cmdMigrate (vshControl *ctl, const vshCmd *cmd)
3390 virDomainPtr dom = NULL;
3391 const char *desturi;
3392 const char *migrateuri;
3393 const char *dname;
3394 int flags = 0, found, ret = FALSE;
3396 if (!vshConnectionUsability (ctl, ctl->conn))
3397 return FALSE;
3399 if (!(dom = vshCommandOptDomain (ctl, cmd, NULL)))
3400 return FALSE;
3402 desturi = vshCommandOptString (cmd, "desturi", &found);
3403 if (!found)
3404 goto done;
3406 migrateuri = vshCommandOptString (cmd, "migrateuri", NULL);
3408 dname = vshCommandOptString (cmd, "dname", NULL);
3410 if (vshCommandOptBool (cmd, "live"))
3411 flags |= VIR_MIGRATE_LIVE;
3412 if (vshCommandOptBool (cmd, "p2p"))
3413 flags |= VIR_MIGRATE_PEER2PEER;
3414 if (vshCommandOptBool (cmd, "tunnelled"))
3415 flags |= VIR_MIGRATE_TUNNELLED;
3417 if (vshCommandOptBool (cmd, "persistent"))
3418 flags |= VIR_MIGRATE_PERSIST_DEST;
3419 if (vshCommandOptBool (cmd, "undefinesource"))
3420 flags |= VIR_MIGRATE_UNDEFINE_SOURCE;
3422 if (vshCommandOptBool (cmd, "suspend"))
3423 flags |= VIR_MIGRATE_PAUSED;
3425 if (vshCommandOptBool (cmd, "copy-storage-all"))
3426 flags |= VIR_MIGRATE_NON_SHARED_DISK;
3428 if (vshCommandOptBool (cmd, "copy-storage-inc"))
3429 flags |= VIR_MIGRATE_NON_SHARED_INC;
3431 if ((flags & VIR_MIGRATE_PEER2PEER) ||
3432 vshCommandOptBool (cmd, "direct")) {
3433 /* For peer2peer migration or direct migration we only expect one URI
3434 * a libvirt URI, or a hypervisor specific URI. */
3436 if (migrateuri != NULL) {
3437 vshError(ctl, "%s", _("migrate: Unexpected migrateuri for peer2peer/direct migration"));
3438 goto done;
3441 if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0)
3442 ret = TRUE;
3443 } else {
3444 /* For traditional live migration, connect to the destination host directly. */
3445 virConnectPtr dconn = NULL;
3446 virDomainPtr ddom = NULL;
3448 dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
3449 if (!dconn) goto done;
3451 ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
3452 if (ddom) {
3453 virDomainFree(ddom);
3454 ret = TRUE;
3456 virConnectClose (dconn);
3459 done:
3460 if (dom) virDomainFree (dom);
3461 return ret;
3465 * "migrate-setmaxdowntime" command
3467 static const vshCmdInfo info_migrate_setmaxdowntime[] = {
3468 {"help", N_("set maximum tolerable downtime")},
3469 {"desc", N_("Set maximum tolerable downtime of a domain which is being live-migrated to another host.")},
3470 {NULL, NULL}
3473 static const vshCmdOptDef opts_migrate_setmaxdowntime[] = {
3474 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3475 {"downtime", VSH_OT_INT, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in milliseconds) for migration")},
3476 {NULL, 0, 0, NULL}
3479 static int
3480 cmdMigrateSetMaxDowntime(vshControl *ctl, const vshCmd *cmd)
3482 virDomainPtr dom = NULL;
3483 long long downtime;
3484 int found;
3485 int ret = FALSE;
3487 if (!vshConnectionUsability(ctl, ctl->conn))
3488 return FALSE;
3490 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
3491 return FALSE;
3493 downtime = vshCommandOptLongLong(cmd, "downtime", &found);
3494 if (!found || downtime < 1) {
3495 vshError(ctl, "%s", _("migrate: Invalid downtime"));
3496 goto done;
3499 if (virDomainMigrateSetMaxDowntime(dom, downtime, 0))
3500 goto done;
3502 ret = TRUE;
3504 done:
3505 virDomainFree(dom);
3506 return ret;
3510 * "net-autostart" command
3512 static const vshCmdInfo info_network_autostart[] = {
3513 {"help", N_("autostart a network")},
3514 {"desc",
3515 N_("Configure a network to be automatically started at boot.")},
3516 {NULL, NULL}
3519 static const vshCmdOptDef opts_network_autostart[] = {
3520 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
3521 {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
3522 {NULL, 0, 0, NULL}
3525 static int
3526 cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd)
3528 virNetworkPtr network;
3529 char *name;
3530 int autostart;
3532 if (!vshConnectionUsability(ctl, ctl->conn))
3533 return FALSE;
3535 if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
3536 return FALSE;
3538 autostart = !vshCommandOptBool(cmd, "disable");
3540 if (virNetworkSetAutostart(network, autostart) < 0) {
3541 if (autostart)
3542 vshError(ctl, _("failed to mark network %s as autostarted"), name);
3543 else
3544 vshError(ctl, _("failed to unmark network %s as autostarted"), name);
3545 virNetworkFree(network);
3546 return FALSE;
3549 if (autostart)
3550 vshPrint(ctl, _("Network %s marked as autostarted\n"), name);
3551 else
3552 vshPrint(ctl, _("Network %s unmarked as autostarted\n"), name);
3554 virNetworkFree(network);
3555 return TRUE;
3559 * "net-create" command
3561 static const vshCmdInfo info_network_create[] = {
3562 {"help", N_("create a network from an XML file")},
3563 {"desc", N_("Create a network.")},
3564 {NULL, NULL}
3567 static const vshCmdOptDef opts_network_create[] = {
3568 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
3569 {NULL, 0, 0, NULL}
3572 static int
3573 cmdNetworkCreate(vshControl *ctl, const vshCmd *cmd)
3575 virNetworkPtr network;
3576 char *from;
3577 int found;
3578 int ret = TRUE;
3579 char *buffer;
3581 if (!vshConnectionUsability(ctl, ctl->conn))
3582 return FALSE;
3584 from = vshCommandOptString(cmd, "file", &found);
3585 if (!found)
3586 return FALSE;
3588 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
3589 return FALSE;
3591 network = virNetworkCreateXML(ctl->conn, buffer);
3592 VIR_FREE(buffer);
3594 if (network != NULL) {
3595 vshPrint(ctl, _("Network %s created from %s\n"),
3596 virNetworkGetName(network), from);
3597 virNetworkFree(network);
3598 } else {
3599 vshError(ctl, _("Failed to create network from %s"), from);
3600 ret = FALSE;
3602 return ret;
3607 * "net-define" command
3609 static const vshCmdInfo info_network_define[] = {
3610 {"help", N_("define (but don't start) a network from an XML file")},
3611 {"desc", N_("Define a network.")},
3612 {NULL, NULL}
3615 static const vshCmdOptDef opts_network_define[] = {
3616 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
3617 {NULL, 0, 0, NULL}
3620 static int
3621 cmdNetworkDefine(vshControl *ctl, const vshCmd *cmd)
3623 virNetworkPtr network;
3624 char *from;
3625 int found;
3626 int ret = TRUE;
3627 char *buffer;
3629 if (!vshConnectionUsability(ctl, ctl->conn))
3630 return FALSE;
3632 from = vshCommandOptString(cmd, "file", &found);
3633 if (!found)
3634 return FALSE;
3636 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
3637 return FALSE;
3639 network = virNetworkDefineXML(ctl->conn, buffer);
3640 VIR_FREE(buffer);
3642 if (network != NULL) {
3643 vshPrint(ctl, _("Network %s defined from %s\n"),
3644 virNetworkGetName(network), from);
3645 virNetworkFree(network);
3646 } else {
3647 vshError(ctl, _("Failed to define network from %s"), from);
3648 ret = FALSE;
3650 return ret;
3655 * "net-destroy" command
3657 static const vshCmdInfo info_network_destroy[] = {
3658 {"help", N_("destroy a network")},
3659 {"desc", N_("Destroy a given network.")},
3660 {NULL, NULL}
3663 static const vshCmdOptDef opts_network_destroy[] = {
3664 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
3665 {NULL, 0, 0, NULL}
3668 static int
3669 cmdNetworkDestroy(vshControl *ctl, const vshCmd *cmd)
3671 virNetworkPtr network;
3672 int ret = TRUE;
3673 char *name;
3675 if (!vshConnectionUsability(ctl, ctl->conn))
3676 return FALSE;
3678 if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
3679 return FALSE;
3681 if (virNetworkDestroy(network) == 0) {
3682 vshPrint(ctl, _("Network %s destroyed\n"), name);
3683 } else {
3684 vshError(ctl, _("Failed to destroy network %s"), name);
3685 ret = FALSE;
3688 virNetworkFree(network);
3689 return ret;
3694 * "net-dumpxml" command
3696 static const vshCmdInfo info_network_dumpxml[] = {
3697 {"help", N_("network information in XML")},
3698 {"desc", N_("Output the network information as an XML dump to stdout.")},
3699 {NULL, NULL}
3702 static const vshCmdOptDef opts_network_dumpxml[] = {
3703 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
3704 {NULL, 0, 0, NULL}
3707 static int
3708 cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd)
3710 virNetworkPtr network;
3711 int ret = TRUE;
3712 char *dump;
3714 if (!vshConnectionUsability(ctl, ctl->conn))
3715 return FALSE;
3717 if (!(network = vshCommandOptNetwork(ctl, cmd, NULL)))
3718 return FALSE;
3720 dump = virNetworkGetXMLDesc(network, 0);
3721 if (dump != NULL) {
3722 vshPrint(ctl, "%s", dump);
3723 VIR_FREE(dump);
3724 } else {
3725 ret = FALSE;
3728 virNetworkFree(network);
3729 return ret;
3733 * "net-info" command
3735 static const vshCmdInfo info_network_info[] = {
3736 {"help", N_("network information")},
3737 {"desc", "Returns basic information about the network"},
3738 {NULL, NULL}
3741 static const vshCmdOptDef opts_network_info[] = {
3742 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")},
3743 {NULL, 0, 0, NULL}
3746 static int
3747 cmdNetworkInfo(vshControl *ctl, const vshCmd *cmd)
3749 virNetworkPtr network;
3750 char uuid[VIR_UUID_STRING_BUFLEN];
3751 int autostart;
3752 int persistent = -1;
3753 int active = -1;
3754 char *bridge = NULL;
3756 if (!vshConnectionUsability(ctl, ctl->conn))
3757 return FALSE;
3759 if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
3760 VSH_BYNAME)))
3761 return FALSE;
3763 vshPrint(ctl, "%-15s %s\n", _("Name"), virNetworkGetName(network));
3765 if (virNetworkGetUUIDString(network, uuid) == 0)
3766 vshPrint(ctl, "%-15s %s\n", _("UUID"), uuid);
3768 active = virNetworkIsActive(network);
3769 if (active >= 0)
3770 vshPrint(ctl, "%-15s %s\n", _("Active:"), active? _("yes") : _("no"));
3772 persistent = virNetworkIsPersistent(network);
3773 if (persistent < 0)
3774 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
3775 else
3776 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));
3778 if (virNetworkGetAutostart(network, &autostart) < 0)
3779 vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart"));
3780 else
3781 vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));
3783 bridge = virNetworkGetBridgeName(network);
3784 if (bridge)
3785 vshPrint(ctl, "%-15s %s\n", _("Bridge:"), bridge);
3787 virNetworkFree(network);
3788 return TRUE;
3792 * "iface-edit" command
3794 static const vshCmdInfo info_interface_edit[] = {
3795 {"help", N_("edit XML configuration for a physical host interface")},
3796 {"desc", N_("Edit the XML configuration for a physical host interface.")},
3797 {NULL, NULL}
3800 static const vshCmdOptDef opts_interface_edit[] = {
3801 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
3802 {NULL, 0, 0, NULL}
3805 static int
3806 cmdInterfaceEdit (vshControl *ctl, const vshCmd *cmd)
3808 int ret = FALSE;
3809 virInterfacePtr iface = NULL;
3810 char *tmp = NULL;
3811 char *doc = NULL;
3812 char *doc_edited = NULL;
3813 char *doc_reread = NULL;
3814 int flags = VIR_INTERFACE_XML_INACTIVE;
3816 if (!vshConnectionUsability(ctl, ctl->conn))
3817 goto cleanup;
3819 iface = vshCommandOptInterface (ctl, cmd, NULL);
3820 if (iface == NULL)
3821 goto cleanup;
3823 /* Get the XML configuration of the interface. */
3824 doc = virInterfaceGetXMLDesc (iface, flags);
3825 if (!doc)
3826 goto cleanup;
3828 /* Create and open the temporary file. */
3829 tmp = editWriteToTempFile (ctl, doc);
3830 if (!tmp) goto cleanup;
3832 /* Start the editor. */
3833 if (editFile (ctl, tmp) == -1) goto cleanup;
3835 /* Read back the edited file. */
3836 doc_edited = editReadBackFile (ctl, tmp);
3837 if (!doc_edited) goto cleanup;
3839 /* Compare original XML with edited. Has it changed at all? */
3840 if (STREQ (doc, doc_edited)) {
3841 vshPrint (ctl, _("Interface %s XML configuration not changed.\n"),
3842 virInterfaceGetName (iface));
3843 ret = TRUE;
3844 goto cleanup;
3847 /* Now re-read the interface XML. Did someone else change it while
3848 * it was being edited? This also catches problems such as us
3849 * losing a connection or the interface going away.
3851 doc_reread = virInterfaceGetXMLDesc (iface, flags);
3852 if (!doc_reread)
3853 goto cleanup;
3855 if (STRNEQ (doc, doc_reread)) {
3856 vshError(ctl, "%s",
3857 _("ERROR: the XML configuration was changed by another user"));
3858 goto cleanup;
3861 /* Everything checks out, so redefine the interface. */
3862 virInterfaceFree (iface);
3863 iface = virInterfaceDefineXML (ctl->conn, doc_edited, 0);
3864 if (!iface)
3865 goto cleanup;
3867 vshPrint (ctl, _("Interface %s XML configuration edited.\n"),
3868 virInterfaceGetName(iface));
3870 ret = TRUE;
3872 cleanup:
3873 if (iface)
3874 virInterfaceFree (iface);
3876 VIR_FREE(doc);
3877 VIR_FREE(doc_edited);
3878 VIR_FREE(doc_reread);
3880 if (tmp) {
3881 unlink (tmp);
3882 VIR_FREE(tmp);
3885 return ret;
3889 * "net-list" command
3891 static const vshCmdInfo info_network_list[] = {
3892 {"help", N_("list networks")},
3893 {"desc", N_("Returns list of networks.")},
3894 {NULL, NULL}
3897 static const vshCmdOptDef opts_network_list[] = {
3898 {"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")},
3899 {"all", VSH_OT_BOOL, 0, N_("list inactive & active networks")},
3900 {NULL, 0, 0, NULL}
3903 static int
3904 cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3906 int inactive = vshCommandOptBool(cmd, "inactive");
3907 int all = vshCommandOptBool(cmd, "all");
3908 int active = !inactive || all ? 1 : 0;
3909 int maxactive = 0, maxinactive = 0, i;
3910 char **activeNames = NULL, **inactiveNames = NULL;
3911 inactive |= all;
3913 if (!vshConnectionUsability(ctl, ctl->conn))
3914 return FALSE;
3916 if (active) {
3917 maxactive = virConnectNumOfNetworks(ctl->conn);
3918 if (maxactive < 0) {
3919 vshError(ctl, "%s", _("Failed to list active networks"));
3920 return FALSE;
3922 if (maxactive) {
3923 activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
3925 if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
3926 maxactive)) < 0) {
3927 vshError(ctl, "%s", _("Failed to list active networks"));
3928 VIR_FREE(activeNames);
3929 return FALSE;
3932 qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
3935 if (inactive) {
3936 maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
3937 if (maxinactive < 0) {
3938 vshError(ctl, "%s", _("Failed to list inactive networks"));
3939 VIR_FREE(activeNames);
3940 return FALSE;
3942 if (maxinactive) {
3943 inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
3945 if ((maxinactive =
3946 virConnectListDefinedNetworks(ctl->conn, inactiveNames,
3947 maxinactive)) < 0) {
3948 vshError(ctl, "%s", _("Failed to list inactive networks"));
3949 VIR_FREE(activeNames);
3950 VIR_FREE(inactiveNames);
3951 return FALSE;
3954 qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
3957 vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
3958 _("Autostart"));
3959 vshPrintExtra(ctl, "-----------------------------------------\n");
3961 for (i = 0; i < maxactive; i++) {
3962 virNetworkPtr network =
3963 virNetworkLookupByName(ctl->conn, activeNames[i]);
3964 const char *autostartStr;
3965 int autostart = 0;
3967 /* this kind of work with networks is not atomic operation */
3968 if (!network) {
3969 VIR_FREE(activeNames[i]);
3970 continue;
3973 if (virNetworkGetAutostart(network, &autostart) < 0)
3974 autostartStr = _("no autostart");
3975 else
3976 autostartStr = autostart ? _("yes") : _("no");
3978 vshPrint(ctl, "%-20s %-10s %-10s\n",
3979 virNetworkGetName(network),
3980 _("active"),
3981 autostartStr);
3982 virNetworkFree(network);
3983 VIR_FREE(activeNames[i]);
3985 for (i = 0; i < maxinactive; i++) {
3986 virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
3987 const char *autostartStr;
3988 int autostart = 0;
3990 /* this kind of work with networks is not atomic operation */
3991 if (!network) {
3992 VIR_FREE(inactiveNames[i]);
3993 continue;
3996 if (virNetworkGetAutostart(network, &autostart) < 0)
3997 autostartStr = _("no autostart");
3998 else
3999 autostartStr = autostart ? _("yes") : _("no");
4001 vshPrint(ctl, "%-20s %-10s %-10s\n",
4002 inactiveNames[i],
4003 _("inactive"),
4004 autostartStr);
4006 virNetworkFree(network);
4007 VIR_FREE(inactiveNames[i]);
4009 VIR_FREE(activeNames);
4010 VIR_FREE(inactiveNames);
4011 return TRUE;
4016 * "net-name" command
4018 static const vshCmdInfo info_network_name[] = {
4019 {"help", N_("convert a network UUID to network name")},
4020 {"desc", ""},
4021 {NULL, NULL}
4024 static const vshCmdOptDef opts_network_name[] = {
4025 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network uuid")},
4026 {NULL, 0, 0, NULL}
4029 static int
4030 cmdNetworkName(vshControl *ctl, const vshCmd *cmd)
4032 virNetworkPtr network;
4034 if (!vshConnectionUsability(ctl, ctl->conn))
4035 return FALSE;
4036 if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
4037 VSH_BYUUID)))
4038 return FALSE;
4040 vshPrint(ctl, "%s\n", virNetworkGetName(network));
4041 virNetworkFree(network);
4042 return TRUE;
4047 * "net-start" command
4049 static const vshCmdInfo info_network_start[] = {
4050 {"help", N_("start a (previously defined) inactive network")},
4051 {"desc", N_("Start a network.")},
4052 {NULL, NULL}
4055 static const vshCmdOptDef opts_network_start[] = {
4056 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive network")},
4057 {NULL, 0, 0, NULL}
4060 static int
4061 cmdNetworkStart(vshControl *ctl, const vshCmd *cmd)
4063 virNetworkPtr network;
4064 int ret = TRUE;
4066 if (!vshConnectionUsability(ctl, ctl->conn))
4067 return FALSE;
4069 if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, VSH_BYNAME)))
4070 return FALSE;
4072 if (virNetworkCreate(network) == 0) {
4073 vshPrint(ctl, _("Network %s started\n"),
4074 virNetworkGetName(network));
4075 } else {
4076 vshError(ctl, _("Failed to start network %s"),
4077 virNetworkGetName(network));
4078 ret = FALSE;
4080 virNetworkFree(network);
4081 return ret;
4086 * "net-undefine" command
4088 static const vshCmdInfo info_network_undefine[] = {
4089 {"help", N_("undefine an inactive network")},
4090 {"desc", N_("Undefine the configuration for an inactive network.")},
4091 {NULL, NULL}
4094 static const vshCmdOptDef opts_network_undefine[] = {
4095 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
4096 {NULL, 0, 0, NULL}
4099 static int
4100 cmdNetworkUndefine(vshControl *ctl, const vshCmd *cmd)
4102 virNetworkPtr network;
4103 int ret = TRUE;
4104 char *name;
4106 if (!vshConnectionUsability(ctl, ctl->conn))
4107 return FALSE;
4109 if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
4110 return FALSE;
4112 if (virNetworkUndefine(network) == 0) {
4113 vshPrint(ctl, _("Network %s has been undefined\n"), name);
4114 } else {
4115 vshError(ctl, _("Failed to undefine network %s"), name);
4116 ret = FALSE;
4119 virNetworkFree(network);
4120 return ret;
4125 * "net-uuid" command
4127 static const vshCmdInfo info_network_uuid[] = {
4128 {"help", N_("convert a network name to network UUID")},
4129 {"desc", ""},
4130 {NULL, NULL}
4133 static const vshCmdOptDef opts_network_uuid[] = {
4134 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")},
4135 {NULL, 0, 0, NULL}
4138 static int
4139 cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd)
4141 virNetworkPtr network;
4142 char uuid[VIR_UUID_STRING_BUFLEN];
4144 if (!vshConnectionUsability(ctl, ctl->conn))
4145 return FALSE;
4147 if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
4148 VSH_BYNAME)))
4149 return FALSE;
4151 if (virNetworkGetUUIDString(network, uuid) != -1)
4152 vshPrint(ctl, "%s\n", uuid);
4153 else
4154 vshError(ctl, "%s", _("failed to get network UUID"));
4156 virNetworkFree(network);
4157 return TRUE;
4161 /**************************************************************************/
4163 * "iface-list" command
4165 static const vshCmdInfo info_interface_list[] = {
4166 {"help", N_("list physical host interfaces")},
4167 {"desc", N_("Returns list of physical host interfaces.")},
4168 {NULL, NULL}
4171 static const vshCmdOptDef opts_interface_list[] = {
4172 {"inactive", VSH_OT_BOOL, 0, N_("list inactive interfaces")},
4173 {"all", VSH_OT_BOOL, 0, N_("list inactive & active interfaces")},
4174 {NULL, 0, 0, NULL}
4176 static int
4177 cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
4179 int inactive = vshCommandOptBool(cmd, "inactive");
4180 int all = vshCommandOptBool(cmd, "all");
4181 int active = !inactive || all ? 1 : 0;
4182 int maxactive = 0, maxinactive = 0, i;
4183 char **activeNames = NULL, **inactiveNames = NULL;
4184 inactive |= all;
4186 if (!vshConnectionUsability(ctl, ctl->conn))
4187 return FALSE;
4189 if (active) {
4190 maxactive = virConnectNumOfInterfaces(ctl->conn);
4191 if (maxactive < 0) {
4192 vshError(ctl, "%s", _("Failed to list active interfaces"));
4193 return FALSE;
4195 if (maxactive) {
4196 activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
4198 if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames,
4199 maxactive)) < 0) {
4200 vshError(ctl, "%s", _("Failed to list active interfaces"));
4201 VIR_FREE(activeNames);
4202 return FALSE;
4205 qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
4208 if (inactive) {
4209 maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn);
4210 if (maxinactive < 0) {
4211 vshError(ctl, "%s", _("Failed to list inactive interfaces"));
4212 VIR_FREE(activeNames);
4213 return FALSE;
4215 if (maxinactive) {
4216 inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
4218 if ((maxinactive =
4219 virConnectListDefinedInterfaces(ctl->conn, inactiveNames,
4220 maxinactive)) < 0) {
4221 vshError(ctl, "%s", _("Failed to list inactive interfaces"));
4222 VIR_FREE(activeNames);
4223 VIR_FREE(inactiveNames);
4224 return FALSE;
4227 qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
4230 vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
4231 _("MAC Address"));
4232 vshPrintExtra(ctl, "--------------------------------------------\n");
4234 for (i = 0; i < maxactive; i++) {
4235 virInterfacePtr iface =
4236 virInterfaceLookupByName(ctl->conn, activeNames[i]);
4238 /* this kind of work with interfaces is not atomic */
4239 if (!iface) {
4240 VIR_FREE(activeNames[i]);
4241 continue;
4244 vshPrint(ctl, "%-20s %-10s %s\n",
4245 virInterfaceGetName(iface),
4246 _("active"),
4247 virInterfaceGetMACString(iface));
4248 virInterfaceFree(iface);
4249 VIR_FREE(activeNames[i]);
4251 for (i = 0; i < maxinactive; i++) {
4252 virInterfacePtr iface =
4253 virInterfaceLookupByName(ctl->conn, inactiveNames[i]);
4255 /* this kind of work with interfaces is not atomic */
4256 if (!iface) {
4257 VIR_FREE(inactiveNames[i]);
4258 continue;
4261 vshPrint(ctl, "%-20s %-10s %s\n",
4262 virInterfaceGetName(iface),
4263 _("inactive"),
4264 virInterfaceGetMACString(iface));
4265 virInterfaceFree(iface);
4266 VIR_FREE(inactiveNames[i]);
4268 VIR_FREE(activeNames);
4269 VIR_FREE(inactiveNames);
4270 return TRUE;
4275 * "iface-name" command
4277 static const vshCmdInfo info_interface_name[] = {
4278 {"help", N_("convert an interface MAC address to interface name")},
4279 {"desc", ""},
4280 {NULL, NULL}
4283 static const vshCmdOptDef opts_interface_name[] = {
4284 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface mac")},
4285 {NULL, 0, 0, NULL}
4288 static int
4289 cmdInterfaceName(vshControl *ctl, const vshCmd *cmd)
4291 virInterfacePtr iface;
4293 if (!vshConnectionUsability(ctl, ctl->conn))
4294 return FALSE;
4295 if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
4296 VSH_BYMAC)))
4297 return FALSE;
4299 vshPrint(ctl, "%s\n", virInterfaceGetName(iface));
4300 virInterfaceFree(iface);
4301 return TRUE;
4305 * "iface-mac" command
4307 static const vshCmdInfo info_interface_mac[] = {
4308 {"help", N_("convert an interface name to interface MAC address")},
4309 {"desc", ""},
4310 {NULL, NULL}
4313 static const vshCmdOptDef opts_interface_mac[] = {
4314 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name")},
4315 {NULL, 0, 0, NULL}
4318 static int
4319 cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd)
4321 virInterfacePtr iface;
4323 if (!vshConnectionUsability(ctl, ctl->conn))
4324 return FALSE;
4325 if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
4326 VSH_BYNAME)))
4327 return FALSE;
4329 vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface));
4330 virInterfaceFree(iface);
4331 return TRUE;
4335 * "iface-dumpxml" command
4337 static const vshCmdInfo info_interface_dumpxml[] = {
4338 {"help", N_("interface information in XML")},
4339 {"desc", N_("Output the physical host interface information as an XML dump to stdout.")},
4340 {NULL, NULL}
4343 static const vshCmdOptDef opts_interface_dumpxml[] = {
4344 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4345 {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")},
4346 {NULL, 0, 0, NULL}
4349 static int
4350 cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd)
4352 virInterfacePtr iface;
4353 int ret = TRUE;
4354 char *dump;
4355 int flags = 0;
4356 int inactive = vshCommandOptBool(cmd, "inactive");
4358 if (inactive)
4359 flags |= VIR_INTERFACE_XML_INACTIVE;
4361 if (!vshConnectionUsability(ctl, ctl->conn))
4362 return FALSE;
4364 if (!(iface = vshCommandOptInterface(ctl, cmd, NULL)))
4365 return FALSE;
4367 dump = virInterfaceGetXMLDesc(iface, flags);
4368 if (dump != NULL) {
4369 vshPrint(ctl, "%s", dump);
4370 VIR_FREE(dump);
4371 } else {
4372 ret = FALSE;
4375 virInterfaceFree(iface);
4376 return ret;
4380 * "iface-define" command
4382 static const vshCmdInfo info_interface_define[] = {
4383 {"help", N_("define (but don't start) a physical host interface from an XML file")},
4384 {"desc", N_("Define a physical host interface.")},
4385 {NULL, NULL}
4388 static const vshCmdOptDef opts_interface_define[] = {
4389 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML interface description")},
4390 {NULL, 0, 0, NULL}
4393 static int
4394 cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd)
4396 virInterfacePtr iface;
4397 char *from;
4398 int found;
4399 int ret = TRUE;
4400 char *buffer;
4402 if (!vshConnectionUsability(ctl, ctl->conn))
4403 return FALSE;
4405 from = vshCommandOptString(cmd, "file", &found);
4406 if (!found)
4407 return FALSE;
4409 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4410 return FALSE;
4412 iface = virInterfaceDefineXML(ctl->conn, buffer, 0);
4413 VIR_FREE(buffer);
4415 if (iface != NULL) {
4416 vshPrint(ctl, _("Interface %s defined from %s\n"),
4417 virInterfaceGetName(iface), from);
4418 virInterfaceFree (iface);
4419 } else {
4420 vshError(ctl, _("Failed to define interface from %s"), from);
4421 ret = FALSE;
4423 return ret;
4427 * "iface-undefine" command
4429 static const vshCmdInfo info_interface_undefine[] = {
4430 {"help", N_("undefine a physical host interface (remove it from configuration)")},
4431 {"desc", N_("undefine an interface.")},
4432 {NULL, NULL}
4435 static const vshCmdOptDef opts_interface_undefine[] = {
4436 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4437 {NULL, 0, 0, NULL}
4440 static int
4441 cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd)
4443 virInterfacePtr iface;
4444 int ret = TRUE;
4445 char *name;
4447 if (!vshConnectionUsability(ctl, ctl->conn))
4448 return FALSE;
4450 if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
4451 return FALSE;
4453 if (virInterfaceUndefine(iface) == 0) {
4454 vshPrint(ctl, _("Interface %s undefined\n"), name);
4455 } else {
4456 vshError(ctl, _("Failed to undefine interface %s"), name);
4457 ret = FALSE;
4460 virInterfaceFree(iface);
4461 return ret;
4465 * "iface-start" command
4467 static const vshCmdInfo info_interface_start[] = {
4468 {"help", N_("start a physical host interface (enable it / \"if-up\")")},
4469 {"desc", N_("start a physical host interface.")},
4470 {NULL, NULL}
4473 static const vshCmdOptDef opts_interface_start[] = {
4474 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4475 {NULL, 0, 0, NULL}
4478 static int
4479 cmdInterfaceStart(vshControl *ctl, const vshCmd *cmd)
4481 virInterfacePtr iface;
4482 int ret = TRUE;
4483 char *name;
4485 if (!vshConnectionUsability(ctl, ctl->conn))
4486 return FALSE;
4488 if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
4489 return FALSE;
4491 if (virInterfaceCreate(iface, 0) == 0) {
4492 vshPrint(ctl, _("Interface %s started\n"), name);
4493 } else {
4494 vshError(ctl, _("Failed to start interface %s"), name);
4495 ret = FALSE;
4498 virInterfaceFree(iface);
4499 return ret;
4503 * "iface-destroy" command
4505 static const vshCmdInfo info_interface_destroy[] = {
4506 {"help", N_("destroy a physical host interface (disable it / \"if-down\")")},
4507 {"desc", N_("destroy a physical host interface.")},
4508 {NULL, NULL}
4511 static const vshCmdOptDef opts_interface_destroy[] = {
4512 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4513 {NULL, 0, 0, NULL}
4516 static int
4517 cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd)
4519 virInterfacePtr iface;
4520 int ret = TRUE;
4521 char *name;
4523 if (!vshConnectionUsability(ctl, ctl->conn))
4524 return FALSE;
4526 if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
4527 return FALSE;
4529 if (virInterfaceDestroy(iface, 0) == 0) {
4530 vshPrint(ctl, _("Interface %s destroyed\n"), name);
4531 } else {
4532 vshError(ctl, _("Failed to destroy interface %s"), name);
4533 ret = FALSE;
4536 virInterfaceFree(iface);
4537 return ret;
4542 * "nwfilter-define" command
4544 static const vshCmdInfo info_nwfilter_define[] = {
4545 {"help", N_("define or update a network filter from an XML file")},
4546 {"desc", N_("Define a new network filter or update an existing one.")},
4547 {NULL, NULL}
4550 static const vshCmdOptDef opts_nwfilter_define[] = {
4551 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network filter description")},
4552 {NULL, 0, 0, NULL}
4555 static int
4556 cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd)
4558 virNWFilterPtr nwfilter;
4559 char *from;
4560 int found;
4561 int ret = TRUE;
4562 char *buffer;
4564 if (!vshConnectionUsability(ctl, ctl->conn))
4565 return FALSE;
4567 from = vshCommandOptString(cmd, "file", &found);
4568 if (!found)
4569 return FALSE;
4571 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4572 return FALSE;
4574 nwfilter = virNWFilterDefineXML(ctl->conn, buffer);
4575 VIR_FREE(buffer);
4577 if (nwfilter != NULL) {
4578 vshPrint(ctl, _("Network filter %s defined from %s\n"),
4579 virNWFilterGetName(nwfilter), from);
4580 virNWFilterFree(nwfilter);
4581 } else {
4582 vshError(ctl, _("Failed to define network filter from %s"), from);
4583 ret = FALSE;
4585 return ret;
4590 * "nwfilter-undefine" command
4592 static const vshCmdInfo info_nwfilter_undefine[] = {
4593 {"help", N_("undefine a network filter")},
4594 {"desc", N_("Undefine a given network filter.")},
4595 {NULL, NULL}
4598 static const vshCmdOptDef opts_nwfilter_undefine[] = {
4599 {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
4600 {NULL, 0, 0, NULL}
4603 static int
4604 cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd)
4606 virNWFilterPtr nwfilter;
4607 int ret = TRUE;
4608 char *name;
4610 if (!vshConnectionUsability(ctl, ctl->conn))
4611 return FALSE;
4613 if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, &name)))
4614 return FALSE;
4616 if (virNWFilterUndefine(nwfilter) == 0) {
4617 vshPrint(ctl, _("Network filter %s undefined\n"), name);
4618 } else {
4619 vshError(ctl, _("Failed to undefine network filter %s"), name);
4620 ret = FALSE;
4623 virNWFilterFree(nwfilter);
4624 return ret;
4629 * "nwfilter-dumpxml" command
4631 static const vshCmdInfo info_nwfilter_dumpxml[] = {
4632 {"help", N_("network filter information in XML")},
4633 {"desc", N_("Output the network filter information as an XML dump to stdout.")},
4634 {NULL, NULL}
4637 static const vshCmdOptDef opts_nwfilter_dumpxml[] = {
4638 {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
4639 {NULL, 0, 0, NULL}
4642 static int
4643 cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd)
4645 virNWFilterPtr nwfilter;
4646 int ret = TRUE;
4647 char *dump;
4649 if (!vshConnectionUsability(ctl, ctl->conn))
4650 return FALSE;
4652 if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL)))
4653 return FALSE;
4655 dump = virNWFilterGetXMLDesc(nwfilter, 0);
4656 if (dump != NULL) {
4657 vshPrint(ctl, "%s", dump);
4658 VIR_FREE(dump);
4659 } else {
4660 ret = FALSE;
4663 virNWFilterFree(nwfilter);
4664 return ret;
4668 * "nwfilter-list" command
4670 static const vshCmdInfo info_nwfilter_list[] = {
4671 {"help", N_("list network filters")},
4672 {"desc", N_("Returns list of network filters.")},
4673 {NULL, NULL}
4676 static const vshCmdOptDef opts_nwfilter_list[] = {
4677 {NULL, 0, 0, NULL}
4680 static int
4681 cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
4683 int numfilters, i;
4684 char **names;
4685 char uuid[VIR_UUID_STRING_BUFLEN];
4687 if (!vshConnectionUsability(ctl, ctl->conn))
4688 return FALSE;
4690 numfilters = virConnectNumOfNWFilters(ctl->conn);
4691 if (numfilters < 0) {
4692 vshError(ctl, "%s", _("Failed to list network filters"));
4693 return FALSE;
4696 names = vshMalloc(ctl, sizeof(char *) * numfilters);
4698 if ((numfilters = virConnectListNWFilters(ctl->conn, names,
4699 numfilters)) < 0) {
4700 vshError(ctl, "%s", _("Failed to list network filters"));
4701 VIR_FREE(names);
4702 return FALSE;
4705 qsort(&names[0], numfilters, sizeof(char *), namesorter);
4707 vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name"));
4708 vshPrintExtra(ctl,
4709 "----------------------------------------------------------------\n");
4711 for (i = 0; i < numfilters; i++) {
4712 virNWFilterPtr nwfilter =
4713 virNWFilterLookupByName(ctl->conn, names[i]);
4715 /* this kind of work with networks is not atomic operation */
4716 if (!nwfilter) {
4717 VIR_FREE(names[i]);
4718 continue;
4721 virNWFilterGetUUIDString(nwfilter, uuid);
4722 vshPrint(ctl, "%-36s %-20s\n",
4723 uuid,
4724 virNWFilterGetName(nwfilter));
4725 virNWFilterFree(nwfilter);
4726 VIR_FREE(names[i]);
4729 VIR_FREE(names);
4730 return TRUE;
4735 * "nwfilter-edit" command
4737 static const vshCmdInfo info_nwfilter_edit[] = {
4738 {"help", N_("edit XML configuration for a network filter")},
4739 {"desc", N_("Edit the XML configuration for a network filter.")},
4740 {NULL, NULL}
4743 static const vshCmdOptDef opts_nwfilter_edit[] = {
4744 {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
4745 {NULL, 0, 0, NULL}
4748 static int
4749 cmdNWFilterEdit (vshControl *ctl, const vshCmd *cmd)
4751 int ret = FALSE;
4752 virNWFilterPtr nwfilter = NULL;
4753 char *tmp = NULL;
4754 char *doc = NULL;
4755 char *doc_edited = NULL;
4756 char *doc_reread = NULL;
4758 if (!vshConnectionUsability(ctl, ctl->conn))
4759 goto cleanup;
4761 nwfilter = vshCommandOptNWFilter (ctl, cmd, NULL);
4762 if (nwfilter == NULL)
4763 goto cleanup;
4765 /* Get the XML configuration of the interface. */
4766 doc = virNWFilterGetXMLDesc (nwfilter, 0);
4767 if (!doc)
4768 goto cleanup;
4770 /* Create and open the temporary file. */
4771 tmp = editWriteToTempFile (ctl, doc);
4772 if (!tmp) goto cleanup;
4774 /* Start the editor. */
4775 if (editFile (ctl, tmp) == -1) goto cleanup;
4777 /* Read back the edited file. */
4778 doc_edited = editReadBackFile (ctl, tmp);
4779 if (!doc_edited) goto cleanup;
4781 /* Compare original XML with edited. Has it changed at all? */
4782 if (STREQ (doc, doc_edited)) {
4783 vshPrint (ctl, _("Network filter %s XML configuration not changed.\n"),
4784 virNWFilterGetName (nwfilter));
4785 ret = TRUE;
4786 goto cleanup;
4789 /* Now re-read the network filter XML. Did someone else change it while
4790 * it was being edited? This also catches problems such as us
4791 * losing a connection or the interface going away.
4793 doc_reread = virNWFilterGetXMLDesc (nwfilter, 0);
4794 if (!doc_reread)
4795 goto cleanup;
4797 if (STRNEQ (doc, doc_reread)) {
4798 vshError(ctl, "%s",
4799 _("ERROR: the XML configuration was changed by another user"));
4800 goto cleanup;
4803 /* Everything checks out, so redefine the interface. */
4804 virNWFilterFree (nwfilter);
4805 nwfilter = virNWFilterDefineXML (ctl->conn, doc_edited);
4806 if (!nwfilter)
4807 goto cleanup;
4809 vshPrint (ctl, _("Network filter %s XML configuration edited.\n"),
4810 virNWFilterGetName(nwfilter));
4812 ret = TRUE;
4814 cleanup:
4815 if (nwfilter)
4816 virNWFilterFree (nwfilter);
4818 VIR_FREE(doc);
4819 VIR_FREE(doc_edited);
4820 VIR_FREE(doc_reread);
4822 if (tmp) {
4823 unlink (tmp);
4824 VIR_FREE(tmp);
4827 return ret;
4831 /**************************************************************************/
4833 * "pool-autostart" command
4835 static const vshCmdInfo info_pool_autostart[] = {
4836 {"help", N_("autostart a pool")},
4837 {"desc",
4838 N_("Configure a pool to be automatically started at boot.")},
4839 {NULL, NULL}
4842 static const vshCmdOptDef opts_pool_autostart[] = {
4843 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4844 {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
4845 {NULL, 0, 0, NULL}
4848 static int
4849 cmdPoolAutostart(vshControl *ctl, const vshCmd *cmd)
4851 virStoragePoolPtr pool;
4852 char *name;
4853 int autostart;
4855 if (!vshConnectionUsability(ctl, ctl->conn))
4856 return FALSE;
4858 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
4859 return FALSE;
4861 autostart = !vshCommandOptBool(cmd, "disable");
4863 if (virStoragePoolSetAutostart(pool, autostart) < 0) {
4864 if (autostart)
4865 vshError(ctl, _("failed to mark pool %s as autostarted"), name);
4866 else
4867 vshError(ctl, _("failed to unmark pool %s as autostarted"), name);
4868 virStoragePoolFree(pool);
4869 return FALSE;
4872 if (autostart)
4873 vshPrint(ctl, _("Pool %s marked as autostarted\n"), name);
4874 else
4875 vshPrint(ctl, _("Pool %s unmarked as autostarted\n"), name);
4877 virStoragePoolFree(pool);
4878 return TRUE;
4882 * "pool-create" command
4884 static const vshCmdInfo info_pool_create[] = {
4885 {"help", N_("create a pool from an XML file")},
4886 {"desc", N_("Create a pool.")},
4887 {NULL, NULL}
4890 static const vshCmdOptDef opts_pool_create[] = {
4891 {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
4892 N_("file containing an XML pool description")},
4893 {NULL, 0, 0, NULL}
4896 static int
4897 cmdPoolCreate(vshControl *ctl, const vshCmd *cmd)
4899 virStoragePoolPtr pool;
4900 char *from;
4901 int found;
4902 int ret = TRUE;
4903 char *buffer;
4905 if (!vshConnectionUsability(ctl, ctl->conn))
4906 return FALSE;
4908 from = vshCommandOptString(cmd, "file", &found);
4909 if (!found)
4910 return FALSE;
4912 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4913 return FALSE;
4915 pool = virStoragePoolCreateXML(ctl->conn, buffer, 0);
4916 VIR_FREE(buffer);
4918 if (pool != NULL) {
4919 vshPrint(ctl, _("Pool %s created from %s\n"),
4920 virStoragePoolGetName(pool), from);
4921 virStoragePoolFree(pool);
4922 } else {
4923 vshError(ctl, _("Failed to create pool from %s"), from);
4924 ret = FALSE;
4926 return ret;
4931 * "nodedev-create" command
4933 static const vshCmdInfo info_node_device_create[] = {
4934 {"help", N_("create a device defined "
4935 "by an XML file on the node")},
4936 {"desc", N_("Create a device on the node. Note that this "
4937 "command creates devices on the physical host "
4938 "that can then be assigned to a virtual machine.")},
4939 {NULL, NULL}
4942 static const vshCmdOptDef opts_node_device_create[] = {
4943 {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
4944 N_("file containing an XML description of the device")},
4945 {NULL, 0, 0, NULL}
4948 static int
4949 cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
4951 virNodeDevicePtr dev = NULL;
4952 char *from;
4953 int found = 0;
4954 int ret = TRUE;
4955 char *buffer;
4957 if (!vshConnectionUsability(ctl, ctl->conn))
4958 return FALSE;
4960 from = vshCommandOptString(cmd, "file", &found);
4961 if (!found) {
4962 return FALSE;
4965 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4966 return FALSE;
4968 dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0);
4969 VIR_FREE(buffer);
4971 if (dev != NULL) {
4972 vshPrint(ctl, _("Node device %s created from %s\n"),
4973 virNodeDeviceGetName(dev), from);
4974 virNodeDeviceFree(dev);
4975 } else {
4976 vshError(ctl, _("Failed to create node device from %s"), from);
4977 ret = FALSE;
4980 return ret;
4985 * "nodedev-destroy" command
4987 static const vshCmdInfo info_node_device_destroy[] = {
4988 {"help", N_("destroy a device on the node")},
4989 {"desc", N_("Destroy a device on the node. Note that this "
4990 "command destroys devices on the physical host ")},
4991 {NULL, NULL}
4994 static const vshCmdOptDef opts_node_device_destroy[] = {
4995 {"name", VSH_OT_DATA, VSH_OFLAG_REQ,
4996 N_("name of the device to be destroyed")},
4997 {NULL, 0, 0, NULL}
5000 static int
5001 cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
5003 virNodeDevicePtr dev = NULL;
5004 int ret = TRUE;
5005 int found = 0;
5006 char *name;
5008 if (!vshConnectionUsability(ctl, ctl->conn)) {
5009 return FALSE;
5012 name = vshCommandOptString(cmd, "name", &found);
5013 if (!found) {
5014 return FALSE;
5017 dev = virNodeDeviceLookupByName(ctl->conn, name);
5019 if (virNodeDeviceDestroy(dev) == 0) {
5020 vshPrint(ctl, _("Destroyed node device '%s'\n"), name);
5021 } else {
5022 vshError(ctl, _("Failed to destroy node device '%s'"), name);
5023 ret = FALSE;
5026 virNodeDeviceFree(dev);
5027 return ret;
5032 * XML Building helper for pool-define-as and pool-create-as
5034 static const vshCmdOptDef opts_pool_X_as[] = {
5035 {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the pool")},
5036 {"print-xml", VSH_OT_BOOL, 0, N_("print XML document, but don't define/create")},
5037 {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("type of the pool")},
5038 {"source-host", VSH_OT_DATA, 0, N_("source-host for underlying storage")},
5039 {"source-path", VSH_OT_DATA, 0, N_("source path for underlying storage")},
5040 {"source-dev", VSH_OT_DATA, 0, N_("source device for underlying storage")},
5041 {"source-name", VSH_OT_DATA, 0, N_("source name for underlying storage")},
5042 {"target", VSH_OT_DATA, 0, N_("target for underlying storage")},
5043 {"source-format", VSH_OT_STRING, 0, N_("format for underlying storage")},
5044 {NULL, 0, 0, NULL}
5047 static int buildPoolXML(const vshCmd *cmd, char **retname, char **xml) {
5049 int found;
5050 char *name, *type, *srcHost, *srcPath, *srcDev, *srcName, *srcFormat, *target;
5051 virBuffer buf = VIR_BUFFER_INITIALIZER;
5053 name = vshCommandOptString(cmd, "name", &found);
5054 if (!found)
5055 goto cleanup;
5056 type = vshCommandOptString(cmd, "type", &found);
5057 if (!found)
5058 goto cleanup;
5060 srcHost = vshCommandOptString(cmd, "source-host", &found);
5061 srcPath = vshCommandOptString(cmd, "source-path", &found);
5062 srcDev = vshCommandOptString(cmd, "source-dev", &found);
5063 srcName = vshCommandOptString(cmd, "source-name", &found);
5064 srcFormat = vshCommandOptString(cmd, "source-format", &found);
5065 target = vshCommandOptString(cmd, "target", &found);
5067 virBufferVSprintf(&buf, "<pool type='%s'>\n", type);
5068 virBufferVSprintf(&buf, " <name>%s</name>\n", name);
5069 if (srcHost || srcPath || srcDev) {
5070 virBufferAddLit(&buf, " <source>\n");
5072 if (srcHost)
5073 virBufferVSprintf(&buf, " <host name='%s'/>\n", srcHost);
5074 if (srcPath)
5075 virBufferVSprintf(&buf, " <dir path='%s'/>\n", srcPath);
5076 if (srcDev)
5077 virBufferVSprintf(&buf, " <device path='%s'/>\n", srcDev);
5078 if (srcFormat)
5079 virBufferVSprintf(&buf, " <format type='%s'/>\n", srcFormat);
5080 if (srcName)
5081 virBufferVSprintf(&buf, " <name>%s</name>\n", srcName);
5083 virBufferAddLit(&buf, " </source>\n");
5085 if (target) {
5086 virBufferAddLit(&buf, " <target>\n");
5087 virBufferVSprintf(&buf, " <path>%s</path>\n", target);
5088 virBufferAddLit(&buf, " </target>\n");
5090 virBufferAddLit(&buf, "</pool>\n");
5092 if (virBufferError(&buf)) {
5093 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
5094 return FALSE;
5097 *xml = virBufferContentAndReset(&buf);
5098 *retname = name;
5099 return TRUE;
5101 cleanup:
5102 virBufferFreeAndReset(&buf);
5103 return FALSE;
5107 * "pool-create-as" command
5109 static const vshCmdInfo info_pool_create_as[] = {
5110 {"help", N_("create a pool from a set of args")},
5111 {"desc", N_("Create a pool.")},
5112 {NULL, NULL}
5115 static int
5116 cmdPoolCreateAs(vshControl *ctl, const vshCmd *cmd)
5118 virStoragePoolPtr pool;
5119 char *xml, *name;
5120 int printXML = vshCommandOptBool(cmd, "print-xml");
5122 if (!vshConnectionUsability(ctl, ctl->conn))
5123 return FALSE;
5125 if (!buildPoolXML(cmd, &name, &xml))
5126 return FALSE;
5128 if (printXML) {
5129 vshPrint(ctl, "%s", xml);
5130 VIR_FREE(xml);
5131 } else {
5132 pool = virStoragePoolCreateXML(ctl->conn, xml, 0);
5133 VIR_FREE(xml);
5135 if (pool != NULL) {
5136 vshPrint(ctl, _("Pool %s created\n"), name);
5137 virStoragePoolFree(pool);
5138 } else {
5139 vshError(ctl, _("Failed to create pool %s"), name);
5140 return FALSE;
5143 return TRUE;
5148 * "pool-define" command
5150 static const vshCmdInfo info_pool_define[] = {
5151 {"help", N_("define (but don't start) a pool from an XML file")},
5152 {"desc", N_("Define a pool.")},
5153 {NULL, NULL}
5156 static const vshCmdOptDef opts_pool_define[] = {
5157 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML pool description")},
5158 {NULL, 0, 0, NULL}
5161 static int
5162 cmdPoolDefine(vshControl *ctl, const vshCmd *cmd)
5164 virStoragePoolPtr pool;
5165 char *from;
5166 int found;
5167 int ret = TRUE;
5168 char *buffer;
5170 if (!vshConnectionUsability(ctl, ctl->conn))
5171 return FALSE;
5173 from = vshCommandOptString(cmd, "file", &found);
5174 if (!found)
5175 return FALSE;
5177 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
5178 return FALSE;
5180 pool = virStoragePoolDefineXML(ctl->conn, buffer, 0);
5181 VIR_FREE(buffer);
5183 if (pool != NULL) {
5184 vshPrint(ctl, _("Pool %s defined from %s\n"),
5185 virStoragePoolGetName(pool), from);
5186 virStoragePoolFree(pool);
5187 } else {
5188 vshError(ctl, _("Failed to define pool from %s"), from);
5189 ret = FALSE;
5191 return ret;
5196 * "pool-define-as" command
5198 static const vshCmdInfo info_pool_define_as[] = {
5199 {"help", N_("define a pool from a set of args")},
5200 {"desc", N_("Define a pool.")},
5201 {NULL, NULL}
5204 static int
5205 cmdPoolDefineAs(vshControl *ctl, const vshCmd *cmd)
5207 virStoragePoolPtr pool;
5208 char *xml, *name;
5209 int printXML = vshCommandOptBool(cmd, "print-xml");
5211 if (!vshConnectionUsability(ctl, ctl->conn))
5212 return FALSE;
5214 if (!buildPoolXML(cmd, &name, &xml))
5215 return FALSE;
5217 if (printXML) {
5218 vshPrint(ctl, "%s", xml);
5219 VIR_FREE(xml);
5220 } else {
5221 pool = virStoragePoolDefineXML(ctl->conn, xml, 0);
5222 VIR_FREE(xml);
5224 if (pool != NULL) {
5225 vshPrint(ctl, _("Pool %s defined\n"), name);
5226 virStoragePoolFree(pool);
5227 } else {
5228 vshError(ctl, _("Failed to define pool %s"), name);
5229 return FALSE;
5232 return TRUE;
5237 * "pool-build" command
5239 static const vshCmdInfo info_pool_build[] = {
5240 {"help", N_("build a pool")},
5241 {"desc", N_("Build a given pool.")},
5242 {NULL, NULL}
5245 static const vshCmdOptDef opts_pool_build[] = {
5246 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5247 {NULL, 0, 0, NULL}
5250 static int
5251 cmdPoolBuild(vshControl *ctl, const vshCmd *cmd)
5253 virStoragePoolPtr pool;
5254 int ret = TRUE;
5255 char *name;
5257 if (!vshConnectionUsability(ctl, ctl->conn))
5258 return FALSE;
5260 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5261 return FALSE;
5263 if (virStoragePoolBuild(pool, 0) == 0) {
5264 vshPrint(ctl, _("Pool %s built\n"), name);
5265 } else {
5266 vshError(ctl, _("Failed to build pool %s"), name);
5267 ret = FALSE;
5270 virStoragePoolFree(pool);
5272 return ret;
5277 * "pool-destroy" command
5279 static const vshCmdInfo info_pool_destroy[] = {
5280 {"help", N_("destroy a pool")},
5281 {"desc", N_("Destroy a given pool.")},
5282 {NULL, NULL}
5285 static const vshCmdOptDef opts_pool_destroy[] = {
5286 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5287 {NULL, 0, 0, NULL}
5290 static int
5291 cmdPoolDestroy(vshControl *ctl, const vshCmd *cmd)
5293 virStoragePoolPtr pool;
5294 int ret = TRUE;
5295 char *name;
5297 if (!vshConnectionUsability(ctl, ctl->conn))
5298 return FALSE;
5300 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5301 return FALSE;
5303 if (virStoragePoolDestroy(pool) == 0) {
5304 vshPrint(ctl, _("Pool %s destroyed\n"), name);
5305 } else {
5306 vshError(ctl, _("Failed to destroy pool %s"), name);
5307 ret = FALSE;
5310 virStoragePoolFree(pool);
5311 return ret;
5316 * "pool-delete" command
5318 static const vshCmdInfo info_pool_delete[] = {
5319 {"help", N_("delete a pool")},
5320 {"desc", N_("Delete a given pool.")},
5321 {NULL, NULL}
5324 static const vshCmdOptDef opts_pool_delete[] = {
5325 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5326 {NULL, 0, 0, NULL}
5329 static int
5330 cmdPoolDelete(vshControl *ctl, const vshCmd *cmd)
5332 virStoragePoolPtr pool;
5333 int ret = TRUE;
5334 char *name;
5336 if (!vshConnectionUsability(ctl, ctl->conn))
5337 return FALSE;
5339 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5340 return FALSE;
5342 if (virStoragePoolDelete(pool, 0) == 0) {
5343 vshPrint(ctl, _("Pool %s deleted\n"), name);
5344 } else {
5345 vshError(ctl, _("Failed to delete pool %s"), name);
5346 ret = FALSE;
5349 virStoragePoolFree(pool);
5350 return ret;
5355 * "pool-refresh" command
5357 static const vshCmdInfo info_pool_refresh[] = {
5358 {"help", N_("refresh a pool")},
5359 {"desc", N_("Refresh a given pool.")},
5360 {NULL, NULL}
5363 static const vshCmdOptDef opts_pool_refresh[] = {
5364 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5365 {NULL, 0, 0, NULL}
5368 static int
5369 cmdPoolRefresh(vshControl *ctl, const vshCmd *cmd)
5371 virStoragePoolPtr pool;
5372 int ret = TRUE;
5373 char *name;
5375 if (!vshConnectionUsability(ctl, ctl->conn))
5376 return FALSE;
5378 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5379 return FALSE;
5381 if (virStoragePoolRefresh(pool, 0) == 0) {
5382 vshPrint(ctl, _("Pool %s refreshed\n"), name);
5383 } else {
5384 vshError(ctl, _("Failed to refresh pool %s"), name);
5385 ret = FALSE;
5387 virStoragePoolFree(pool);
5389 return ret;
5394 * "pool-dumpxml" command
5396 static const vshCmdInfo info_pool_dumpxml[] = {
5397 {"help", N_("pool information in XML")},
5398 {"desc", N_("Output the pool information as an XML dump to stdout.")},
5399 {NULL, NULL}
5402 static const vshCmdOptDef opts_pool_dumpxml[] = {
5403 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5404 {NULL, 0, 0, NULL}
5407 static int
5408 cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd)
5410 virStoragePoolPtr pool;
5411 int ret = TRUE;
5412 char *dump;
5414 if (!vshConnectionUsability(ctl, ctl->conn))
5415 return FALSE;
5417 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
5418 return FALSE;
5420 dump = virStoragePoolGetXMLDesc(pool, 0);
5421 if (dump != NULL) {
5422 vshPrint(ctl, "%s", dump);
5423 VIR_FREE(dump);
5424 } else {
5425 ret = FALSE;
5428 virStoragePoolFree(pool);
5429 return ret;
5434 * "pool-list" command
5436 static const vshCmdInfo info_pool_list[] = {
5437 {"help", N_("list pools")},
5438 {"desc", N_("Returns list of pools.")},
5439 {NULL, NULL}
5442 static const vshCmdOptDef opts_pool_list[] = {
5443 {"inactive", VSH_OT_BOOL, 0, N_("list inactive pools")},
5444 {"all", VSH_OT_BOOL, 0, N_("list inactive & active pools")},
5445 {"details", VSH_OT_BOOL, 0, N_("display extended details for pools")},
5446 {NULL, 0, 0, NULL}
5449 static int
5450 cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
5452 virStoragePoolInfo info;
5453 char **poolNames = NULL;
5454 int i, functionReturn, ret;
5455 int numActivePools = 0, numInactivePools = 0, numAllPools = 0;
5456 size_t stringLength = 0, nameStrLength = 0;
5457 size_t autostartStrLength = 0, persistStrLength = 0;
5458 size_t stateStrLength = 0, capStrLength = 0;
5459 size_t allocStrLength = 0, availStrLength = 0;
5460 struct poolInfoText {
5461 char *state;
5462 char *autostart;
5463 char *persistent;
5464 char *capacity;
5465 char *allocation;
5466 char *available;
5468 struct poolInfoText *poolInfoTexts = NULL;
5470 /* Determine the options passed by the user */
5471 int all = vshCommandOptBool(cmd, "all");
5472 int details = vshCommandOptBool(cmd, "details");
5473 int inactive = vshCommandOptBool(cmd, "inactive");
5474 int active = !inactive || all ? 1 : 0;
5475 inactive |= all;
5477 /* Check the connection to libvirtd daemon is still working */
5478 if (!vshConnectionUsability(ctl, ctl->conn))
5479 return FALSE;
5481 /* Retrieve the number of active storage pools */
5482 if (active) {
5483 numActivePools = virConnectNumOfStoragePools(ctl->conn);
5484 if (numActivePools < 0) {
5485 vshError(ctl, "%s", _("Failed to list active pools"));
5486 return FALSE;
5490 /* Retrieve the number of inactive storage pools */
5491 if (inactive) {
5492 numInactivePools = virConnectNumOfDefinedStoragePools(ctl->conn);
5493 if (numInactivePools < 0) {
5494 vshError(ctl, "%s", _("Failed to list inactive pools"));
5495 return FALSE;
5499 /* Determine the total number of pools to list */
5500 numAllPools = numActivePools + numInactivePools;
5502 /* Allocate memory for arrays of storage pool names and info */
5503 poolNames = vshCalloc(ctl, numAllPools, sizeof(*poolNames));
5504 poolInfoTexts =
5505 vshCalloc(ctl, numAllPools, sizeof(*poolInfoTexts));
5507 /* Retrieve a list of active storage pool names */
5508 if (active) {
5509 if ((virConnectListStoragePools(ctl->conn,
5510 poolNames, numActivePools)) < 0) {
5511 vshError(ctl, "%s", _("Failed to list active pools"));
5512 VIR_FREE(poolInfoTexts);
5513 VIR_FREE(poolNames);
5514 return FALSE;
5518 /* Add the inactive storage pools to the end of the name list */
5519 if (inactive) {
5520 if ((virConnectListDefinedStoragePools(ctl->conn,
5521 &poolNames[numActivePools],
5522 numInactivePools)) < 0) {
5523 vshError(ctl, "%s", _("Failed to list inactive pools"));
5524 VIR_FREE(poolInfoTexts);
5525 VIR_FREE(poolNames);
5526 return FALSE;
5530 /* Sort the storage pool names */
5531 qsort(poolNames, numAllPools, sizeof(*poolNames), namesorter);
5533 /* Collect the storage pool information for display */
5534 for (i = 0; i < numAllPools; i++) {
5535 int autostart = 0, persistent = 0;
5537 /* Retrieve a pool object, looking it up by name */
5538 virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn,
5539 poolNames[i]);
5540 if (!pool) {
5541 VIR_FREE(poolNames[i]);
5542 continue;
5545 /* Retrieve the autostart status of the pool */
5546 if (virStoragePoolGetAutostart(pool, &autostart) < 0)
5547 poolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart"));
5548 else
5549 poolInfoTexts[i].autostart = vshStrdup(ctl, autostart ?
5550 _("yes") : _("no"));
5552 /* Retrieve the persistence status of the pool */
5553 if (details) {
5554 persistent = virStoragePoolIsPersistent(pool);
5555 vshDebug(ctl, 5, "Persistent flag value: %d\n", persistent);
5556 if (persistent < 0)
5557 poolInfoTexts[i].persistent = vshStrdup(ctl, _("unknown"));
5558 else
5559 poolInfoTexts[i].persistent = vshStrdup(ctl, persistent ?
5560 _("yes") : _("no"));
5562 /* Keep the length of persistent string if longest so far */
5563 stringLength = strlen(poolInfoTexts[i].persistent);
5564 if (stringLength > persistStrLength)
5565 persistStrLength = stringLength;
5568 /* Collect further extended information about the pool */
5569 if (virStoragePoolGetInfo(pool, &info) != 0) {
5570 /* Something went wrong retrieving pool info, cope with it */
5571 vshError(ctl, "%s", _("Could not retrieve pool information"));
5572 poolInfoTexts[i].state = vshStrdup(ctl, _("unknown"));
5573 if (details) {
5574 poolInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
5575 poolInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
5576 poolInfoTexts[i].available = vshStrdup(ctl, _("unknown"));
5578 } else {
5579 /* Decide which state string to display */
5580 if (details) {
5581 /* --details option was specified, we're using detailed state
5582 * strings */
5583 switch (info.state) {
5584 case VIR_STORAGE_POOL_INACTIVE:
5585 poolInfoTexts[i].state = vshStrdup(ctl, _("inactive"));
5586 break;
5587 case VIR_STORAGE_POOL_BUILDING:
5588 poolInfoTexts[i].state = vshStrdup(ctl, _("building"));
5589 break;
5590 case VIR_STORAGE_POOL_RUNNING:
5591 poolInfoTexts[i].state = vshStrdup(ctl, _("running"));
5592 break;
5593 case VIR_STORAGE_POOL_DEGRADED:
5594 poolInfoTexts[i].state = vshStrdup(ctl, _("degraded"));
5595 break;
5596 case VIR_STORAGE_POOL_INACCESSIBLE:
5597 poolInfoTexts[i].state = vshStrdup(ctl, _("inaccessible"));
5598 break;
5601 /* Create the pool size related strings */
5602 if (info.state == VIR_STORAGE_POOL_RUNNING ||
5603 info.state == VIR_STORAGE_POOL_DEGRADED) {
5604 double val;
5605 const char *unit;
5607 /* Create the capacity output string */
5608 val = prettyCapacity(info.capacity, &unit);
5609 ret = virAsprintf(&poolInfoTexts[i].capacity,
5610 "%.2lf %s", val, unit);
5611 if (ret < 0) {
5612 /* An error occurred creating the string, return */
5613 goto asprintf_failure;
5616 /* Create the allocation output string */
5617 val = prettyCapacity(info.allocation, &unit);
5618 ret = virAsprintf(&poolInfoTexts[i].allocation,
5619 "%.2lf %s", val, unit);
5620 if (ret < 0) {
5621 /* An error occurred creating the string, return */
5622 goto asprintf_failure;
5625 /* Create the available space output string */
5626 val = prettyCapacity(info.available, &unit);
5627 ret = virAsprintf(&poolInfoTexts[i].available,
5628 "%.2lf %s", val, unit);
5629 if (ret < 0) {
5630 /* An error occurred creating the string, return */
5631 goto asprintf_failure;
5633 } else {
5634 /* Capacity related information isn't available */
5635 poolInfoTexts[i].capacity = vshStrdup(ctl, _("-"));
5636 poolInfoTexts[i].allocation = vshStrdup(ctl, _("-"));
5637 poolInfoTexts[i].available = vshStrdup(ctl, _("-"));
5640 /* Keep the length of capacity string if longest so far */
5641 stringLength = strlen(poolInfoTexts[i].capacity);
5642 if (stringLength > capStrLength)
5643 capStrLength = stringLength;
5645 /* Keep the length of allocation string if longest so far */
5646 stringLength = strlen(poolInfoTexts[i].allocation);
5647 if (stringLength > allocStrLength)
5648 allocStrLength = stringLength;
5650 /* Keep the length of available string if longest so far */
5651 stringLength = strlen(poolInfoTexts[i].available);
5652 if (stringLength > availStrLength)
5653 availStrLength = stringLength;
5654 } else {
5655 /* --details option was not specified, only active/inactive
5656 * state strings are used */
5657 if (info.state == VIR_STORAGE_POOL_INACTIVE)
5658 poolInfoTexts[i].state = vshStrdup(ctl, _("inactive"));
5659 else
5660 poolInfoTexts[i].state = vshStrdup(ctl, _("active"));
5664 /* Keep the length of name string if longest so far */
5665 stringLength = strlen(poolNames[i]);
5666 if (stringLength > nameStrLength)
5667 nameStrLength = stringLength;
5669 /* Keep the length of state string if longest so far */
5670 stringLength = strlen(poolInfoTexts[i].state);
5671 if (stringLength > stateStrLength)
5672 stateStrLength = stringLength;
5674 /* Keep the length of autostart string if longest so far */
5675 stringLength = strlen(poolInfoTexts[i].autostart);
5676 if (stringLength > autostartStrLength)
5677 autostartStrLength = stringLength;
5679 /* Free the pool object */
5680 virStoragePoolFree(pool);
5683 /* If the --details option wasn't selected, we output the pool
5684 * info using the fixed string format from previous versions to
5685 * maintain backward compatibility.
5688 /* Output basic info then return if --details option not selected */
5689 if (!details) {
5690 /* Output old style header */
5691 vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("State"),
5692 _("Autostart"));
5693 vshPrintExtra(ctl, "-----------------------------------------\n");
5695 /* Output old style pool info */
5696 for (i = 0; i < numAllPools; i++) {
5697 vshPrint(ctl, "%-20s %-10s %-10s\n",
5698 poolNames[i],
5699 poolInfoTexts[i].state,
5700 poolInfoTexts[i].autostart);
5703 /* Cleanup and return */
5704 functionReturn = TRUE;
5705 goto cleanup;
5708 /* We only get here if the --details option was selected. */
5710 /* Use the length of name header string if it's longest */
5711 stringLength = strlen(_("Name"));
5712 if (stringLength > nameStrLength)
5713 nameStrLength = stringLength;
5715 /* Use the length of state header string if it's longest */
5716 stringLength = strlen(_("State"));
5717 if (stringLength > stateStrLength)
5718 stateStrLength = stringLength;
5720 /* Use the length of autostart header string if it's longest */
5721 stringLength = strlen(_("Autostart"));
5722 if (stringLength > autostartStrLength)
5723 autostartStrLength = stringLength;
5725 /* Use the length of persistent header string if it's longest */
5726 stringLength = strlen(_("Persistent"));
5727 if (stringLength > persistStrLength)
5728 persistStrLength = stringLength;
5730 /* Use the length of capacity header string if it's longest */
5731 stringLength = strlen(_("Capacity"));
5732 if (stringLength > capStrLength)
5733 capStrLength = stringLength;
5735 /* Use the length of allocation header string if it's longest */
5736 stringLength = strlen(_("Allocation"));
5737 if (stringLength > allocStrLength)
5738 allocStrLength = stringLength;
5740 /* Use the length of available header string if it's longest */
5741 stringLength = strlen(_("Available"));
5742 if (stringLength > availStrLength)
5743 availStrLength = stringLength;
5745 /* Display the string lengths for debugging. */
5746 vshDebug(ctl, 5, "Longest name string = %lu chars\n",
5747 (unsigned long) nameStrLength);
5748 vshDebug(ctl, 5, "Longest state string = %lu chars\n",
5749 (unsigned long) stateStrLength);
5750 vshDebug(ctl, 5, "Longest autostart string = %lu chars\n",
5751 (unsigned long) autostartStrLength);
5752 vshDebug(ctl, 5, "Longest persistent string = %lu chars\n",
5753 (unsigned long) persistStrLength);
5754 vshDebug(ctl, 5, "Longest capacity string = %lu chars\n",
5755 (unsigned long) capStrLength);
5756 vshDebug(ctl, 5, "Longest allocation string = %lu chars\n",
5757 (unsigned long) allocStrLength);
5758 vshDebug(ctl, 5, "Longest available string = %lu chars\n",
5759 (unsigned long) availStrLength);
5761 /* Create the output template. Each column is sized according to
5762 * the longest string.
5764 char *outputStr;
5765 ret = virAsprintf(&outputStr,
5766 "%%-%lus %%-%lus %%-%lus %%-%lus %%%lus %%%lus %%%lus\n",
5767 (unsigned long) nameStrLength,
5768 (unsigned long) stateStrLength,
5769 (unsigned long) autostartStrLength,
5770 (unsigned long) persistStrLength,
5771 (unsigned long) capStrLength,
5772 (unsigned long) allocStrLength,
5773 (unsigned long) availStrLength);
5774 if (ret < 0) {
5775 /* An error occurred creating the string, return */
5776 goto asprintf_failure;
5779 /* Display the header */
5780 vshPrint(ctl, outputStr, _("Name"), _("State"), _("Autostart"),
5781 _("Persistent"), _("Capacity"), _("Allocation"), _("Available"));
5782 for (i = nameStrLength + stateStrLength + autostartStrLength
5783 + persistStrLength + capStrLength
5784 + allocStrLength + availStrLength
5785 + 12; i > 0; i--)
5786 vshPrintExtra(ctl, "-");
5787 vshPrintExtra(ctl, "\n");
5789 /* Display the pool info rows */
5790 for (i = 0; i < numAllPools; i++) {
5791 vshPrint(ctl, outputStr,
5792 poolNames[i],
5793 poolInfoTexts[i].state,
5794 poolInfoTexts[i].autostart,
5795 poolInfoTexts[i].persistent,
5796 poolInfoTexts[i].capacity,
5797 poolInfoTexts[i].allocation,
5798 poolInfoTexts[i].available);
5801 /* Cleanup and return */
5802 functionReturn = TRUE;
5803 goto cleanup;
5805 asprintf_failure:
5807 /* Display an appropriate error message then cleanup and return */
5808 switch (errno) {
5809 case ENOMEM:
5810 /* Couldn't allocate memory */
5811 vshError(ctl, "%s", _("Out of memory"));
5812 break;
5813 default:
5814 /* Some other error */
5815 vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
5817 functionReturn = FALSE;
5819 cleanup:
5821 /* Safely free the memory allocated in this function */
5822 for (i = 0; i < numAllPools; i++) {
5823 /* Cleanup the memory for one pool info structure */
5824 VIR_FREE(poolInfoTexts[i].state);
5825 VIR_FREE(poolInfoTexts[i].autostart);
5826 VIR_FREE(poolInfoTexts[i].persistent);
5827 VIR_FREE(poolInfoTexts[i].capacity);
5828 VIR_FREE(poolInfoTexts[i].allocation);
5829 VIR_FREE(poolInfoTexts[i].available);
5830 VIR_FREE(poolNames[i]);
5833 /* Cleanup the memory for the initial arrays*/
5834 VIR_FREE(poolInfoTexts);
5835 VIR_FREE(poolNames);
5837 /* Return the desired value */
5838 return functionReturn;
5842 * "find-storage-pool-sources-as" command
5844 static const vshCmdInfo info_find_storage_pool_sources_as[] = {
5845 {"help", N_("find potential storage pool sources")},
5846 {"desc", N_("Returns XML <sources> document.")},
5847 {NULL, NULL}
5850 static const vshCmdOptDef opts_find_storage_pool_sources_as[] = {
5851 {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
5852 N_("type of storage pool sources to find")},
5853 {"host", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional host to query")},
5854 {"port", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional port to query")},
5855 {"initiator", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional initiator IQN to use for query")},
5856 {NULL, 0, 0, NULL}
5859 static int
5860 cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
5862 char *type, *host;
5863 char *srcSpec = NULL;
5864 char *srcList;
5865 char *initiator;
5866 int found;
5868 type = vshCommandOptString(cmd, "type", &found);
5869 if (!found)
5870 return FALSE;
5871 host = vshCommandOptString(cmd, "host", &found);
5872 if (!found)
5873 host = NULL;
5874 initiator = vshCommandOptString(cmd, "initiator", &found);
5875 if (!found)
5876 initiator = NULL;
5878 if (!vshConnectionUsability(ctl, ctl->conn))
5879 return FALSE;
5881 if (host) {
5882 char *port = vshCommandOptString(cmd, "port", &found);
5883 if (!found)
5884 port = NULL;
5885 virBuffer buf = VIR_BUFFER_INITIALIZER;
5886 virBufferAddLit(&buf, "<source>\n");
5887 virBufferVSprintf(&buf, " <host name='%s'", host);
5888 if (port)
5889 virBufferVSprintf(&buf, " port='%s'", port);
5890 virBufferAddLit(&buf, "/>\n");
5891 if (initiator) {
5892 virBufferAddLit(&buf, " <initiator>\n");
5893 virBufferVSprintf(&buf, " <iqn name='%s'/>\n", initiator);
5894 virBufferAddLit(&buf, " </initiator>\n");
5896 virBufferAddLit(&buf, "</source>\n");
5897 if (virBufferError(&buf)) {
5898 vshError(ctl, "%s", _("Out of memory"));
5899 return FALSE;
5901 srcSpec = virBufferContentAndReset(&buf);
5904 srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
5905 VIR_FREE(srcSpec);
5906 if (srcList == NULL) {
5907 vshError(ctl, _("Failed to find any %s pool sources"), type);
5908 return FALSE;
5910 vshPrint(ctl, "%s", srcList);
5911 VIR_FREE(srcList);
5913 return TRUE;
5918 * "find-storage-pool-sources" command
5920 static const vshCmdInfo info_find_storage_pool_sources[] = {
5921 {"help", N_("discover potential storage pool sources")},
5922 {"desc", N_("Returns XML <sources> document.")},
5923 {NULL, NULL}
5926 static const vshCmdOptDef opts_find_storage_pool_sources[] = {
5927 {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
5928 N_("type of storage pool sources to discover")},
5929 {"srcSpec", VSH_OT_DATA, VSH_OFLAG_NONE,
5930 N_("optional file of source xml to query for pools")},
5931 {NULL, 0, 0, NULL}
5934 static int
5935 cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
5937 char *type, *srcSpecFile, *srcList;
5938 char *srcSpec = NULL;
5939 int found;
5941 type = vshCommandOptString(cmd, "type", &found);
5942 if (!found)
5943 return FALSE;
5944 srcSpecFile = vshCommandOptString(cmd, "srcSpec", &found);
5945 if (!found)
5946 srcSpecFile = NULL;
5948 if (!vshConnectionUsability(ctl, ctl->conn))
5949 return FALSE;
5951 if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0)
5952 return FALSE;
5954 srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
5955 VIR_FREE(srcSpec);
5956 if (srcList == NULL) {
5957 vshError(ctl, _("Failed to find any %s pool sources"), type);
5958 return FALSE;
5960 vshPrint(ctl, "%s", srcList);
5961 VIR_FREE(srcList);
5963 return TRUE;
5968 * "pool-info" command
5970 static const vshCmdInfo info_pool_info[] = {
5971 {"help", N_("storage pool information")},
5972 {"desc", N_("Returns basic information about the storage pool.")},
5973 {NULL, NULL}
5976 static const vshCmdOptDef opts_pool_info[] = {
5977 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5978 {NULL, 0, 0, NULL}
5981 static int
5982 cmdPoolInfo(vshControl *ctl, const vshCmd *cmd)
5984 virStoragePoolInfo info;
5985 virStoragePoolPtr pool;
5986 int autostart = 0;
5987 int persistent = 0;
5988 int ret = TRUE;
5989 char uuid[VIR_UUID_STRING_BUFLEN];
5991 if (!vshConnectionUsability(ctl, ctl->conn))
5992 return FALSE;
5994 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
5995 return FALSE;
5997 vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool));
5999 if (virStoragePoolGetUUIDString(pool, &uuid[0])==0)
6000 vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
6002 if (virStoragePoolGetInfo(pool, &info) == 0) {
6003 double val;
6004 const char *unit;
6005 switch (info.state) {
6006 case VIR_STORAGE_POOL_INACTIVE:
6007 vshPrint(ctl, "%-15s %s\n", _("State:"),
6008 _("inactive"));
6009 break;
6010 case VIR_STORAGE_POOL_BUILDING:
6011 vshPrint(ctl, "%-15s %s\n", _("State:"),
6012 _("building"));
6013 break;
6014 case VIR_STORAGE_POOL_RUNNING:
6015 vshPrint(ctl, "%-15s %s\n", _("State:"),
6016 _("running"));
6017 break;
6018 case VIR_STORAGE_POOL_DEGRADED:
6019 vshPrint(ctl, "%-15s %s\n", _("State:"),
6020 _("degraded"));
6021 break;
6022 case VIR_STORAGE_POOL_INACCESSIBLE:
6023 vshPrint(ctl, "%-15s %s\n", _("State:"),
6024 _("inaccessible"));
6025 break;
6028 /* Check and display whether the pool is persistent or not */
6029 persistent = virStoragePoolIsPersistent(pool);
6030 vshDebug(ctl, 5, "Pool persistent flag value: %d\n", persistent);
6031 if (persistent < 0)
6032 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
6033 else
6034 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));
6036 /* Check and display whether the pool is autostarted or not */
6037 virStoragePoolGetAutostart(pool, &autostart);
6038 vshDebug(ctl, 5, "Pool autostart flag value: %d\n", autostart);
6039 if (autostart < 0)
6040 vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart"));
6041 else
6042 vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));
6044 if (info.state == VIR_STORAGE_POOL_RUNNING ||
6045 info.state == VIR_STORAGE_POOL_DEGRADED) {
6046 val = prettyCapacity(info.capacity, &unit);
6047 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);
6049 val = prettyCapacity(info.allocation, &unit);
6050 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
6052 val = prettyCapacity(info.available, &unit);
6053 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit);
6055 } else {
6056 ret = FALSE;
6059 virStoragePoolFree(pool);
6060 return ret;
6065 * "pool-name" command
6067 static const vshCmdInfo info_pool_name[] = {
6068 {"help", N_("convert a pool UUID to pool name")},
6069 {"desc", ""},
6070 {NULL, NULL}
6073 static const vshCmdOptDef opts_pool_name[] = {
6074 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")},
6075 {NULL, 0, 0, NULL}
6078 static int
6079 cmdPoolName(vshControl *ctl, const vshCmd *cmd)
6081 virStoragePoolPtr pool;
6083 if (!vshConnectionUsability(ctl, ctl->conn))
6084 return FALSE;
6085 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6086 VSH_BYUUID)))
6087 return FALSE;
6089 vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
6090 virStoragePoolFree(pool);
6091 return TRUE;
6096 * "pool-start" command
6098 static const vshCmdInfo info_pool_start[] = {
6099 {"help", N_("start a (previously defined) inactive pool")},
6100 {"desc", N_("Start a pool.")},
6101 {NULL, NULL}
6104 static const vshCmdOptDef opts_pool_start[] = {
6105 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive pool")},
6106 {NULL, 0, 0, NULL}
6109 static int
6110 cmdPoolStart(vshControl *ctl, const vshCmd *cmd)
6112 virStoragePoolPtr pool;
6113 int ret = TRUE;
6115 if (!vshConnectionUsability(ctl, ctl->conn))
6116 return FALSE;
6118 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
6119 return FALSE;
6121 if (virStoragePoolCreate(pool, 0) == 0) {
6122 vshPrint(ctl, _("Pool %s started\n"),
6123 virStoragePoolGetName(pool));
6124 } else {
6125 vshError(ctl, _("Failed to start pool %s"), virStoragePoolGetName(pool));
6126 ret = FALSE;
6129 virStoragePoolFree(pool);
6130 return ret;
6135 * "vol-create-as" command
6137 static const vshCmdInfo info_vol_create_as[] = {
6138 {"help", N_("create a volume from a set of args")},
6139 {"desc", N_("Create a vol.")},
6140 {NULL, NULL}
6143 static const vshCmdOptDef opts_vol_create_as[] = {
6144 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6145 {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")},
6146 {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, N_("size of the vol with optional k,M,G,T suffix")},
6147 {"allocation", VSH_OT_STRING, 0, N_("initial allocation size with optional k,M,G,T suffix")},
6148 {"format", VSH_OT_STRING, 0, N_("file format type raw,bochs,qcow,qcow2,vmdk")},
6149 {"backing-vol", VSH_OT_STRING, 0, N_("the backing volume if taking a snapshot")},
6150 {"backing-vol-format", VSH_OT_STRING, 0, N_("format of backing volume if taking a snapshot")},
6151 {NULL, 0, 0, NULL}
6154 static int cmdVolSize(const char *data, unsigned long long *val)
6156 char *end;
6157 if (virStrToLong_ull(data, &end, 10, val) < 0)
6158 return -1;
6160 if (end && *end) {
6161 /* Deliberate fallthrough cases here :-) */
6162 switch (*end) {
6163 case 'T':
6164 *val *= 1024;
6165 case 'G':
6166 *val *= 1024;
6167 case 'M':
6168 *val *= 1024;
6169 case 'k':
6170 *val *= 1024;
6171 break;
6172 default:
6173 return -1;
6175 end++;
6176 if (*end)
6177 return -1;
6179 return 0;
6182 static int
6183 cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd)
6185 virStoragePoolPtr pool;
6186 virStorageVolPtr vol;
6187 int found;
6188 char *xml;
6189 char *name, *capacityStr, *allocationStr, *format;
6190 char *snapshotStrVol, *snapshotStrFormat;
6191 unsigned long long capacity, allocation = 0;
6192 virBuffer buf = VIR_BUFFER_INITIALIZER;
6194 if (!vshConnectionUsability(ctl, ctl->conn))
6195 return FALSE;
6197 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6198 VSH_BYNAME)))
6199 return FALSE;
6201 name = vshCommandOptString(cmd, "name", &found);
6202 if (!found)
6203 goto cleanup;
6205 capacityStr = vshCommandOptString(cmd, "capacity", &found);
6206 if (!found)
6207 goto cleanup;
6208 if (cmdVolSize(capacityStr, &capacity) < 0)
6209 vshError(ctl, _("Malformed size %s"), capacityStr);
6211 allocationStr = vshCommandOptString(cmd, "allocation", &found);
6212 if (allocationStr &&
6213 cmdVolSize(allocationStr, &allocation) < 0)
6214 vshError(ctl, _("Malformed size %s"), allocationStr);
6216 format = vshCommandOptString(cmd, "format", &found);
6217 snapshotStrVol = vshCommandOptString(cmd, "backing-vol", &found);
6218 snapshotStrFormat = vshCommandOptString(cmd, "backing-vol-format", &found);
6220 virBufferAddLit(&buf, "<volume>\n");
6221 virBufferVSprintf(&buf, " <name>%s</name>\n", name);
6222 virBufferVSprintf(&buf, " <capacity>%llu</capacity>\n", capacity);
6223 if (allocationStr)
6224 virBufferVSprintf(&buf, " <allocation>%llu</allocation>\n", allocation);
6226 if (format) {
6227 virBufferAddLit(&buf, " <target>\n");
6228 virBufferVSprintf(&buf, " <format type='%s'/>\n",format);
6229 virBufferAddLit(&buf, " </target>\n");
6232 /* Convert the snapshot parameters into backingStore XML */
6233 if (snapshotStrVol) {
6234 /* Lookup snapshot backing volume. Try the backing-vol
6235 * parameter as a name */
6236 vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as name\n",
6237 cmd->def->name, snapshotStrVol);
6238 virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol);
6239 if (snapVol)
6240 vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as name\n",
6241 cmd->def->name, snapshotStrVol);
6243 if (snapVol == NULL) {
6244 /* Snapshot backing volume not found by name. Try the
6245 * backing-vol parameter as a key */
6246 vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as key\n",
6247 cmd->def->name, snapshotStrVol);
6248 snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol);
6249 if (snapVol)
6250 vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as key\n",
6251 cmd->def->name, snapshotStrVol);
6253 if (snapVol == NULL) {
6254 /* Snapshot backing volume not found by key. Try the
6255 * backing-vol parameter as a path */
6256 vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as path\n",
6257 cmd->def->name, snapshotStrVol);
6258 snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol);
6259 if (snapVol)
6260 vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as path\n",
6261 cmd->def->name, snapshotStrVol);
6263 if (snapVol == NULL) {
6264 vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol);
6265 return FALSE;
6268 char *snapshotStrVolPath;
6269 if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) {
6270 virStorageVolFree(snapVol);
6271 return FALSE;
6274 /* Create XML for the backing store */
6275 virBufferAddLit(&buf, " <backingStore>\n");
6276 virBufferVSprintf(&buf, " <path>%s</path>\n",snapshotStrVolPath);
6277 if (snapshotStrFormat)
6278 virBufferVSprintf(&buf, " <format type='%s'/>\n",snapshotStrFormat);
6279 virBufferAddLit(&buf, " </backingStore>\n");
6281 /* Cleanup snapshot allocations */
6282 VIR_FREE(snapshotStrVolPath);
6283 virStorageVolFree(snapVol);
6286 virBufferAddLit(&buf, "</volume>\n");
6288 if (virBufferError(&buf)) {
6289 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
6290 return FALSE;
6292 xml = virBufferContentAndReset(&buf);
6293 vol = virStorageVolCreateXML(pool, xml, 0);
6294 VIR_FREE(xml);
6295 virStoragePoolFree(pool);
6297 if (vol != NULL) {
6298 vshPrint(ctl, _("Vol %s created\n"), name);
6299 virStorageVolFree(vol);
6300 return TRUE;
6301 } else {
6302 vshError(ctl, _("Failed to create vol %s"), name);
6303 return FALSE;
6306 cleanup:
6307 virBufferFreeAndReset(&buf);
6308 virStoragePoolFree(pool);
6309 return FALSE;
6314 * "pool-undefine" command
6316 static const vshCmdInfo info_pool_undefine[] = {
6317 {"help", N_("undefine an inactive pool")},
6318 {"desc", N_("Undefine the configuration for an inactive pool.")},
6319 {NULL, NULL}
6322 static const vshCmdOptDef opts_pool_undefine[] = {
6323 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
6324 {NULL, 0, 0, NULL}
6327 static int
6328 cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd)
6330 virStoragePoolPtr pool;
6331 int ret = TRUE;
6332 char *name;
6334 if (!vshConnectionUsability(ctl, ctl->conn))
6335 return FALSE;
6337 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
6338 return FALSE;
6340 if (virStoragePoolUndefine(pool) == 0) {
6341 vshPrint(ctl, _("Pool %s has been undefined\n"), name);
6342 } else {
6343 vshError(ctl, _("Failed to undefine pool %s"), name);
6344 ret = FALSE;
6347 virStoragePoolFree(pool);
6348 return ret;
6353 * "pool-uuid" command
6355 static const vshCmdInfo info_pool_uuid[] = {
6356 {"help", N_("convert a pool name to pool UUID")},
6357 {"desc", ""},
6358 {NULL, NULL}
6361 static const vshCmdOptDef opts_pool_uuid[] = {
6362 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6363 {NULL, 0, 0, NULL}
6366 static int
6367 cmdPoolUuid(vshControl *ctl, const vshCmd *cmd)
6369 virStoragePoolPtr pool;
6370 char uuid[VIR_UUID_STRING_BUFLEN];
6372 if (!vshConnectionUsability(ctl, ctl->conn))
6373 return FALSE;
6375 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6376 VSH_BYNAME)))
6377 return FALSE;
6379 if (virStoragePoolGetUUIDString(pool, uuid) != -1)
6380 vshPrint(ctl, "%s\n", uuid);
6381 else
6382 vshError(ctl, "%s", _("failed to get pool UUID"));
6384 virStoragePoolFree(pool);
6385 return TRUE;
6390 * "vol-create" command
6392 static const vshCmdInfo info_vol_create[] = {
6393 {"help", N_("create a vol from an XML file")},
6394 {"desc", N_("Create a vol.")},
6395 {NULL, NULL}
6398 static const vshCmdOptDef opts_vol_create[] = {
6399 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6400 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
6401 {NULL, 0, 0, NULL}
6404 static int
6405 cmdVolCreate(vshControl *ctl, const vshCmd *cmd)
6407 virStoragePoolPtr pool;
6408 virStorageVolPtr vol;
6409 char *from;
6410 int found;
6411 int ret = TRUE;
6412 char *buffer;
6414 if (!vshConnectionUsability(ctl, ctl->conn))
6415 return FALSE;
6417 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6418 VSH_BYNAME)))
6419 return FALSE;
6421 from = vshCommandOptString(cmd, "file", &found);
6422 if (!found) {
6423 virStoragePoolFree(pool);
6424 return FALSE;
6427 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
6428 virshReportError(ctl);
6429 virStoragePoolFree(pool);
6430 return FALSE;
6433 vol = virStorageVolCreateXML(pool, buffer, 0);
6434 VIR_FREE(buffer);
6435 virStoragePoolFree(pool);
6437 if (vol != NULL) {
6438 vshPrint(ctl, _("Vol %s created from %s\n"),
6439 virStorageVolGetName(vol), from);
6440 virStorageVolFree(vol);
6441 } else {
6442 vshError(ctl, _("Failed to create vol from %s"), from);
6443 ret = FALSE;
6445 return ret;
6449 * "vol-create-from" command
6451 static const vshCmdInfo info_vol_create_from[] = {
6452 {"help", N_("create a vol, using another volume as input")},
6453 {"desc", N_("Create a vol from an existing volume.")},
6454 {NULL, NULL}
6457 static const vshCmdOptDef opts_vol_create_from[] = {
6458 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6459 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
6460 {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")},
6461 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")},
6462 {NULL, 0, 0, NULL}
6465 static int
6466 cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd)
6468 virStoragePoolPtr pool = NULL;
6469 virStorageVolPtr newvol = NULL, inputvol = NULL;
6470 char *from;
6471 int found;
6472 int ret = FALSE;
6473 char *buffer = NULL;
6475 if (!vshConnectionUsability(ctl, ctl->conn))
6476 goto cleanup;
6478 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
6479 goto cleanup;
6481 from = vshCommandOptString(cmd, "file", &found);
6482 if (!found) {
6483 goto cleanup;
6486 if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL)))
6487 goto cleanup;
6489 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
6490 virshReportError(ctl);
6491 goto cleanup;
6494 newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0);
6496 if (newvol != NULL) {
6497 vshPrint(ctl, _("Vol %s created from input vol %s\n"),
6498 virStorageVolGetName(newvol), virStorageVolGetName(inputvol));
6499 } else {
6500 vshError(ctl, _("Failed to create vol from %s"), from);
6501 goto cleanup;
6504 ret = TRUE;
6505 cleanup:
6506 VIR_FREE(buffer);
6507 if (pool)
6508 virStoragePoolFree(pool);
6509 if (inputvol)
6510 virStorageVolFree(inputvol);
6511 if (newvol)
6512 virStorageVolFree(newvol);
6513 return ret;
6516 static xmlChar *
6517 makeCloneXML(char *origxml, char *newname) {
6519 xmlDocPtr doc = NULL;
6520 xmlXPathContextPtr ctxt = NULL;
6521 xmlXPathObjectPtr obj = NULL;
6522 xmlChar *newxml = NULL;
6523 int size;
6525 doc = xmlReadDoc((const xmlChar *) origxml, "domain.xml", NULL,
6526 XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOWARNING);
6527 if (!doc)
6528 goto cleanup;
6529 ctxt = xmlXPathNewContext(doc);
6530 if (!ctxt)
6531 goto cleanup;
6533 obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt);
6534 if ((obj == NULL) || (obj->nodesetval == NULL) ||
6535 (obj->nodesetval->nodeTab == NULL))
6536 goto cleanup;
6538 xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname);
6539 xmlDocDumpMemory(doc, &newxml, &size);
6541 cleanup:
6542 xmlXPathFreeObject(obj);
6543 xmlXPathFreeContext(ctxt);
6544 xmlFreeDoc(doc);
6545 return newxml;
6549 * "vol-clone" command
6551 static const vshCmdInfo info_vol_clone[] = {
6552 {"help", N_("clone a volume.")},
6553 {"desc", N_("Clone an existing volume.")},
6554 {NULL, NULL}
6557 static const vshCmdOptDef opts_vol_clone[] = {
6558 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6559 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")},
6560 {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")},
6561 {NULL, 0, 0, NULL}
6564 static int
6565 cmdVolClone(vshControl *ctl, const vshCmd *cmd)
6567 virStoragePoolPtr origpool = NULL;
6568 virStorageVolPtr origvol = NULL, newvol = NULL;
6569 char *name, *origxml = NULL;
6570 xmlChar *newxml = NULL;
6571 int found;
6572 int ret = FALSE;
6574 if (!vshConnectionUsability(ctl, ctl->conn))
6575 goto cleanup;
6577 if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
6578 goto cleanup;
6580 origpool = virStoragePoolLookupByVolume(origvol);
6581 if (!origpool) {
6582 vshError(ctl, "%s", _("failed to get parent pool"));
6583 goto cleanup;
6586 name = vshCommandOptString(cmd, "newname", &found);
6587 if (!found)
6588 goto cleanup;
6590 origxml = virStorageVolGetXMLDesc(origvol, 0);
6591 if (!origxml)
6592 goto cleanup;
6594 newxml = makeCloneXML(origxml, name);
6595 if (!newxml) {
6596 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
6597 goto cleanup;
6600 newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0);
6602 if (newvol != NULL) {
6603 vshPrint(ctl, _("Vol %s cloned from %s\n"),
6604 virStorageVolGetName(newvol), virStorageVolGetName(origvol));
6605 } else {
6606 vshError(ctl, _("Failed to clone vol from %s"),
6607 virStorageVolGetName(origvol));
6608 goto cleanup;
6611 ret = TRUE;
6613 cleanup:
6614 VIR_FREE(origxml);
6615 xmlFree(newxml);
6616 if (origvol)
6617 virStorageVolFree(origvol);
6618 if (newvol)
6619 virStorageVolFree(newvol);
6620 if (origpool)
6621 virStoragePoolFree(origpool);
6622 return ret;
6626 * "vol-delete" command
6628 static const vshCmdInfo info_vol_delete[] = {
6629 {"help", N_("delete a vol")},
6630 {"desc", N_("Delete a given vol.")},
6631 {NULL, NULL}
6634 static const vshCmdOptDef opts_vol_delete[] = {
6635 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6636 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6637 {NULL, 0, 0, NULL}
6640 static int
6641 cmdVolDelete(vshControl *ctl, const vshCmd *cmd)
6643 virStorageVolPtr vol;
6644 int ret = TRUE;
6645 char *name;
6647 if (!vshConnectionUsability(ctl, ctl->conn))
6648 return FALSE;
6650 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
6651 return FALSE;
6654 if (virStorageVolDelete(vol, 0) == 0) {
6655 vshPrint(ctl, _("Vol %s deleted\n"), name);
6656 } else {
6657 vshError(ctl, _("Failed to delete vol %s"), name);
6658 ret = FALSE;
6661 virStorageVolFree(vol);
6662 return ret;
6667 * "vol-wipe" command
6669 static const vshCmdInfo info_vol_wipe[] = {
6670 {"help", N_("wipe a vol")},
6671 {"desc", N_("Ensure data previously on a volume is not accessible to future reads")},
6672 {NULL, NULL}
6675 static const vshCmdOptDef opts_vol_wipe[] = {
6676 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6677 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6678 {NULL, 0, 0, NULL}
6681 static int
6682 cmdVolWipe(vshControl *ctl, const vshCmd *cmd)
6684 virStorageVolPtr vol;
6685 int ret = TRUE;
6686 char *name;
6688 if (!vshConnectionUsability(ctl, ctl->conn))
6689 return FALSE;
6691 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
6692 return FALSE;
6695 if (virStorageVolWipe(vol, 0) == 0) {
6696 vshPrint(ctl, _("Vol %s wiped\n"), name);
6697 } else {
6698 vshError(ctl, _("Failed to wipe vol %s"), name);
6699 ret = FALSE;
6702 virStorageVolFree(vol);
6703 return ret;
6708 * "vol-info" command
6710 static const vshCmdInfo info_vol_info[] = {
6711 {"help", N_("storage vol information")},
6712 {"desc", N_("Returns basic information about the storage vol.")},
6713 {NULL, NULL}
6716 static const vshCmdOptDef opts_vol_info[] = {
6717 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6718 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6719 {NULL, 0, 0, NULL}
6722 static int
6723 cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
6725 virStorageVolInfo info;
6726 virStorageVolPtr vol;
6727 int ret = TRUE;
6729 if (!vshConnectionUsability(ctl, ctl->conn))
6730 return FALSE;
6732 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
6733 return FALSE;
6735 vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol));
6737 if (virStorageVolGetInfo(vol, &info) == 0) {
6738 double val;
6739 const char *unit;
6740 vshPrint(ctl, "%-15s %s\n", _("Type:"),
6741 info.type == VIR_STORAGE_VOL_FILE ?
6742 _("file") : _("block"));
6744 val = prettyCapacity(info.capacity, &unit);
6745 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);
6747 val = prettyCapacity(info.allocation, &unit);
6748 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
6749 } else {
6750 ret = FALSE;
6753 virStorageVolFree(vol);
6754 return ret;
6759 * "vol-dumpxml" command
6761 static const vshCmdInfo info_vol_dumpxml[] = {
6762 {"help", N_("vol information in XML")},
6763 {"desc", N_("Output the vol information as an XML dump to stdout.")},
6764 {NULL, NULL}
6767 static const vshCmdOptDef opts_vol_dumpxml[] = {
6768 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6769 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6770 {NULL, 0, 0, NULL}
6773 static int
6774 cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd)
6776 virStorageVolPtr vol;
6777 int ret = TRUE;
6778 char *dump;
6780 if (!vshConnectionUsability(ctl, ctl->conn))
6781 return FALSE;
6783 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
6784 return FALSE;
6786 dump = virStorageVolGetXMLDesc(vol, 0);
6787 if (dump != NULL) {
6788 vshPrint(ctl, "%s", dump);
6789 VIR_FREE(dump);
6790 } else {
6791 ret = FALSE;
6794 virStorageVolFree(vol);
6795 return ret;
6800 * "vol-list" command
6802 static const vshCmdInfo info_vol_list[] = {
6803 {"help", N_("list vols")},
6804 {"desc", N_("Returns list of vols by pool.")},
6805 {NULL, NULL}
6808 static const vshCmdOptDef opts_vol_list[] = {
6809 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
6810 {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")},
6811 {NULL, 0, 0, NULL}
6814 static int
6815 cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
6817 virStorageVolInfo volumeInfo;
6818 virStoragePoolPtr pool;
6819 char **activeNames = NULL;
6820 char *outputStr = NULL;
6821 const char *unit;
6822 double val;
6823 int details = vshCommandOptBool(cmd, "details");
6824 int numVolumes = 0, i;
6825 int ret, functionReturn;
6826 int stringLength = 0;
6827 size_t allocStrLength = 0, capStrLength = 0;
6828 size_t nameStrLength = 0, pathStrLength = 0;
6829 size_t typeStrLength = 0;
6830 struct volInfoText {
6831 char *allocation;
6832 char *capacity;
6833 char *path;
6834 char *type;
6836 struct volInfoText *volInfoTexts = NULL;
6838 /* Check the connection to libvirtd daemon is still working */
6839 if (!vshConnectionUsability(ctl, ctl->conn))
6840 return FALSE;
6842 /* Look up the pool information given to us by the user */
6843 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
6844 return FALSE;
6846 /* Determine the number of volumes in the pool */
6847 numVolumes = virStoragePoolNumOfVolumes(pool);
6849 if (numVolumes < 0) {
6850 vshError(ctl, "%s", _("Failed to list storage volumes"));
6851 virStoragePoolFree(pool);
6852 return FALSE;
6855 /* Retrieve the list of volume names in the pool */
6856 if (numVolumes > 0) {
6857 activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames));
6858 if ((numVolumes = virStoragePoolListVolumes(pool, activeNames,
6859 numVolumes)) < 0) {
6860 vshError(ctl, "%s", _("Failed to list active vols"));
6861 VIR_FREE(activeNames);
6862 virStoragePoolFree(pool);
6863 return FALSE;
6866 /* Sort the volume names */
6867 qsort(&activeNames[0], numVolumes, sizeof(*activeNames), namesorter);
6869 /* Set aside memory for volume information pointers */
6870 volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts));
6873 /* Collect the rest of the volume information for display */
6874 for (i = 0; i < numVolumes; i++) {
6875 /* Retrieve volume info */
6876 virStorageVolPtr vol = virStorageVolLookupByName(pool,
6877 activeNames[i]);
6879 /* Retrieve the volume path */
6880 if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) {
6881 /* Something went wrong retrieving a volume path, cope with it */
6882 volInfoTexts[i].path = vshStrdup(ctl, _("unknown"));
6885 /* If requested, retrieve volume type and sizing information */
6886 if (details) {
6887 if (virStorageVolGetInfo(vol, &volumeInfo) != 0) {
6888 /* Something went wrong retrieving volume info, cope with it */
6889 volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
6890 volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
6891 volInfoTexts[i].type = vshStrdup(ctl, _("unknown"));
6892 } else {
6893 /* Convert the returned volume info into output strings */
6895 /* Volume type */
6896 if (volumeInfo.type == VIR_STORAGE_VOL_FILE)
6897 volInfoTexts[i].type = vshStrdup(ctl, _("file"));
6898 else
6899 volInfoTexts[i].type = vshStrdup(ctl, _("block"));
6901 /* Create the capacity output string */
6902 val = prettyCapacity(volumeInfo.capacity, &unit);
6903 ret = virAsprintf(&volInfoTexts[i].capacity,
6904 "%.2lf %s", val, unit);
6905 if (ret < 0) {
6906 /* An error occurred creating the string, return */
6907 goto asprintf_failure;
6910 /* Create the allocation output string */
6911 val = prettyCapacity(volumeInfo.allocation, &unit);
6912 ret = virAsprintf(&volInfoTexts[i].allocation,
6913 "%.2lf %s", val, unit);
6914 if (ret < 0) {
6915 /* An error occurred creating the string, return */
6916 goto asprintf_failure;
6920 /* Remember the largest length for each output string.
6921 * This lets us displaying header and volume information rows
6922 * using a single, properly sized, printf style output string.
6925 /* Keep the length of name string if longest so far */
6926 stringLength = strlen(activeNames[i]);
6927 if (stringLength > nameStrLength)
6928 nameStrLength = stringLength;
6930 /* Keep the length of path string if longest so far */
6931 stringLength = strlen(volInfoTexts[i].path);
6932 if (stringLength > pathStrLength)
6933 pathStrLength = stringLength;
6935 /* Keep the length of type string if longest so far */
6936 stringLength = strlen(volInfoTexts[i].type);
6937 if (stringLength > typeStrLength)
6938 typeStrLength = stringLength;
6940 /* Keep the length of capacity string if longest so far */
6941 stringLength = strlen(volInfoTexts[i].capacity);
6942 if (stringLength > capStrLength)
6943 capStrLength = stringLength;
6945 /* Keep the length of allocation string if longest so far */
6946 stringLength = strlen(volInfoTexts[i].allocation);
6947 if (stringLength > allocStrLength)
6948 allocStrLength = stringLength;
6951 /* Cleanup memory allocation */
6952 virStorageVolFree(vol);
6955 /* If the --details option wasn't selected, we output the volume
6956 * info using the fixed string format from previous versions to
6957 * maintain backward compatibility.
6960 /* Output basic info then return if --details option not selected */
6961 if (!details) {
6962 /* The old output format */
6963 vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path"));
6964 vshPrintExtra(ctl, "-----------------------------------------\n");
6965 for (i = 0; i < numVolumes; i++) {
6966 vshPrint(ctl, "%-20s %-40s\n", activeNames[i],
6967 volInfoTexts[i].path);
6970 /* Cleanup and return */
6971 functionReturn = TRUE;
6972 goto cleanup;
6975 /* We only get here if the --details option was selected. */
6977 /* Use the length of name header string if it's longest */
6978 stringLength = strlen(_("Name"));
6979 if (stringLength > nameStrLength)
6980 nameStrLength = stringLength;
6982 /* Use the length of path header string if it's longest */
6983 stringLength = strlen(_("Path"));
6984 if (stringLength > pathStrLength)
6985 pathStrLength = stringLength;
6987 /* Use the length of type header string if it's longest */
6988 stringLength = strlen(_("Type"));
6989 if (stringLength > typeStrLength)
6990 typeStrLength = stringLength;
6992 /* Use the length of capacity header string if it's longest */
6993 stringLength = strlen(_("Capacity"));
6994 if (stringLength > capStrLength)
6995 capStrLength = stringLength;
6997 /* Use the length of allocation header string if it's longest */
6998 stringLength = strlen(_("Allocation"));
6999 if (stringLength > allocStrLength)
7000 allocStrLength = stringLength;
7002 /* Display the string lengths for debugging */
7003 vshDebug(ctl, 5, "Longest name string = %zu chars\n", nameStrLength);
7004 vshDebug(ctl, 5, "Longest path string = %zu chars\n", pathStrLength);
7005 vshDebug(ctl, 5, "Longest type string = %zu chars\n", typeStrLength);
7006 vshDebug(ctl, 5, "Longest capacity string = %zu chars\n", capStrLength);
7007 vshDebug(ctl, 5, "Longest allocation string = %zu chars\n", allocStrLength);
7009 /* Create the output template */
7010 ret = virAsprintf(&outputStr,
7011 "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n",
7012 (unsigned long) nameStrLength,
7013 (unsigned long) pathStrLength,
7014 (unsigned long) typeStrLength,
7015 (unsigned long) capStrLength,
7016 (unsigned long) allocStrLength);
7017 if (ret < 0) {
7018 /* An error occurred creating the string, return */
7019 goto asprintf_failure;
7022 /* Display the header */
7023 vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"),
7024 ("Capacity"), _("Allocation"));
7025 for (i = nameStrLength + pathStrLength + typeStrLength
7026 + capStrLength + allocStrLength
7027 + 8; i > 0; i--)
7028 vshPrintExtra(ctl, "-");
7029 vshPrintExtra(ctl, "\n");
7031 /* Display the volume info rows */
7032 for (i = 0; i < numVolumes; i++) {
7033 vshPrint(ctl, outputStr,
7034 activeNames[i],
7035 volInfoTexts[i].path,
7036 volInfoTexts[i].type,
7037 volInfoTexts[i].capacity,
7038 volInfoTexts[i].allocation);
7041 /* Cleanup and return */
7042 functionReturn = TRUE;
7043 goto cleanup;
7045 asprintf_failure:
7047 /* Display an appropriate error message then cleanup and return */
7048 switch (errno) {
7049 case ENOMEM:
7050 /* Couldn't allocate memory */
7051 vshError(ctl, "%s", _("Out of memory"));
7052 break;
7053 default:
7054 /* Some other error */
7055 vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
7057 functionReturn = FALSE;
7059 cleanup:
7061 /* Safely free the memory allocated in this function */
7062 for (i = 0; i < numVolumes; i++) {
7063 /* Cleanup the memory for one volume info structure per loop */
7064 VIR_FREE(volInfoTexts[i].path);
7065 VIR_FREE(volInfoTexts[i].type);
7066 VIR_FREE(volInfoTexts[i].capacity);
7067 VIR_FREE(volInfoTexts[i].allocation);
7068 VIR_FREE(activeNames[i]);
7071 /* Cleanup remaining memory */
7072 VIR_FREE(outputStr);
7073 VIR_FREE(volInfoTexts);
7074 VIR_FREE(activeNames);
7075 virStoragePoolFree(pool);
7077 /* Return the desired value */
7078 return functionReturn;
7083 * "vol-name" command
7085 static const vshCmdInfo info_vol_name[] = {
7086 {"help", N_("returns the volume name for a given volume key or path")},
7087 {"desc", ""},
7088 {NULL, NULL}
7091 static const vshCmdOptDef opts_vol_name[] = {
7092 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")},
7093 {NULL, 0, 0, NULL}
7096 static int
7097 cmdVolName(vshControl *ctl, const vshCmd *cmd)
7099 virStorageVolPtr vol;
7101 if (!vshConnectionUsability(ctl, ctl->conn))
7102 return FALSE;
7104 if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
7105 VSH_BYUUID)))
7106 return FALSE;
7108 vshPrint(ctl, "%s\n", virStorageVolGetName(vol));
7109 virStorageVolFree(vol);
7110 return TRUE;
7115 * "vol-pool" command
7117 static const vshCmdInfo info_vol_pool[] = {
7118 {"help", N_("returns the storage pool for a given volume key or path")},
7119 {"desc", ""},
7120 {NULL, NULL}
7123 static const vshCmdOptDef opts_vol_pool[] = {
7124 {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")},
7125 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")},
7126 {NULL, 0, 0, NULL}
7129 static int
7130 cmdVolPool(vshControl *ctl, const vshCmd *cmd)
7132 virStoragePoolPtr pool;
7133 virStorageVolPtr vol;
7134 char uuid[VIR_UUID_STRING_BUFLEN];
7136 /* Check the connection to libvirtd daemon is still working */
7137 if (!vshConnectionUsability(ctl, ctl->conn))
7138 return FALSE;
7140 /* Use the supplied string to locate the volume */
7141 if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
7142 VSH_BYUUID))) {
7143 return FALSE;
7146 /* Look up the parent storage pool for the volume */
7147 pool = virStoragePoolLookupByVolume(vol);
7148 if (pool == NULL) {
7149 vshError(ctl, "%s", _("failed to get parent pool"));
7150 virStorageVolFree(vol);
7151 return FALSE;
7154 /* Return the requested details of the parent storage pool */
7155 if (vshCommandOptBool(cmd, "uuid")) {
7156 /* Retrieve and return pool UUID string */
7157 if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0)
7158 vshPrint(ctl, "%s\n", uuid);
7159 } else {
7160 /* Return the storage pool name */
7161 vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
7164 /* Cleanup */
7165 virStorageVolFree(vol);
7166 virStoragePoolFree(pool);
7167 return TRUE;
7172 * "vol-key" command
7174 static const vshCmdInfo info_vol_key[] = {
7175 {"help", N_("returns the volume key for a given volume name or path")},
7176 {"desc", ""},
7177 {NULL, NULL}
7180 static const vshCmdOptDef opts_vol_key[] = {
7181 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7182 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")},
7183 {NULL, 0, 0, NULL}
7186 static int
7187 cmdVolKey(vshControl *ctl, const vshCmd *cmd)
7189 virStorageVolPtr vol;
7191 if (!vshConnectionUsability(ctl, ctl->conn))
7192 return FALSE;
7194 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
7195 return FALSE;
7197 vshPrint(ctl, "%s\n", virStorageVolGetKey(vol));
7198 virStorageVolFree(vol);
7199 return TRUE;
7205 * "vol-path" command
7207 static const vshCmdInfo info_vol_path[] = {
7208 {"help", N_("returns the volume path for a given volume name or key")},
7209 {"desc", ""},
7210 {NULL, NULL}
7213 static const vshCmdOptDef opts_vol_path[] = {
7214 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7215 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")},
7216 {NULL, 0, 0, NULL}
7219 static int
7220 cmdVolPath(vshControl *ctl, const vshCmd *cmd)
7222 virStorageVolPtr vol;
7223 char *name = NULL;
7225 if (!vshConnectionUsability(ctl, ctl->conn))
7226 return FALSE;
7228 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
7229 return FALSE;
7232 vshPrint(ctl, "%s\n", virStorageVolGetPath(vol));
7233 virStorageVolFree(vol);
7234 return TRUE;
7239 * "secret-define" command
7241 static const vshCmdInfo info_secret_define[] = {
7242 {"help", N_("define or modify a secret from an XML file")},
7243 {"desc", N_("Define or modify a secret.")},
7244 {NULL, NULL}
7247 static const vshCmdOptDef opts_secret_define[] = {
7248 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")},
7249 {NULL, 0, 0, NULL}
7252 static int
7253 cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
7255 char *from, *buffer;
7256 virSecretPtr res;
7257 char uuid[VIR_UUID_STRING_BUFLEN];
7259 if (!vshConnectionUsability(ctl, ctl->conn))
7260 return FALSE;
7262 from = vshCommandOptString(cmd, "file", NULL);
7263 if (!from)
7264 return FALSE;
7266 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
7267 return FALSE;
7269 res = virSecretDefineXML(ctl->conn, buffer, 0);
7270 VIR_FREE(buffer);
7272 if (res == NULL) {
7273 vshError(ctl, _("Failed to set attributes from %s"), from);
7274 return FALSE;
7276 if (virSecretGetUUIDString(res, &(uuid[0])) < 0) {
7277 vshError(ctl, "%s", _("Failed to get UUID of created secret"));
7278 virSecretFree(res);
7279 return FALSE;
7281 vshPrint(ctl, _("Secret %s created\n"), uuid);
7282 virSecretFree(res);
7283 return TRUE;
7287 * "secret-dumpxml" command
7289 static const vshCmdInfo info_secret_dumpxml[] = {
7290 {"help", N_("secret attributes in XML")},
7291 {"desc", N_("Output attributes of a secret as an XML dump to stdout.")},
7292 {NULL, NULL}
7295 static const vshCmdOptDef opts_secret_dumpxml[] = {
7296 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7297 {NULL, 0, 0, NULL}
7300 static int
7301 cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
7303 virSecretPtr secret;
7304 int ret = FALSE;
7305 char *xml;
7307 if (!vshConnectionUsability(ctl, ctl->conn))
7308 return FALSE;
7310 secret = vshCommandOptSecret(ctl, cmd, NULL);
7311 if (secret == NULL)
7312 return FALSE;
7314 xml = virSecretGetXMLDesc(secret, 0);
7315 if (xml == NULL)
7316 goto cleanup;
7317 vshPrint(ctl, "%s", xml);
7318 VIR_FREE(xml);
7319 ret = TRUE;
7321 cleanup:
7322 virSecretFree(secret);
7323 return ret;
7327 * "secret-set-value" command
7329 static const vshCmdInfo info_secret_set_value[] = {
7330 {"help", N_("set a secret value")},
7331 {"desc", N_("Set a secret value.")},
7332 {NULL, NULL}
7335 static const vshCmdOptDef opts_secret_set_value[] = {
7336 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7337 {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")},
7338 {NULL, 0, 0, NULL}
7341 static int
7342 cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
7344 virSecretPtr secret;
7345 size_t value_size;
7346 char *base64, *value;
7347 int found, res, ret = FALSE;
7349 if (!vshConnectionUsability(ctl, ctl->conn))
7350 return FALSE;
7352 secret = vshCommandOptSecret(ctl, cmd, NULL);
7353 if (secret == NULL)
7354 return FALSE;
7356 base64 = vshCommandOptString(cmd, "base64", &found);
7357 if (!base64)
7358 goto cleanup;
7360 if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
7361 vshError(ctl, "%s", _("Invalid base64 data"));
7362 goto cleanup;
7364 if (value == NULL) {
7365 vshError(ctl, "%s", _("Failed to allocate memory"));
7366 return FALSE;
7369 res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
7370 memset(value, 0, value_size);
7371 VIR_FREE(value);
7373 if (res != 0) {
7374 vshError(ctl, "%s", _("Failed to set secret value"));
7375 goto cleanup;
7377 vshPrint(ctl, "%s", _("Secret value set\n"));
7378 ret = TRUE;
7380 cleanup:
7381 virSecretFree(secret);
7382 return ret;
7386 * "secret-get-value" command
7388 static const vshCmdInfo info_secret_get_value[] = {
7389 {"help", N_("Output a secret value")},
7390 {"desc", N_("Output a secret value to stdout.")},
7391 {NULL, NULL}
7394 static const vshCmdOptDef opts_secret_get_value[] = {
7395 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7396 {NULL, 0, 0, NULL}
7399 static int
7400 cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
7402 virSecretPtr secret;
7403 char *base64;
7404 unsigned char *value;
7405 size_t value_size;
7406 int ret = FALSE;
7408 if (!vshConnectionUsability(ctl, ctl->conn))
7409 return FALSE;
7411 secret = vshCommandOptSecret(ctl, cmd, NULL);
7412 if (secret == NULL)
7413 return FALSE;
7415 value = virSecretGetValue(secret, &value_size, 0);
7416 if (value == NULL)
7417 goto cleanup;
7419 base64_encode_alloc((char *)value, value_size, &base64);
7420 memset(value, 0, value_size);
7421 VIR_FREE(value);
7423 if (base64 == NULL) {
7424 vshError(ctl, "%s", _("Failed to allocate memory"));
7425 goto cleanup;
7427 vshPrint(ctl, "%s", base64);
7428 memset(base64, 0, strlen(base64));
7429 VIR_FREE(base64);
7430 ret = TRUE;
7432 cleanup:
7433 virSecretFree(secret);
7434 return ret;
7438 * "secret-undefine" command
7440 static const vshCmdInfo info_secret_undefine[] = {
7441 {"help", N_("undefine a secret")},
7442 {"desc", N_("Undefine a secret.")},
7443 {NULL, NULL}
7446 static const vshCmdOptDef opts_secret_undefine[] = {
7447 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7448 {NULL, 0, 0, NULL}
7451 static int
7452 cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
7454 virSecretPtr secret;
7455 int ret = FALSE;
7456 char *uuid;
7458 if (!vshConnectionUsability(ctl, ctl->conn))
7459 return FALSE;
7461 secret = vshCommandOptSecret(ctl, cmd, &uuid);
7462 if (secret == NULL)
7463 return FALSE;
7465 if (virSecretUndefine(secret) < 0) {
7466 vshError(ctl, _("Failed to delete secret %s"), uuid);
7467 goto cleanup;
7469 vshPrint(ctl, _("Secret %s deleted\n"), uuid);
7470 ret = TRUE;
7472 cleanup:
7473 virSecretFree(secret);
7474 return ret;
7478 * "secret-list" command
7480 static const vshCmdInfo info_secret_list[] = {
7481 {"help", N_("list secrets")},
7482 {"desc", N_("Returns a list of secrets")},
7483 {NULL, NULL}
7486 static int
7487 cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7489 int maxuuids = 0, i;
7490 char **uuids = NULL;
7492 if (!vshConnectionUsability(ctl, ctl->conn))
7493 return FALSE;
7495 maxuuids = virConnectNumOfSecrets(ctl->conn);
7496 if (maxuuids < 0) {
7497 vshError(ctl, "%s", _("Failed to list secrets"));
7498 return FALSE;
7500 uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);
7502 maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
7503 if (maxuuids < 0) {
7504 vshError(ctl, "%s", _("Failed to list secrets"));
7505 VIR_FREE(uuids);
7506 return FALSE;
7509 qsort(uuids, maxuuids, sizeof(char *), namesorter);
7511 vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage"));
7512 vshPrintExtra(ctl, "-----------------------------------------------------------\n");
7514 for (i = 0; i < maxuuids; i++) {
7515 virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]);
7516 const char *usageType = NULL;
7518 if (!sec) {
7519 VIR_FREE(uuids[i]);
7520 continue;
7523 switch (virSecretGetUsageType(sec)) {
7524 case VIR_SECRET_USAGE_TYPE_VOLUME:
7525 usageType = _("Volume");
7526 break;
7529 if (usageType) {
7530 vshPrint(ctl, "%-36s %s %s\n",
7531 uuids[i], usageType,
7532 virSecretGetUsageID(sec));
7533 } else {
7534 vshPrint(ctl, "%-36s %s\n",
7535 uuids[i], _("Unused"));
7537 virSecretFree(sec);
7538 VIR_FREE(uuids[i]);
7540 VIR_FREE(uuids);
7541 return TRUE;
7546 * "version" command
7548 static const vshCmdInfo info_version[] = {
7549 {"help", N_("show version")},
7550 {"desc", N_("Display the system version information.")},
7551 {NULL, NULL}
7555 static int
7556 cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7558 unsigned long hvVersion;
7559 const char *hvType;
7560 unsigned long libVersion;
7561 unsigned long includeVersion;
7562 unsigned long apiVersion;
7563 int ret;
7564 unsigned int major;
7565 unsigned int minor;
7566 unsigned int rel;
7568 if (!vshConnectionUsability(ctl, ctl->conn))
7569 return FALSE;
7571 hvType = virConnectGetType(ctl->conn);
7572 if (hvType == NULL) {
7573 vshError(ctl, "%s", _("failed to get hypervisor type"));
7574 return FALSE;
7577 includeVersion = LIBVIR_VERSION_NUMBER;
7578 major = includeVersion / 1000000;
7579 includeVersion %= 1000000;
7580 minor = includeVersion / 1000;
7581 rel = includeVersion % 1000;
7582 vshPrint(ctl, _("Compiled against library: libvir %d.%d.%d\n"),
7583 major, minor, rel);
7585 ret = virGetVersion(&libVersion, hvType, &apiVersion);
7586 if (ret < 0) {
7587 vshError(ctl, "%s", _("failed to get the library version"));
7588 return FALSE;
7590 major = libVersion / 1000000;
7591 libVersion %= 1000000;
7592 minor = libVersion / 1000;
7593 rel = libVersion % 1000;
7594 vshPrint(ctl, _("Using library: libvir %d.%d.%d\n"),
7595 major, minor, rel);
7597 major = apiVersion / 1000000;
7598 apiVersion %= 1000000;
7599 minor = apiVersion / 1000;
7600 rel = apiVersion % 1000;
7601 vshPrint(ctl, _("Using API: %s %d.%d.%d\n"), hvType,
7602 major, minor, rel);
7604 ret = virConnectGetVersion(ctl->conn, &hvVersion);
7605 if (ret < 0) {
7606 vshError(ctl, "%s", _("failed to get the hypervisor version"));
7607 return FALSE;
7609 if (hvVersion == 0) {
7610 vshPrint(ctl,
7611 _("Cannot extract running %s hypervisor version\n"), hvType);
7612 } else {
7613 major = hvVersion / 1000000;
7614 hvVersion %= 1000000;
7615 minor = hvVersion / 1000;
7616 rel = hvVersion % 1000;
7618 vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"),
7619 hvType, major, minor, rel);
7621 return TRUE;
7625 * "nodedev-list" command
7627 static const vshCmdInfo info_node_list_devices[] = {
7628 {"help", N_("enumerate devices on this host")},
7629 {"desc", ""},
7630 {NULL, NULL}
7633 static const vshCmdOptDef opts_node_list_devices[] = {
7634 {"tree", VSH_OT_BOOL, 0, N_("list devices in a tree")},
7635 {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability name")},
7636 {NULL, 0, 0, NULL}
7639 #define MAX_DEPTH 100
7640 #define INDENT_SIZE 4
7641 #define INDENT_BUFLEN ((MAX_DEPTH * INDENT_SIZE) + 1)
7643 static void
7644 cmdNodeListDevicesPrint(vshControl *ctl,
7645 char **devices,
7646 char **parents,
7647 int num_devices,
7648 int devid,
7649 int lastdev,
7650 unsigned int depth,
7651 unsigned int indentIdx,
7652 char *indentBuf)
7654 int i;
7655 int nextlastdev = -1;
7657 /* Prepare indent for this device, but not if at root */
7658 if (depth && depth < MAX_DEPTH) {
7659 indentBuf[indentIdx] = '+';
7660 indentBuf[indentIdx+1] = '-';
7661 indentBuf[indentIdx+2] = ' ';
7662 indentBuf[indentIdx+3] = '\0';
7665 /* Print this device */
7666 vshPrint(ctl, "%s", indentBuf);
7667 vshPrint(ctl, "%s\n", devices[devid]);
7670 /* Update indent to show '|' or ' ' for child devices */
7671 if (depth && depth < MAX_DEPTH) {
7672 if (devid == lastdev)
7673 indentBuf[indentIdx] = ' ';
7674 else
7675 indentBuf[indentIdx] = '|';
7676 indentBuf[indentIdx+1] = ' ';
7677 indentIdx+=2;
7680 /* Determine the index of the last child device */
7681 for (i = 0 ; i < num_devices ; i++) {
7682 if (parents[i] &&
7683 STREQ(parents[i], devices[devid])) {
7684 nextlastdev = i;
7688 /* If there is a child device, then print another blank line */
7689 if (nextlastdev != -1) {
7690 vshPrint(ctl, "%s", indentBuf);
7691 vshPrint(ctl, " |\n");
7694 /* Finally print all children */
7695 if (depth < MAX_DEPTH)
7696 indentBuf[indentIdx] = ' ';
7697 for (i = 0 ; i < num_devices ; i++) {
7698 if (depth < MAX_DEPTH) {
7699 indentBuf[indentIdx] = ' ';
7700 indentBuf[indentIdx+1] = ' ';
7702 if (parents[i] &&
7703 STREQ(parents[i], devices[devid]))
7704 cmdNodeListDevicesPrint(ctl, devices, parents,
7705 num_devices, i, nextlastdev,
7706 depth + 1, indentIdx + 2, indentBuf);
7707 if (depth < MAX_DEPTH)
7708 indentBuf[indentIdx] = '\0';
7711 /* If there was no child device, and we're the last in
7712 * a list of devices, then print another blank line */
7713 if (nextlastdev == -1 && devid == lastdev) {
7714 vshPrint(ctl, "%s", indentBuf);
7715 vshPrint(ctl, "\n");
7719 static int
7720 cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7722 char *cap;
7723 char **devices;
7724 int found, num_devices, i;
7725 int tree = vshCommandOptBool(cmd, "tree");
7727 if (!vshConnectionUsability(ctl, ctl->conn))
7728 return FALSE;
7730 cap = vshCommandOptString(cmd, "cap", &found);
7731 if (!found)
7732 cap = NULL;
7734 num_devices = virNodeNumOfDevices(ctl->conn, cap, 0);
7735 if (num_devices < 0) {
7736 vshError(ctl, "%s", _("Failed to count node devices"));
7737 return FALSE;
7738 } else if (num_devices == 0) {
7739 return TRUE;
7742 devices = vshMalloc(ctl, sizeof(char *) * num_devices);
7743 num_devices =
7744 virNodeListDevices(ctl->conn, cap, devices, num_devices, 0);
7745 if (num_devices < 0) {
7746 vshError(ctl, "%s", _("Failed to list node devices"));
7747 VIR_FREE(devices);
7748 return FALSE;
7750 qsort(&devices[0], num_devices, sizeof(char*), namesorter);
7751 if (tree) {
7752 char indentBuf[INDENT_BUFLEN];
7753 char **parents = vshMalloc(ctl, sizeof(char *) * num_devices);
7754 for (i = 0; i < num_devices; i++) {
7755 virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]);
7756 if (dev && STRNEQ(devices[i], "computer")) {
7757 const char *parent = virNodeDeviceGetParent(dev);
7758 parents[i] = parent ? vshStrdup(ctl, parent) : NULL;
7759 } else {
7760 parents[i] = NULL;
7762 virNodeDeviceFree(dev);
7764 for (i = 0 ; i < num_devices ; i++) {
7765 memset(indentBuf, '\0', sizeof indentBuf);
7766 if (parents[i] == NULL)
7767 cmdNodeListDevicesPrint(ctl,
7768 devices,
7769 parents,
7770 num_devices,
7775 indentBuf);
7777 for (i = 0 ; i < num_devices ; i++) {
7778 VIR_FREE(devices[i]);
7779 VIR_FREE(parents[i]);
7781 VIR_FREE(parents);
7782 } else {
7783 for (i = 0; i < num_devices; i++) {
7784 vshPrint(ctl, "%s\n", devices[i]);
7785 VIR_FREE(devices[i]);
7788 VIR_FREE(devices);
7789 return TRUE;
7793 * "nodedev-dumpxml" command
7795 static const vshCmdInfo info_node_device_dumpxml[] = {
7796 {"help", N_("node device details in XML")},
7797 {"desc", N_("Output the node device details as an XML dump to stdout.")},
7798 {NULL, NULL}
7802 static const vshCmdOptDef opts_node_device_dumpxml[] = {
7803 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7804 {NULL, 0, 0, NULL}
7807 static int
7808 cmdNodeDeviceDumpXML (vshControl *ctl, const vshCmd *cmd)
7810 const char *name;
7811 virNodeDevicePtr device;
7812 char *xml;
7814 if (!vshConnectionUsability(ctl, ctl->conn))
7815 return FALSE;
7816 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7817 return FALSE;
7818 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7819 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7820 return FALSE;
7823 xml = virNodeDeviceGetXMLDesc(device, 0);
7824 if (!xml) {
7825 virNodeDeviceFree(device);
7826 return FALSE;
7829 vshPrint(ctl, "%s\n", xml);
7830 VIR_FREE(xml);
7831 virNodeDeviceFree(device);
7832 return TRUE;
7836 * "nodedev-dettach" command
7838 static const vshCmdInfo info_node_device_dettach[] = {
7839 {"help", N_("dettach node device from its device driver")},
7840 {"desc", N_("Dettach node device from its device driver before assigning to a domain.")},
7841 {NULL, NULL}
7845 static const vshCmdOptDef opts_node_device_dettach[] = {
7846 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7847 {NULL, 0, 0, NULL}
7850 static int
7851 cmdNodeDeviceDettach (vshControl *ctl, const vshCmd *cmd)
7853 const char *name;
7854 virNodeDevicePtr device;
7855 int ret = TRUE;
7857 if (!vshConnectionUsability(ctl, ctl->conn))
7858 return FALSE;
7859 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7860 return FALSE;
7861 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7862 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7863 return FALSE;
7866 if (virNodeDeviceDettach(device) == 0) {
7867 vshPrint(ctl, _("Device %s dettached\n"), name);
7868 } else {
7869 vshError(ctl, _("Failed to dettach device %s"), name);
7870 ret = FALSE;
7872 virNodeDeviceFree(device);
7873 return ret;
7877 * "nodedev-reattach" command
7879 static const vshCmdInfo info_node_device_reattach[] = {
7880 {"help", N_("reattach node device to its device driver")},
7881 {"desc", N_("Reattach node device to its device driver once released by the domain.")},
7882 {NULL, NULL}
7886 static const vshCmdOptDef opts_node_device_reattach[] = {
7887 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7888 {NULL, 0, 0, NULL}
7891 static int
7892 cmdNodeDeviceReAttach (vshControl *ctl, const vshCmd *cmd)
7894 const char *name;
7895 virNodeDevicePtr device;
7896 int ret = TRUE;
7898 if (!vshConnectionUsability(ctl, ctl->conn))
7899 return FALSE;
7900 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7901 return FALSE;
7902 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7903 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7904 return FALSE;
7907 if (virNodeDeviceReAttach(device) == 0) {
7908 vshPrint(ctl, _("Device %s re-attached\n"), name);
7909 } else {
7910 vshError(ctl, _("Failed to re-attach device %s"), name);
7911 ret = FALSE;
7913 virNodeDeviceFree(device);
7914 return ret;
7918 * "nodedev-reset" command
7920 static const vshCmdInfo info_node_device_reset[] = {
7921 {"help", N_("reset node device")},
7922 {"desc", N_("Reset node device before or after assigning to a domain.")},
7923 {NULL, NULL}
7927 static const vshCmdOptDef opts_node_device_reset[] = {
7928 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7929 {NULL, 0, 0, NULL}
7932 static int
7933 cmdNodeDeviceReset (vshControl *ctl, const vshCmd *cmd)
7935 const char *name;
7936 virNodeDevicePtr device;
7937 int ret = TRUE;
7939 if (!vshConnectionUsability(ctl, ctl->conn))
7940 return FALSE;
7941 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7942 return FALSE;
7943 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7944 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7945 return FALSE;
7948 if (virNodeDeviceReset(device) == 0) {
7949 vshPrint(ctl, _("Device %s reset\n"), name);
7950 } else {
7951 vshError(ctl, _("Failed to reset device %s"), name);
7952 ret = FALSE;
7954 virNodeDeviceFree(device);
7955 return ret;
7959 * "hostkey" command
7961 static const vshCmdInfo info_hostname[] = {
7962 {"help", N_("print the hypervisor hostname")},
7963 {"desc", ""},
7964 {NULL, NULL}
7967 static int
7968 cmdHostname (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7970 char *hostname;
7972 if (!vshConnectionUsability(ctl, ctl->conn))
7973 return FALSE;
7975 hostname = virConnectGetHostname (ctl->conn);
7976 if (hostname == NULL) {
7977 vshError(ctl, "%s", _("failed to get hostname"));
7978 return FALSE;
7981 vshPrint (ctl, "%s\n", hostname);
7982 VIR_FREE(hostname);
7984 return TRUE;
7988 * "uri" command
7990 static const vshCmdInfo info_uri[] = {
7991 {"help", N_("print the hypervisor canonical URI")},
7992 {"desc", ""},
7993 {NULL, NULL}
7996 static int
7997 cmdURI (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7999 char *uri;
8001 if (!vshConnectionUsability(ctl, ctl->conn))
8002 return FALSE;
8004 uri = virConnectGetURI (ctl->conn);
8005 if (uri == NULL) {
8006 vshError(ctl, "%s", _("failed to get URI"));
8007 return FALSE;
8010 vshPrint (ctl, "%s\n", uri);
8011 VIR_FREE(uri);
8013 return TRUE;
8017 * "vncdisplay" command
8019 static const vshCmdInfo info_vncdisplay[] = {
8020 {"help", N_("vnc display")},
8021 {"desc", N_("Output the IP address and port number for the VNC display.")},
8022 {NULL, NULL}
8025 static const vshCmdOptDef opts_vncdisplay[] = {
8026 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8027 {NULL, 0, 0, NULL}
8030 static int
8031 cmdVNCDisplay(vshControl *ctl, const vshCmd *cmd)
8033 xmlDocPtr xml = NULL;
8034 xmlXPathObjectPtr obj = NULL;
8035 xmlXPathContextPtr ctxt = NULL;
8036 virDomainPtr dom;
8037 int ret = FALSE;
8038 int port = 0;
8039 char *doc;
8041 if (!vshConnectionUsability(ctl, ctl->conn))
8042 return FALSE;
8044 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8045 return FALSE;
8047 doc = virDomainGetXMLDesc(dom, 0);
8048 if (!doc)
8049 goto cleanup;
8051 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
8052 XML_PARSE_NOENT | XML_PARSE_NONET |
8053 XML_PARSE_NOWARNING);
8054 VIR_FREE(doc);
8055 if (!xml)
8056 goto cleanup;
8057 ctxt = xmlXPathNewContext(xml);
8058 if (!ctxt)
8059 goto cleanup;
8061 obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@port)", ctxt);
8062 if ((obj == NULL) || (obj->type != XPATH_STRING) ||
8063 (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
8064 goto cleanup;
8066 if (virStrToLong_i((const char *)obj->stringval, NULL, 10, &port) || port < 0)
8067 goto cleanup;
8068 xmlXPathFreeObject(obj);
8070 obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@listen)", ctxt);
8071 if ((obj == NULL) || (obj->type != XPATH_STRING) ||
8072 (obj->stringval == NULL) || (obj->stringval[0] == 0) ||
8073 STREQ((const char*)obj->stringval, "0.0.0.0")) {
8074 vshPrint(ctl, ":%d\n", port-5900);
8075 } else {
8076 vshPrint(ctl, "%s:%d\n", (const char *)obj->stringval, port-5900);
8078 xmlXPathFreeObject(obj);
8079 obj = NULL;
8080 ret = TRUE;
8082 cleanup:
8083 xmlXPathFreeObject(obj);
8084 xmlXPathFreeContext(ctxt);
8085 if (xml)
8086 xmlFreeDoc(xml);
8087 virDomainFree(dom);
8088 return ret;
8092 * "ttyconsole" command
8094 static const vshCmdInfo info_ttyconsole[] = {
8095 {"help", N_("tty console")},
8096 {"desc", N_("Output the device for the TTY console.")},
8097 {NULL, NULL}
8100 static const vshCmdOptDef opts_ttyconsole[] = {
8101 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8102 {NULL, 0, 0, NULL}
8105 static int
8106 cmdTTYConsole(vshControl *ctl, const vshCmd *cmd)
8108 xmlDocPtr xml = NULL;
8109 xmlXPathObjectPtr obj = NULL;
8110 xmlXPathContextPtr ctxt = NULL;
8111 virDomainPtr dom;
8112 int ret = FALSE;
8113 char *doc;
8115 if (!vshConnectionUsability(ctl, ctl->conn))
8116 return FALSE;
8118 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8119 return FALSE;
8121 doc = virDomainGetXMLDesc(dom, 0);
8122 if (!doc)
8123 goto cleanup;
8125 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
8126 XML_PARSE_NOENT | XML_PARSE_NONET |
8127 XML_PARSE_NOWARNING);
8128 VIR_FREE(doc);
8129 if (!xml)
8130 goto cleanup;
8131 ctxt = xmlXPathNewContext(xml);
8132 if (!ctxt)
8133 goto cleanup;
8135 obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt);
8136 if ((obj == NULL) || (obj->type != XPATH_STRING) ||
8137 (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
8138 goto cleanup;
8140 vshPrint(ctl, "%s\n", (const char *)obj->stringval);
8141 ret = TRUE;
8143 cleanup:
8144 xmlXPathFreeObject(obj);
8145 xmlXPathFreeContext(ctxt);
8146 if (xml)
8147 xmlFreeDoc(xml);
8148 virDomainFree(dom);
8149 return ret;
8153 * "attach-device" command
8155 static const vshCmdInfo info_attach_device[] = {
8156 {"help", N_("attach device from an XML file")},
8157 {"desc", N_("Attach device from an XML <file>.")},
8158 {NULL, NULL}
8161 static const vshCmdOptDef opts_attach_device[] = {
8162 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8163 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
8164 {"persistent", VSH_OT_BOOL, 0, N_("persist device attachment")},
8165 {NULL, 0, 0, NULL}
8168 static int
8169 cmdAttachDevice(vshControl *ctl, const vshCmd *cmd)
8171 virDomainPtr dom;
8172 char *from;
8173 char *buffer;
8174 int ret = TRUE;
8175 int found;
8176 unsigned int flags;
8178 if (!vshConnectionUsability(ctl, ctl->conn))
8179 return FALSE;
8181 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8182 return FALSE;
8184 from = vshCommandOptString(cmd, "file", &found);
8185 if (!found) {
8186 virDomainFree(dom);
8187 return FALSE;
8190 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
8191 virshReportError(ctl);
8192 virDomainFree(dom);
8193 return FALSE;
8196 if (vshCommandOptBool(cmd, "persistent")) {
8197 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8198 if (virDomainIsActive(dom) == 1)
8199 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8200 ret = virDomainAttachDeviceFlags(dom, buffer, flags);
8201 } else {
8202 ret = virDomainAttachDevice(dom, buffer);
8204 VIR_FREE(buffer);
8206 if (ret < 0) {
8207 vshError(ctl, _("Failed to attach device from %s"), from);
8208 virDomainFree(dom);
8209 return FALSE;
8210 } else {
8211 vshPrint(ctl, "%s", _("Device attached successfully\n"));
8214 virDomainFree(dom);
8215 return TRUE;
8220 * "detach-device" command
8222 static const vshCmdInfo info_detach_device[] = {
8223 {"help", N_("detach device from an XML file")},
8224 {"desc", N_("Detach device from an XML <file>")},
8225 {NULL, NULL}
8228 static const vshCmdOptDef opts_detach_device[] = {
8229 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8230 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
8231 {"persistent", VSH_OT_BOOL, 0, N_("persist device detachment")},
8232 {NULL, 0, 0, NULL}
8235 static int
8236 cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
8238 virDomainPtr dom;
8239 char *from;
8240 char *buffer;
8241 int ret = TRUE;
8242 int found;
8243 unsigned int flags;
8245 if (!vshConnectionUsability(ctl, ctl->conn))
8246 return FALSE;
8248 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8249 return FALSE;
8251 from = vshCommandOptString(cmd, "file", &found);
8252 if (!found) {
8253 virDomainFree(dom);
8254 return FALSE;
8257 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
8258 virshReportError(ctl);
8259 virDomainFree(dom);
8260 return FALSE;
8263 if (vshCommandOptBool(cmd, "persistent")) {
8264 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8265 if (virDomainIsActive(dom) == 1)
8266 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8267 ret = virDomainDetachDeviceFlags(dom, buffer, flags);
8268 } else {
8269 ret = virDomainDetachDevice(dom, buffer);
8271 VIR_FREE(buffer);
8273 if (ret < 0) {
8274 vshError(ctl, _("Failed to detach device from %s"), from);
8275 virDomainFree(dom);
8276 return FALSE;
8277 } else {
8278 vshPrint(ctl, "%s", _("Device detached successfully\n"));
8281 virDomainFree(dom);
8282 return TRUE;
8287 * "update-device" command
8289 static const vshCmdInfo info_update_device[] = {
8290 {"help", N_("update device from an XML file")},
8291 {"desc", N_("Update device from an XML <file>.")},
8292 {NULL, NULL}
8295 static const vshCmdOptDef opts_update_device[] = {
8296 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8297 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
8298 {"persistent", VSH_OT_BOOL, 0, N_("persist device update")},
8299 {NULL, 0, 0, NULL}
8302 static int
8303 cmdUpdateDevice(vshControl *ctl, const vshCmd *cmd)
8305 virDomainPtr dom;
8306 char *from;
8307 char *buffer;
8308 int ret = TRUE;
8309 int found;
8310 unsigned int flags;
8312 if (!vshConnectionUsability(ctl, ctl->conn))
8313 return FALSE;
8315 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8316 return FALSE;
8318 from = vshCommandOptString(cmd, "file", &found);
8319 if (!found) {
8320 virDomainFree(dom);
8321 return FALSE;
8324 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
8325 virshReportError(ctl);
8326 virDomainFree(dom);
8327 return FALSE;
8330 if (vshCommandOptBool(cmd, "persistent")) {
8331 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8332 if (virDomainIsActive(dom) == 1)
8333 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8334 } else {
8335 flags = VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8337 ret = virDomainUpdateDeviceFlags(dom, buffer, flags);
8338 VIR_FREE(buffer);
8340 if (ret < 0) {
8341 vshError(ctl, _("Failed to update device from %s"), from);
8342 virDomainFree(dom);
8343 return FALSE;
8344 } else {
8345 vshPrint(ctl, "%s", _("Device updated successfully\n"));
8348 virDomainFree(dom);
8349 return TRUE;
8354 * "attach-interface" command
8356 static const vshCmdInfo info_attach_interface[] = {
8357 {"help", N_("attach network interface")},
8358 {"desc", N_("Attach new network interface.")},
8359 {NULL, NULL}
8362 static const vshCmdOptDef opts_attach_interface[] = {
8363 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8364 {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface type")},
8365 {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of network interface")},
8366 {"target", VSH_OT_DATA, 0, N_("target network name")},
8367 {"mac", VSH_OT_DATA, 0, N_("MAC address")},
8368 {"script", VSH_OT_DATA, 0, N_("script used to bridge network interface")},
8369 {"model", VSH_OT_DATA, 0, N_("model type")},
8370 {"persistent", VSH_OT_BOOL, 0, N_("persist interface attachment")},
8371 {NULL, 0, 0, NULL}
8374 static int
8375 cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
8377 virDomainPtr dom = NULL;
8378 char *mac, *target, *script, *type, *source, *model;
8379 int typ, ret = FALSE;
8380 unsigned int flags;
8381 virBuffer buf = VIR_BUFFER_INITIALIZER;
8382 char *xml;
8384 if (!vshConnectionUsability(ctl, ctl->conn))
8385 goto cleanup;
8387 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8388 goto cleanup;
8390 if (!(type = vshCommandOptString(cmd, "type", NULL)))
8391 goto cleanup;
8393 source = vshCommandOptString(cmd, "source", NULL);
8394 target = vshCommandOptString(cmd, "target", NULL);
8395 mac = vshCommandOptString(cmd, "mac", NULL);
8396 script = vshCommandOptString(cmd, "script", NULL);
8397 model = vshCommandOptString(cmd, "model", NULL);
8399 /* check interface type */
8400 if (STREQ(type, "network")) {
8401 typ = 1;
8402 } else if (STREQ(type, "bridge")) {
8403 typ = 2;
8404 } else {
8405 vshError(ctl, _("No support for %s in command 'attach-interface'"),
8406 type);
8407 goto cleanup;
8410 /* Make XML of interface */
8411 virBufferVSprintf(&buf, "<interface type='%s'>\n", type);
8413 if (typ == 1)
8414 virBufferVSprintf(&buf, " <source network='%s'/>\n", source);
8415 else if (typ == 2)
8416 virBufferVSprintf(&buf, " <source bridge='%s'/>\n", source);
8418 if (target != NULL)
8419 virBufferVSprintf(&buf, " <target dev='%s'/>\n", target);
8420 if (mac != NULL)
8421 virBufferVSprintf(&buf, " <mac address='%s'/>\n", mac);
8422 if (script != NULL)
8423 virBufferVSprintf(&buf, " <script path='%s'/>\n", script);
8424 if (model != NULL)
8425 virBufferVSprintf(&buf, " <model type='%s'/>\n", model);
8427 virBufferAddLit(&buf, "</interface>\n");
8429 if (virBufferError(&buf)) {
8430 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
8431 return FALSE;
8434 xml = virBufferContentAndReset(&buf);
8436 if (vshCommandOptBool(cmd, "persistent")) {
8437 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8438 if (virDomainIsActive(dom) == 1)
8439 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8440 ret = virDomainAttachDeviceFlags(dom, xml, flags);
8441 } else {
8442 ret = virDomainAttachDevice(dom, xml);
8445 VIR_FREE(xml);
8447 if (ret != 0) {
8448 vshError(ctl, "%s", _("Failed to attach interface"));
8449 ret = FALSE;
8450 } else {
8451 vshPrint(ctl, "%s", _("Interface attached successfully\n"));
8452 ret = TRUE;
8455 cleanup:
8456 if (dom)
8457 virDomainFree(dom);
8458 virBufferFreeAndReset(&buf);
8459 return ret;
8463 * "detach-interface" command
8465 static const vshCmdInfo info_detach_interface[] = {
8466 {"help", N_("detach network interface")},
8467 {"desc", N_("Detach network interface.")},
8468 {NULL, NULL}
8471 static const vshCmdOptDef opts_detach_interface[] = {
8472 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8473 {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface type")},
8474 {"mac", VSH_OT_STRING, 0, N_("MAC address")},
8475 {"persistent", VSH_OT_BOOL, 0, N_("persist interface detachment")},
8476 {NULL, 0, 0, NULL}
8479 static int
8480 cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
8482 virDomainPtr dom = NULL;
8483 xmlDocPtr xml = NULL;
8484 xmlXPathObjectPtr obj=NULL;
8485 xmlXPathContextPtr ctxt = NULL;
8486 xmlNodePtr cur = NULL;
8487 xmlBufferPtr xml_buf = NULL;
8488 char *doc, *mac =NULL, *type;
8489 char buf[64];
8490 int i = 0, diff_mac, ret = FALSE;
8491 unsigned int flags;
8493 if (!vshConnectionUsability(ctl, ctl->conn))
8494 goto cleanup;
8496 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8497 goto cleanup;
8499 if (!(type = vshCommandOptString(cmd, "type", NULL)))
8500 goto cleanup;
8502 mac = vshCommandOptString(cmd, "mac", NULL);
8504 doc = virDomainGetXMLDesc(dom, 0);
8505 if (!doc)
8506 goto cleanup;
8508 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
8509 XML_PARSE_NOENT | XML_PARSE_NONET |
8510 XML_PARSE_NOWARNING);
8511 VIR_FREE(doc);
8512 if (!xml) {
8513 vshError(ctl, "%s", _("Failed to get interface information"));
8514 goto cleanup;
8516 ctxt = xmlXPathNewContext(xml);
8517 if (!ctxt) {
8518 vshError(ctl, "%s", _("Failed to get interface information"));
8519 goto cleanup;
8522 snprintf(buf, sizeof(buf), "/domain/devices/interface[@type='%s']", type);
8523 obj = xmlXPathEval(BAD_CAST buf, ctxt);
8524 if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
8525 (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
8526 vshError(ctl, _("No found interface whose type is %s"), type);
8527 goto cleanup;
8530 if (!mac)
8531 goto hit;
8533 /* search mac */
8534 for (; i < obj->nodesetval->nodeNr; i++) {
8535 cur = obj->nodesetval->nodeTab[i]->children;
8536 while (cur != NULL) {
8537 if (cur->type == XML_ELEMENT_NODE &&
8538 xmlStrEqual(cur->name, BAD_CAST "mac")) {
8539 char *tmp_mac = virXMLPropString(cur, "address");
8540 diff_mac = virMacAddrCompare (tmp_mac, mac);
8541 VIR_FREE(tmp_mac);
8542 if (!diff_mac) {
8543 goto hit;
8546 cur = cur->next;
8549 vshError(ctl, _("No found interface whose MAC address is %s"), mac);
8550 goto cleanup;
8552 hit:
8553 xml_buf = xmlBufferCreate();
8554 if (!xml_buf) {
8555 vshError(ctl, "%s", _("Failed to allocate memory"));
8556 goto cleanup;
8559 if(xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0){
8560 vshError(ctl, "%s", _("Failed to create XML"));
8561 goto cleanup;
8564 if (vshCommandOptBool(cmd, "persistent")) {
8565 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8566 if (virDomainIsActive(dom) == 1)
8567 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8568 ret = virDomainDetachDeviceFlags(dom,
8569 (char *)xmlBufferContent(xml_buf),
8570 flags);
8571 } else {
8572 ret = virDomainDetachDevice(dom, (char *)xmlBufferContent(xml_buf));
8575 if (ret != 0) {
8576 vshError(ctl, "%s", _("Failed to detach interface"));
8577 ret = FALSE;
8578 } else {
8579 vshPrint(ctl, "%s", _("Interface detached successfully\n"));
8580 ret = TRUE;
8583 cleanup:
8584 if (dom)
8585 virDomainFree(dom);
8586 xmlXPathFreeObject(obj);
8587 xmlXPathFreeContext(ctxt);
8588 if (xml)
8589 xmlFreeDoc(xml);
8590 if (xml_buf)
8591 xmlBufferFree(xml_buf);
8592 return ret;
8596 * "attach-disk" command
8598 static const vshCmdInfo info_attach_disk[] = {
8599 {"help", N_("attach disk device")},
8600 {"desc", N_("Attach new disk device.")},
8601 {NULL, NULL}
8604 static const vshCmdOptDef opts_attach_disk[] = {
8605 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8606 {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of disk device")},
8607 {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
8608 {"driver", VSH_OT_STRING, 0, N_("driver of disk device")},
8609 {"subdriver", VSH_OT_STRING, 0, N_("subdriver of disk device")},
8610 {"type", VSH_OT_STRING, 0, N_("target device type")},
8611 {"mode", VSH_OT_STRING, 0, N_("mode of device reading and writing")},
8612 {"persistent", VSH_OT_BOOL, 0, N_("persist disk attachment")},
8613 {"sourcetype", VSH_OT_STRING, 0, N_("type of source (block|file)")},
8614 {NULL, 0, 0, NULL}
8617 static int
8618 cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
8620 virDomainPtr dom = NULL;
8621 char *source, *target, *driver, *subdriver, *type, *mode;
8622 int isFile = 0, ret = FALSE;
8623 unsigned int flags;
8624 char *stype;
8625 virBuffer buf = VIR_BUFFER_INITIALIZER;
8626 char *xml;
8628 if (!vshConnectionUsability(ctl, ctl->conn))
8629 goto cleanup;
8631 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8632 goto cleanup;
8634 if (!(source = vshCommandOptString(cmd, "source", NULL)))
8635 goto cleanup;
8637 if (!(target = vshCommandOptString(cmd, "target", NULL)))
8638 goto cleanup;
8640 driver = vshCommandOptString(cmd, "driver", NULL);
8641 subdriver = vshCommandOptString(cmd, "subdriver", NULL);
8642 type = vshCommandOptString(cmd, "type", NULL);
8643 mode = vshCommandOptString(cmd, "mode", NULL);
8644 stype = vshCommandOptString(cmd, "sourcetype", NULL);
8646 if (!stype) {
8647 if (driver && (STREQ(driver, "file") || STREQ(driver, "tap")))
8648 isFile = 1;
8649 } else if (STREQ(stype, "file")) {
8650 isFile = 1;
8651 } else if (STRNEQ(stype, "block")) {
8652 vshError(ctl, _("Unknown source type: '%s'"), stype);
8653 goto cleanup;
8656 if (mode) {
8657 if (STRNEQ(mode, "readonly") && STRNEQ(mode, "shareable")) {
8658 vshError(ctl, _("No support for %s in command 'attach-disk'"),
8659 mode);
8660 goto cleanup;
8664 /* Make XML of disk */
8665 virBufferVSprintf(&buf, "<disk type='%s'",
8666 (isFile) ? "file" : "block");
8667 if (type)
8668 virBufferVSprintf(&buf, " device='%s'", type);
8669 virBufferAddLit(&buf, ">\n");
8671 if (driver || subdriver)
8672 virBufferVSprintf(&buf, " <driver");
8674 if (driver)
8675 virBufferVSprintf(&buf, " name='%s'", driver);
8676 if (subdriver)
8677 virBufferVSprintf(&buf, " type='%s'", subdriver);
8679 if (driver || subdriver)
8680 virBufferAddLit(&buf, "/>\n");
8682 virBufferVSprintf(&buf, " <source %s='%s'/>\n",
8683 (isFile) ? "file" : "dev",
8684 source);
8685 virBufferVSprintf(&buf, " <target dev='%s'/>\n", target);
8686 if (mode)
8687 virBufferVSprintf(&buf, " <%s/>\n", mode);
8689 virBufferAddLit(&buf, "</disk>\n");
8691 if (virBufferError(&buf)) {
8692 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
8693 return FALSE;
8696 xml = virBufferContentAndReset(&buf);
8698 if (vshCommandOptBool(cmd, "persistent")) {
8699 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8700 if (virDomainIsActive(dom) == 1)
8701 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8702 ret = virDomainAttachDeviceFlags(dom, xml, flags);
8703 } else {
8704 ret = virDomainAttachDevice(dom, xml);
8707 VIR_FREE(xml);
8709 if (ret != 0) {
8710 vshError(ctl, "%s", _("Failed to attach disk"));
8711 ret = FALSE;
8712 } else {
8713 vshPrint(ctl, "%s", _("Disk attached successfully\n"));
8714 ret = TRUE;
8717 cleanup:
8718 if (dom)
8719 virDomainFree(dom);
8720 virBufferFreeAndReset(&buf);
8721 return ret;
8725 * "detach-disk" command
8727 static const vshCmdInfo info_detach_disk[] = {
8728 {"help", N_("detach disk device")},
8729 {"desc", N_("Detach disk device.")},
8730 {NULL, NULL}
8733 static const vshCmdOptDef opts_detach_disk[] = {
8734 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8735 {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
8736 {"persistent", VSH_OT_BOOL, 0, N_("persist disk detachment")},
8737 {NULL, 0, 0, NULL}
8740 static int
8741 cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
8743 xmlDocPtr xml = NULL;
8744 xmlXPathObjectPtr obj=NULL;
8745 xmlXPathContextPtr ctxt = NULL;
8746 xmlNodePtr cur = NULL;
8747 xmlBufferPtr xml_buf = NULL;
8748 virDomainPtr dom = NULL;
8749 char *doc, *target;
8750 int i = 0, diff_tgt, ret = FALSE;
8751 unsigned int flags;
8753 if (!vshConnectionUsability(ctl, ctl->conn))
8754 goto cleanup;
8756 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8757 goto cleanup;
8759 if (!(target = vshCommandOptString(cmd, "target", NULL)))
8760 goto cleanup;
8762 doc = virDomainGetXMLDesc(dom, 0);
8763 if (!doc)
8764 goto cleanup;
8766 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
8767 XML_PARSE_NOENT | XML_PARSE_NONET |
8768 XML_PARSE_NOWARNING);
8769 VIR_FREE(doc);
8770 if (!xml) {
8771 vshError(ctl, "%s", _("Failed to get disk information"));
8772 goto cleanup;
8774 ctxt = xmlXPathNewContext(xml);
8775 if (!ctxt) {
8776 vshError(ctl, "%s", _("Failed to get disk information"));
8777 goto cleanup;
8780 obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
8781 if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
8782 (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
8783 vshError(ctl, "%s", _("Failed to get disk information"));
8784 goto cleanup;
8787 /* search target */
8788 for (; i < obj->nodesetval->nodeNr; i++) {
8789 cur = obj->nodesetval->nodeTab[i]->children;
8790 while (cur != NULL) {
8791 if (cur->type == XML_ELEMENT_NODE &&
8792 xmlStrEqual(cur->name, BAD_CAST "target")) {
8793 char *tmp_tgt = virXMLPropString(cur, "dev");
8794 diff_tgt = STREQ(tmp_tgt, target);
8795 VIR_FREE(tmp_tgt);
8796 if (diff_tgt) {
8797 goto hit;
8800 cur = cur->next;
8803 vshError(ctl, _("No found disk whose target is %s"), target);
8804 goto cleanup;
8806 hit:
8807 xml_buf = xmlBufferCreate();
8808 if (!xml_buf) {
8809 vshError(ctl, "%s", _("Failed to allocate memory"));
8810 goto cleanup;
8813 if(xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0){
8814 vshError(ctl, "%s", _("Failed to create XML"));
8815 goto cleanup;
8818 if (vshCommandOptBool(cmd, "persistent")) {
8819 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8820 if (virDomainIsActive(dom) == 1)
8821 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8822 ret = virDomainDetachDeviceFlags(dom,
8823 (char *)xmlBufferContent(xml_buf),
8824 flags);
8825 } else {
8826 ret = virDomainDetachDevice(dom, (char *)xmlBufferContent(xml_buf));
8829 if (ret != 0) {
8830 vshError(ctl, "%s", _("Failed to detach disk"));
8831 ret = FALSE;
8832 } else {
8833 vshPrint(ctl, "%s", _("Disk detached successfully\n"));
8834 ret = TRUE;
8837 cleanup:
8838 xmlXPathFreeObject(obj);
8839 xmlXPathFreeContext(ctxt);
8840 if (xml)
8841 xmlFreeDoc(xml);
8842 if (xml_buf)
8843 xmlBufferFree(xml_buf);
8844 if (dom)
8845 virDomainFree(dom);
8846 return ret;
8850 * "cpu-compare" command
8852 static const vshCmdInfo info_cpu_compare[] = {
8853 {"help", N_("compare host CPU with a CPU described by an XML file")},
8854 {"desc", N_("compare CPU with host CPU")},
8855 {NULL, NULL}
8858 static const vshCmdOptDef opts_cpu_compare[] = {
8859 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML CPU description")},
8860 {NULL, 0, 0, NULL}
8863 static int
8864 cmdCPUCompare(vshControl *ctl, const vshCmd *cmd)
8866 char *from;
8867 int found;
8868 int ret = TRUE;
8869 char *buffer;
8870 int result;
8872 if (!vshConnectionUsability(ctl, ctl->conn))
8873 return FALSE;
8875 from = vshCommandOptString(cmd, "file", &found);
8876 if (!found)
8877 return FALSE;
8879 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
8880 return FALSE;
8882 result = virConnectCompareCPU(ctl->conn, buffer, 0);
8883 VIR_FREE(buffer);
8885 switch (result) {
8886 case VIR_CPU_COMPARE_INCOMPATIBLE:
8887 vshPrint(ctl, _("CPU described in %s is incompatible with host CPU\n"),
8888 from);
8889 ret = FALSE;
8890 break;
8892 case VIR_CPU_COMPARE_IDENTICAL:
8893 vshPrint(ctl, _("CPU described in %s is identical to host CPU\n"),
8894 from);
8895 ret = TRUE;
8896 break;
8898 case VIR_CPU_COMPARE_SUPERSET:
8899 vshPrint(ctl, _("Host CPU is a superset of CPU described in %s\n"),
8900 from);
8901 ret = TRUE;
8902 break;
8904 case VIR_CPU_COMPARE_ERROR:
8905 default:
8906 vshError(ctl, _("Failed to compare host CPU with %s"), from);
8907 ret = FALSE;
8910 return ret;
8914 * "cpu-baseline" command
8916 static const vshCmdInfo info_cpu_baseline[] = {
8917 {"help", N_("compute baseline CPU")},
8918 {"desc", N_("Compute baseline CPU for a set of given CPUs.")},
8919 {NULL, NULL}
8922 static const vshCmdOptDef opts_cpu_baseline[] = {
8923 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing XML CPU descriptions")},
8924 {NULL, 0, 0, NULL}
8927 static int
8928 cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
8930 char *from;
8931 int found;
8932 int ret = TRUE;
8933 char *buffer;
8934 char *result = NULL;
8935 const char **list = NULL;
8936 unsigned int count = 0;
8937 xmlDocPtr doc = NULL;
8938 xmlNodePtr node_list;
8939 xmlXPathContextPtr ctxt = NULL;
8940 xmlSaveCtxtPtr sctxt = NULL;
8941 xmlBufferPtr buf = NULL;
8942 xmlXPathObjectPtr obj = NULL;
8943 int res, i;
8945 if (!vshConnectionUsability(ctl, ctl->conn))
8946 return FALSE;
8948 from = vshCommandOptString(cmd, "file", &found);
8949 if (!found)
8950 return FALSE;
8952 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
8953 return FALSE;
8955 doc = xmlNewDoc(NULL);
8956 if (doc == NULL)
8957 goto no_memory;
8959 res = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
8960 (const xmlChar *)buffer, &node_list);
8961 if (res != 0) {
8962 vshError(ctl, _("Failed to parse XML fragment %s"), from);
8963 ret = FALSE;
8964 goto cleanup;
8967 xmlAddChildList((xmlNodePtr) doc, node_list);
8969 ctxt = xmlXPathNewContext(doc);
8970 if (!ctxt)
8971 goto no_memory;
8973 obj = xmlXPathEval(BAD_CAST "//cpu[not(ancestor::cpu)]", ctxt);
8974 if ((obj == NULL) || (obj->nodesetval == NULL) ||
8975 (obj->nodesetval->nodeTab == NULL))
8976 goto cleanup;
8978 for (i = 0;i < obj->nodesetval->nodeNr;i++) {
8979 buf = xmlBufferCreate();
8980 if (buf == NULL)
8981 goto no_memory;
8982 sctxt = xmlSaveToBuffer(buf, NULL, 0);
8983 if (sctxt == NULL) {
8984 xmlBufferFree(buf);
8985 goto no_memory;
8988 xmlSaveTree(sctxt, obj->nodesetval->nodeTab[i]);
8989 xmlSaveClose(sctxt);
8991 list = vshRealloc(ctl, list, sizeof(char *) * (count + 1));
8992 list[count++] = (char *) buf->content;
8993 buf->content = NULL;
8994 xmlBufferFree(buf);
8995 buf = NULL;
8998 if (count == 0) {
8999 vshError(ctl, _("No host CPU specified in '%s'"), from);
9000 ret = FALSE;
9001 goto cleanup;
9004 result = virConnectBaselineCPU(ctl->conn, list, count, 0);
9006 if (result)
9007 vshPrint(ctl, "%s", result);
9008 else
9009 ret = FALSE;
9011 cleanup:
9012 xmlXPathFreeObject(obj);
9013 xmlXPathFreeContext(ctxt);
9014 xmlFreeDoc(doc);
9015 VIR_FREE(result);
9016 if ((list != NULL) && (count > 0)) {
9017 for (i = 0;i < count;i++)
9018 VIR_FREE(list[i]);
9020 VIR_FREE(list);
9021 VIR_FREE(buffer);
9023 return ret;
9025 no_memory:
9026 vshError(ctl, "%s", _("Out of memory"));
9027 ret = FALSE;
9028 goto cleanup;
9031 /* Common code for the edit / net-edit / pool-edit functions which follow. */
9032 static char *
9033 editWriteToTempFile (vshControl *ctl, const char *doc)
9035 char *ret;
9036 const char *tmpdir;
9037 int fd;
9039 ret = vshMalloc(ctl, PATH_MAX);
9041 tmpdir = getenv ("TMPDIR");
9042 if (!tmpdir) tmpdir = "/tmp";
9043 snprintf (ret, PATH_MAX, "%s/virshXXXXXX.xml", tmpdir);
9044 fd = mkstemps(ret, 4);
9045 if (fd == -1) {
9046 vshError(ctl, _("mkstemps: failed to create temporary file: %s"),
9047 strerror(errno));
9048 VIR_FREE(ret);
9049 return NULL;
9052 if (safewrite (fd, doc, strlen (doc)) == -1) {
9053 vshError(ctl, _("write: %s: failed to write to temporary file: %s"),
9054 ret, strerror(errno));
9055 VIR_FORCE_CLOSE(fd);
9056 unlink (ret);
9057 VIR_FREE(ret);
9058 return NULL;
9060 if (VIR_CLOSE(fd) < 0) {
9061 vshError(ctl, _("close: %s: failed to write or close temporary file: %s"),
9062 ret, strerror(errno));
9063 unlink (ret);
9064 VIR_FREE(ret);
9065 return NULL;
9068 /* Temporary filename: caller frees. */
9069 return ret;
9072 /* Characters permitted in $EDITOR environment variable and temp filename. */
9073 #define ACCEPTED_CHARS \
9074 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/_.:@"
9076 static int
9077 editFile (vshControl *ctl, const char *filename)
9079 const char *editor;
9080 char *command;
9081 int command_ret;
9083 editor = getenv ("VISUAL");
9084 if (!editor) editor = getenv ("EDITOR");
9085 if (!editor) editor = "vi"; /* could be cruel & default to ed(1) here */
9087 /* Check that filename doesn't contain shell meta-characters, and
9088 * if it does, refuse to run. Follow the Unix conventions for
9089 * EDITOR: the user can intentionally specify command options, so
9090 * we don't protect any shell metacharacters there. Lots more
9091 * than virsh will misbehave if EDITOR has bogus contents (which
9092 * is why sudo scrubs it by default).
9094 if (strspn (filename, ACCEPTED_CHARS) != strlen (filename)) {
9095 vshError(ctl,
9096 _("%s: temporary filename contains shell meta or other "
9097 "unacceptable characters (is $TMPDIR wrong?)"),
9098 filename);
9099 return -1;
9102 if (virAsprintf(&command, "%s %s", editor, filename) == -1) {
9103 vshError(ctl,
9104 _("virAsprintf: could not create editing command: %s"),
9105 strerror(errno));
9106 return -1;
9109 command_ret = system (command);
9110 if (command_ret == -1) {
9111 vshError(ctl,
9112 _("%s: edit command failed: %s"), command, strerror(errno));
9113 VIR_FREE(command);
9114 return -1;
9116 if (WEXITSTATUS(command_ret) != 0) {
9117 vshError(ctl,
9118 _("%s: command exited with non-zero status"), command);
9119 VIR_FREE(command);
9120 return -1;
9122 VIR_FREE(command);
9123 return 0;
9126 static char *
9127 editReadBackFile (vshControl *ctl, const char *filename)
9129 char *ret;
9131 if (virFileReadAll (filename, VIRSH_MAX_XML_FILE, &ret) == -1) {
9132 vshError(ctl,
9133 _("%s: failed to read temporary file: %s"),
9134 filename, strerror(errno));
9135 return NULL;
9137 return ret;
9141 #ifndef WIN32
9143 * "cd" command
9145 static const vshCmdInfo info_cd[] = {
9146 {"help", N_("change the current directory")},
9147 {"desc", N_("Change the current directory.")},
9148 {NULL, NULL}
9151 static const vshCmdOptDef opts_cd[] = {
9152 {"dir", VSH_OT_DATA, 0, N_("directory to switch to (default: home or else root)")},
9153 {NULL, 0, 0, NULL}
9156 static int
9157 cmdCd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
9159 const char *dir;
9160 int found;
9162 if (!ctl->imode) {
9163 vshError(ctl, "%s", _("cd: command valid only in interactive mode"));
9164 return FALSE;
9167 dir = vshCommandOptString(cmd, "dir", &found);
9168 if (!found) {
9169 uid_t uid = geteuid();
9170 dir = virGetUserDirectory(uid);
9172 if (!dir)
9173 dir = "/";
9175 if (chdir (dir) == -1) {
9176 vshError(ctl, _("cd: %s: %s"), strerror(errno), dir);
9177 return FALSE;
9180 return TRUE;
9183 #endif
9185 #ifndef WIN32
9187 * "pwd" command
9189 static const vshCmdInfo info_pwd[] = {
9190 {"help", N_("print the current directory")},
9191 {"desc", N_("Print the current directory.")},
9192 {NULL, NULL}
9195 static int
9196 cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
9198 char *cwd;
9199 size_t path_max;
9200 int err = TRUE;
9202 path_max = (size_t) PATH_MAX + 2;
9203 cwd = vshMalloc (ctl, path_max);
9204 while (cwd) {
9205 err = getcwd (cwd, path_max) == NULL;
9206 if (!err || errno != ERANGE)
9207 break;
9209 path_max *= 2;
9210 cwd = vshRealloc (ctl, cwd, path_max);
9213 if (err)
9214 vshError(ctl, _("pwd: cannot get current directory: %s"),
9215 strerror(errno));
9216 else
9217 vshPrint (ctl, _("%s\n"), cwd);
9219 VIR_FREE(cwd);
9220 return !err;
9222 #endif
9225 * "echo" command
9227 static const vshCmdInfo info_echo[] = {
9228 {"help", N_("echo arguments")},
9229 {"desc", N_("Echo back arguments, possibly with quoting.")},
9230 {NULL, NULL}
9233 static const vshCmdOptDef opts_echo[] = {
9234 {"shell", VSH_OT_BOOL, 0, N_("escape for shell use")},
9235 {"xml", VSH_OT_BOOL, 0, N_("escape for XML use")},
9236 {"", VSH_OT_ARGV, 0, N_("arguments to echo")},
9237 {NULL, 0, 0, NULL}
9240 /* Exists mainly for debugging virsh, but also handy for adding back
9241 * quotes for later evaluation.
9243 static int
9244 cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd)
9246 bool shell = false;
9247 bool xml = false;
9248 int count = 0;
9249 char *arg;
9250 virBuffer buf = VIR_BUFFER_INITIALIZER;
9252 if (vshCommandOptBool(cmd, "shell"))
9253 shell = true;
9254 if (vshCommandOptBool(cmd, "xml"))
9255 xml = true;
9257 while ((arg = vshCommandOptArgv(cmd, count)) != NULL) {
9258 bool close_quote = false;
9259 char *q;
9261 if (count)
9262 virBufferAddChar(&buf, ' ');
9263 /* Add outer '' only if arg included shell metacharacters. */
9264 if (shell &&
9265 (strpbrk(arg, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") || !*arg)) {
9266 virBufferAddChar(&buf, '\'');
9267 close_quote = true;
9269 if (xml) {
9270 virBufferEscapeString(&buf, "%s", arg);
9271 } else {
9272 if (shell && (q = strchr(arg, '\''))) {
9273 do {
9274 virBufferAdd(&buf, arg, q - arg);
9275 virBufferAddLit(&buf, "'\\''");
9276 arg = q + 1;
9277 q = strchr(arg, '\'');
9278 } while (q);
9280 virBufferAdd(&buf, arg, strlen(arg));
9282 if (close_quote)
9283 virBufferAddChar(&buf, '\'');
9284 count++;
9287 if (virBufferError(&buf)) {
9288 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
9289 return FALSE;
9291 arg = virBufferContentAndReset(&buf);
9292 if (arg)
9293 vshPrint(ctl, "%s", arg);
9294 VIR_FREE(arg);
9295 return TRUE;
9299 * "edit" command
9301 static const vshCmdInfo info_edit[] = {
9302 {"help", N_("edit XML configuration for a domain")},
9303 {"desc", N_("Edit the XML configuration for a domain.")},
9304 {NULL, NULL}
9307 static const vshCmdOptDef opts_edit[] = {
9308 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9309 {NULL, 0, 0, NULL}
9312 /* This function also acts as a template to generate cmdNetworkEdit
9313 * and cmdPoolEdit functions (below) using a sed script in the Makefile.
9315 static int
9316 cmdEdit (vshControl *ctl, const vshCmd *cmd)
9318 int ret = FALSE;
9319 virDomainPtr dom = NULL;
9320 char *tmp = NULL;
9321 char *doc = NULL;
9322 char *doc_edited = NULL;
9323 char *doc_reread = NULL;
9324 int flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_INACTIVE;
9326 if (!vshConnectionUsability(ctl, ctl->conn))
9327 goto cleanup;
9329 dom = vshCommandOptDomain (ctl, cmd, NULL);
9330 if (dom == NULL)
9331 goto cleanup;
9333 /* Get the XML configuration of the domain. */
9334 doc = virDomainGetXMLDesc (dom, flags);
9335 if (!doc)
9336 goto cleanup;
9338 /* Create and open the temporary file. */
9339 tmp = editWriteToTempFile (ctl, doc);
9340 if (!tmp) goto cleanup;
9342 /* Start the editor. */
9343 if (editFile (ctl, tmp) == -1) goto cleanup;
9345 /* Read back the edited file. */
9346 doc_edited = editReadBackFile (ctl, tmp);
9347 if (!doc_edited) goto cleanup;
9349 /* Compare original XML with edited. Has it changed at all? */
9350 if (STREQ (doc, doc_edited)) {
9351 vshPrint (ctl, _("Domain %s XML configuration not changed.\n"),
9352 virDomainGetName (dom));
9353 ret = TRUE;
9354 goto cleanup;
9357 /* Now re-read the domain XML. Did someone else change it while
9358 * it was being edited? This also catches problems such as us
9359 * losing a connection or the domain going away.
9361 doc_reread = virDomainGetXMLDesc (dom, flags);
9362 if (!doc_reread)
9363 goto cleanup;
9365 if (STRNEQ (doc, doc_reread)) {
9366 vshError(ctl,
9367 "%s", _("ERROR: the XML configuration was changed by another user"));
9368 goto cleanup;
9371 /* Everything checks out, so redefine the domain. */
9372 virDomainFree (dom);
9373 dom = virDomainDefineXML (ctl->conn, doc_edited);
9374 if (!dom)
9375 goto cleanup;
9377 vshPrint (ctl, _("Domain %s XML configuration edited.\n"),
9378 virDomainGetName(dom));
9380 ret = TRUE;
9382 cleanup:
9383 if (dom)
9384 virDomainFree (dom);
9386 VIR_FREE(doc);
9387 VIR_FREE(doc_edited);
9388 VIR_FREE(doc_reread);
9390 if (tmp) {
9391 unlink (tmp);
9392 VIR_FREE(tmp);
9395 return ret;
9399 * "net-edit" command
9401 static const vshCmdInfo info_network_edit[] = {
9402 {"help", N_("edit XML configuration for a network")},
9403 {"desc", N_("Edit the XML configuration for a network.")},
9404 {NULL, NULL}
9407 static const vshCmdOptDef opts_network_edit[] = {
9408 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
9409 {NULL, 0, 0, NULL}
9412 /* This is generated from this file by a sed script in the Makefile. */
9413 #include "virsh-net-edit.c"
9416 * "pool-edit" command
9418 static const vshCmdInfo info_pool_edit[] = {
9419 {"help", N_("edit XML configuration for a storage pool")},
9420 {"desc", N_("Edit the XML configuration for a storage pool.")},
9421 {NULL, NULL}
9424 static const vshCmdOptDef opts_pool_edit[] = {
9425 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
9426 {NULL, 0, 0, NULL}
9429 /* This is generated from this file by a sed script in the Makefile. */
9430 #include "virsh-pool-edit.c"
9433 * "quit" command
9435 static const vshCmdInfo info_quit[] = {
9436 {"help", N_("quit this interactive terminal")},
9437 {"desc", ""},
9438 {NULL, NULL}
9441 static int
9442 cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
9444 ctl->imode = FALSE;
9445 return TRUE;
9449 * "snapshot-create" command
9451 static const vshCmdInfo info_snapshot_create[] = {
9452 {"help", N_("Create a snapshot")},
9453 {"desc", N_("Snapshot create")},
9454 {NULL, NULL}
9457 static const vshCmdOptDef opts_snapshot_create[] = {
9458 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9459 {"xmlfile", VSH_OT_DATA, 0, N_("domain snapshot XML")},
9460 {NULL, 0, 0, NULL}
9463 static int
9464 cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
9466 virDomainPtr dom = NULL;
9467 int ret = FALSE;
9468 char *from;
9469 char *buffer = NULL;
9470 virDomainSnapshotPtr snapshot = NULL;
9471 xmlDocPtr xml = NULL;
9472 xmlXPathContextPtr ctxt = NULL;
9473 char *doc = NULL;
9474 char *name = NULL;
9476 if (!vshConnectionUsability(ctl, ctl->conn))
9477 goto cleanup;
9479 dom = vshCommandOptDomain(ctl, cmd, NULL);
9480 if (dom == NULL)
9481 goto cleanup;
9483 from = vshCommandOptString(cmd, "xmlfile", NULL);
9484 if (from == NULL)
9485 buffer = vshStrdup(ctl, "<domainsnapshot/>");
9486 else {
9487 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
9488 /* we have to report the error here because during cleanup
9489 * we'll run through virDomainFree(), which loses the
9490 * last error
9492 virshReportError(ctl);
9493 goto cleanup;
9496 if (buffer == NULL) {
9497 vshError(ctl, "%s", _("Out of memory"));
9498 goto cleanup;
9501 snapshot = virDomainSnapshotCreateXML(dom, buffer, 0);
9502 if (snapshot == NULL)
9503 goto cleanup;
9505 doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
9506 if (!doc)
9507 goto cleanup;
9509 xml = xmlReadDoc((const xmlChar *) doc, "domainsnapshot.xml", NULL,
9510 XML_PARSE_NOENT | XML_PARSE_NONET |
9511 XML_PARSE_NOWARNING);
9512 if (!xml)
9513 goto cleanup;
9514 ctxt = xmlXPathNewContext(xml);
9515 if (!ctxt)
9516 goto cleanup;
9518 name = virXPathString("string(/domainsnapshot/name)", ctxt);
9519 if (!name) {
9520 vshError(ctl, "%s",
9521 _("Could not find 'name' element in domain snapshot XML"));
9522 goto cleanup;
9525 vshPrint(ctl, _("Domain snapshot %s created"), name);
9526 if (from)
9527 vshPrint(ctl, _(" from '%s'"), from);
9528 vshPrint(ctl, "\n");
9530 ret = TRUE;
9532 cleanup:
9533 VIR_FREE(name);
9534 xmlXPathFreeContext(ctxt);
9535 if (xml)
9536 xmlFreeDoc(xml);
9537 if (snapshot)
9538 virDomainSnapshotFree(snapshot);
9539 VIR_FREE(doc);
9540 VIR_FREE(buffer);
9541 if (dom)
9542 virDomainFree(dom);
9544 return ret;
9548 * "snapshot-current" command
9550 static const vshCmdInfo info_snapshot_current[] = {
9551 {"help", N_("Get the current snapshot")},
9552 {"desc", N_("Get the current snapshot")},
9553 {NULL, NULL}
9556 static const vshCmdOptDef opts_snapshot_current[] = {
9557 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9558 {NULL, 0, 0, NULL}
9561 static int
9562 cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
9564 virDomainPtr dom = NULL;
9565 int ret = FALSE;
9566 int current;
9567 virDomainSnapshotPtr snapshot = NULL;
9569 if (!vshConnectionUsability(ctl, ctl->conn))
9570 goto cleanup;
9572 dom = vshCommandOptDomain(ctl, cmd, NULL);
9573 if (dom == NULL)
9574 goto cleanup;
9576 current = virDomainHasCurrentSnapshot(dom, 0);
9577 if (current < 0)
9578 goto cleanup;
9579 else if (current) {
9580 char *xml;
9582 if (!(snapshot = virDomainSnapshotCurrent(dom, 0)))
9583 goto cleanup;
9585 xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
9586 if (!xml)
9587 goto cleanup;
9589 vshPrint(ctl, "%s", xml);
9590 VIR_FREE(xml);
9593 ret = TRUE;
9595 cleanup:
9596 if (snapshot)
9597 virDomainSnapshotFree(snapshot);
9598 if (dom)
9599 virDomainFree(dom);
9601 return ret;
9605 * "snapshot-list" command
9607 static const vshCmdInfo info_snapshot_list[] = {
9608 {"help", N_("List snapshots for a domain")},
9609 {"desc", N_("Snapshot List")},
9610 {NULL, NULL}
9613 static const vshCmdOptDef opts_snapshot_list[] = {
9614 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9615 {NULL, 0, 0, NULL}
9618 static int
9619 cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
9621 virDomainPtr dom = NULL;
9622 int ret = FALSE;
9623 int numsnaps;
9624 char **names = NULL;
9625 int actual = 0;
9626 int i;
9627 xmlDocPtr xml = NULL;
9628 xmlXPathContextPtr ctxt = NULL;
9629 char *doc = NULL;
9630 virDomainSnapshotPtr snapshot = NULL;
9631 char *state = NULL;
9632 long creation;
9633 char timestr[100];
9634 struct tm time_info;
9636 if (!vshConnectionUsability(ctl, ctl->conn))
9637 goto cleanup;
9639 dom = vshCommandOptDomain(ctl, cmd, NULL);
9640 if (dom == NULL)
9641 goto cleanup;
9643 numsnaps = virDomainSnapshotNum(dom, 0);
9645 if (numsnaps < 0)
9646 goto cleanup;
9648 vshPrint(ctl, " %-20s %-25s %s\n", _("Name"), _("Creation Time"), _("State"));
9649 vshPrint(ctl, "---------------------------------------------------\n");
9651 if (numsnaps) {
9652 if (VIR_ALLOC_N(names, numsnaps) < 0)
9653 goto cleanup;
9655 actual = virDomainSnapshotListNames(dom, names, numsnaps, 0);
9656 if (actual < 0)
9657 goto cleanup;
9659 qsort(&names[0], actual, sizeof(char*), namesorter);
9661 for (i = 0; i < actual; i++) {
9662 /* free up memory from previous iterations of the loop */
9663 VIR_FREE(state);
9664 if (snapshot)
9665 virDomainSnapshotFree(snapshot);
9666 xmlXPathFreeContext(ctxt);
9667 if (xml)
9668 xmlFreeDoc(xml);
9669 VIR_FREE(doc);
9671 snapshot = virDomainSnapshotLookupByName(dom, names[i], 0);
9672 if (snapshot == NULL)
9673 continue;
9675 doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
9676 if (!doc)
9677 continue;
9679 xml = xmlReadDoc((const xmlChar *) doc, "domainsnapshot.xml", NULL,
9680 XML_PARSE_NOENT | XML_PARSE_NONET |
9681 XML_PARSE_NOWARNING);
9682 if (!xml)
9683 continue;
9684 ctxt = xmlXPathNewContext(xml);
9685 if (!ctxt)
9686 continue;
9688 state = virXPathString("string(/domainsnapshot/state)", ctxt);
9689 if (state == NULL)
9690 continue;
9691 if (virXPathLong("string(/domainsnapshot/creationTime)", ctxt,
9692 &creation) < 0)
9693 continue;
9694 localtime_r(&creation, &time_info);
9695 strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", &time_info);
9697 vshPrint(ctl, " %-20s %-25s %s\n", names[i], timestr, state);
9701 ret = TRUE;
9703 cleanup:
9704 /* this frees up memory from the last iteration of the loop */
9705 VIR_FREE(state);
9706 if (snapshot)
9707 virDomainSnapshotFree(snapshot);
9708 xmlXPathFreeContext(ctxt);
9709 if (xml)
9710 xmlFreeDoc(xml);
9711 VIR_FREE(doc);
9712 for (i = 0; i < actual; i++)
9713 VIR_FREE(names[i]);
9714 VIR_FREE(names);
9715 if (dom)
9716 virDomainFree(dom);
9718 return ret;
9722 * "snapshot-dumpxml" command
9724 static const vshCmdInfo info_snapshot_dumpxml[] = {
9725 {"help", N_("Dump XML for a domain snapshot")},
9726 {"desc", N_("Snapshot Dump XML")},
9727 {NULL, NULL}
9730 static const vshCmdOptDef opts_snapshot_dumpxml[] = {
9731 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9732 {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
9733 {NULL, 0, 0, NULL}
9736 static int
9737 cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd)
9739 virDomainPtr dom = NULL;
9740 int ret = FALSE;
9741 char *name;
9742 virDomainSnapshotPtr snapshot = NULL;
9743 char *xml = NULL;
9745 if (!vshConnectionUsability(ctl, ctl->conn))
9746 goto cleanup;
9748 dom = vshCommandOptDomain(ctl, cmd, NULL);
9749 if (dom == NULL)
9750 goto cleanup;
9752 name = vshCommandOptString(cmd, "snapshotname", NULL);
9753 if (name == NULL)
9754 goto cleanup;
9756 snapshot = virDomainSnapshotLookupByName(dom, name, 0);
9757 if (snapshot == NULL)
9758 goto cleanup;
9760 xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
9761 if (!xml)
9762 goto cleanup;
9764 vshPrint(ctl, "%s", xml);
9766 ret = TRUE;
9768 cleanup:
9769 VIR_FREE(xml);
9770 if (snapshot)
9771 virDomainSnapshotFree(snapshot);
9772 if (dom)
9773 virDomainFree(dom);
9775 return ret;
9779 * "snapshot-revert" command
9781 static const vshCmdInfo info_snapshot_revert[] = {
9782 {"help", N_("Revert a domain to a snapshot")},
9783 {"desc", N_("Revert domain to snapshot")},
9784 {NULL, NULL}
9787 static const vshCmdOptDef opts_snapshot_revert[] = {
9788 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9789 {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
9790 {NULL, 0, 0, NULL}
9793 static int
9794 cmdDomainSnapshotRevert(vshControl *ctl, const vshCmd *cmd)
9796 virDomainPtr dom = NULL;
9797 int ret = FALSE;
9798 char *name;
9799 virDomainSnapshotPtr snapshot = NULL;
9801 if (!vshConnectionUsability(ctl, ctl->conn))
9802 goto cleanup;
9804 dom = vshCommandOptDomain(ctl, cmd, NULL);
9805 if (dom == NULL)
9806 goto cleanup;
9808 name = vshCommandOptString(cmd, "snapshotname", NULL);
9809 if (name == NULL)
9810 goto cleanup;
9812 snapshot = virDomainSnapshotLookupByName(dom, name, 0);
9813 if (snapshot == NULL)
9814 goto cleanup;
9816 if (virDomainRevertToSnapshot(snapshot, 0) < 0)
9817 goto cleanup;
9819 ret = TRUE;
9821 cleanup:
9822 if (snapshot)
9823 virDomainSnapshotFree(snapshot);
9824 if (dom)
9825 virDomainFree(dom);
9827 return ret;
9831 * "snapshot-delete" command
9833 static const vshCmdInfo info_snapshot_delete[] = {
9834 {"help", N_("Delete a domain snapshot")},
9835 {"desc", N_("Snapshot Delete")},
9836 {NULL, NULL}
9839 static const vshCmdOptDef opts_snapshot_delete[] = {
9840 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9841 {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
9842 {"children", VSH_OT_BOOL, 0, N_("delete snapshot and all children")},
9843 {NULL, 0, 0, NULL}
9846 static int
9847 cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd)
9849 virDomainPtr dom = NULL;
9850 int ret = FALSE;
9851 char *name;
9852 virDomainSnapshotPtr snapshot = NULL;
9853 unsigned int flags = 0;
9855 if (!vshConnectionUsability(ctl, ctl->conn))
9856 goto cleanup;
9858 dom = vshCommandOptDomain(ctl, cmd, NULL);
9859 if (dom == NULL)
9860 goto cleanup;
9862 name = vshCommandOptString(cmd, "snapshotname", NULL);
9863 if (name == NULL)
9864 goto cleanup;
9866 if (vshCommandOptBool(cmd, "children"))
9867 flags |= VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN;
9869 snapshot = virDomainSnapshotLookupByName(dom, name, 0);
9870 if (snapshot == NULL)
9871 goto cleanup;
9873 if (virDomainSnapshotDelete(snapshot, flags) < 0)
9874 goto cleanup;
9876 ret = TRUE;
9878 cleanup:
9879 if (snapshot)
9880 virDomainSnapshotFree(snapshot);
9881 if (dom)
9882 virDomainFree(dom);
9884 return ret;
9888 * "qemu-monitor-command" command
9890 static const vshCmdInfo info_qemu_monitor_command[] = {
9891 {"help", N_("Qemu Monitor Command")},
9892 {"desc", N_("Qemu Monitor Command")},
9893 {NULL, NULL}
9896 static const vshCmdOptDef opts_qemu_monitor_command[] = {
9897 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9898 {"cmd", VSH_OT_DATA, VSH_OFLAG_REQ, N_("command")},
9899 {NULL, 0, 0, NULL}
9902 static int
9903 cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
9905 virDomainPtr dom = NULL;
9906 int ret = FALSE;
9907 char *monitor_cmd;
9908 char *result = NULL;
9910 if (!vshConnectionUsability(ctl, ctl->conn))
9911 goto cleanup;
9913 dom = vshCommandOptDomain(ctl, cmd, NULL);
9914 if (dom == NULL)
9915 goto cleanup;
9917 monitor_cmd = vshCommandOptString(cmd, "cmd", NULL);
9918 if (monitor_cmd == NULL) {
9919 vshError(ctl, "%s", _("missing monitor command"));
9920 goto cleanup;
9923 if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, 0) < 0)
9924 goto cleanup;
9926 printf("%s\n", result);
9928 ret = TRUE;
9930 cleanup:
9931 VIR_FREE(result);
9932 if (dom)
9933 virDomainFree(dom);
9935 return ret;
9938 static const vshCmdDef domManagementCmds[] = {
9939 {"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device},
9940 {"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk},
9941 {"attach-interface", cmdAttachInterface, opts_attach_interface, info_attach_interface},
9942 {"autostart", cmdAutostart, opts_autostart, info_autostart},
9943 #ifndef WIN32
9944 {"console", cmdConsole, opts_console, info_console},
9945 #endif
9946 {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline},
9947 {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare},
9948 {"create", cmdCreate, opts_create, info_create},
9949 {"define", cmdDefine, opts_define, info_define},
9950 {"destroy", cmdDestroy, opts_destroy, info_destroy},
9951 {"detach-device", cmdDetachDevice, opts_detach_device, info_detach_device},
9952 {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk},
9953 {"detach-interface", cmdDetachInterface, opts_detach_interface, info_detach_interface},
9954 {"domid", cmdDomid, opts_domid, info_domid},
9955 {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort},
9956 {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo},
9957 {"domname", cmdDomname, opts_domname, info_domname},
9958 {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
9959 {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, info_domxmlfromnative},
9960 {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, info_domxmltonative},
9961 {"dump", cmdDump, opts_dump, info_dump},
9962 {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
9963 {"echo", cmdEcho, opts_echo, info_echo},
9964 {"edit", cmdEdit, opts_edit, info_edit},
9965 {"freecell", cmdFreecell, opts_freecell, info_freecell},
9966 {"hostname", cmdHostname, NULL, info_hostname},
9967 {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave},
9968 {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, info_managedsaveremove},
9969 {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus},
9970 {"memtune", cmdMemtune, opts_memtune, info_memtune},
9971 {"migrate", cmdMigrate, opts_migrate, info_migrate},
9972 {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime},
9973 {"reboot", cmdReboot, opts_reboot, info_reboot},
9974 {"restore", cmdRestore, opts_restore, info_restore},
9975 {"resume", cmdResume, opts_resume, info_resume},
9976 {"save", cmdSave, opts_save, info_save},
9977 {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo},
9978 {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
9979 {"setmem", cmdSetmem, opts_setmem, info_setmem},
9980 {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
9981 {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
9982 {"start", cmdStart, opts_start, info_start},
9983 {"suspend", cmdSuspend, opts_suspend, info_suspend},
9984 {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},
9985 {"undefine", cmdUndefine, opts_undefine, info_undefine},
9986 {"update-device", cmdUpdateDevice, opts_update_device, info_update_device},
9987 {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount},
9988 {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
9989 {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
9990 {"version", cmdVersion, NULL, info_version},
9991 {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
9992 {NULL, NULL, NULL, NULL}
9995 static const vshCmdDef domMonitoringCmds[] = {
9996 {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo},
9997 {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
9998 {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat},
9999 {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
10000 {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat},
10001 {"domstate", cmdDomstate, opts_domstate, info_domstate},
10002 {"list", cmdList, opts_list, info_list},
10003 {NULL, NULL, NULL, NULL}
10006 static const vshCmdDef storagePoolCmds[] = {
10007 {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs,
10008 opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as},
10009 {"find-storage-pool-sources", cmdPoolDiscoverSources,
10010 opts_find_storage_pool_sources, info_find_storage_pool_sources},
10011 {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
10012 {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
10013 {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as},
10014 {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create},
10015 {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as},
10016 {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define},
10017 {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete},
10018 {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy},
10019 {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml},
10020 {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit},
10021 {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info},
10022 {"pool-list", cmdPoolList, opts_pool_list, info_pool_list},
10023 {"pool-name", cmdPoolName, opts_pool_name, info_pool_name},
10024 {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh},
10025 {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start},
10026 {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine},
10027 {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid},
10028 {NULL, NULL, NULL, NULL}
10031 static const vshCmdDef storageVolCmds[] = {
10032 {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone},
10033 {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
10034 {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
10035 {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from},
10036 {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete},
10037 {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml},
10038 {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info},
10039 {"vol-key", cmdVolKey, opts_vol_key, info_vol_key},
10040 {"vol-list", cmdVolList, opts_vol_list, info_vol_list},
10041 {"vol-name", cmdVolName, opts_vol_name, info_vol_name},
10042 {"vol-path", cmdVolPath, opts_vol_path, info_vol_path},
10043 {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool},
10044 {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe},
10045 {NULL, NULL, NULL, NULL}
10048 static const vshCmdDef networkCmds[] = {
10049 {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart},
10050 {"net-create", cmdNetworkCreate, opts_network_create, info_network_create},
10051 {"net-define", cmdNetworkDefine, opts_network_define, info_network_define},
10052 {"net-destroy", cmdNetworkDestroy, opts_network_destroy, info_network_destroy},
10053 {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, info_network_dumpxml},
10054 {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit},
10055 {"net-info", cmdNetworkInfo, opts_network_info, info_network_info},
10056 {"net-list", cmdNetworkList, opts_network_list, info_network_list},
10057 {"net-name", cmdNetworkName, opts_network_name, info_network_name},
10058 {"net-start", cmdNetworkStart, opts_network_start, info_network_start},
10059 {"net-undefine", cmdNetworkUndefine, opts_network_undefine, info_network_undefine},
10060 {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid},
10061 {NULL, NULL, NULL, NULL}
10064 static const vshCmdDef nodedevCmds[] = {
10065 {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
10066 {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},
10067 {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach},
10068 {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml},
10069 {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices},
10070 {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach},
10071 {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset},
10072 {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
10073 {NULL, NULL, NULL, NULL}
10076 static const vshCmdDef ifaceCmds[] = {
10077 {"iface-define", cmdInterfaceDefine, opts_interface_define, info_interface_define},
10078 {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, info_interface_destroy},
10079 {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, info_interface_dumpxml},
10080 {"iface-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit},
10081 {"iface-list", cmdInterfaceList, opts_interface_list, info_interface_list},
10082 {"iface-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac},
10083 {"iface-name", cmdInterfaceName, opts_interface_name, info_interface_name},
10084 {"iface-start", cmdInterfaceStart, opts_interface_start, info_interface_start},
10085 {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, info_interface_undefine},
10086 {NULL, NULL, NULL, NULL}
10089 static const vshCmdDef nwfilterCmds[] = {
10090 {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, info_nwfilter_define},
10091 {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, info_nwfilter_dumpxml},
10092 {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, info_nwfilter_edit},
10093 {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, info_nwfilter_list},
10094 {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, info_nwfilter_undefine},
10095 {NULL, NULL, NULL, NULL}
10098 static const vshCmdDef secretCmds[] = {
10099 {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define},
10100 {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml},
10101 {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value},
10102 {"secret-list", cmdSecretList, NULL, info_secret_list},
10103 {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value},
10104 {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine},
10105 {NULL, NULL, NULL, NULL}
10108 static const vshCmdDef virshCmds[] = {
10109 #ifndef WIN32
10110 {"cd", cmdCd, opts_cd, info_cd},
10111 #endif
10112 {"echo", cmdEcho, opts_echo, info_echo},
10113 {"exit", cmdQuit, NULL, info_quit},
10114 {"help", cmdHelp, opts_help, info_help},
10115 #ifndef WIN32
10116 {"pwd", cmdPwd, NULL, info_pwd},
10117 #endif
10118 {"quit", cmdQuit, NULL, info_quit},
10119 {NULL, NULL, NULL, NULL}
10122 static const vshCmdDef snapshotCmds[] = {
10123 {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create},
10124 {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, info_snapshot_current},
10125 {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete},
10126 {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, info_snapshot_dumpxml},
10127 {"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list},
10128 {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, info_snapshot_revert},
10129 {NULL, NULL, NULL, NULL}
10132 static const vshCmdDef hostAndHypervisorCmds[] = {
10133 {"capabilities", cmdCapabilities, NULL, info_capabilities},
10134 {"connect", cmdConnect, opts_connect, info_connect},
10135 {"freecell", cmdFreecell, opts_freecell, info_freecell},
10136 {"hostname", cmdHostname, NULL, info_hostname},
10137 {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, info_qemu_monitor_command},
10138 {"uri", cmdURI, NULL, info_uri},
10139 {NULL, NULL, NULL, NULL}
10142 static const vshCmdGrp cmdGroups[] = {
10143 {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds},
10144 {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds},
10145 {VSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds},
10146 {VSH_CMD_GRP_IFACE, "interface", ifaceCmds},
10147 {VSH_CMD_GRP_NWFILTER, "filter", nwfilterCmds},
10148 {VSH_CMD_GRP_NETWORK, "network", networkCmds},
10149 {VSH_CMD_GRP_NODEDEV, "nodedev", nodedevCmds},
10150 {VSH_CMD_GRP_SECRET, "secret", secretCmds},
10151 {VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds},
10152 {VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds},
10153 {VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds},
10154 {VSH_CMD_GRP_VIRSH, "virsh", virshCmds},
10155 {NULL, NULL, NULL}
10159 /* ---------------
10160 * Utils for work with command definition
10161 * ---------------
10163 static const char *
10164 vshCmddefGetInfo(const vshCmdDef * cmd, const char *name)
10166 const vshCmdInfo *info;
10168 for (info = cmd->info; info && info->name; info++) {
10169 if (STREQ(info->name, name))
10170 return info->data;
10172 return NULL;
10175 static const vshCmdOptDef *
10176 vshCmddefGetOption(const vshCmdDef * cmd, const char *name)
10178 const vshCmdOptDef *opt;
10180 for (opt = cmd->opts; opt && opt->name; opt++)
10181 if (STREQ(opt->name, name))
10182 return opt;
10183 return NULL;
10186 static const vshCmdOptDef *
10187 vshCmddefGetData(const vshCmdDef * cmd, int data_ct)
10189 const vshCmdOptDef *opt;
10191 for (opt = cmd->opts; opt && opt->name; opt++) {
10192 if (opt->type >= VSH_OT_DATA ||
10193 (opt->type == VSH_OT_INT && (opt->flag & VSH_OFLAG_REQ))) {
10194 if (data_ct == 0 || opt->type == VSH_OT_ARGV)
10195 return opt;
10196 else
10197 data_ct--;
10200 return NULL;
10204 * Checks for required options
10206 static int
10207 vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd)
10209 const vshCmdDef *def = cmd->def;
10210 const vshCmdOptDef *d;
10211 int err = 0;
10213 for (d = def->opts; d && d->name; d++) {
10214 if (d->flag & VSH_OFLAG_REQ) {
10215 vshCmdOpt *o = cmd->opts;
10216 int ok = 0;
10218 while (o && ok == 0) {
10219 if (o->def == d)
10220 ok = 1;
10221 o = o->next;
10223 if (!ok) {
10224 vshError(ctl,
10225 d->type == VSH_OT_DATA ?
10226 _("command '%s' requires <%s> option") :
10227 _("command '%s' requires --%s option"),
10228 def->name, d->name);
10229 err = 1;
10234 return !err;
10237 static const vshCmdDef *
10238 vshCmddefSearch(const char *cmdname)
10240 const vshCmdGrp *g;
10241 const vshCmdDef *c;
10243 for (g = cmdGroups; g->name; g++) {
10244 for (c = g->commands; c->name; c++) {
10245 if(STREQ(c->name, cmdname))
10246 return c;
10250 return NULL;
10253 static const vshCmdGrp *
10254 vshCmdGrpSearch(const char *grpname)
10256 const vshCmdGrp *g;
10258 for (g = cmdGroups; g->name; g++) {
10259 if(STREQ(g->name, grpname) || STREQ(g->keyword, grpname))
10260 return g;
10263 return NULL;
10266 static int
10267 vshCmdGrpHelp(vshControl *ctl, const char *grpname)
10269 const vshCmdGrp *grp = vshCmdGrpSearch(grpname);
10270 const vshCmdDef *cmd = NULL;
10272 if (!grp) {
10273 vshError(ctl, _("command group '%s' doesn't exist"), grpname);
10274 return FALSE;
10275 } else {
10276 vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
10277 grp->keyword);
10279 for (cmd = grp->commands; cmd->name; cmd++) {
10280 vshPrint(ctl, " %-30s %s\n", cmd->name,
10281 _(vshCmddefGetInfo(cmd, "help")));
10285 return TRUE;
10288 static int
10289 vshCmddefHelp(vshControl *ctl, const char *cmdname)
10291 const vshCmdDef *def = vshCmddefSearch(cmdname);
10293 if (!def) {
10294 vshError(ctl, _("command '%s' doesn't exist"), cmdname);
10295 return FALSE;
10296 } else {
10297 const char *desc = _(vshCmddefGetInfo(def, "desc"));
10298 const char *help = _(vshCmddefGetInfo(def, "help"));
10299 char buf[256];
10301 fputs(_(" NAME\n"), stdout);
10302 fprintf(stdout, " %s - %s\n", def->name, help);
10304 fputs(_("\n SYNOPSIS\n"), stdout);
10305 fprintf(stdout, " %s", def->name);
10306 if (def->opts) {
10307 const vshCmdOptDef *opt;
10308 for (opt = def->opts; opt->name; opt++) {
10309 const char *fmt;
10310 switch (opt->type) {
10311 case VSH_OT_BOOL:
10312 fmt = "[--%s]";
10313 break;
10314 case VSH_OT_INT:
10315 /* xgettext:c-format */
10316 fmt = ((opt->flag & VSH_OFLAG_REQ) ? "<%s>"
10317 : _("[--%s <number>]"));
10318 break;
10319 case VSH_OT_STRING:
10320 /* xgettext:c-format */
10321 fmt = _("[--%s <string>]");
10322 break;
10323 case VSH_OT_DATA:
10324 fmt = ((opt->flag & VSH_OFLAG_REQ) ? "<%s>" : "[<%s>]");
10325 break;
10326 case VSH_OT_ARGV:
10327 /* xgettext:c-format */
10328 fmt = _("[<string>]...");
10329 break;
10330 default:
10331 assert(0);
10333 fputc(' ', stdout);
10334 fprintf(stdout, fmt, opt->name);
10337 fputc('\n', stdout);
10339 if (desc[0]) {
10340 /* Print the description only if it's not empty. */
10341 fputs(_("\n DESCRIPTION\n"), stdout);
10342 fprintf(stdout, " %s\n", desc);
10345 if (def->opts) {
10346 const vshCmdOptDef *opt;
10347 fputs(_("\n OPTIONS\n"), stdout);
10348 for (opt = def->opts; opt->name; opt++) {
10349 switch (opt->type) {
10350 case VSH_OT_BOOL:
10351 snprintf(buf, sizeof(buf), "--%s", opt->name);
10352 break;
10353 case VSH_OT_INT:
10354 snprintf(buf, sizeof(buf),
10355 (opt->flag & VSH_OFLAG_REQ) ? _("[--%s] <number>")
10356 : _("--%s <number>"), opt->name);
10357 break;
10358 case VSH_OT_STRING:
10359 /* OT_STRING should never be VSH_OFLAG_REQ */
10360 snprintf(buf, sizeof(buf), _("--%s <string>"), opt->name);
10361 break;
10362 case VSH_OT_DATA:
10363 snprintf(buf, sizeof(buf), _("[--%s] <string>"),
10364 opt->name);
10365 break;
10366 case VSH_OT_ARGV:
10367 /* Not really an option. */
10368 continue;
10369 default:
10370 assert(0);
10373 fprintf(stdout, " %-15s %s\n", buf, _(opt->help));
10376 fputc('\n', stdout);
10378 return TRUE;
10381 /* ---------------
10382 * Utils for work with runtime commands data
10383 * ---------------
10385 static void
10386 vshCommandOptFree(vshCmdOpt * arg)
10388 vshCmdOpt *a = arg;
10390 while (a) {
10391 vshCmdOpt *tmp = a;
10393 a = a->next;
10395 VIR_FREE(tmp->data);
10396 VIR_FREE(tmp);
10400 static void
10401 vshCommandFree(vshCmd *cmd)
10403 vshCmd *c = cmd;
10405 while (c) {
10406 vshCmd *tmp = c;
10408 c = c->next;
10410 if (tmp->opts)
10411 vshCommandOptFree(tmp->opts);
10412 VIR_FREE(tmp);
10417 * Returns option by name
10419 static vshCmdOpt *
10420 vshCommandOpt(const vshCmd *cmd, const char *name)
10422 vshCmdOpt *opt = cmd->opts;
10424 while (opt) {
10425 if (opt->def && STREQ(opt->def->name, name))
10426 return opt;
10427 opt = opt->next;
10429 return NULL;
10433 * Returns option as INT
10435 static int
10436 vshCommandOptInt(const vshCmd *cmd, const char *name, int *found)
10438 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10439 int res = 0, num_found = FALSE;
10440 char *end_p = NULL;
10442 if ((arg != NULL) && (arg->data != NULL)) {
10443 res = strtol(arg->data, &end_p, 10);
10444 if ((arg->data == end_p) || (*end_p!= 0))
10445 num_found = FALSE;
10446 else
10447 num_found = TRUE;
10449 if (found)
10450 *found = num_found;
10451 return res;
10454 static unsigned long
10455 vshCommandOptUL(const vshCmd *cmd, const char *name, int *found)
10457 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10458 unsigned long res = 0;
10459 int num_found = FALSE;
10460 char *end_p = NULL;
10462 if ((arg != NULL) && (arg->data != NULL)) {
10463 res = strtoul(arg->data, &end_p, 10);
10464 if ((arg->data == end_p) || (*end_p!= 0))
10465 num_found = FALSE;
10466 else
10467 num_found = TRUE;
10469 if (found)
10470 *found = num_found;
10471 return res;
10475 * Returns option as STRING
10477 static char *
10478 vshCommandOptString(const vshCmd *cmd, const char *name, int *found)
10480 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10482 if (found)
10483 *found = arg ? TRUE : FALSE;
10485 if (arg && arg->data && *arg->data)
10486 return arg->data;
10488 if (arg && arg->def && ((arg->def->flag) & VSH_OFLAG_REQ))
10489 vshError(NULL, _("Missing required option '%s'"), name);
10491 return NULL;
10495 * Returns option as long long
10497 static long long
10498 vshCommandOptLongLong(const vshCmd *cmd, const char *name, int *found)
10500 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10501 int num_found = FALSE;
10502 long long res = 0;
10503 char *end_p = NULL;
10505 if ((arg != NULL) && (arg->data != NULL))
10506 num_found = !virStrToLong_ll(arg->data, &end_p, 10, &res);
10507 if (found)
10508 *found = num_found;
10509 return res;
10513 * Returns TRUE/FALSE if the option exists
10515 static int
10516 vshCommandOptBool(const vshCmd *cmd, const char *name)
10518 return vshCommandOpt(cmd, name) ? TRUE : FALSE;
10522 * Returns the COUNT argv argument, or NULL after last argument.
10524 * Requires that a VSH_OT_ARGV option with the name "" be last in the
10525 * list of supported options in CMD->def->opts.
10527 static char *
10528 vshCommandOptArgv(const vshCmd *cmd, int count)
10530 vshCmdOpt *opt = cmd->opts;
10532 while (opt) {
10533 if (opt->def && opt->def->type == VSH_OT_ARGV) {
10534 if (count-- == 0)
10535 return opt->data;
10537 opt = opt->next;
10539 return NULL;
10542 /* Determine whether CMD->opts includes an option with name OPTNAME.
10543 If not, give a diagnostic and return false.
10544 If so, return true. */
10545 static bool
10546 cmd_has_option (vshControl *ctl, const vshCmd *cmd, const char *optname)
10548 /* Iterate through cmd->opts, to ensure that there is an entry
10549 with name OPTNAME and type VSH_OT_DATA. */
10550 bool found = false;
10551 const vshCmdOpt *opt;
10552 for (opt = cmd->opts; opt; opt = opt->next) {
10553 if (STREQ (opt->def->name, optname) && opt->def->type == VSH_OT_DATA) {
10554 found = true;
10555 break;
10559 if (!found)
10560 vshError(ctl, _("internal error: virsh %s: no %s VSH_OT_DATA option"),
10561 cmd->def->name, optname);
10562 return found;
10565 static virDomainPtr
10566 vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
10567 char **name, int flag)
10569 virDomainPtr dom = NULL;
10570 char *n;
10571 int id;
10572 const char *optname = "domain";
10573 if (!cmd_has_option (ctl, cmd, optname))
10574 return NULL;
10576 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10577 return NULL;
10579 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10580 cmd->def->name, optname, n);
10582 if (name)
10583 *name = n;
10585 /* try it by ID */
10586 if (flag & VSH_BYID) {
10587 if (virStrToLong_i(n, NULL, 10, &id) == 0 && id >= 0) {
10588 vshDebug(ctl, 5, "%s: <%s> seems like domain ID\n",
10589 cmd->def->name, optname);
10590 dom = virDomainLookupByID(ctl->conn, id);
10593 /* try it by UUID */
10594 if (dom==NULL && (flag & VSH_BYUUID) && strlen(n)==VIR_UUID_STRING_BUFLEN-1) {
10595 vshDebug(ctl, 5, "%s: <%s> trying as domain UUID\n",
10596 cmd->def->name, optname);
10597 dom = virDomainLookupByUUIDString(ctl->conn, n);
10599 /* try it by NAME */
10600 if (dom==NULL && (flag & VSH_BYNAME)) {
10601 vshDebug(ctl, 5, "%s: <%s> trying as domain NAME\n",
10602 cmd->def->name, optname);
10603 dom = virDomainLookupByName(ctl->conn, n);
10606 if (!dom)
10607 vshError(ctl, _("failed to get domain '%s'"), n);
10609 return dom;
10612 static virNetworkPtr
10613 vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
10614 char **name, int flag)
10616 virNetworkPtr network = NULL;
10617 char *n;
10618 const char *optname = "network";
10619 if (!cmd_has_option (ctl, cmd, optname))
10620 return NULL;
10622 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10623 return NULL;
10625 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10626 cmd->def->name, optname, n);
10628 if (name)
10629 *name = n;
10631 /* try it by UUID */
10632 if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
10633 vshDebug(ctl, 5, "%s: <%s> trying as network UUID\n",
10634 cmd->def->name, optname);
10635 network = virNetworkLookupByUUIDString(ctl->conn, n);
10637 /* try it by NAME */
10638 if (network==NULL && (flag & VSH_BYNAME)) {
10639 vshDebug(ctl, 5, "%s: <%s> trying as network NAME\n",
10640 cmd->def->name, optname);
10641 network = virNetworkLookupByName(ctl->conn, n);
10644 if (!network)
10645 vshError(ctl, _("failed to get network '%s'"), n);
10647 return network;
10651 static virNWFilterPtr
10652 vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
10653 char **name, int flag)
10655 virNWFilterPtr nwfilter = NULL;
10656 char *n;
10657 const char *optname = "nwfilter";
10658 if (!cmd_has_option (ctl, cmd, optname))
10659 return NULL;
10661 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10662 return NULL;
10664 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10665 cmd->def->name, optname, n);
10667 if (name)
10668 *name = n;
10670 /* try it by UUID */
10671 if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
10672 vshDebug(ctl, 5, "%s: <%s> trying as nwfilter UUID\n",
10673 cmd->def->name, optname);
10674 nwfilter = virNWFilterLookupByUUIDString(ctl->conn, n);
10676 /* try it by NAME */
10677 if (nwfilter == NULL && (flag & VSH_BYNAME)) {
10678 vshDebug(ctl, 5, "%s: <%s> trying as nwfilter NAME\n",
10679 cmd->def->name, optname);
10680 nwfilter = virNWFilterLookupByName(ctl->conn, n);
10683 if (!nwfilter)
10684 vshError(ctl, _("failed to get nwfilter '%s'"), n);
10686 return nwfilter;
10689 static virInterfacePtr
10690 vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
10691 char **name, int flag)
10693 virInterfacePtr iface = NULL;
10694 char *n;
10695 const char *optname = "interface";
10696 if (!cmd_has_option (ctl, cmd, optname))
10697 return NULL;
10699 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10700 return NULL;
10702 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10703 cmd->def->name, optname, n);
10705 if (name)
10706 *name = n;
10708 /* try it by NAME */
10709 if ((flag & VSH_BYNAME)) {
10710 vshDebug(ctl, 5, "%s: <%s> trying as interface NAME\n",
10711 cmd->def->name, optname);
10712 iface = virInterfaceLookupByName(ctl->conn, n);
10714 /* try it by MAC */
10715 if ((iface == NULL) && (flag & VSH_BYMAC)) {
10716 vshDebug(ctl, 5, "%s: <%s> trying as interface MAC\n",
10717 cmd->def->name, optname);
10718 iface = virInterfaceLookupByMACString(ctl->conn, n);
10721 if (!iface)
10722 vshError(ctl, _("failed to get interface '%s'"), n);
10724 return iface;
10727 static virStoragePoolPtr
10728 vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
10729 char **name, int flag)
10731 virStoragePoolPtr pool = NULL;
10732 char *n;
10734 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10735 return NULL;
10737 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10738 cmd->def->name, optname, n);
10740 if (name)
10741 *name = n;
10743 /* try it by UUID */
10744 if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
10745 vshDebug(ctl, 5, "%s: <%s> trying as pool UUID\n",
10746 cmd->def->name, optname);
10747 pool = virStoragePoolLookupByUUIDString(ctl->conn, n);
10749 /* try it by NAME */
10750 if (pool == NULL && (flag & VSH_BYNAME)) {
10751 vshDebug(ctl, 5, "%s: <%s> trying as pool NAME\n",
10752 cmd->def->name, optname);
10753 pool = virStoragePoolLookupByName(ctl->conn, n);
10756 if (!pool)
10757 vshError(ctl, _("failed to get pool '%s'"), n);
10759 return pool;
10762 static virStorageVolPtr
10763 vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
10764 const char *optname,
10765 const char *pooloptname,
10766 char **name, int flag)
10768 virStorageVolPtr vol = NULL;
10769 virStoragePoolPtr pool = NULL;
10770 char *n, *p;
10771 int found;
10773 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10774 return NULL;
10776 if (!(p = vshCommandOptString(cmd, pooloptname, &found)) && found)
10777 return NULL;
10779 if (p)
10780 pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag);
10782 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10783 cmd->def->name, optname, n);
10785 if (name)
10786 *name = n;
10788 /* try it by name */
10789 if (pool && (flag & VSH_BYNAME)) {
10790 vshDebug(ctl, 5, "%s: <%s> trying as vol name\n",
10791 cmd->def->name, optname);
10792 vol = virStorageVolLookupByName(pool, n);
10794 /* try it by key */
10795 if (vol == NULL && (flag & VSH_BYUUID)) {
10796 vshDebug(ctl, 5, "%s: <%s> trying as vol key\n",
10797 cmd->def->name, optname);
10798 vol = virStorageVolLookupByKey(ctl->conn, n);
10800 /* try it by path */
10801 if (vol == NULL && (flag & VSH_BYUUID)) {
10802 vshDebug(ctl, 5, "%s: <%s> trying as vol path\n",
10803 cmd->def->name, optname);
10804 vol = virStorageVolLookupByPath(ctl->conn, n);
10807 if (!vol)
10808 vshError(ctl, _("failed to get vol '%s'"), n);
10810 if (pool)
10811 virStoragePoolFree(pool);
10813 return vol;
10816 static virSecretPtr
10817 vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, char **name)
10819 virSecretPtr secret = NULL;
10820 char *n;
10821 const char *optname = "secret";
10823 if (!cmd_has_option (ctl, cmd, optname))
10824 return NULL;
10826 n = vshCommandOptString(cmd, optname, NULL);
10827 if (n == NULL)
10828 return NULL;
10830 vshDebug(ctl, 5, "%s: found option <%s>: %s\n", cmd->def->name, optname, n);
10832 if (name != NULL)
10833 *name = n;
10835 secret = virSecretLookupByUUIDString(ctl->conn, n);
10837 if (secret == NULL)
10838 vshError(ctl, _("failed to get secret '%s'"), n);
10840 return secret;
10844 * Executes command(s) and returns return code from last command
10846 static int
10847 vshCommandRun(vshControl *ctl, const vshCmd *cmd)
10849 int ret = TRUE;
10851 while (cmd) {
10852 struct timeval before, after;
10853 bool enable_timing = ctl->timing;
10855 if ((ctl->conn == NULL) || (disconnected != 0))
10856 vshReconnect(ctl);
10858 if (enable_timing)
10859 GETTIMEOFDAY(&before);
10861 ret = cmd->def->handler(ctl, cmd);
10863 if (enable_timing)
10864 GETTIMEOFDAY(&after);
10866 if (ret == FALSE)
10867 virshReportError(ctl);
10869 /* try to automatically catch disconnections */
10870 if ((ret == FALSE) &&
10871 ((disconnected != 0) ||
10872 ((last_error != NULL) &&
10873 (((last_error->code == VIR_ERR_SYSTEM_ERROR) &&
10874 (last_error->domain == VIR_FROM_REMOTE)) ||
10875 (last_error->code == VIR_ERR_RPC) ||
10876 (last_error->code == VIR_ERR_NO_CONNECT) ||
10877 (last_error->code == VIR_ERR_INVALID_CONN)))))
10878 vshReconnect(ctl);
10880 if (STREQ(cmd->def->name, "quit")) /* hack ... */
10881 return ret;
10883 if (enable_timing)
10884 vshPrint(ctl, _("\n(Time: %.3f ms)\n\n"),
10885 DIFF_MSEC(&after, &before));
10886 else
10887 vshPrintExtra(ctl, "\n");
10888 cmd = cmd->next;
10890 return ret;
10893 /* ---------------
10894 * Command parsing
10895 * ---------------
10898 typedef enum {
10899 VSH_TK_ERROR, /* Failed to parse a token */
10900 VSH_TK_ARG, /* Arbitrary argument, might be option or empty */
10901 VSH_TK_SUBCMD_END, /* Separation between commands */
10902 VSH_TK_END /* No more commands */
10903 } vshCommandToken;
10905 typedef struct __vshCommandParser {
10906 vshCommandToken (*getNextArg)(vshControl *, struct __vshCommandParser *,
10907 char **);
10908 /* vshCommandStringGetArg() */
10909 char *pos;
10910 /* vshCommandArgvGetArg() */
10911 char **arg_pos;
10912 char **arg_end;
10913 } vshCommandParser;
10915 static int
10916 vshCommandParse(vshControl *ctl, vshCommandParser *parser)
10918 char *tkdata = NULL;
10919 vshCmd *clast = NULL;
10920 vshCmdOpt *first = NULL;
10922 if (ctl->cmd) {
10923 vshCommandFree(ctl->cmd);
10924 ctl->cmd = NULL;
10927 while (1) {
10928 vshCmdOpt *last = NULL;
10929 const vshCmdDef *cmd = NULL;
10930 vshCommandToken tk;
10931 bool data_only = false;
10932 int data_ct = 0;
10934 first = NULL;
10936 while (1) {
10937 const vshCmdOptDef *opt = NULL;
10939 tkdata = NULL;
10940 tk = parser->getNextArg(ctl, parser, &tkdata);
10942 if (tk == VSH_TK_ERROR)
10943 goto syntaxError;
10944 if (tk != VSH_TK_ARG)
10945 break;
10947 if (cmd == NULL) {
10948 /* first token must be command name */
10949 if (!(cmd = vshCmddefSearch(tkdata))) {
10950 vshError(ctl, _("unknown command: '%s'"), tkdata);
10951 goto syntaxError; /* ... or ignore this command only? */
10953 VIR_FREE(tkdata);
10954 } else if (data_only) {
10955 goto get_data;
10956 } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
10957 c_isalnum(tkdata[2])) {
10958 char *optstr = strchr(tkdata + 2, '=');
10959 if (optstr) {
10960 *optstr = '\0'; /* convert the '=' to '\0' */
10961 optstr = vshStrdup(ctl, optstr + 1);
10963 if (!(opt = vshCmddefGetOption(cmd, tkdata + 2))) {
10964 vshError(ctl,
10965 _("command '%s' doesn't support option --%s"),
10966 cmd->name, tkdata + 2);
10967 VIR_FREE(optstr);
10968 goto syntaxError;
10970 VIR_FREE(tkdata);
10972 if (opt->type != VSH_OT_BOOL) {
10973 /* option data */
10974 if (optstr)
10975 tkdata = optstr;
10976 else
10977 tk = parser->getNextArg(ctl, parser, &tkdata);
10978 if (tk == VSH_TK_ERROR)
10979 goto syntaxError;
10980 if (tk != VSH_TK_ARG) {
10981 vshError(ctl,
10982 _("expected syntax: --%s <%s>"),
10983 opt->name,
10984 opt->type ==
10985 VSH_OT_INT ? _("number") : _("string"));
10986 goto syntaxError;
10988 } else {
10989 tkdata = NULL;
10990 if (optstr) {
10991 vshError(ctl, _("invalid '=' after option --%s"),
10992 opt->name);
10993 VIR_FREE(optstr);
10994 goto syntaxError;
10997 } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
10998 tkdata[2] == '\0') {
10999 data_only = true;
11000 continue;
11001 } else {
11002 get_data:
11003 if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
11004 vshError(ctl, _("unexpected data '%s'"), tkdata);
11005 goto syntaxError;
11008 if (opt) {
11009 /* save option */
11010 vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
11012 arg->def = opt;
11013 arg->data = tkdata;
11014 arg->next = NULL;
11015 tkdata = NULL;
11017 if (!first)
11018 first = arg;
11019 if (last)
11020 last->next = arg;
11021 last = arg;
11023 vshDebug(ctl, 4, "%s: %s(%s): %s\n",
11024 cmd->name,
11025 opt->name,
11026 opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
11027 opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
11031 /* command parsed -- allocate new struct for the command */
11032 if (cmd) {
11033 vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
11035 c->opts = first;
11036 c->def = cmd;
11037 c->next = NULL;
11039 if (!vshCommandCheckOpts(ctl, c)) {
11040 VIR_FREE(c);
11041 goto syntaxError;
11044 if (!ctl->cmd)
11045 ctl->cmd = c;
11046 if (clast)
11047 clast->next = c;
11048 clast = c;
11051 if (tk == VSH_TK_END)
11052 break;
11055 return TRUE;
11057 syntaxError:
11058 if (ctl->cmd) {
11059 vshCommandFree(ctl->cmd);
11060 ctl->cmd = NULL;
11062 if (first)
11063 vshCommandOptFree(first);
11064 VIR_FREE(tkdata);
11065 return FALSE;
11068 /* --------------------
11069 * Command argv parsing
11070 * --------------------
11073 static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
11074 vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
11076 if (parser->arg_pos == parser->arg_end) {
11077 *res = NULL;
11078 return VSH_TK_END;
11081 *res = vshStrdup(ctl, *parser->arg_pos);
11082 parser->arg_pos++;
11083 return VSH_TK_ARG;
11086 static int vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
11088 vshCommandParser parser;
11090 if (nargs <= 0)
11091 return FALSE;
11093 parser.arg_pos = argv;
11094 parser.arg_end = argv + nargs;
11095 parser.getNextArg = vshCommandArgvGetArg;
11096 return vshCommandParse(ctl, &parser);
11099 /* ----------------------
11100 * Command string parsing
11101 * ----------------------
11104 static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
11105 vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
11107 bool single_quote = false;
11108 bool double_quote = false;
11109 int sz = 0;
11110 char *p = parser->pos;
11111 char *q = vshStrdup(ctl, p);
11113 *res = q;
11115 while (*p && (*p == ' ' || *p == '\t'))
11116 p++;
11118 if (*p == '\0')
11119 return VSH_TK_END;
11120 if (*p == ';') {
11121 parser->pos = ++p; /* = \0 or begin of next command */
11122 return VSH_TK_SUBCMD_END;
11125 while (*p) {
11126 /* end of token is blank space or ';' */
11127 if (!double_quote && !single_quote &&
11128 (*p == ' ' || *p == '\t' || *p == ';'))
11129 break;
11131 if (!double_quote && *p == '\'') { /* single quote */
11132 single_quote = !single_quote;
11133 p++;
11134 continue;
11135 } else if (!single_quote && *p == '\\') { /* escape */
11137 * The same as the bash, a \ in "" is an escaper,
11138 * but a \ in '' is not an escaper.
11140 p++;
11141 if (*p == '\0') {
11142 vshError(ctl, "%s", _("dangling \\"));
11143 return VSH_TK_ERROR;
11145 } else if (!single_quote && *p == '"') { /* double quote */
11146 double_quote = !double_quote;
11147 p++;
11148 continue;
11151 *q++ = *p++;
11152 sz++;
11154 if (double_quote) {
11155 vshError(ctl, "%s", _("missing \""));
11156 return VSH_TK_ERROR;
11159 *q = '\0';
11160 parser->pos = p;
11161 return VSH_TK_ARG;
11164 static int vshCommandStringParse(vshControl *ctl, char *cmdstr)
11166 vshCommandParser parser;
11168 if (cmdstr == NULL || *cmdstr == '\0')
11169 return FALSE;
11171 parser.pos = cmdstr;
11172 parser.getNextArg = vshCommandStringGetArg;
11173 return vshCommandParse(ctl, &parser);
11176 /* ---------------
11177 * Misc utils
11178 * ---------------
11180 static const char *
11181 vshDomainStateToString(int state)
11183 switch (state) {
11184 case VIR_DOMAIN_RUNNING:
11185 return N_("running");
11186 case VIR_DOMAIN_BLOCKED:
11187 return N_("idle");
11188 case VIR_DOMAIN_PAUSED:
11189 return N_("paused");
11190 case VIR_DOMAIN_SHUTDOWN:
11191 return N_("in shutdown");
11192 case VIR_DOMAIN_SHUTOFF:
11193 return N_("shut off");
11194 case VIR_DOMAIN_CRASHED:
11195 return N_("crashed");
11196 default:
11197 ;/*FALLTHROUGH*/
11199 return N_("no state"); /* = dom0 state */
11202 static const char *
11203 vshDomainVcpuStateToString(int state)
11205 switch (state) {
11206 case VIR_VCPU_OFFLINE:
11207 return N_("offline");
11208 case VIR_VCPU_BLOCKED:
11209 return N_("idle");
11210 case VIR_VCPU_RUNNING:
11211 return N_("running");
11212 default:
11213 ;/*FALLTHROUGH*/
11215 return N_("no state");
11218 static int
11219 vshConnectionUsability(vshControl *ctl, virConnectPtr conn)
11221 /* TODO: use something like virConnectionState() to
11222 * check usability of the connection
11224 if (!conn) {
11225 vshError(ctl, "%s", _("no valid connection"));
11226 return FALSE;
11228 return TRUE;
11231 static void
11232 vshDebug(vshControl *ctl, int level, const char *format, ...)
11234 va_list ap;
11236 va_start(ap, format);
11237 vshOutputLogFile(ctl, VSH_ERR_DEBUG, format, ap);
11238 va_end(ap);
11240 if (level > ctl->debug)
11241 return;
11243 va_start(ap, format);
11244 vfprintf(stdout, format, ap);
11245 va_end(ap);
11248 static void
11249 vshPrintExtra(vshControl *ctl, const char *format, ...)
11251 va_list ap;
11253 if (ctl->quiet == TRUE)
11254 return;
11256 va_start(ap, format);
11257 vfprintf(stdout, format, ap);
11258 va_end(ap);
11262 static void
11263 vshError(vshControl *ctl, const char *format, ...)
11265 va_list ap;
11267 if (ctl != NULL) {
11268 va_start(ap, format);
11269 vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
11270 va_end(ap);
11273 fputs(_("error: "), stderr);
11275 va_start(ap, format);
11276 vfprintf(stderr, format, ap);
11277 va_end(ap);
11279 fputc('\n', stderr);
11283 * Initialize connection.
11285 static int
11286 vshInit(vshControl *ctl)
11288 if (ctl->conn)
11289 return FALSE;
11291 vshOpenLogFile(ctl);
11293 /* set up the library error handler */
11294 virSetErrorFunc(NULL, virshErrorHandler);
11296 /* set up the signals handlers to catch disconnections */
11297 vshSetupSignals();
11299 virEventRegisterImpl(virEventAddHandleImpl,
11300 virEventUpdateHandleImpl,
11301 virEventRemoveHandleImpl,
11302 virEventAddTimeoutImpl,
11303 virEventUpdateTimeoutImpl,
11304 virEventRemoveTimeoutImpl);
11305 virEventInit();
11307 ctl->conn = virConnectOpenAuth(ctl->name,
11308 virConnectAuthPtrDefault,
11309 ctl->readonly ? VIR_CONNECT_RO : 0);
11312 /* This is not necessarily fatal. All the individual commands check
11313 * vshConnectionUsability, except ones which don't need a connection
11314 * such as "help".
11316 if (!ctl->conn) {
11317 virshReportError(ctl);
11318 vshError(ctl, "%s", _("failed to connect to the hypervisor"));
11319 return FALSE;
11322 return TRUE;
11325 #define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT | O_SYNC)
11328 * vshOpenLogFile:
11330 * Open log file.
11332 static void
11333 vshOpenLogFile(vshControl *ctl)
11335 struct stat st;
11337 if (ctl->logfile == NULL)
11338 return;
11340 /* check log file */
11341 if (stat(ctl->logfile, &st) == -1) {
11342 switch (errno) {
11343 case ENOENT:
11344 break;
11345 default:
11346 vshError(ctl, "%s",
11347 _("failed to get the log file information"));
11348 exit(EXIT_FAILURE);
11350 } else {
11351 if (!S_ISREG(st.st_mode)) {
11352 vshError(ctl, "%s", _("the log path is not a file"));
11353 exit(EXIT_FAILURE);
11357 /* log file open */
11358 if ((ctl->log_fd = open(ctl->logfile, LOGFILE_FLAGS, FILE_MODE)) < 0) {
11359 vshError(ctl, "%s",
11360 _("failed to open the log file. check the log file path"));
11361 exit(EXIT_FAILURE);
11366 * vshOutputLogFile:
11368 * Outputting an error to log file.
11370 static void
11371 vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format, va_list ap)
11373 char msg_buf[MSG_BUFFER];
11374 const char *lvl = "";
11375 struct timeval stTimeval;
11376 struct tm *stTm;
11378 if (ctl->log_fd == -1)
11379 return;
11382 * create log format
11384 * [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message
11386 gettimeofday(&stTimeval, NULL);
11387 stTm = localtime(&stTimeval.tv_sec);
11388 snprintf(msg_buf, sizeof(msg_buf),
11389 "[%d.%02d.%02d %02d:%02d:%02d ",
11390 (1900 + stTm->tm_year),
11391 (1 + stTm->tm_mon),
11392 (stTm->tm_mday),
11393 (stTm->tm_hour),
11394 (stTm->tm_min),
11395 (stTm->tm_sec));
11396 snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
11397 "%s] ", SIGN_NAME);
11398 switch (log_level) {
11399 case VSH_ERR_DEBUG:
11400 lvl = LVL_DEBUG;
11401 break;
11402 case VSH_ERR_INFO:
11403 lvl = LVL_INFO;
11404 break;
11405 case VSH_ERR_NOTICE:
11406 lvl = LVL_INFO;
11407 break;
11408 case VSH_ERR_WARNING:
11409 lvl = LVL_WARNING;
11410 break;
11411 case VSH_ERR_ERROR:
11412 lvl = LVL_ERROR;
11413 break;
11414 default:
11415 lvl = LVL_DEBUG;
11416 break;
11418 snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
11419 "%s ", lvl);
11420 vsnprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
11421 msg_format, ap);
11423 if (msg_buf[strlen(msg_buf) - 1] != '\n')
11424 snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf), "\n");
11426 /* write log */
11427 if (safewrite(ctl->log_fd, msg_buf, strlen(msg_buf)) < 0) {
11428 vshCloseLogFile(ctl);
11429 vshError(ctl, "%s", _("failed to write the log file"));
11434 * vshCloseLogFile:
11436 * Close log file.
11438 static void
11439 vshCloseLogFile(vshControl *ctl)
11441 /* log file close */
11442 if (VIR_CLOSE(ctl->log_fd) < 0) {
11443 vshError(ctl, _("%s: failed to write log file: %s"),
11444 ctl->logfile ? ctl->logfile : "?", strerror (errno));
11447 if (ctl->logfile) {
11448 VIR_FREE(ctl->logfile);
11449 ctl->logfile = NULL;
11453 #ifdef USE_READLINE
11455 /* -----------------
11456 * Readline stuff
11457 * -----------------
11461 * Generator function for command completion. STATE lets us
11462 * know whether to start from scratch; without any state
11463 * (i.e. STATE == 0), then we start at the top of the list.
11465 static char *
11466 vshReadlineCommandGenerator(const char *text, int state)
11468 static int grp_list_index, cmd_list_index, len;
11469 const char *name;
11470 const vshCmdGrp *grp;
11471 const vshCmdDef *cmds;
11473 if (!state) {
11474 grp_list_index = 0;
11475 cmd_list_index = 0;
11476 len = strlen(text);
11479 grp = cmdGroups;
11481 /* Return the next name which partially matches from the
11482 * command list.
11484 while (grp[grp_list_index].name) {
11485 cmds = grp[grp_list_index].commands;
11487 if (cmds[cmd_list_index].name) {
11488 while ((name = cmds[cmd_list_index].name)) {
11489 cmd_list_index++;
11491 if (STREQLEN(name, text, len))
11492 return vshStrdup(NULL, name);
11494 } else {
11495 cmd_list_index = 0;
11496 grp_list_index++;
11500 /* If no names matched, then return NULL. */
11501 return NULL;
11504 static char *
11505 vshReadlineOptionsGenerator(const char *text, int state)
11507 static int list_index, len;
11508 static const vshCmdDef *cmd = NULL;
11509 const char *name;
11511 if (!state) {
11512 /* determine command name */
11513 char *p;
11514 char *cmdname;
11516 if (!(p = strchr(rl_line_buffer, ' ')))
11517 return NULL;
11519 cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
11520 memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
11522 cmd = vshCmddefSearch(cmdname);
11523 list_index = 0;
11524 len = strlen(text);
11525 VIR_FREE(cmdname);
11528 if (!cmd)
11529 return NULL;
11531 if (!cmd->opts)
11532 return NULL;
11534 while ((name = cmd->opts[list_index].name)) {
11535 const vshCmdOptDef *opt = &cmd->opts[list_index];
11536 char *res;
11538 list_index++;
11540 if (opt->type == VSH_OT_DATA)
11541 /* ignore non --option */
11542 continue;
11544 if (len > 2) {
11545 if (STRNEQLEN(name, text + 2, len - 2))
11546 continue;
11548 res = vshMalloc(NULL, strlen(name) + 3);
11549 snprintf(res, strlen(name) + 3, "--%s", name);
11550 return res;
11553 /* If no names matched, then return NULL. */
11554 return NULL;
11557 static char **
11558 vshReadlineCompletion(const char *text, int start,
11559 int end ATTRIBUTE_UNUSED)
11561 char **matches = (char **) NULL;
11563 if (start == 0)
11564 /* command name generator */
11565 matches = rl_completion_matches(text, vshReadlineCommandGenerator);
11566 else
11567 /* commands options */
11568 matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
11569 return matches;
11573 static int
11574 vshReadlineInit(vshControl *ctl)
11576 char *userdir = NULL;
11578 /* Allow conditional parsing of the ~/.inputrc file. */
11579 rl_readline_name = "virsh";
11581 /* Tell the completer that we want a crack first. */
11582 rl_attempted_completion_function = vshReadlineCompletion;
11584 /* Limit the total size of the history buffer */
11585 stifle_history(500);
11587 /* Prepare to read/write history from/to the ~/.virsh/history file */
11588 userdir = virGetUserDirectory(getuid());
11590 if (userdir == NULL)
11591 return -1;
11593 if (virAsprintf(&ctl->historydir, "%s/.virsh", userdir) < 0) {
11594 vshError(ctl, "%s", _("Out of memory"));
11595 VIR_FREE(userdir);
11596 return -1;
11599 if (virAsprintf(&ctl->historyfile, "%s/history", ctl->historydir) < 0) {
11600 vshError(ctl, "%s", _("Out of memory"));
11601 VIR_FREE(userdir);
11602 return -1;
11605 VIR_FREE(userdir);
11607 read_history(ctl->historyfile);
11609 return 0;
11612 static void
11613 vshReadlineDeinit (vshControl *ctl)
11615 if (ctl->historyfile != NULL) {
11616 if (mkdir(ctl->historydir, 0755) < 0 && errno != EEXIST) {
11617 char ebuf[1024];
11618 vshError(ctl, _("Failed to create '%s': %s"),
11619 ctl->historydir, virStrerror(errno, ebuf, sizeof ebuf));
11620 } else
11621 write_history(ctl->historyfile);
11624 VIR_FREE(ctl->historydir);
11625 VIR_FREE(ctl->historyfile);
11628 static char *
11629 vshReadline (vshControl *ctl ATTRIBUTE_UNUSED, const char *prompt)
11631 return readline (prompt);
11634 #else /* !USE_READLINE */
11636 static int
11637 vshReadlineInit (vshControl *ctl ATTRIBUTE_UNUSED)
11639 /* empty */
11640 return 0;
11643 static void
11644 vshReadlineDeinit (vshControl *ctl ATTRIBUTE_UNUSED)
11646 /* empty */
11649 static char *
11650 vshReadline (vshControl *ctl, const char *prompt)
11652 char line[1024];
11653 char *r;
11654 int len;
11656 fputs (prompt, stdout);
11657 r = fgets (line, sizeof line, stdin);
11658 if (r == NULL) return NULL; /* EOF */
11660 /* Chomp trailing \n */
11661 len = strlen (r);
11662 if (len > 0 && r[len-1] == '\n')
11663 r[len-1] = '\0';
11665 return vshStrdup (ctl, r);
11668 #endif /* !USE_READLINE */
11671 * Deinitialize virsh
11673 static int
11674 vshDeinit(vshControl *ctl)
11676 vshReadlineDeinit(ctl);
11677 vshCloseLogFile(ctl);
11678 VIR_FREE(ctl->name);
11679 if (ctl->conn) {
11680 int ret;
11681 if ((ret = virConnectClose(ctl->conn)) != 0) {
11682 vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret);
11685 virResetLastError();
11687 return TRUE;
11691 * Print usage
11693 static void
11694 vshUsage(void)
11696 const vshCmdGrp *grp;
11697 const vshCmdDef *cmd;
11699 fprintf(stdout, _("\n%s [options]... [<command_string>]"
11700 "\n%s [options]... <command> [args...]\n\n"
11701 " options:\n"
11702 " -c | --connect <uri> hypervisor connection URI\n"
11703 " -r | --readonly connect readonly\n"
11704 " -d | --debug <num> debug level [0-5]\n"
11705 " -h | --help this help\n"
11706 " -q | --quiet quiet mode\n"
11707 " -t | --timing print timing information\n"
11708 " -l | --log <file> output logging to file\n"
11709 " -v | --version[=short] program version\n"
11710 " -V | --version=long version and full options\n\n"
11711 " commands (non interactive mode):\n\n"), progname, progname);
11713 for (grp = cmdGroups; grp->name; grp++) {
11714 fprintf(stdout, _(" %s (help keyword '%s')\n"), grp->name, grp->keyword);
11716 for (cmd = grp->commands; cmd->name; cmd++)
11717 fprintf(stdout,
11718 " %-30s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help")));
11720 fprintf(stdout, "\n");
11723 fprintf(stdout, "%s",
11724 _("\n (specify help <group> for details about the commands in the group)\n"));
11725 fprintf(stdout, "%s",
11726 _("\n (specify help <command> for details about the command)\n\n"));
11727 return;
11731 * Show version and options compiled in
11733 static void
11734 vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED)
11736 /* FIXME - list a copyright blurb, as in GNU programs? */
11737 vshPrint(ctl, _("Virsh command line tool of libvirt %s\n"), VERSION);
11738 vshPrint(ctl, _("See web site at %s\n\n"), "http://libvirt.org/");
11740 vshPrint(ctl, "%s", _("Compiled with support for:\n"));
11741 vshPrint(ctl, "%s", _(" Hypervisors:"));
11742 #ifdef WITH_XEN
11743 vshPrint(ctl, " Xen");
11744 #endif
11745 #ifdef WITH_QEMU
11746 vshPrint(ctl, " QEmu/KVM");
11747 #endif
11748 #ifdef WITH_UML
11749 vshPrint(ctl, " UML");
11750 #endif
11751 #ifdef WITH_OPENVZ
11752 vshPrint(ctl, " OpenVZ");
11753 #endif
11754 #ifdef WITH_VBOX
11755 vshPrint(ctl, " VirtualBox");
11756 #endif
11757 #ifdef WITH_XENAPI
11758 vshPrint(ctl, " XenAPI");
11759 #endif
11760 #ifdef WITH_LXC
11761 vshPrint(ctl, " LXC");
11762 #endif
11763 #ifdef WITH_ESX
11764 vshPrint(ctl, " ESX");
11765 #endif
11766 #ifdef WITH_PHYP
11767 vshPrint(ctl, " PHYP");
11768 #endif
11769 #ifdef WITH_ONE
11770 vshPrint(ctl, " ONE");
11771 #endif
11772 #ifdef WITH_TEST
11773 vshPrint(ctl, " Test");
11774 #endif
11775 vshPrint(ctl, "\n");
11777 vshPrint(ctl, "%s", _(" Networking:"));
11778 #ifdef WITH_REMOTE
11779 vshPrint(ctl, " Remote");
11780 #endif
11781 #ifdef WITH_PROXY
11782 vshPrint(ctl, " Proxy");
11783 #endif
11784 #ifdef WITH_LIBVIRTD
11785 vshPrint(ctl, " Daemon");
11786 #endif
11787 #ifdef WITH_NETWORK
11788 vshPrint(ctl, " Network");
11789 #endif
11790 #ifdef WITH_BRIDGE
11791 vshPrint(ctl, " Bridging");
11792 #endif
11793 #ifdef WITH_NETCF
11794 vshPrint(ctl, " Netcf");
11795 #endif
11796 #ifdef WITH_NWFILTER
11797 vshPrint(ctl, " Nwfilter");
11798 #endif
11799 #ifdef WITH_VIRTUALPORT
11800 vshPrint(ctl, " VirtualPort");
11801 #endif
11802 vshPrint(ctl, "\n");
11804 vshPrint(ctl, "%s", _(" Storage:"));
11805 #ifdef WITH_STORAGE_DIR
11806 vshPrint(ctl, " Dir");
11807 #endif
11808 #ifdef WITH_STORAGE_DISK
11809 vshPrint(ctl, " Disk");
11810 #endif
11811 #ifdef WITH_STORAGE_FS
11812 vshPrint(ctl, " Filesystem");
11813 #endif
11814 #ifdef WITH_STORAGE_SCSI
11815 vshPrint(ctl, " SCSI");
11816 #endif
11817 #ifdef WITH_STORAGE_MPATH
11818 vshPrint(ctl, " Multipath");
11819 #endif
11820 #ifdef WITH_STORAGE_ISCSI
11821 vshPrint(ctl, " iSCSI");
11822 #endif
11823 #ifdef WITH_STORAGE_LVM
11824 vshPrint(ctl, " LVM");
11825 #endif
11826 vshPrint(ctl, "\n");
11828 vshPrint(ctl, "%s", _(" Miscellaneous:"));
11829 #ifdef ENABLE_SECDRIVER_APPARMOR
11830 vshPrint(ctl, " AppArmor");
11831 #endif
11832 #ifdef WITH_SECDRIVER_SELINUX
11833 vshPrint(ctl, " SELinux");
11834 #endif
11835 #ifdef WITH_SECRETS
11836 vshPrint(ctl, " Secrets");
11837 #endif
11838 #ifdef ENABLE_DEBUG
11839 vshPrint(ctl, " Debug");
11840 #endif
11841 #ifdef WITH_DTRACE
11842 vshPrint(ctl, " DTrace");
11843 #endif
11844 #ifdef USE_READLINE
11845 vshPrint(ctl, " Readline");
11846 #endif
11847 #ifdef WITH_DRIVER_MODULES
11848 vshPrint(ctl, " Modular");
11849 #endif
11850 vshPrint(ctl, "\n");
11854 * argv[]: virsh [options] [command]
11857 static int
11858 vshParseArgv(vshControl *ctl, int argc, char **argv)
11860 bool help = false;
11861 int arg;
11862 struct option opt[] = {
11863 {"debug", required_argument, NULL, 'd'},
11864 {"help", no_argument, NULL, 'h'},
11865 {"quiet", no_argument, NULL, 'q'},
11866 {"timing", no_argument, NULL, 't'},
11867 {"version", optional_argument, NULL, 'v'},
11868 {"connect", required_argument, NULL, 'c'},
11869 {"readonly", no_argument, NULL, 'r'},
11870 {"log", required_argument, NULL, 'l'},
11871 {NULL, 0, NULL, 0}
11874 /* Standard (non-command) options. The leading + ensures that no
11875 * argument reordering takes place, so that command options are
11876 * not confused with top-level virsh options. */
11877 while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:", opt, NULL)) != -1) {
11878 switch (arg) {
11879 case 'd':
11880 if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) {
11881 vshError(ctl, "%s", _("option -d takes a numeric argument"));
11882 exit(EXIT_FAILURE);
11884 break;
11885 case 'h':
11886 help = true;
11887 break;
11888 case 'q':
11889 ctl->quiet = TRUE;
11890 break;
11891 case 't':
11892 ctl->timing = TRUE;
11893 break;
11894 case 'c':
11895 ctl->name = vshStrdup(ctl, optarg);
11896 break;
11897 case 'v':
11898 if (STRNEQ_NULLABLE(optarg, "long")) {
11899 puts(VERSION);
11900 exit(EXIT_SUCCESS);
11902 /* fall through */
11903 case 'V':
11904 vshShowVersion(ctl);
11905 exit(EXIT_SUCCESS);
11906 case 'r':
11907 ctl->readonly = TRUE;
11908 break;
11909 case 'l':
11910 ctl->logfile = vshStrdup(ctl, optarg);
11911 break;
11912 default:
11913 vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
11914 exit(EXIT_FAILURE);
11918 if (help) {
11919 if (optind < argc) {
11920 vshError(ctl, _("extra argument '%s'. See --help."), argv[optind]);
11921 exit(EXIT_FAILURE);
11924 /* list all command */
11925 vshUsage();
11926 exit(EXIT_SUCCESS);
11929 if (argc > optind) {
11930 /* parse command */
11931 ctl->imode = FALSE;
11932 if (argc - optind == 1) {
11933 vshDebug(ctl, 2, "commands: \"%s\"\n", argv[optind]);
11934 return vshCommandStringParse(ctl, argv[optind]);
11935 } else {
11936 return vshCommandArgvParse(ctl, argc - optind, argv + optind);
11939 return TRUE;
11943 main(int argc, char **argv)
11945 vshControl _ctl, *ctl = &_ctl;
11946 char *defaultConn;
11947 int ret = TRUE;
11949 if (!setlocale(LC_ALL, "")) {
11950 perror("setlocale");
11951 /* failure to setup locale is not fatal */
11953 if (!bindtextdomain(PACKAGE, LOCALEDIR)) {
11954 perror("bindtextdomain");
11955 return EXIT_FAILURE;
11957 if (!textdomain(PACKAGE)) {
11958 perror("textdomain");
11959 return EXIT_FAILURE;
11962 if (!(progname = strrchr(argv[0], '/')))
11963 progname = argv[0];
11964 else
11965 progname++;
11967 memset(ctl, 0, sizeof(vshControl));
11968 ctl->imode = TRUE; /* default is interactive mode */
11969 ctl->log_fd = -1; /* Initialize log file descriptor */
11971 if ((defaultConn = getenv("VIRSH_DEFAULT_CONNECT_URI"))) {
11972 ctl->name = vshStrdup(ctl, defaultConn);
11975 if (!vshParseArgv(ctl, argc, argv)) {
11976 vshDeinit(ctl);
11977 exit(EXIT_FAILURE);
11980 if (!vshInit(ctl)) {
11981 vshDeinit(ctl);
11982 exit(EXIT_FAILURE);
11985 if (!ctl->imode) {
11986 ret = vshCommandRun(ctl, ctl->cmd);
11987 } else {
11988 /* interactive mode */
11989 if (!ctl->quiet) {
11990 vshPrint(ctl,
11991 _("Welcome to %s, the virtualization interactive terminal.\n\n"),
11992 progname);
11993 vshPrint(ctl, "%s",
11994 _("Type: 'help' for help with commands\n"
11995 " 'quit' to quit\n\n"));
11998 if (vshReadlineInit(ctl) < 0) {
11999 vshDeinit(ctl);
12000 exit(EXIT_FAILURE);
12003 do {
12004 const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW;
12005 ctl->cmdstr =
12006 vshReadline(ctl, prompt);
12007 if (ctl->cmdstr == NULL)
12008 break; /* EOF */
12009 if (*ctl->cmdstr) {
12010 #if USE_READLINE
12011 add_history(ctl->cmdstr);
12012 #endif
12013 if (vshCommandStringParse(ctl, ctl->cmdstr))
12014 vshCommandRun(ctl, ctl->cmd);
12016 VIR_FREE(ctl->cmdstr);
12017 } while (ctl->imode);
12019 if (ctl->cmdstr == NULL)
12020 fputc('\n', stdout); /* line break after alone prompt */
12023 vshDeinit(ctl);
12024 exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);