TEMP comment out libvirtd.stp
[libvirt/apevec.git] / tools / virsh.c
blobe7047999ab7b45334ed316def17612bf95dc436c
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"
55 static char *progname;
57 #ifndef TRUE
58 # define TRUE 1
59 # define FALSE 0
60 #endif
62 #define VIRSH_MAX_XML_FILE 10*1024*1024
64 #define VSH_PROMPT_RW "virsh # "
65 #define VSH_PROMPT_RO "virsh > "
67 #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
68 #define DIFF_MSEC(T, U) \
69 ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
70 ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
72 /**
73 * The log configuration
75 #define MSG_BUFFER 4096
76 #define SIGN_NAME "virsh"
77 #define DIR_MODE (S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) /* 0755 */
78 #define FILE_MODE (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) /* 0644 */
79 #define LOCK_MODE (S_IWUSR | S_IRUSR) /* 0600 */
80 #define LVL_DEBUG "DEBUG"
81 #define LVL_INFO "INFO"
82 #define LVL_NOTICE "NOTICE"
83 #define LVL_WARNING "WARNING"
84 #define LVL_ERROR "ERROR"
86 /**
87 * vshErrorLevel:
89 * Indicates the level of a log message
91 typedef enum {
92 VSH_ERR_DEBUG = 0,
93 VSH_ERR_INFO,
94 VSH_ERR_NOTICE,
95 VSH_ERR_WARNING,
96 VSH_ERR_ERROR
97 } vshErrorLevel;
100 * virsh command line grammar:
102 * command_line = <command>\n | <command>; <command>; ...
104 * command = <keyword> <option> [--] <data>
106 * option = <bool_option> | <int_option> | <string_option>
107 * data = <string>
109 * bool_option = --optionname
110 * int_option = --optionname <number> | --optionname=<number>
111 * string_option = --optionname <string> | --optionname=<string>
113 * keyword = [a-zA-Z][a-zA-Z-]*
114 * number = [0-9]+
115 * string = ('[^']*'|"([^\\"]|\\.)*"|([^ \t\n\\'"]|\\.))+
120 * vshCmdOptType - command option type
122 typedef enum {
123 VSH_OT_BOOL, /* optional boolean option */
124 VSH_OT_STRING, /* optional string option */
125 VSH_OT_INT, /* optional or mandatory int option */
126 VSH_OT_DATA, /* string data (as non-option) */
127 VSH_OT_ARGV /* remaining arguments, opt->name should be "" */
128 } vshCmdOptType;
131 * Command Option Flags
133 #define VSH_OFLAG_NONE 0 /* without flags */
134 #define VSH_OFLAG_REQ (1 << 1) /* option required */
136 /* dummy */
137 typedef struct __vshControl vshControl;
138 typedef struct __vshCmd vshCmd;
141 * vshCmdInfo -- information about command
143 typedef struct {
144 const char *name; /* name of information */
145 const char *data; /* information */
146 } vshCmdInfo;
149 * vshCmdOptDef - command option definition
151 typedef struct {
152 const char *name; /* the name of option */
153 vshCmdOptType type; /* option type */
154 int flag; /* flags */
155 const char *help; /* help string */
156 } vshCmdOptDef;
159 * vshCmdOpt - command options
161 typedef struct vshCmdOpt {
162 const vshCmdOptDef *def; /* pointer to relevant option */
163 char *data; /* allocated data */
164 struct vshCmdOpt *next;
165 } vshCmdOpt;
168 * vshCmdDef - command definition
170 typedef struct {
171 const char *name;
172 int (*handler) (vshControl *, const vshCmd *); /* command handler */
173 const vshCmdOptDef *opts; /* definition of command options */
174 const vshCmdInfo *info; /* details about command */
175 } vshCmdDef;
178 * vshCmd - parsed command
180 typedef struct __vshCmd {
181 const vshCmdDef *def; /* command definition */
182 vshCmdOpt *opts; /* list of command arguments */
183 struct __vshCmd *next; /* next command */
184 } __vshCmd;
187 * vshControl
189 typedef struct __vshControl {
190 char *name; /* connection name */
191 virConnectPtr conn; /* connection to hypervisor (MAY BE NULL) */
192 vshCmd *cmd; /* the current command */
193 char *cmdstr; /* string with command */
194 int imode; /* interactive mode? */
195 int quiet; /* quiet mode */
196 int debug; /* print debug messages? */
197 int timing; /* print timing info? */
198 int readonly; /* connect readonly (first time only, not
199 * during explicit connect command)
201 char *logfile; /* log file name */
202 int log_fd; /* log file descriptor */
203 char *historydir; /* readline history directory name */
204 char *historyfile; /* readline history file name */
205 } __vshControl;
208 static const vshCmdDef commands[];
210 static void vshError(vshControl *ctl, const char *format, ...)
211 ATTRIBUTE_FMT_PRINTF(2, 3);
212 static int vshInit(vshControl *ctl);
213 static int vshDeinit(vshControl *ctl);
214 static void vshUsage(void);
215 static void vshOpenLogFile(vshControl *ctl);
216 static void vshOutputLogFile(vshControl *ctl, int log_level, const char *format, va_list ap);
217 static void vshCloseLogFile(vshControl *ctl);
219 static int vshParseArgv(vshControl *ctl, int argc, char **argv);
221 static const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info);
222 static const vshCmdDef *vshCmddefSearch(const char *cmdname);
223 static int vshCmddefHelp(vshControl *ctl, const char *name);
225 static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
226 static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found);
227 static unsigned long vshCommandOptUL(const vshCmd *cmd, const char *name,
228 int *found);
229 static char *vshCommandOptString(const vshCmd *cmd, const char *name,
230 int *found);
231 static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name,
232 int *found);
233 static int vshCommandOptBool(const vshCmd *cmd, const char *name);
234 static char *vshCommandOptArgv(const vshCmd *cmd, int count);
236 #define VSH_BYID (1 << 1)
237 #define VSH_BYUUID (1 << 2)
238 #define VSH_BYNAME (1 << 3)
239 #define VSH_BYMAC (1 << 4)
241 static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
242 char **name, int flag);
244 /* default is lookup by Id, Name and UUID */
245 #define vshCommandOptDomain(_ctl, _cmd, _name) \
246 vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME)
248 static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
249 char **name, int flag);
251 /* default is lookup by Name and UUID */
252 #define vshCommandOptNetwork(_ctl, _cmd, _name) \
253 vshCommandOptNetworkBy(_ctl, _cmd, _name, \
254 VSH_BYUUID|VSH_BYNAME)
256 static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
257 char **name, int flag);
259 /* default is lookup by Name and UUID */
260 #define vshCommandOptNWFilter(_ctl, _cmd, _name) \
261 vshCommandOptNWFilterBy(_ctl, _cmd, _name, \
262 VSH_BYUUID|VSH_BYNAME)
264 static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
265 char **name, int flag);
267 /* default is lookup by Name and MAC */
268 #define vshCommandOptInterface(_ctl, _cmd, _name) \
269 vshCommandOptInterfaceBy(_ctl, _cmd, _name, \
270 VSH_BYMAC|VSH_BYNAME)
272 static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd,
273 const char *optname, char **name, int flag);
275 /* default is lookup by Name and UUID */
276 #define vshCommandOptPool(_ctl, _cmd, _optname, _name) \
277 vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \
278 VSH_BYUUID|VSH_BYNAME)
280 static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
281 const char *optname,
282 const char *pooloptname,
283 char **name, int flag);
285 /* default is lookup by Name and UUID */
286 #define vshCommandOptVol(_ctl, _cmd,_optname, _pooloptname, _name) \
287 vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \
288 VSH_BYUUID|VSH_BYNAME)
290 static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd,
291 char **name);
293 static void vshPrintExtra(vshControl *ctl, const char *format, ...)
294 ATTRIBUTE_FMT_PRINTF(2, 3);
295 static void vshDebug(vshControl *ctl, int level, const char *format, ...)
296 ATTRIBUTE_FMT_PRINTF(3, 4);
298 /* XXX: add batch support */
299 #define vshPrint(_ctl, ...) fprintf(stdout, __VA_ARGS__)
301 static const char *vshDomainStateToString(int state);
302 static const char *vshDomainVcpuStateToString(int state);
303 static int vshConnectionUsability(vshControl *ctl, virConnectPtr conn);
305 static char *editWriteToTempFile (vshControl *ctl, const char *doc);
306 static int editFile (vshControl *ctl, const char *filename);
307 static char *editReadBackFile (vshControl *ctl, const char *filename);
309 static void *_vshMalloc(vshControl *ctl, size_t sz, const char *filename, int line);
310 #define vshMalloc(_ctl, _sz) _vshMalloc(_ctl, _sz, __FILE__, __LINE__)
312 static void *_vshCalloc(vshControl *ctl, size_t nmemb, size_t sz, const char *filename, int line);
313 #define vshCalloc(_ctl, _nmemb, _sz) _vshCalloc(_ctl, _nmemb, _sz, __FILE__, __LINE__)
315 static void *_vshRealloc(vshControl *ctl, void *ptr, size_t sz, const char *filename, int line);
316 #define vshRealloc(_ctl, _ptr, _sz) _vshRealloc(_ctl, _ptr, _sz, __FILE__, __LINE__)
318 static char *_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line);
319 #define vshStrdup(_ctl, _s) _vshStrdup(_ctl, _s, __FILE__, __LINE__)
321 static void *
322 _vshMalloc(vshControl *ctl, size_t size, const char *filename, int line)
324 void *x;
326 if ((x = malloc(size)))
327 return x;
328 vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
329 filename, line, (int) size);
330 exit(EXIT_FAILURE);
333 static void *
334 _vshCalloc(vshControl *ctl, size_t nmemb, size_t size, const char *filename, int line)
336 void *x;
338 if ((x = calloc(nmemb, size)))
339 return x;
340 vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
341 filename, line, (int) (size*nmemb));
342 exit(EXIT_FAILURE);
345 static void *
346 _vshRealloc(vshControl *ctl, void *ptr, size_t size, const char *filename, int line)
348 void *x;
350 if ((x = realloc(ptr, size)))
351 return x;
352 VIR_FREE(ptr);
353 vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
354 filename, line, (int) size);
355 exit(EXIT_FAILURE);
358 static char *
359 _vshStrdup(vshControl *ctl, const char *s, const char *filename, int line)
361 char *x;
363 if (s == NULL)
364 return(NULL);
365 if ((x = strdup(s)))
366 return x;
367 vshError(ctl, _("%s: %d: failed to allocate %lu bytes"),
368 filename, line, (unsigned long)strlen(s));
369 exit(EXIT_FAILURE);
372 /* Poison the raw allocating identifiers in favor of our vsh variants. */
373 #undef malloc
374 #undef calloc
375 #undef realloc
376 #undef strdup
377 #define malloc use_vshMalloc_instead_of_malloc
378 #define calloc use_vshCalloc_instead_of_calloc
379 #define realloc use_vshRealloc_instead_of_realloc
380 #define strdup use_vshStrdup_instead_of_strdup
382 static int idsorter(const void *a, const void *b) {
383 const int *ia = (const int *)a;
384 const int *ib = (const int *)b;
386 if (*ia > *ib)
387 return 1;
388 else if (*ia < *ib)
389 return -1;
390 return 0;
392 static int namesorter(const void *a, const void *b) {
393 const char **sa = (const char**)a;
394 const char **sb = (const char**)b;
396 return strcasecmp(*sa, *sb);
399 static double
400 prettyCapacity(unsigned long long val,
401 const char **unit) {
402 if (val < 1024) {
403 *unit = "";
404 return (double)val;
405 } else if (val < (1024.0l * 1024.0l)) {
406 *unit = "KB";
407 return (((double)val / 1024.0l));
408 } else if (val < (1024.0l * 1024.0l * 1024.0l)) {
409 *unit = "MB";
410 return ((double)val / (1024.0l * 1024.0l));
411 } else if (val < (1024.0l * 1024.0l * 1024.0l * 1024.0l)) {
412 *unit = "GB";
413 return ((double)val / (1024.0l * 1024.0l * 1024.0l));
414 } else {
415 *unit = "TB";
416 return ((double)val / (1024.0l * 1024.0l * 1024.0l * 1024.0l));
421 static virErrorPtr last_error;
424 * Quieten libvirt until we're done with the command.
426 static void
427 virshErrorHandler(void *unused ATTRIBUTE_UNUSED, virErrorPtr error)
429 virFreeError(last_error);
430 last_error = virSaveLastError();
431 if (getenv("VIRSH_DEBUG") != NULL)
432 virDefaultErrorFunc(error);
436 * Report an error when a command finishes. This is better than before
437 * (when correct operation would report errors), but it has some
438 * problems: we lose the smarter formatting of virDefaultErrorFunc(),
439 * and it can become harder to debug problems, if errors get reported
440 * twice during one command. This case shouldn't really happen anyway,
441 * and it's IMHO a bug that libvirt does that sometimes.
443 static void
444 virshReportError(vshControl *ctl)
446 if (last_error == NULL) {
447 /* Calling directly into libvirt util functions won't trigger the
448 * error callback (which sets last_error), so check it ourselves.
450 * If the returned error has CODE_OK, this most likely means that
451 * no error was ever raised, so just ignore */
452 last_error = virSaveLastError();
453 if (!last_error || last_error->code == VIR_ERR_OK)
454 goto out;
457 if (last_error->code == VIR_ERR_OK) {
458 vshError(ctl, "%s", _("unknown error"));
459 goto out;
462 vshError(ctl, "%s", last_error->message);
464 out:
465 virFreeError(last_error);
466 last_error = NULL;
470 * Detection of disconnections and automatic reconnection support
472 static int disconnected = 0; /* we may have been disconnected */
474 #ifdef SIGPIPE
476 * vshCatchDisconnect:
478 * We get here when a SIGPIPE is being raised, we can't do much in the
479 * handler, just save the fact it was raised
481 static void vshCatchDisconnect(int sig, siginfo_t * siginfo,
482 void* context ATTRIBUTE_UNUSED) {
483 if ((sig == SIGPIPE) || (siginfo->si_signo == SIGPIPE))
484 disconnected++;
488 * vshSetupSignals:
490 * Catch SIGPIPE signals which may arise when disconnection
491 * from libvirtd occurs
493 static void
494 vshSetupSignals(void) {
495 struct sigaction sig_action;
497 sig_action.sa_sigaction = vshCatchDisconnect;
498 sig_action.sa_flags = SA_SIGINFO;
499 sigemptyset(&sig_action.sa_mask);
501 sigaction(SIGPIPE, &sig_action, NULL);
503 #else
504 static void
505 vshSetupSignals(void) {}
506 #endif
509 * vshReconnect:
511 * Reconnect after a disconnect from libvirtd
514 static void
515 vshReconnect(vshControl *ctl) {
516 if (ctl->conn != NULL)
517 virConnectClose(ctl->conn);
519 ctl->conn = virConnectOpenAuth(ctl->name,
520 virConnectAuthPtrDefault,
521 ctl->readonly ? VIR_CONNECT_RO : 0);
522 if (!ctl->conn)
523 vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
524 else
525 vshError(ctl, "%s", _("Reconnected to the hypervisor"));
526 disconnected = 0;
529 /* ---------------
530 * Commands
531 * ---------------
535 * "help" command
537 static const vshCmdInfo info_help[] = {
538 {"help", N_("print help")},
539 {"desc", N_("Prints global help or command specific help.")},
541 {NULL, NULL}
544 static const vshCmdOptDef opts_help[] = {
545 {"command", VSH_OT_DATA, 0, N_("name of command")},
546 {NULL, 0, 0, NULL}
549 static int
550 cmdHelp(vshControl *ctl, const vshCmd *cmd)
552 const char *cmdname = vshCommandOptString(cmd, "command", NULL);
554 if (!cmdname) {
555 const vshCmdDef *def;
557 vshPrint(ctl, "%s", _("Commands:\n\n"));
558 for (def = commands; def->name; def++)
559 vshPrint(ctl, " %-15s %s\n", def->name,
560 _(vshCmddefGetInfo(def, "help")));
561 return TRUE;
563 return vshCmddefHelp(ctl, cmdname);
567 * "autostart" command
569 static const vshCmdInfo info_autostart[] = {
570 {"help", N_("autostart a domain")},
571 {"desc",
572 N_("Configure a domain to be automatically started at boot.")},
573 {NULL, NULL}
576 static const vshCmdOptDef opts_autostart[] = {
577 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
578 {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
579 {NULL, 0, 0, NULL}
582 static int
583 cmdAutostart(vshControl *ctl, const vshCmd *cmd)
585 virDomainPtr dom;
586 char *name;
587 int autostart;
589 if (!vshConnectionUsability(ctl, ctl->conn))
590 return FALSE;
592 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
593 return FALSE;
595 autostart = !vshCommandOptBool(cmd, "disable");
597 if (virDomainSetAutostart(dom, autostart) < 0) {
598 if (autostart)
599 vshError(ctl, _("Failed to mark domain %s as autostarted"), name);
600 else
601 vshError(ctl, _("Failed to unmark domain %s as autostarted"), name);
602 virDomainFree(dom);
603 return FALSE;
606 if (autostart)
607 vshPrint(ctl, _("Domain %s marked as autostarted\n"), name);
608 else
609 vshPrint(ctl, _("Domain %s unmarked as autostarted\n"), name);
611 virDomainFree(dom);
612 return TRUE;
616 * "connect" command
618 static const vshCmdInfo info_connect[] = {
619 {"help", N_("(re)connect to hypervisor")},
620 {"desc",
621 N_("Connect to local hypervisor. This is built-in command after shell start up.")},
622 {NULL, NULL}
625 static const vshCmdOptDef opts_connect[] = {
626 {"name", VSH_OT_DATA, 0, N_("hypervisor connection URI")},
627 {"readonly", VSH_OT_BOOL, 0, N_("read-only connection")},
628 {NULL, 0, 0, NULL}
631 static int
632 cmdConnect(vshControl *ctl, const vshCmd *cmd)
634 int ro = vshCommandOptBool(cmd, "readonly");
635 char *name;
637 if (ctl->conn) {
638 if (virConnectClose(ctl->conn) != 0) {
639 vshError(ctl, "%s", _("Failed to disconnect from the hypervisor"));
640 return FALSE;
642 ctl->conn = NULL;
645 VIR_FREE(ctl->name);
646 name = vshCommandOptString(cmd, "name", NULL);
647 if (!name)
648 return FALSE;
649 ctl->name = vshStrdup(ctl, name);
651 if (!ro) {
652 ctl->readonly = 0;
653 } else {
654 ctl->readonly = 1;
657 ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault,
658 ctl->readonly ? VIR_CONNECT_RO : 0);
660 if (!ctl->conn)
661 vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
663 return ctl->conn ? TRUE : FALSE;
666 #ifndef WIN32
669 * "console" command
671 static const vshCmdInfo info_console[] = {
672 {"help", N_("connect to the guest console")},
673 {"desc",
674 N_("Connect the virtual serial console for the guest")},
675 {NULL, NULL}
678 static const vshCmdOptDef opts_console[] = {
679 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
680 {NULL, 0, 0, NULL}
683 static int
684 cmdRunConsole(vshControl *ctl, virDomainPtr dom)
686 xmlDocPtr xml = NULL;
687 xmlXPathObjectPtr obj = NULL;
688 xmlXPathContextPtr ctxt = NULL;
689 int ret = FALSE;
690 char *doc;
691 char *thatHost = NULL;
692 char *thisHost = NULL;
693 virDomainInfo dominfo;
695 if (!(thisHost = virGetHostname(ctl->conn))) {
696 vshError(ctl, "%s", _("Failed to get local hostname"));
697 goto cleanup;
700 if (!(thatHost = virConnectGetHostname(ctl->conn))) {
701 vshError(ctl, "%s", _("Failed to get connection hostname"));
702 goto cleanup;
705 if (STRNEQ(thisHost, thatHost)) {
706 vshError(ctl, "%s", _("Cannot connect to a remote console device"));
707 goto cleanup;
710 if (virDomainGetInfo(dom, &dominfo) < 0) {
711 vshError(ctl, "%s", _("Unable to get domain status"));
712 goto cleanup;
715 if (dominfo.state == VIR_DOMAIN_SHUTOFF) {
716 vshError(ctl, "%s", _("The domain is not running"));
717 goto cleanup;
720 doc = virDomainGetXMLDesc(dom, 0);
721 if (!doc)
722 goto cleanup;
724 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
725 XML_PARSE_NOENT | XML_PARSE_NONET |
726 XML_PARSE_NOWARNING);
727 VIR_FREE(doc);
728 if (!xml)
729 goto cleanup;
730 ctxt = xmlXPathNewContext(xml);
731 if (!ctxt)
732 goto cleanup;
734 obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt);
735 if ((obj != NULL) && ((obj->type == XPATH_STRING) &&
736 (obj->stringval != NULL) && (obj->stringval[0] != 0))) {
737 vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom));
738 vshPrintExtra(ctl, "%s", _("Escape character is ^]\n"));
739 if (vshRunConsole((const char *)obj->stringval) == 0)
740 ret = TRUE;
741 } else {
742 vshPrintExtra(ctl, "%s", _("No console available for domain\n"));
744 xmlXPathFreeObject(obj);
746 cleanup:
747 xmlXPathFreeContext(ctxt);
748 if (xml)
749 xmlFreeDoc(xml);
750 VIR_FREE(thisHost);
751 VIR_FREE(thatHost);
753 return ret;
756 static int
757 cmdConsole(vshControl *ctl, const vshCmd *cmd)
759 virDomainPtr dom;
760 int ret;
762 if (!vshConnectionUsability(ctl, ctl->conn))
763 return FALSE;
765 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
766 return FALSE;
768 ret = cmdRunConsole(ctl, dom);
770 virDomainFree(dom);
771 return ret;
774 #endif /* WIN32 */
778 * "list" command
780 static const vshCmdInfo info_list[] = {
781 {"help", N_("list domains")},
782 {"desc", N_("Returns list of domains.")},
783 {NULL, NULL}
786 static const vshCmdOptDef opts_list[] = {
787 {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")},
788 {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")},
789 {NULL, 0, 0, NULL}
793 static int
794 cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
796 int inactive = vshCommandOptBool(cmd, "inactive");
797 int all = vshCommandOptBool(cmd, "all");
798 int active = !inactive || all ? 1 : 0;
799 int *ids = NULL, maxid = 0, i;
800 char **names = NULL;
801 int maxname = 0;
802 inactive |= all;
804 if (!vshConnectionUsability(ctl, ctl->conn))
805 return FALSE;
807 if (active) {
808 maxid = virConnectNumOfDomains(ctl->conn);
809 if (maxid < 0) {
810 vshError(ctl, "%s", _("Failed to list active domains"));
811 return FALSE;
813 if (maxid) {
814 ids = vshMalloc(ctl, sizeof(int) * maxid);
816 if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
817 vshError(ctl, "%s", _("Failed to list active domains"));
818 VIR_FREE(ids);
819 return FALSE;
822 qsort(&ids[0], maxid, sizeof(int), idsorter);
825 if (inactive) {
826 maxname = virConnectNumOfDefinedDomains(ctl->conn);
827 if (maxname < 0) {
828 vshError(ctl, "%s", _("Failed to list inactive domains"));
829 VIR_FREE(ids);
830 return FALSE;
832 if (maxname) {
833 names = vshMalloc(ctl, sizeof(char *) * maxname);
835 if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
836 vshError(ctl, "%s", _("Failed to list inactive domains"));
837 VIR_FREE(ids);
838 VIR_FREE(names);
839 return FALSE;
842 qsort(&names[0], maxname, sizeof(char*), namesorter);
845 vshPrintExtra(ctl, "%3s %-20s %s\n", _("Id"), _("Name"), _("State"));
846 vshPrintExtra(ctl, "----------------------------------\n");
848 for (i = 0; i < maxid; i++) {
849 virDomainInfo info;
850 virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
851 const char *state;
853 /* this kind of work with domains is not atomic operation */
854 if (!dom)
855 continue;
857 if (virDomainGetInfo(dom, &info) < 0)
858 state = _("no state");
859 else
860 state = _(vshDomainStateToString(info.state));
862 vshPrint(ctl, "%3d %-20s %s\n",
863 virDomainGetID(dom),
864 virDomainGetName(dom),
865 state);
866 virDomainFree(dom);
868 for (i = 0; i < maxname; i++) {
869 virDomainInfo info;
870 virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
871 const char *state;
873 /* this kind of work with domains is not atomic operation */
874 if (!dom) {
875 VIR_FREE(names[i]);
876 continue;
879 if (virDomainGetInfo(dom, &info) < 0)
880 state = _("no state");
881 else
882 state = _(vshDomainStateToString(info.state));
884 vshPrint(ctl, "%3s %-20s %s\n", "-", names[i], state);
886 virDomainFree(dom);
887 VIR_FREE(names[i]);
889 VIR_FREE(ids);
890 VIR_FREE(names);
891 return TRUE;
895 * "domstate" command
897 static const vshCmdInfo info_domstate[] = {
898 {"help", N_("domain state")},
899 {"desc", N_("Returns state about a domain.")},
900 {NULL, NULL}
903 static const vshCmdOptDef opts_domstate[] = {
904 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
905 {NULL, 0, 0, NULL}
908 static int
909 cmdDomstate(vshControl *ctl, const vshCmd *cmd)
911 virDomainInfo info;
912 virDomainPtr dom;
913 int ret = TRUE;
915 if (!vshConnectionUsability(ctl, ctl->conn))
916 return FALSE;
918 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
919 return FALSE;
921 if (virDomainGetInfo(dom, &info) == 0)
922 vshPrint(ctl, "%s\n",
923 _(vshDomainStateToString(info.state)));
924 else
925 ret = FALSE;
927 virDomainFree(dom);
928 return ret;
931 /* "domblkstat" command
933 static const vshCmdInfo info_domblkstat[] = {
934 {"help", N_("get device block stats for a domain")},
935 {"desc", N_("Get device block stats for a running domain.")},
936 {NULL,NULL}
939 static const vshCmdOptDef opts_domblkstat[] = {
940 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
941 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
942 {NULL, 0, 0, NULL}
945 static int
946 cmdDomblkstat (vshControl *ctl, const vshCmd *cmd)
948 virDomainPtr dom;
949 char *name, *device;
950 struct _virDomainBlockStats stats;
952 if (!vshConnectionUsability (ctl, ctl->conn))
953 return FALSE;
955 if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
956 return FALSE;
958 if (!(device = vshCommandOptString (cmd, "device", NULL))) {
959 virDomainFree(dom);
960 return FALSE;
963 if (virDomainBlockStats (dom, device, &stats, sizeof stats) == -1) {
964 vshError(ctl, _("Failed to get block stats %s %s"), name, device);
965 virDomainFree(dom);
966 return FALSE;
969 if (stats.rd_req >= 0)
970 vshPrint (ctl, "%s rd_req %lld\n", device, stats.rd_req);
972 if (stats.rd_bytes >= 0)
973 vshPrint (ctl, "%s rd_bytes %lld\n", device, stats.rd_bytes);
975 if (stats.wr_req >= 0)
976 vshPrint (ctl, "%s wr_req %lld\n", device, stats.wr_req);
978 if (stats.wr_bytes >= 0)
979 vshPrint (ctl, "%s wr_bytes %lld\n", device, stats.wr_bytes);
981 if (stats.errs >= 0)
982 vshPrint (ctl, "%s errs %lld\n", device, stats.errs);
984 virDomainFree(dom);
985 return TRUE;
988 /* "domifstat" command
990 static const vshCmdInfo info_domifstat[] = {
991 {"help", N_("get network interface stats for a domain")},
992 {"desc", N_("Get network interface stats for a running domain.")},
993 {NULL,NULL}
996 static const vshCmdOptDef opts_domifstat[] = {
997 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
998 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")},
999 {NULL, 0, 0, NULL}
1002 static int
1003 cmdDomIfstat (vshControl *ctl, const vshCmd *cmd)
1005 virDomainPtr dom;
1006 char *name, *device;
1007 struct _virDomainInterfaceStats stats;
1009 if (!vshConnectionUsability (ctl, ctl->conn))
1010 return FALSE;
1012 if (!(dom = vshCommandOptDomain (ctl, cmd, &name)))
1013 return FALSE;
1015 if (!(device = vshCommandOptString (cmd, "interface", NULL))) {
1016 virDomainFree(dom);
1017 return FALSE;
1020 if (virDomainInterfaceStats (dom, device, &stats, sizeof stats) == -1) {
1021 vshError(ctl, _("Failed to get interface stats %s %s"), name, device);
1022 virDomainFree(dom);
1023 return FALSE;
1026 if (stats.rx_bytes >= 0)
1027 vshPrint (ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes);
1029 if (stats.rx_packets >= 0)
1030 vshPrint (ctl, "%s rx_packets %lld\n", device, stats.rx_packets);
1032 if (stats.rx_errs >= 0)
1033 vshPrint (ctl, "%s rx_errs %lld\n", device, stats.rx_errs);
1035 if (stats.rx_drop >= 0)
1036 vshPrint (ctl, "%s rx_drop %lld\n", device, stats.rx_drop);
1038 if (stats.tx_bytes >= 0)
1039 vshPrint (ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes);
1041 if (stats.tx_packets >= 0)
1042 vshPrint (ctl, "%s tx_packets %lld\n", device, stats.tx_packets);
1044 if (stats.tx_errs >= 0)
1045 vshPrint (ctl, "%s tx_errs %lld\n", device, stats.tx_errs);
1047 if (stats.tx_drop >= 0)
1048 vshPrint (ctl, "%s tx_drop %lld\n", device, stats.tx_drop);
1050 virDomainFree(dom);
1051 return TRUE;
1055 * "dommemstats" command
1057 static const vshCmdInfo info_dommemstat[] = {
1058 {"help", N_("get memory statistics for a domain")},
1059 {"desc", N_("Get memory statistics for a runnng domain.")},
1060 {NULL,NULL}
1063 static const vshCmdOptDef opts_dommemstat[] = {
1064 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1065 {NULL, 0, 0, NULL}
1068 static int
1069 cmdDomMemStat(vshControl *ctl, const vshCmd *cmd)
1071 virDomainPtr dom;
1072 char *name;
1073 struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR];
1074 unsigned int nr_stats, i;
1076 if (!vshConnectionUsability(ctl, ctl->conn))
1077 return FALSE;
1079 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1080 return FALSE;
1082 nr_stats = virDomainMemoryStats (dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0);
1083 if (nr_stats == -1) {
1084 vshError(ctl, _("Failed to get memory statistics for domain %s"), name);
1085 virDomainFree(dom);
1086 return FALSE;
1089 for (i = 0; i < nr_stats; i++) {
1090 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
1091 vshPrint (ctl, "swap_in %llu\n", stats[i].val);
1092 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
1093 vshPrint (ctl, "swap_out %llu\n", stats[i].val);
1094 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
1095 vshPrint (ctl, "major_fault %llu\n", stats[i].val);
1096 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
1097 vshPrint (ctl, "minor_fault %llu\n", stats[i].val);
1098 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED)
1099 vshPrint (ctl, "unused %llu\n", stats[i].val);
1100 if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE)
1101 vshPrint (ctl, "available %llu\n", stats[i].val);
1104 virDomainFree(dom);
1105 return TRUE;
1109 * "domblkinfo" command
1111 static const vshCmdInfo info_domblkinfo[] = {
1112 {"help", N_("domain block device size information")},
1113 {"desc", N_("Get block device size info for a domain.")},
1114 {NULL, NULL}
1117 static const vshCmdOptDef opts_domblkinfo[] = {
1118 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1119 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
1120 {NULL, 0, 0, NULL}
1123 static int
1124 cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd)
1126 virDomainBlockInfo info;
1127 virDomainPtr dom;
1128 int ret = TRUE;
1129 const char *device;
1131 if (!vshConnectionUsability(ctl, ctl->conn))
1132 return FALSE;
1134 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
1135 return FALSE;
1137 if (!(device = vshCommandOptString (cmd, "device", NULL))) {
1138 virDomainFree(dom);
1139 return FALSE;
1142 if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) {
1143 virDomainFree(dom);
1144 return FALSE;
1147 vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity);
1148 vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation);
1149 vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical);
1151 virDomainFree(dom);
1152 return ret;
1156 * "suspend" command
1158 static const vshCmdInfo info_suspend[] = {
1159 {"help", N_("suspend a domain")},
1160 {"desc", N_("Suspend a running domain.")},
1161 {NULL, NULL}
1164 static const vshCmdOptDef opts_suspend[] = {
1165 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1166 {NULL, 0, 0, NULL}
1169 static int
1170 cmdSuspend(vshControl *ctl, const vshCmd *cmd)
1172 virDomainPtr dom;
1173 char *name;
1174 int ret = TRUE;
1176 if (!vshConnectionUsability(ctl, ctl->conn))
1177 return FALSE;
1179 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1180 return FALSE;
1182 if (virDomainSuspend(dom) == 0) {
1183 vshPrint(ctl, _("Domain %s suspended\n"), name);
1184 } else {
1185 vshError(ctl, _("Failed to suspend domain %s"), name);
1186 ret = FALSE;
1189 virDomainFree(dom);
1190 return ret;
1194 * "create" command
1196 static const vshCmdInfo info_create[] = {
1197 {"help", N_("create a domain from an XML file")},
1198 {"desc", N_("Create a domain.")},
1199 {NULL, NULL}
1202 static const vshCmdOptDef opts_create[] = {
1203 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1204 #ifndef WIN32
1205 {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1206 #endif
1207 {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
1208 {NULL, 0, 0, NULL}
1211 static int
1212 cmdCreate(vshControl *ctl, const vshCmd *cmd)
1214 virDomainPtr dom;
1215 char *from;
1216 int found;
1217 int ret = TRUE;
1218 char *buffer;
1219 #ifndef WIN32
1220 int console = vshCommandOptBool(cmd, "console");
1221 #endif
1222 unsigned int flags = VIR_DOMAIN_NONE;
1224 if (!vshConnectionUsability(ctl, ctl->conn))
1225 return FALSE;
1227 from = vshCommandOptString(cmd, "file", &found);
1228 if (!found)
1229 return FALSE;
1231 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
1232 return FALSE;
1234 if (vshCommandOptBool(cmd, "paused"))
1235 flags |= VIR_DOMAIN_START_PAUSED;
1237 dom = virDomainCreateXML(ctl->conn, buffer, flags);
1238 VIR_FREE(buffer);
1240 if (dom != NULL) {
1241 vshPrint(ctl, _("Domain %s created from %s\n"),
1242 virDomainGetName(dom), from);
1243 #ifndef WIN32
1244 if (console)
1245 cmdRunConsole(ctl, dom);
1246 #endif
1247 virDomainFree(dom);
1248 } else {
1249 vshError(ctl, _("Failed to create domain from %s"), from);
1250 ret = FALSE;
1252 return ret;
1256 * "define" command
1258 static const vshCmdInfo info_define[] = {
1259 {"help", N_("define (but don't start) a domain from an XML file")},
1260 {"desc", N_("Define a domain.")},
1261 {NULL, NULL}
1264 static const vshCmdOptDef opts_define[] = {
1265 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
1266 {NULL, 0, 0, NULL}
1269 static int
1270 cmdDefine(vshControl *ctl, const vshCmd *cmd)
1272 virDomainPtr dom;
1273 char *from;
1274 int found;
1275 int ret = TRUE;
1276 char *buffer;
1278 if (!vshConnectionUsability(ctl, ctl->conn))
1279 return FALSE;
1281 from = vshCommandOptString(cmd, "file", &found);
1282 if (!found)
1283 return FALSE;
1285 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
1286 return FALSE;
1288 dom = virDomainDefineXML(ctl->conn, buffer);
1289 VIR_FREE(buffer);
1291 if (dom != NULL) {
1292 vshPrint(ctl, _("Domain %s defined from %s\n"),
1293 virDomainGetName(dom), from);
1294 virDomainFree(dom);
1295 } else {
1296 vshError(ctl, _("Failed to define domain from %s"), from);
1297 ret = FALSE;
1299 return ret;
1303 * "undefine" command
1305 static const vshCmdInfo info_undefine[] = {
1306 {"help", N_("undefine an inactive domain")},
1307 {"desc", N_("Undefine the configuration for an inactive domain.")},
1308 {NULL, NULL}
1311 static const vshCmdOptDef opts_undefine[] = {
1312 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
1313 {NULL, 0, 0, NULL}
1316 static int
1317 cmdUndefine(vshControl *ctl, const vshCmd *cmd)
1319 virDomainPtr dom;
1320 int ret = TRUE;
1321 char *name;
1322 int found;
1323 int id;
1325 if (!vshConnectionUsability(ctl, ctl->conn))
1326 return FALSE;
1328 name = vshCommandOptString(cmd, "domain", &found);
1329 if (!found)
1330 return FALSE;
1332 if (name && virStrToLong_i(name, NULL, 10, &id) == 0
1333 && id >= 0 && (dom = virDomainLookupByID(ctl->conn, id))) {
1334 vshError(ctl,
1335 _("a running domain like %s cannot be undefined;\n"
1336 "to undefine, first shutdown then undefine"
1337 " using its name or UUID"),
1338 name);
1339 virDomainFree(dom);
1340 return FALSE;
1342 if (!(dom = vshCommandOptDomainBy(ctl, cmd, &name,
1343 VSH_BYNAME|VSH_BYUUID)))
1344 return FALSE;
1346 if (virDomainUndefine(dom) == 0) {
1347 vshPrint(ctl, _("Domain %s has been undefined\n"), name);
1348 } else {
1349 vshError(ctl, _("Failed to undefine domain %s"), name);
1350 ret = FALSE;
1353 virDomainFree(dom);
1354 return ret;
1359 * "start" command
1361 static const vshCmdInfo info_start[] = {
1362 {"help", N_("start a (previously defined) inactive domain")},
1363 {"desc", N_("Start a domain, either from the last managedsave\n"
1364 " state, or via a fresh boot if no managedsave state\n"
1365 " is present.")},
1366 {NULL, NULL}
1369 static const vshCmdOptDef opts_start[] = {
1370 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive domain")},
1371 #ifndef WIN32
1372 {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
1373 #endif
1374 {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
1375 {NULL, 0, 0, NULL}
1378 static int
1379 cmdStart(vshControl *ctl, const vshCmd *cmd)
1381 virDomainPtr dom;
1382 int ret = TRUE;
1383 #ifndef WIN32
1384 int console = vshCommandOptBool(cmd, "console");
1385 #endif
1386 unsigned int flags = VIR_DOMAIN_NONE;
1388 if (!vshConnectionUsability(ctl, ctl->conn))
1389 return FALSE;
1391 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL, VSH_BYNAME)))
1392 return FALSE;
1394 if (virDomainGetID(dom) != (unsigned int)-1) {
1395 vshError(ctl, "%s", _("Domain is already active"));
1396 virDomainFree(dom);
1397 return FALSE;
1400 if (vshCommandOptBool(cmd, "paused"))
1401 flags |= VIR_DOMAIN_START_PAUSED;
1403 /* Prefer older API unless we have to pass a flag. */
1404 if ((flags ? virDomainCreateWithFlags(dom, flags)
1405 : virDomainCreate(dom)) == 0) {
1406 vshPrint(ctl, _("Domain %s started\n"),
1407 virDomainGetName(dom));
1408 #ifndef WIN32
1409 if (console)
1410 cmdRunConsole(ctl, dom);
1411 #endif
1412 } else {
1413 vshError(ctl, _("Failed to start domain %s"), virDomainGetName(dom));
1414 ret = FALSE;
1416 virDomainFree(dom);
1417 return ret;
1421 * "save" command
1423 static const vshCmdInfo info_save[] = {
1424 {"help", N_("save a domain state to a file")},
1425 {"desc", N_("Save a running domain.")},
1426 {NULL, NULL}
1429 static const vshCmdOptDef opts_save[] = {
1430 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1431 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to save the data")},
1432 {NULL, 0, 0, NULL}
1435 static int
1436 cmdSave(vshControl *ctl, const vshCmd *cmd)
1438 virDomainPtr dom;
1439 char *name;
1440 char *to;
1441 int ret = TRUE;
1443 if (!vshConnectionUsability(ctl, ctl->conn))
1444 return FALSE;
1446 if (!(to = vshCommandOptString(cmd, "file", NULL)))
1447 return FALSE;
1449 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1450 return FALSE;
1452 if (virDomainSave(dom, to) == 0) {
1453 vshPrint(ctl, _("Domain %s saved to %s\n"), name, to);
1454 } else {
1455 vshError(ctl, _("Failed to save domain %s to %s"), name, to);
1456 ret = FALSE;
1459 virDomainFree(dom);
1460 return ret;
1464 * "managedsave" command
1466 static const vshCmdInfo info_managedsave[] = {
1467 {"help", N_("managed save of a domain state")},
1468 {"desc", N_("Save and destroy a running domain, so it can be restarted from\n"
1469 " the same state at a later time. When the virsh 'start'\n"
1470 " command is next run for the domain, it will automatically\n"
1471 " be started from this saved state.")},
1472 {NULL, NULL}
1475 static const vshCmdOptDef opts_managedsave[] = {
1476 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1477 {NULL, 0, 0, NULL}
1480 static int
1481 cmdManagedSave(vshControl *ctl, const vshCmd *cmd)
1483 virDomainPtr dom;
1484 char *name;
1485 int ret = TRUE;
1487 if (!vshConnectionUsability(ctl, ctl->conn))
1488 return FALSE;
1490 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1491 return FALSE;
1493 if (virDomainManagedSave(dom, 0) == 0) {
1494 vshPrint(ctl, _("Domain %s state saved by libvirt\n"), name);
1495 } else {
1496 vshError(ctl, _("Failed to save domain %s state"), name);
1497 ret = FALSE;
1500 virDomainFree(dom);
1501 return ret;
1505 * "managedsave-remove" command
1507 static const vshCmdInfo info_managedsaveremove[] = {
1508 {"help", N_("Remove managed save of a domain")},
1509 {"desc", N_("Remove an existing managed save state file from a domain")},
1510 {NULL, NULL}
1513 static const vshCmdOptDef opts_managedsaveremove[] = {
1514 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1515 {NULL, 0, 0, NULL}
1518 static int
1519 cmdManagedSaveRemove(vshControl *ctl, const vshCmd *cmd)
1521 virDomainPtr dom;
1522 char *name;
1523 int ret = FALSE;
1524 int hassave;
1526 if (!vshConnectionUsability(ctl, ctl->conn))
1527 return FALSE;
1529 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1530 return FALSE;
1532 hassave = virDomainHasManagedSaveImage(dom, 0);
1533 if (hassave < 0) {
1534 vshError(ctl, "%s", _("Failed to check for domain managed save image"));
1535 goto cleanup;
1538 if (hassave) {
1539 if (virDomainManagedSaveRemove(dom, 0) < 0) {
1540 vshError(ctl, _("Failed to remove managed save image for domain %s"),
1541 name);
1542 goto cleanup;
1544 else
1545 vshPrint(ctl, _("Removed managedsave image for domain %s"), name);
1547 else
1548 vshPrint(ctl, _("Domain %s has no manage save image; removal skipped"),
1549 name);
1551 ret = TRUE;
1553 cleanup:
1554 virDomainFree(dom);
1555 return ret;
1559 * "schedinfo" command
1561 static const vshCmdInfo info_schedinfo[] = {
1562 {"help", N_("show/set scheduler parameters")},
1563 {"desc", N_("Show/Set scheduler parameters.")},
1564 {NULL, NULL}
1567 static const vshCmdOptDef opts_schedinfo[] = {
1568 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1569 {"set", VSH_OT_STRING, VSH_OFLAG_NONE, N_("parameter=value")},
1570 {"weight", VSH_OT_INT, VSH_OFLAG_NONE, N_("weight for XEN_CREDIT")},
1571 {"cap", VSH_OT_INT, VSH_OFLAG_NONE, N_("cap for XEN_CREDIT")},
1572 {NULL, 0, 0, NULL}
1575 static int
1576 cmdSchedInfoUpdate(vshControl *ctl, const vshCmd *cmd,
1577 virSchedParameterPtr param)
1579 int found;
1580 char *data;
1582 /* Legacy 'weight' parameter */
1583 if (STREQ(param->field, "weight") &&
1584 param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
1585 vshCommandOptBool(cmd, "weight")) {
1586 int val;
1587 val = vshCommandOptInt(cmd, "weight", &found);
1588 if (!found) {
1589 vshError(ctl, "%s", _("Invalid value of weight"));
1590 return -1;
1591 } else {
1592 param->value.ui = val;
1594 return 1;
1597 /* Legacy 'cap' parameter */
1598 if (STREQ(param->field, "cap") &&
1599 param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
1600 vshCommandOptBool(cmd, "cap")) {
1601 int val;
1602 val = vshCommandOptInt(cmd, "cap", &found);
1603 if (!found) {
1604 vshError(ctl, "%s", _("Invalid value of cap"));
1605 return -1;
1606 } else {
1607 param->value.ui = val;
1609 return 1;
1612 if ((data = vshCommandOptString(cmd, "set", NULL))) {
1613 char *val = strchr(data, '=');
1614 int match = 0;
1615 if (!val) {
1616 vshError(ctl, "%s", _("Invalid syntax for --set, expecting name=value"));
1617 return -1;
1619 *val = '\0';
1620 match = STREQ(data, param->field);
1621 *val = '=';
1622 val++;
1624 if (!match)
1625 return 0;
1627 switch (param->type) {
1628 case VIR_DOMAIN_SCHED_FIELD_INT:
1629 if (virStrToLong_i(val, NULL, 10, &param->value.i) < 0) {
1630 vshError(ctl, "%s",
1631 _("Invalid value for parameter, expecting an int"));
1632 return -1;
1634 break;
1635 case VIR_DOMAIN_SCHED_FIELD_UINT:
1636 if (virStrToLong_ui(val, NULL, 10, &param->value.ui) < 0) {
1637 vshError(ctl, "%s",
1638 _("Invalid value for parameter, expecting an unsigned int"));
1639 return -1;
1641 break;
1642 case VIR_DOMAIN_SCHED_FIELD_LLONG:
1643 if (virStrToLong_ll(val, NULL, 10, &param->value.l) < 0) {
1644 vshError(ctl, "%s",
1645 _("Invalid value for parameter, expecting a long long"));
1646 return -1;
1648 break;
1649 case VIR_DOMAIN_SCHED_FIELD_ULLONG:
1650 if (virStrToLong_ull(val, NULL, 10, &param->value.ul) < 0) {
1651 vshError(ctl, "%s",
1652 _("Invalid value for parameter, expecting an unsigned long long"));
1653 return -1;
1655 break;
1656 case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
1657 if (virStrToDouble(val, NULL, &param->value.d) < 0) {
1658 vshError(ctl, "%s", _("Invalid value for parameter, expecting a double"));
1659 return -1;
1661 break;
1662 case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
1663 param->value.b = STREQ(val, "0") ? 0 : 1;
1665 return 1;
1668 return 0;
1672 static int
1673 cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
1675 char *schedulertype;
1676 virDomainPtr dom;
1677 virSchedParameterPtr params = NULL;
1678 int nparams = 0;
1679 int update = 0;
1680 int i, ret;
1681 int ret_val = FALSE;
1683 if (!vshConnectionUsability(ctl, ctl->conn))
1684 return FALSE;
1686 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
1687 return FALSE;
1689 /* Print SchedulerType */
1690 schedulertype = virDomainGetSchedulerType(dom, &nparams);
1691 if (schedulertype!= NULL){
1692 vshPrint(ctl, "%-15s: %s\n", _("Scheduler"),
1693 schedulertype);
1694 VIR_FREE(schedulertype);
1695 } else {
1696 vshPrint(ctl, "%-15s: %s\n", _("Scheduler"), _("Unknown"));
1697 goto cleanup;
1700 if (nparams) {
1701 params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams);
1703 memset(params, 0, sizeof(virSchedParameter)* nparams);
1704 ret = virDomainGetSchedulerParameters(dom, params, &nparams);
1705 if (ret == -1)
1706 goto cleanup;
1708 /* See if any params are being set */
1709 for (i = 0; i < nparams; i++){
1710 ret = cmdSchedInfoUpdate(ctl, cmd, &(params[i]));
1711 if (ret == -1)
1712 goto cleanup;
1714 if (ret == 1)
1715 update = 1;
1718 /* Update parameters & refresh data */
1719 if (update) {
1720 ret = virDomainSetSchedulerParameters(dom, params, nparams);
1721 if (ret == -1)
1722 goto cleanup;
1724 ret = virDomainGetSchedulerParameters(dom, params, &nparams);
1725 if (ret == -1)
1726 goto cleanup;
1727 } else {
1728 /* See if we've tried to --set var=val. If so, the fact that
1729 we reach this point (with update == 0) means that "var" did
1730 not match any of the settable parameters. Report the error. */
1731 char *var_value_pair = vshCommandOptString(cmd, "set", NULL);
1732 if (var_value_pair) {
1733 vshError(ctl, _("invalid scheduler option: %s"),
1734 var_value_pair);
1735 goto cleanup;
1739 ret_val = TRUE;
1740 for (i = 0; i < nparams; i++){
1741 switch (params[i].type) {
1742 case VIR_DOMAIN_SCHED_FIELD_INT:
1743 vshPrint(ctl, "%-15s: %d\n", params[i].field, params[i].value.i);
1744 break;
1745 case VIR_DOMAIN_SCHED_FIELD_UINT:
1746 vshPrint(ctl, "%-15s: %u\n", params[i].field, params[i].value.ui);
1747 break;
1748 case VIR_DOMAIN_SCHED_FIELD_LLONG:
1749 vshPrint(ctl, "%-15s: %lld\n", params[i].field, params[i].value.l);
1750 break;
1751 case VIR_DOMAIN_SCHED_FIELD_ULLONG:
1752 vshPrint(ctl, "%-15s: %llu\n", params[i].field, params[i].value.ul);
1753 break;
1754 case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
1755 vshPrint(ctl, "%-15s: %f\n", params[i].field, params[i].value.d);
1756 break;
1757 case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
1758 vshPrint(ctl, "%-15s: %d\n", params[i].field, params[i].value.b);
1759 break;
1760 default:
1761 vshPrint(ctl, "not implemented scheduler parameter type\n");
1766 cleanup:
1767 VIR_FREE(params);
1768 virDomainFree(dom);
1769 return ret_val;
1773 * "restore" command
1775 static const vshCmdInfo info_restore[] = {
1776 {"help", N_("restore a domain from a saved state in a file")},
1777 {"desc", N_("Restore a domain.")},
1778 {NULL, NULL}
1781 static const vshCmdOptDef opts_restore[] = {
1782 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("the state to restore")},
1783 {NULL, 0, 0, NULL}
1786 static int
1787 cmdRestore(vshControl *ctl, const vshCmd *cmd)
1789 char *from;
1790 int found;
1791 int ret = TRUE;
1793 if (!vshConnectionUsability(ctl, ctl->conn))
1794 return FALSE;
1796 from = vshCommandOptString(cmd, "file", &found);
1797 if (!found)
1798 return FALSE;
1800 if (virDomainRestore(ctl->conn, from) == 0) {
1801 vshPrint(ctl, _("Domain restored from %s\n"), from);
1802 } else {
1803 vshError(ctl, _("Failed to restore domain from %s"), from);
1804 ret = FALSE;
1806 return ret;
1810 * "dump" command
1812 static const vshCmdInfo info_dump[] = {
1813 {"help", N_("dump the core of a domain to a file for analysis")},
1814 {"desc", N_("Core dump a domain.")},
1815 {NULL, NULL}
1818 static const vshCmdOptDef opts_dump[] = {
1819 {"live", VSH_OT_BOOL, 0, N_("perform a live core dump if supported")},
1820 {"crash", VSH_OT_BOOL, 0, N_("crash the domain after core dump")},
1821 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1822 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("where to dump the core")},
1823 {NULL, 0, 0, NULL}
1826 static int
1827 cmdDump(vshControl *ctl, const vshCmd *cmd)
1829 virDomainPtr dom;
1830 char *name;
1831 char *to;
1832 int ret = TRUE;
1833 int flags = 0;
1835 if (!vshConnectionUsability(ctl, ctl->conn))
1836 return FALSE;
1838 if (!(to = vshCommandOptString(cmd, "file", NULL)))
1839 return FALSE;
1841 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1842 return FALSE;
1844 if (vshCommandOptBool (cmd, "live"))
1845 flags |= VIR_DUMP_LIVE;
1846 if (vshCommandOptBool (cmd, "crash"))
1847 flags |= VIR_DUMP_CRASH;
1849 if (virDomainCoreDump(dom, to, flags) == 0) {
1850 vshPrint(ctl, _("Domain %s dumped to %s\n"), name, to);
1851 } else {
1852 vshError(ctl, _("Failed to core dump domain %s to %s"), name, to);
1853 ret = FALSE;
1856 virDomainFree(dom);
1857 return ret;
1861 * "resume" command
1863 static const vshCmdInfo info_resume[] = {
1864 {"help", N_("resume a domain")},
1865 {"desc", N_("Resume a previously suspended domain.")},
1866 {NULL, NULL}
1869 static const vshCmdOptDef opts_resume[] = {
1870 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1871 {NULL, 0, 0, NULL}
1874 static int
1875 cmdResume(vshControl *ctl, const vshCmd *cmd)
1877 virDomainPtr dom;
1878 int ret = TRUE;
1879 char *name;
1881 if (!vshConnectionUsability(ctl, ctl->conn))
1882 return FALSE;
1884 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1885 return FALSE;
1887 if (virDomainResume(dom) == 0) {
1888 vshPrint(ctl, _("Domain %s resumed\n"), name);
1889 } else {
1890 vshError(ctl, _("Failed to resume domain %s"), name);
1891 ret = FALSE;
1894 virDomainFree(dom);
1895 return ret;
1899 * "shutdown" command
1901 static const vshCmdInfo info_shutdown[] = {
1902 {"help", N_("gracefully shutdown a domain")},
1903 {"desc", N_("Run shutdown in the target domain.")},
1904 {NULL, NULL}
1907 static const vshCmdOptDef opts_shutdown[] = {
1908 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1909 {NULL, 0, 0, NULL}
1912 static int
1913 cmdShutdown(vshControl *ctl, const vshCmd *cmd)
1915 virDomainPtr dom;
1916 int ret = TRUE;
1917 char *name;
1919 if (!vshConnectionUsability(ctl, ctl->conn))
1920 return FALSE;
1922 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1923 return FALSE;
1925 if (virDomainShutdown(dom) == 0) {
1926 vshPrint(ctl, _("Domain %s is being shutdown\n"), name);
1927 } else {
1928 vshError(ctl, _("Failed to shutdown domain %s"), name);
1929 ret = FALSE;
1932 virDomainFree(dom);
1933 return ret;
1937 * "reboot" command
1939 static const vshCmdInfo info_reboot[] = {
1940 {"help", N_("reboot a domain")},
1941 {"desc", N_("Run a reboot command in the target domain.")},
1942 {NULL, NULL}
1945 static const vshCmdOptDef opts_reboot[] = {
1946 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1947 {NULL, 0, 0, NULL}
1950 static int
1951 cmdReboot(vshControl *ctl, const vshCmd *cmd)
1953 virDomainPtr dom;
1954 int ret = TRUE;
1955 char *name;
1957 if (!vshConnectionUsability(ctl, ctl->conn))
1958 return FALSE;
1960 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1961 return FALSE;
1963 if (virDomainReboot(dom, 0) == 0) {
1964 vshPrint(ctl, _("Domain %s is being rebooted\n"), name);
1965 } else {
1966 vshError(ctl, _("Failed to reboot domain %s"), name);
1967 ret = FALSE;
1970 virDomainFree(dom);
1971 return ret;
1975 * "destroy" command
1977 static const vshCmdInfo info_destroy[] = {
1978 {"help", N_("destroy a domain")},
1979 {"desc", N_("Destroy a given domain.")},
1980 {NULL, NULL}
1983 static const vshCmdOptDef opts_destroy[] = {
1984 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
1985 {NULL, 0, 0, NULL}
1988 static int
1989 cmdDestroy(vshControl *ctl, const vshCmd *cmd)
1991 virDomainPtr dom;
1992 int ret = TRUE;
1993 char *name;
1995 if (!vshConnectionUsability(ctl, ctl->conn))
1996 return FALSE;
1998 if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
1999 return FALSE;
2001 if (virDomainDestroy(dom) == 0) {
2002 vshPrint(ctl, _("Domain %s destroyed\n"), name);
2003 } else {
2004 vshError(ctl, _("Failed to destroy domain %s"), name);
2005 ret = FALSE;
2008 virDomainFree(dom);
2009 return ret;
2013 * "dominfo" command
2015 static const vshCmdInfo info_dominfo[] = {
2016 {"help", N_("domain information")},
2017 {"desc", N_("Returns basic information about the domain.")},
2018 {NULL, NULL}
2021 static const vshCmdOptDef opts_dominfo[] = {
2022 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2023 {NULL, 0, 0, NULL}
2026 static int
2027 cmdDominfo(vshControl *ctl, const vshCmd *cmd)
2029 virDomainInfo info;
2030 virDomainPtr dom;
2031 virSecurityModel secmodel;
2032 virSecurityLabel seclabel;
2033 int persistent = 0;
2034 int ret = TRUE, autostart;
2035 unsigned int id;
2036 char *str, uuid[VIR_UUID_STRING_BUFLEN];
2038 if (!vshConnectionUsability(ctl, ctl->conn))
2039 return FALSE;
2041 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2042 return FALSE;
2044 id = virDomainGetID(dom);
2045 if (id == ((unsigned int)-1))
2046 vshPrint(ctl, "%-15s %s\n", _("Id:"), "-");
2047 else
2048 vshPrint(ctl, "%-15s %d\n", _("Id:"), id);
2049 vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom));
2051 if (virDomainGetUUIDString(dom, &uuid[0])==0)
2052 vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
2054 if ((str = virDomainGetOSType(dom))) {
2055 vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str);
2056 VIR_FREE(str);
2059 if (virDomainGetInfo(dom, &info) == 0) {
2060 vshPrint(ctl, "%-15s %s\n", _("State:"),
2061 _(vshDomainStateToString(info.state)));
2063 vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu);
2065 if (info.cpuTime != 0) {
2066 double cpuUsed = info.cpuTime;
2068 cpuUsed /= 1000000000.0;
2070 vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed);
2073 if (info.maxMem != UINT_MAX)
2074 vshPrint(ctl, "%-15s %lu kB\n", _("Max memory:"),
2075 info.maxMem);
2076 else
2077 vshPrint(ctl, "%-15s %s\n", _("Max memory:"),
2078 _("no limit"));
2080 vshPrint(ctl, "%-15s %lu kB\n", _("Used memory:"),
2081 info.memory);
2083 } else {
2084 ret = FALSE;
2087 /* Check and display whether the domain is persistent or not */
2088 persistent = virDomainIsPersistent(dom);
2089 vshDebug(ctl, 5, "Domain persistent flag value: %d\n", persistent);
2090 if (persistent < 0)
2091 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
2092 else
2093 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));
2095 /* Check and display whether the domain autostarts or not */
2096 if (!virDomainGetAutostart(dom, &autostart)) {
2097 vshPrint(ctl, "%-15s %s\n", _("Autostart:"),
2098 autostart ? _("enable") : _("disable") );
2101 /* Security model and label information */
2102 memset(&secmodel, 0, sizeof secmodel);
2103 if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) {
2104 if (last_error->code != VIR_ERR_NO_SUPPORT) {
2105 virDomainFree(dom);
2106 return FALSE;
2108 } else {
2109 /* Only print something if a security model is active */
2110 if (secmodel.model[0] != '\0') {
2111 vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model);
2112 vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi);
2114 /* Security labels are only valid for active domains */
2115 memset(&seclabel, 0, sizeof seclabel);
2116 if (virDomainGetSecurityLabel(dom, &seclabel) == -1) {
2117 virDomainFree(dom);
2118 return FALSE;
2119 } else {
2120 if (seclabel.label[0] != '\0')
2121 vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"),
2122 seclabel.label, seclabel.enforcing ? "enforcing" : "permissive");
2126 virDomainFree(dom);
2127 return ret;
2131 * "domjobinfo" command
2133 static const vshCmdInfo info_domjobinfo[] = {
2134 {"help", N_("domain job information")},
2135 {"desc", N_("Returns information about jobs running on a domain.")},
2136 {NULL, NULL}
2139 static const vshCmdOptDef opts_domjobinfo[] = {
2140 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2141 {NULL, 0, 0, NULL}
2145 static int
2146 cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd)
2148 virDomainJobInfo info;
2149 virDomainPtr dom;
2150 int ret = TRUE;
2152 if (!vshConnectionUsability(ctl, ctl->conn))
2153 return FALSE;
2155 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2156 return FALSE;
2158 if (virDomainGetJobInfo(dom, &info) == 0) {
2159 const char *unit;
2160 double val;
2162 vshPrint(ctl, "%-17s ", _("Job type:"));
2163 switch (info.type) {
2164 case VIR_DOMAIN_JOB_BOUNDED:
2165 vshPrint(ctl, "%-12s\n", _("Bounded"));
2166 break;
2168 case VIR_DOMAIN_JOB_UNBOUNDED:
2169 vshPrint(ctl, "%-12s\n", _("Unbounded"));
2170 break;
2172 case VIR_DOMAIN_JOB_NONE:
2173 default:
2174 vshPrint(ctl, "%-12s\n", _("None"));
2175 goto cleanup;
2178 vshPrint(ctl, "%-17s %-12llu ms\n", _("Time elapsed:"), info.timeElapsed);
2179 if (info.type == VIR_DOMAIN_JOB_BOUNDED)
2180 vshPrint(ctl, "%-17s %-12llu ms\n", _("Time remaining:"), info.timeRemaining);
2181 if (info.dataTotal || info.dataRemaining || info.dataProcessed) {
2182 val = prettyCapacity(info.dataProcessed, &unit);
2183 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data processed:"), val, unit);
2184 val = prettyCapacity(info.dataRemaining, &unit);
2185 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data remaining:"), val, unit);
2186 val = prettyCapacity(info.dataTotal, &unit);
2187 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data total:"), val, unit);
2189 if (info.memTotal || info.memRemaining || info.memProcessed) {
2190 val = prettyCapacity(info.memProcessed, &unit);
2191 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory processed:"), val, unit);
2192 val = prettyCapacity(info.memRemaining, &unit);
2193 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory remaining:"), val, unit);
2194 val = prettyCapacity(info.memTotal, &unit);
2195 vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory total:"), val, unit);
2197 if (info.fileTotal || info.fileRemaining || info.fileProcessed) {
2198 val = prettyCapacity(info.fileProcessed, &unit);
2199 vshPrint(ctl, "%-17s %-.3lf %s\n", _("File processed:"), val, unit);
2200 val = prettyCapacity(info.fileRemaining, &unit);
2201 vshPrint(ctl, "%-17s %-.3lf %s\n", _("File remaining:"), val, unit);
2202 val = prettyCapacity(info.fileTotal, &unit);
2203 vshPrint(ctl, "%-17s %-.3lf %s\n", _("File total:"), val, unit);
2205 } else {
2206 ret = FALSE;
2208 cleanup:
2209 virDomainFree(dom);
2210 return ret;
2214 * "domjobabort" command
2216 static const vshCmdInfo info_domjobabort[] = {
2217 {"help", N_("abort active domain job")},
2218 {"desc", N_("Aborts the currently running domain job")},
2219 {NULL, NULL}
2222 static const vshCmdOptDef opts_domjobabort[] = {
2223 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2224 {NULL, 0, 0, NULL}
2227 static int
2228 cmdDomjobabort(vshControl *ctl, const vshCmd *cmd)
2230 virDomainPtr dom;
2231 int ret = TRUE;
2233 if (!vshConnectionUsability(ctl, ctl->conn))
2234 return FALSE;
2236 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2237 return FALSE;
2239 if (virDomainAbortJob(dom) < 0)
2240 ret = FALSE;
2242 virDomainFree(dom);
2243 return ret;
2247 * "freecell" command
2249 static const vshCmdInfo info_freecell[] = {
2250 {"help", N_("NUMA free memory")},
2251 {"desc", N_("display available free memory for the NUMA cell.")},
2252 {NULL, NULL}
2255 static const vshCmdOptDef opts_freecell[] = {
2256 {"cellno", VSH_OT_INT, 0, N_("NUMA cell number")},
2257 {NULL, 0, 0, NULL}
2260 static int
2261 cmdFreecell(vshControl *ctl, const vshCmd *cmd)
2263 int ret;
2264 int cell, cell_given;
2265 unsigned long long memory;
2267 if (!vshConnectionUsability(ctl, ctl->conn))
2268 return FALSE;
2270 cell = vshCommandOptInt(cmd, "cellno", &cell_given);
2271 if (!cell_given) {
2272 memory = virNodeGetFreeMemory(ctl->conn);
2273 if (memory == 0)
2274 return FALSE;
2275 } else {
2276 ret = virNodeGetCellsFreeMemory(ctl->conn, &memory, cell, 1);
2277 if (ret != 1)
2278 return FALSE;
2281 if (cell == -1)
2282 vshPrint(ctl, "%s: %llu kB\n", _("Total"), (memory/1024));
2283 else
2284 vshPrint(ctl, "%d: %llu kB\n", cell, (memory/1024));
2286 return TRUE;
2290 * "maxvcpus" command
2292 static const vshCmdInfo info_maxvcpus[] = {
2293 {"help", N_("connection vcpu maximum")},
2294 {"desc", N_("Show maximum number of virtual CPUs for guests on this connection.")},
2295 {NULL, NULL}
2298 static const vshCmdOptDef opts_maxvcpus[] = {
2299 {"type", VSH_OT_STRING, 0, N_("domain type")},
2300 {NULL, 0, 0, NULL}
2303 static int
2304 cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd)
2306 char *type;
2307 int vcpus;
2309 type = vshCommandOptString(cmd, "type", NULL);
2311 if (!vshConnectionUsability(ctl, ctl->conn))
2312 return FALSE;
2314 vcpus = virConnectGetMaxVcpus(ctl->conn, type);
2315 if (vcpus < 0)
2316 return FALSE;
2317 vshPrint(ctl, "%d\n", vcpus);
2319 return TRUE;
2323 * "vcpucount" command
2325 static const vshCmdInfo info_vcpucount[] = {
2326 {"help", N_("domain vcpu counts")},
2327 {"desc", N_("Returns the number of virtual CPUs used by the domain.")},
2328 {NULL, NULL}
2331 static const vshCmdOptDef opts_vcpucount[] = {
2332 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2333 {"maximum", VSH_OT_BOOL, 0, N_("get maximum cap on vcpus")},
2334 {"current", VSH_OT_BOOL, 0, N_("get current vcpu usage")},
2335 {"config", VSH_OT_BOOL, 0, N_("get value to be used on next boot")},
2336 {"live", VSH_OT_BOOL, 0, N_("get value from running domain")},
2337 {NULL, 0, 0, NULL}
2340 static int
2341 cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
2343 virDomainPtr dom;
2344 int ret = TRUE;
2345 int maximum = vshCommandOptBool(cmd, "maximum");
2346 int current = vshCommandOptBool(cmd, "current");
2347 int config = vshCommandOptBool(cmd, "config");
2348 int live = vshCommandOptBool(cmd, "live");
2349 bool all = maximum + current + config + live == 0;
2350 int count;
2352 if (maximum && current) {
2353 vshError(ctl, "%s",
2354 _("--maximum and --current cannot both be specified"));
2355 return FALSE;
2357 if (config && live) {
2358 vshError(ctl, "%s",
2359 _("--config and --live cannot both be specified"));
2360 return FALSE;
2362 /* We want one of each pair of mutually exclusive options; that
2363 * is, use of flags requires exactly two options. */
2364 if (maximum + current + config + live == 1) {
2365 vshError(ctl,
2366 _("when using --%s, either --%s or --%s must be specified"),
2367 (maximum ? "maximum" : current ? "current"
2368 : config ? "config" : "live"),
2369 maximum + current ? "config" : "maximum",
2370 maximum + current ? "live" : "current");
2371 return FALSE;
2374 if (!vshConnectionUsability(ctl, ctl->conn))
2375 return FALSE;
2377 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2378 return FALSE;
2380 /* In all cases, try the new API first; if it fails because we are
2381 * talking to an older client, try a fallback API before giving
2382 * up. */
2383 if (all || (maximum && config)) {
2384 count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
2385 VIR_DOMAIN_VCPU_CONFIG));
2386 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2387 || last_error->code == VIR_ERR_INVALID_ARG)) {
2388 char *tmp;
2389 char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
2390 if (xml && (tmp = strstr(xml, "<vcpu"))) {
2391 tmp = strchr(tmp, '>');
2392 if (!tmp || virStrToLong_i(tmp + 1, &tmp, 10, &count) < 0)
2393 count = -1;
2395 VIR_FREE(xml);
2398 if (count < 0) {
2399 virshReportError(ctl);
2400 ret = FALSE;
2401 } else if (all) {
2402 vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("config"),
2403 count);
2404 } else {
2405 vshPrint(ctl, "%d\n", count);
2407 virFreeError(last_error);
2408 last_error = NULL;
2411 if (all || (maximum && live)) {
2412 count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
2413 VIR_DOMAIN_VCPU_LIVE));
2414 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2415 || last_error->code == VIR_ERR_INVALID_ARG)) {
2416 count = virDomainGetMaxVcpus(dom);
2419 if (count < 0) {
2420 virshReportError(ctl);
2421 ret = FALSE;
2422 } else if (all) {
2423 vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("live"),
2424 count);
2425 } else {
2426 vshPrint(ctl, "%d\n", count);
2428 virFreeError(last_error);
2429 last_error = NULL;
2432 if (all || (current && config)) {
2433 count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_CONFIG);
2434 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2435 || last_error->code == VIR_ERR_INVALID_ARG)) {
2436 char *tmp, *end;
2437 char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
2438 if (xml && (tmp = strstr(xml, "<vcpu"))) {
2439 end = strchr(tmp, '>');
2440 if (end) {
2441 *end = '\0';
2442 tmp = strstr(tmp, "current=");
2443 if (!tmp)
2444 tmp = end + 1;
2445 else {
2446 tmp += strlen("current=");
2447 tmp += *tmp == '\'' || *tmp == '"';
2450 if (!tmp || virStrToLong_i(tmp, &tmp, 10, &count) < 0)
2451 count = -1;
2453 VIR_FREE(xml);
2456 if (count < 0) {
2457 virshReportError(ctl);
2458 ret = FALSE;
2459 } else if (all) {
2460 vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("config"),
2461 count);
2462 } else {
2463 vshPrint(ctl, "%d\n", count);
2465 virFreeError(last_error);
2466 last_error = NULL;
2469 if (all || (current && live)) {
2470 count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_LIVE);
2471 if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
2472 || last_error->code == VIR_ERR_INVALID_ARG)) {
2473 virDomainInfo info;
2474 if (virDomainGetInfo(dom, &info) == 0)
2475 count = info.nrVirtCpu;
2478 if (count < 0) {
2479 virshReportError(ctl);
2480 ret = FALSE;
2481 } else if (all) {
2482 vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("live"),
2483 count);
2484 } else {
2485 vshPrint(ctl, "%d\n", count);
2487 virFreeError(last_error);
2488 last_error = NULL;
2491 virDomainFree(dom);
2492 return ret;
2496 * "vcpuinfo" command
2498 static const vshCmdInfo info_vcpuinfo[] = {
2499 {"help", N_("detailed domain vcpu information")},
2500 {"desc", N_("Returns basic information about the domain virtual CPUs.")},
2501 {NULL, NULL}
2504 static const vshCmdOptDef opts_vcpuinfo[] = {
2505 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2506 {NULL, 0, 0, NULL}
2509 static int
2510 cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
2512 virDomainInfo info;
2513 virDomainPtr dom;
2514 virNodeInfo nodeinfo;
2515 virVcpuInfoPtr cpuinfo;
2516 unsigned char *cpumap;
2517 int ncpus;
2518 size_t cpumaplen;
2519 int ret = TRUE;
2521 if (!vshConnectionUsability(ctl, ctl->conn))
2522 return FALSE;
2524 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2525 return FALSE;
2527 if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
2528 virDomainFree(dom);
2529 return FALSE;
2532 if (virDomainGetInfo(dom, &info) != 0) {
2533 virDomainFree(dom);
2534 return FALSE;
2537 cpuinfo = vshMalloc(ctl, sizeof(virVcpuInfo)*info.nrVirtCpu);
2538 cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2539 cpumap = vshMalloc(ctl, info.nrVirtCpu * cpumaplen);
2541 if ((ncpus = virDomainGetVcpus(dom,
2542 cpuinfo, info.nrVirtCpu,
2543 cpumap, cpumaplen)) >= 0) {
2544 int n;
2545 for (n = 0 ; n < ncpus ; n++) {
2546 unsigned int m;
2547 vshPrint(ctl, "%-15s %d\n", _("VCPU:"), n);
2548 vshPrint(ctl, "%-15s %d\n", _("CPU:"), cpuinfo[n].cpu);
2549 vshPrint(ctl, "%-15s %s\n", _("State:"),
2550 _(vshDomainVcpuStateToString(cpuinfo[n].state)));
2551 if (cpuinfo[n].cpuTime != 0) {
2552 double cpuUsed = cpuinfo[n].cpuTime;
2554 cpuUsed /= 1000000000.0;
2556 vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed);
2558 vshPrint(ctl, "%-15s ", _("CPU Affinity:"));
2559 for (m = 0 ; m < VIR_NODEINFO_MAXCPUS(nodeinfo) ; m++) {
2560 vshPrint(ctl, "%c", VIR_CPU_USABLE(cpumap, cpumaplen, n, m) ? 'y' : '-');
2562 vshPrint(ctl, "\n");
2563 if (n < (ncpus - 1)) {
2564 vshPrint(ctl, "\n");
2567 } else {
2568 if (info.state == VIR_DOMAIN_SHUTOFF) {
2569 vshError(ctl, "%s",
2570 _("Domain shut off, virtual CPUs not present."));
2572 ret = FALSE;
2575 VIR_FREE(cpumap);
2576 VIR_FREE(cpuinfo);
2577 virDomainFree(dom);
2578 return ret;
2582 * "vcpupin" command
2584 static const vshCmdInfo info_vcpupin[] = {
2585 {"help", N_("control domain vcpu affinity")},
2586 {"desc", N_("Pin domain VCPUs to host physical CPUs.")},
2587 {NULL, NULL}
2590 static const vshCmdOptDef opts_vcpupin[] = {
2591 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2592 {"vcpu", VSH_OT_INT, VSH_OFLAG_REQ, N_("vcpu number")},
2593 {"cpulist", VSH_OT_DATA, VSH_OFLAG_REQ, N_("host cpu number(s) (comma separated)")},
2594 {NULL, 0, 0, NULL}
2597 static int
2598 cmdVcpupin(vshControl *ctl, const vshCmd *cmd)
2600 virDomainInfo info;
2601 virDomainPtr dom;
2602 virNodeInfo nodeinfo;
2603 int vcpu;
2604 char *cpulist;
2605 int ret = TRUE;
2606 int vcpufound = 0;
2607 unsigned char *cpumap;
2608 int cpumaplen;
2609 int i;
2610 enum { expect_num, expect_num_or_comma } state;
2612 if (!vshConnectionUsability(ctl, ctl->conn))
2613 return FALSE;
2615 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2616 return FALSE;
2618 vcpu = vshCommandOptInt(cmd, "vcpu", &vcpufound);
2619 if (!vcpufound) {
2620 vshError(ctl, "%s", _("vcpupin: Invalid or missing vCPU number."));
2621 virDomainFree(dom);
2622 return FALSE;
2625 if (!(cpulist = vshCommandOptString(cmd, "cpulist", NULL))) {
2626 virDomainFree(dom);
2627 return FALSE;
2630 if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) {
2631 virDomainFree(dom);
2632 return FALSE;
2635 if (virDomainGetInfo(dom, &info) != 0) {
2636 vshError(ctl, "%s", _("vcpupin: failed to get domain informations."));
2637 virDomainFree(dom);
2638 return FALSE;
2641 if (vcpu >= info.nrVirtCpu) {
2642 vshError(ctl, "%s", _("vcpupin: Invalid vCPU number."));
2643 virDomainFree(dom);
2644 return FALSE;
2647 /* Check that the cpulist parameter is a comma-separated list of
2648 * numbers and give an intelligent error message if not.
2650 if (cpulist[0] == '\0') {
2651 vshError(ctl, "%s", _("cpulist: Invalid format. Empty string."));
2652 virDomainFree (dom);
2653 return FALSE;
2656 state = expect_num;
2657 for (i = 0; cpulist[i]; i++) {
2658 switch (state) {
2659 case expect_num:
2660 if (!c_isdigit (cpulist[i])) {
2661 vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
2662 "digit at position %d (near '%c')."),
2663 cpulist, i, cpulist[i]);
2664 virDomainFree (dom);
2665 return FALSE;
2667 state = expect_num_or_comma;
2668 break;
2669 case expect_num_or_comma:
2670 if (cpulist[i] == ',')
2671 state = expect_num;
2672 else if (!c_isdigit (cpulist[i])) {
2673 vshError(ctl, _("cpulist: %s: Invalid format. Expecting "
2674 "digit or comma at position %d (near '%c')."),
2675 cpulist, i, cpulist[i]);
2676 virDomainFree (dom);
2677 return FALSE;
2681 if (state == expect_num) {
2682 vshError(ctl, _("cpulist: %s: Invalid format. Trailing comma "
2683 "at position %d."),
2684 cpulist, i);
2685 virDomainFree (dom);
2686 return FALSE;
2689 cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
2690 cpumap = vshCalloc(ctl, 1, cpumaplen);
2692 do {
2693 unsigned int cpu = atoi(cpulist);
2695 if (cpu < VIR_NODEINFO_MAXCPUS(nodeinfo)) {
2696 VIR_USE_CPU(cpumap, cpu);
2697 } else {
2698 vshError(ctl, _("Physical CPU %d doesn't exist."), cpu);
2699 VIR_FREE(cpumap);
2700 virDomainFree(dom);
2701 return FALSE;
2703 cpulist = strchr(cpulist, ',');
2704 if (cpulist)
2705 cpulist++;
2706 } while (cpulist);
2708 if (virDomainPinVcpu(dom, vcpu, cpumap, cpumaplen) != 0) {
2709 ret = FALSE;
2712 VIR_FREE(cpumap);
2713 virDomainFree(dom);
2714 return ret;
2718 * "setvcpus" command
2720 static const vshCmdInfo info_setvcpus[] = {
2721 {"help", N_("change number of virtual CPUs")},
2722 {"desc", N_("Change the number of virtual CPUs in the guest domain.")},
2723 {NULL, NULL}
2726 static const vshCmdOptDef opts_setvcpus[] = {
2727 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2728 {"count", VSH_OT_INT, VSH_OFLAG_REQ, N_("number of virtual CPUs")},
2729 {"maximum", VSH_OT_BOOL, 0, N_("set maximum limit on next boot")},
2730 {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
2731 {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
2732 {NULL, 0, 0, NULL}
2735 static int
2736 cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
2738 virDomainPtr dom;
2739 int count;
2740 int ret = TRUE;
2741 int maximum = vshCommandOptBool(cmd, "maximum");
2742 int config = vshCommandOptBool(cmd, "config");
2743 int live = vshCommandOptBool(cmd, "live");
2744 int flags = ((maximum ? VIR_DOMAIN_VCPU_MAXIMUM : 0) |
2745 (config ? VIR_DOMAIN_VCPU_CONFIG : 0) |
2746 (live ? VIR_DOMAIN_VCPU_LIVE : 0));
2748 if (!vshConnectionUsability(ctl, ctl->conn))
2749 return FALSE;
2751 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2752 return FALSE;
2754 count = vshCommandOptInt(cmd, "count", &count);
2756 if (!flags) {
2757 if (virDomainSetVcpus(dom, count) != 0) {
2758 ret = FALSE;
2760 } else {
2761 if (virDomainSetVcpusFlags(dom, count, flags) < 0) {
2762 ret = FALSE;
2766 virDomainFree(dom);
2767 return ret;
2771 * "setmemory" command
2773 static const vshCmdInfo info_setmem[] = {
2774 {"help", N_("change memory allocation")},
2775 {"desc", N_("Change the current memory allocation in the guest domain.")},
2776 {NULL, NULL}
2779 static const vshCmdOptDef opts_setmem[] = {
2780 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2781 {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("number of kilobytes of memory")},
2782 {NULL, 0, 0, NULL}
2785 static int
2786 cmdSetmem(vshControl *ctl, const vshCmd *cmd)
2788 virDomainPtr dom;
2789 virDomainInfo info;
2790 unsigned long kilobytes;
2791 int ret = TRUE;
2793 if (!vshConnectionUsability(ctl, ctl->conn))
2794 return FALSE;
2796 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2797 return FALSE;
2799 kilobytes = vshCommandOptUL(cmd, "kilobytes", NULL);
2800 if (kilobytes <= 0) {
2801 virDomainFree(dom);
2802 vshError(ctl, _("Invalid value of %lu for memory size"), kilobytes);
2803 return FALSE;
2806 if (virDomainGetInfo(dom, &info) != 0) {
2807 virDomainFree(dom);
2808 vshError(ctl, "%s", _("Unable to verify MaxMemorySize"));
2809 return FALSE;
2812 if (kilobytes > info.maxMem) {
2813 virDomainFree(dom);
2814 vshError(ctl, _("Requested memory size %lu kb is larger than maximum of %lu kb"),
2815 kilobytes, info.maxMem);
2816 return FALSE;
2819 if (virDomainSetMemory(dom, kilobytes) != 0) {
2820 ret = FALSE;
2823 virDomainFree(dom);
2824 return ret;
2828 * "setmaxmem" command
2830 static const vshCmdInfo info_setmaxmem[] = {
2831 {"help", N_("change maximum memory limit")},
2832 {"desc", N_("Change the maximum memory allocation limit in the guest domain.")},
2833 {NULL, NULL}
2836 static const vshCmdOptDef opts_setmaxmem[] = {
2837 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2838 {"kilobytes", VSH_OT_INT, VSH_OFLAG_REQ, N_("maximum memory limit in kilobytes")},
2839 {NULL, 0, 0, NULL}
2842 static int
2843 cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
2845 virDomainPtr dom;
2846 virDomainInfo info;
2847 int kilobytes;
2848 int ret = TRUE;
2850 if (!vshConnectionUsability(ctl, ctl->conn))
2851 return FALSE;
2853 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2854 return FALSE;
2856 kilobytes = vshCommandOptInt(cmd, "kilobytes", &kilobytes);
2857 if (kilobytes <= 0) {
2858 virDomainFree(dom);
2859 vshError(ctl, _("Invalid value of %d for memory size"), kilobytes);
2860 return FALSE;
2863 if (virDomainGetInfo(dom, &info) != 0) {
2864 virDomainFree(dom);
2865 vshError(ctl, "%s", _("Unable to verify current MemorySize"));
2866 return FALSE;
2869 if (virDomainSetMaxMemory(dom, kilobytes) != 0) {
2870 vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
2871 virDomainFree(dom);
2872 return FALSE;
2875 if (kilobytes < info.memory) {
2876 if (virDomainSetMemory(dom, kilobytes) != 0) {
2877 vshError(ctl, "%s", _("Unable to shrink current MemorySize"));
2878 ret = FALSE;
2882 virDomainFree(dom);
2883 return ret;
2887 * "memtune" command
2889 static const vshCmdInfo info_memtune[] = {
2890 {"help", N_("Get/Set memory paramters")},
2891 {"desc", N_("Get/Set the current memory paramters for the guest domain.\n" \
2892 " To get the memory parameters use following command: \n\n" \
2893 " virsh # memtune <domain>")},
2894 {NULL, NULL}
2897 static const vshCmdOptDef opts_memtune[] = {
2898 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
2899 {"hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
2900 N_("Max memory in kilobytes")},
2901 {"soft-limit", VSH_OT_INT, VSH_OFLAG_NONE,
2902 N_("Memory during contention in kilobytes")},
2903 {"swap-hard-limit", VSH_OT_INT, VSH_OFLAG_NONE,
2904 N_("Max swap in kilobytes")},
2905 {"min-guarantee", VSH_OT_INT, VSH_OFLAG_NONE,
2906 N_("Min guaranteed memory in kilobytes")},
2907 {NULL, 0, 0, NULL}
2910 static int
2911 cmdMemtune(vshControl * ctl, const vshCmd * cmd)
2913 virDomainPtr dom;
2914 long long hard_limit, soft_limit, swap_hard_limit, min_guarantee;
2915 int nparams = 0;
2916 unsigned int i = 0;
2917 virMemoryParameterPtr params = NULL, temp = NULL;
2918 int ret = FALSE;
2920 if (!vshConnectionUsability(ctl, ctl->conn))
2921 return FALSE;
2923 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
2924 return FALSE;
2926 hard_limit =
2927 vshCommandOptLongLong(cmd, "hard-limit", NULL);
2928 if (hard_limit)
2929 nparams++;
2931 soft_limit =
2932 vshCommandOptLongLong(cmd, "soft-limit", NULL);
2933 if (soft_limit)
2934 nparams++;
2936 swap_hard_limit =
2937 vshCommandOptLongLong(cmd, "swap-hard-limit", NULL);
2938 if (swap_hard_limit)
2939 nparams++;
2941 min_guarantee =
2942 vshCommandOptLongLong(cmd, "min-guarantee", NULL);
2943 if (min_guarantee)
2944 nparams++;
2946 if (nparams == 0) {
2947 /* get the number of memory parameters */
2948 if (virDomainGetMemoryParameters(dom, NULL, &nparams, 0) != 0) {
2949 vshError(ctl, "%s",
2950 _("Unable to get number of memory parameters"));
2951 goto cleanup;
2954 if (nparams == 0) {
2955 /* nothing to output */
2956 ret = TRUE;
2957 goto cleanup;
2960 /* now go get all the memory parameters */
2961 params = vshCalloc(ctl, nparams, sizeof(*params));
2962 if (virDomainGetMemoryParameters(dom, params, &nparams, 0) != 0) {
2963 vshError(ctl, "%s", _("Unable to get memory parameters"));
2964 goto cleanup;
2967 for (i = 0; i < nparams; i++) {
2968 switch (params[i].type) {
2969 case VIR_DOMAIN_MEMORY_PARAM_INT:
2970 vshPrint(ctl, "%-15s: %d\n", params[i].field,
2971 params[i].value.i);
2972 break;
2973 case VIR_DOMAIN_MEMORY_PARAM_UINT:
2974 vshPrint(ctl, "%-15s: %u\n", params[i].field,
2975 params[i].value.ui);
2976 break;
2977 case VIR_DOMAIN_MEMORY_PARAM_LLONG:
2978 vshPrint(ctl, "%-15s: %lld\n", params[i].field,
2979 params[i].value.l);
2980 break;
2981 case VIR_DOMAIN_MEMORY_PARAM_ULLONG:
2982 vshPrint(ctl, "%-15s: %llu\n", params[i].field,
2983 params[i].value.ul);
2984 break;
2985 case VIR_DOMAIN_MEMORY_PARAM_DOUBLE:
2986 vshPrint(ctl, "%-15s: %f\n", params[i].field,
2987 params[i].value.d);
2988 break;
2989 case VIR_DOMAIN_MEMORY_PARAM_BOOLEAN:
2990 vshPrint(ctl, "%-15s: %d\n", params[i].field,
2991 params[i].value.b);
2992 break;
2993 default:
2994 vshPrint(ctl, "unimplemented memory parameter type\n");
2998 ret = TRUE;
2999 } else {
3000 /* set the memory parameters */
3001 params = vshCalloc(ctl, nparams, sizeof(*params));
3003 for (i = 0; i < nparams; i++) {
3004 temp = &params[i];
3005 temp->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG;
3008 * Some magic here, this is used to fill the params structure with
3009 * the valid arguments passed, after filling the particular
3010 * argument we purposely make them 0, so on the next pass it goes
3011 * to the next valid argument and so on.
3013 if (soft_limit) {
3014 temp->value.ul = soft_limit;
3015 strncpy(temp->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
3016 sizeof(temp->field));
3017 soft_limit = 0;
3018 } else if (hard_limit) {
3019 temp->value.ul = hard_limit;
3020 strncpy(temp->field, VIR_DOMAIN_MEMORY_HARD_LIMIT,
3021 sizeof(temp->field));
3022 hard_limit = 0;
3023 } else if (swap_hard_limit) {
3024 temp->value.ul = swap_hard_limit;
3025 strncpy(temp->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
3026 sizeof(temp->field));
3027 swap_hard_limit = 0;
3028 } else if (min_guarantee) {
3029 temp->value.ul = min_guarantee;
3030 strncpy(temp->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
3031 sizeof(temp->field));
3032 min_guarantee = 0;
3035 if (virDomainSetMemoryParameters(dom, params, nparams, 0) != 0)
3036 vshError(ctl, "%s", _("Unable to change memory parameters"));
3037 else
3038 ret = TRUE;
3041 cleanup:
3042 VIR_FREE(params);
3043 virDomainFree(dom);
3044 return ret;
3048 * "nodeinfo" command
3050 static const vshCmdInfo info_nodeinfo[] = {
3051 {"help", N_("node information")},
3052 {"desc", N_("Returns basic information about the node.")},
3053 {NULL, NULL}
3056 static int
3057 cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3059 virNodeInfo info;
3061 if (!vshConnectionUsability(ctl, ctl->conn))
3062 return FALSE;
3064 if (virNodeGetInfo(ctl->conn, &info) < 0) {
3065 vshError(ctl, "%s", _("failed to get node information"));
3066 return FALSE;
3068 vshPrint(ctl, "%-20s %s\n", _("CPU model:"), info.model);
3069 vshPrint(ctl, "%-20s %d\n", _("CPU(s):"), info.cpus);
3070 vshPrint(ctl, "%-20s %d MHz\n", _("CPU frequency:"), info.mhz);
3071 vshPrint(ctl, "%-20s %d\n", _("CPU socket(s):"), info.sockets);
3072 vshPrint(ctl, "%-20s %d\n", _("Core(s) per socket:"), info.cores);
3073 vshPrint(ctl, "%-20s %d\n", _("Thread(s) per core:"), info.threads);
3074 vshPrint(ctl, "%-20s %d\n", _("NUMA cell(s):"), info.nodes);
3075 vshPrint(ctl, "%-20s %lu kB\n", _("Memory size:"), info.memory);
3077 return TRUE;
3081 * "capabilities" command
3083 static const vshCmdInfo info_capabilities[] = {
3084 {"help", N_("capabilities")},
3085 {"desc", N_("Returns capabilities of hypervisor/driver.")},
3086 {NULL, NULL}
3089 static int
3090 cmdCapabilities (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3092 char *caps;
3094 if (!vshConnectionUsability(ctl, ctl->conn))
3095 return FALSE;
3097 if ((caps = virConnectGetCapabilities (ctl->conn)) == NULL) {
3098 vshError(ctl, "%s", _("failed to get capabilities"));
3099 return FALSE;
3101 vshPrint (ctl, "%s\n", caps);
3102 VIR_FREE(caps);
3104 return TRUE;
3108 * "dumpxml" command
3110 static const vshCmdInfo info_dumpxml[] = {
3111 {"help", N_("domain information in XML")},
3112 {"desc", N_("Output the domain information as an XML dump to stdout.")},
3113 {NULL, NULL}
3116 static const vshCmdOptDef opts_dumpxml[] = {
3117 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3118 {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")},
3119 {"security-info", VSH_OT_BOOL, 0, N_("include security sensitive information in XML dump")},
3120 {"update-cpu", VSH_OT_BOOL, 0, N_("update guest CPU according to host CPU")},
3121 {NULL, 0, 0, NULL}
3124 static int
3125 cmdDumpXML(vshControl *ctl, const vshCmd *cmd)
3127 virDomainPtr dom;
3128 int ret = TRUE;
3129 char *dump;
3130 int flags = 0;
3131 int inactive = vshCommandOptBool(cmd, "inactive");
3132 int secure = vshCommandOptBool(cmd, "security-info");
3133 int update = vshCommandOptBool(cmd, "update-cpu");
3135 if (inactive)
3136 flags |= VIR_DOMAIN_XML_INACTIVE;
3137 if (secure)
3138 flags |= VIR_DOMAIN_XML_SECURE;
3139 if (update)
3140 flags |= VIR_DOMAIN_XML_UPDATE_CPU;
3142 if (!vshConnectionUsability(ctl, ctl->conn))
3143 return FALSE;
3145 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
3146 return FALSE;
3148 dump = virDomainGetXMLDesc(dom, flags);
3149 if (dump != NULL) {
3150 vshPrint(ctl, "%s", dump);
3151 VIR_FREE(dump);
3152 } else {
3153 ret = FALSE;
3156 virDomainFree(dom);
3157 return ret;
3161 * "domxml-from-native" command
3163 static const vshCmdInfo info_domxmlfromnative[] = {
3164 {"help", N_("Convert native config to domain XML")},
3165 {"desc", N_("Convert native guest configuration format to domain XML format.")},
3166 {NULL, NULL}
3169 static const vshCmdOptDef opts_domxmlfromnative[] = {
3170 {"format", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source config data format")},
3171 {"config", VSH_OT_DATA, VSH_OFLAG_REQ, N_("config data file to import from")},
3172 {NULL, 0, 0, NULL}
3175 static int
3176 cmdDomXMLFromNative(vshControl *ctl, const vshCmd *cmd)
3178 int ret = TRUE;
3179 char *format;
3180 char *configFile;
3181 char *configData;
3182 char *xmlData;
3183 int flags = 0;
3185 if (!vshConnectionUsability(ctl, ctl->conn))
3186 return FALSE;
3188 format = vshCommandOptString(cmd, "format", NULL);
3189 configFile = vshCommandOptString(cmd, "config", NULL);
3191 if (virFileReadAll(configFile, 1024*1024, &configData) < 0)
3192 return FALSE;
3194 xmlData = virConnectDomainXMLFromNative(ctl->conn, format, configData, flags);
3195 if (xmlData != NULL) {
3196 vshPrint(ctl, "%s", xmlData);
3197 VIR_FREE(xmlData);
3198 } else {
3199 ret = FALSE;
3202 return ret;
3206 * "domxml-to-native" command
3208 static const vshCmdInfo info_domxmltonative[] = {
3209 {"help", N_("Convert domain XML to native config")},
3210 {"desc", N_("Convert domain XML config to a native guest configuration format.")},
3211 {NULL, NULL}
3214 static const vshCmdOptDef opts_domxmltonative[] = {
3215 {"format", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target config data type format")},
3216 {"xml", VSH_OT_DATA, VSH_OFLAG_REQ, N_("xml data file to export from")},
3217 {NULL, 0, 0, NULL}
3220 static int
3221 cmdDomXMLToNative(vshControl *ctl, const vshCmd *cmd)
3223 int ret = TRUE;
3224 char *format;
3225 char *xmlFile;
3226 char *configData;
3227 char *xmlData;
3228 int flags = 0;
3230 if (!vshConnectionUsability(ctl, ctl->conn))
3231 return FALSE;
3233 format = vshCommandOptString(cmd, "format", NULL);
3234 xmlFile = vshCommandOptString(cmd, "xml", NULL);
3236 if (virFileReadAll(xmlFile, 1024*1024, &xmlData) < 0)
3237 return FALSE;
3239 configData = virConnectDomainXMLToNative(ctl->conn, format, xmlData, flags);
3240 if (configData != NULL) {
3241 vshPrint(ctl, "%s", configData);
3242 VIR_FREE(configData);
3243 } else {
3244 ret = FALSE;
3247 return ret;
3251 * "domname" command
3253 static const vshCmdInfo info_domname[] = {
3254 {"help", N_("convert a domain id or UUID to domain name")},
3255 {"desc", ""},
3256 {NULL, NULL}
3259 static const vshCmdOptDef opts_domname[] = {
3260 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or uuid")},
3261 {NULL, 0, 0, NULL}
3264 static int
3265 cmdDomname(vshControl *ctl, const vshCmd *cmd)
3267 virDomainPtr dom;
3269 if (!vshConnectionUsability(ctl, ctl->conn))
3270 return FALSE;
3271 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3272 VSH_BYID|VSH_BYUUID)))
3273 return FALSE;
3275 vshPrint(ctl, "%s\n", virDomainGetName(dom));
3276 virDomainFree(dom);
3277 return TRUE;
3281 * "domid" command
3283 static const vshCmdInfo info_domid[] = {
3284 {"help", N_("convert a domain name or UUID to domain id")},
3285 {"desc", ""},
3286 {NULL, NULL}
3289 static const vshCmdOptDef opts_domid[] = {
3290 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
3291 {NULL, 0, 0, NULL}
3294 static int
3295 cmdDomid(vshControl *ctl, const vshCmd *cmd)
3297 virDomainPtr dom;
3298 unsigned int id;
3300 if (!vshConnectionUsability(ctl, ctl->conn))
3301 return FALSE;
3302 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3303 VSH_BYNAME|VSH_BYUUID)))
3304 return FALSE;
3306 id = virDomainGetID(dom);
3307 if (id == ((unsigned int)-1))
3308 vshPrint(ctl, "%s\n", "-");
3309 else
3310 vshPrint(ctl, "%d\n", id);
3311 virDomainFree(dom);
3312 return TRUE;
3316 * "domuuid" command
3318 static const vshCmdInfo info_domuuid[] = {
3319 {"help", N_("convert a domain name or id to domain UUID")},
3320 {"desc", ""},
3321 {NULL, NULL}
3324 static const vshCmdOptDef opts_domuuid[] = {
3325 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain id or name")},
3326 {NULL, 0, 0, NULL}
3329 static int
3330 cmdDomuuid(vshControl *ctl, const vshCmd *cmd)
3332 virDomainPtr dom;
3333 char uuid[VIR_UUID_STRING_BUFLEN];
3335 if (!vshConnectionUsability(ctl, ctl->conn))
3336 return FALSE;
3337 if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL,
3338 VSH_BYNAME|VSH_BYID)))
3339 return FALSE;
3341 if (virDomainGetUUIDString(dom, uuid) != -1)
3342 vshPrint(ctl, "%s\n", uuid);
3343 else
3344 vshError(ctl, "%s", _("failed to get domain UUID"));
3346 virDomainFree(dom);
3347 return TRUE;
3351 * "migrate" command
3353 static const vshCmdInfo info_migrate[] = {
3354 {"help", N_("migrate domain to another host")},
3355 {"desc", N_("Migrate domain to another host. Add --live for live migration.")},
3356 {NULL, NULL}
3359 static const vshCmdOptDef opts_migrate[] = {
3360 {"live", VSH_OT_BOOL, 0, N_("live migration")},
3361 {"p2p", VSH_OT_BOOL, 0, N_("peer-2-peer migration")},
3362 {"direct", VSH_OT_BOOL, 0, N_("direct migration")},
3363 {"tunnelled", VSH_OT_BOOL, 0, N_("tunnelled migration")},
3364 {"persistent", VSH_OT_BOOL, 0, N_("persist VM on destination")},
3365 {"undefinesource", VSH_OT_BOOL, 0, N_("undefine VM on source")},
3366 {"suspend", VSH_OT_BOOL, 0, N_("do not restart the domain on the destination host")},
3367 {"copy-storage-all", VSH_OT_BOOL, 0, N_("migration with non-shared storage with full disk copy")},
3368 {"copy-storage-inc", VSH_OT_BOOL, 0, N_("migration with non-shared storage with incremental copy (same base image shared between source and destination)")},
3369 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3370 {"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, N_("connection URI of the destination host")},
3371 {"migrateuri", VSH_OT_DATA, 0, N_("migration URI, usually can be omitted")},
3372 {"dname", VSH_OT_DATA, 0, N_("rename to new name during migration (if supported)")},
3373 {NULL, 0, 0, NULL}
3376 static int
3377 cmdMigrate (vshControl *ctl, const vshCmd *cmd)
3379 virDomainPtr dom = NULL;
3380 const char *desturi;
3381 const char *migrateuri;
3382 const char *dname;
3383 int flags = 0, found, ret = FALSE;
3385 if (!vshConnectionUsability (ctl, ctl->conn))
3386 return FALSE;
3388 if (!(dom = vshCommandOptDomain (ctl, cmd, NULL)))
3389 return FALSE;
3391 desturi = vshCommandOptString (cmd, "desturi", &found);
3392 if (!found)
3393 goto done;
3395 migrateuri = vshCommandOptString (cmd, "migrateuri", NULL);
3397 dname = vshCommandOptString (cmd, "dname", NULL);
3399 if (vshCommandOptBool (cmd, "live"))
3400 flags |= VIR_MIGRATE_LIVE;
3401 if (vshCommandOptBool (cmd, "p2p"))
3402 flags |= VIR_MIGRATE_PEER2PEER;
3403 if (vshCommandOptBool (cmd, "tunnelled"))
3404 flags |= VIR_MIGRATE_TUNNELLED;
3406 if (vshCommandOptBool (cmd, "persistent"))
3407 flags |= VIR_MIGRATE_PERSIST_DEST;
3408 if (vshCommandOptBool (cmd, "undefinesource"))
3409 flags |= VIR_MIGRATE_UNDEFINE_SOURCE;
3411 if (vshCommandOptBool (cmd, "suspend"))
3412 flags |= VIR_MIGRATE_PAUSED;
3414 if (vshCommandOptBool (cmd, "copy-storage-all"))
3415 flags |= VIR_MIGRATE_NON_SHARED_DISK;
3417 if (vshCommandOptBool (cmd, "copy-storage-inc"))
3418 flags |= VIR_MIGRATE_NON_SHARED_INC;
3420 if ((flags & VIR_MIGRATE_PEER2PEER) ||
3421 vshCommandOptBool (cmd, "direct")) {
3422 /* For peer2peer migration or direct migration we only expect one URI
3423 * a libvirt URI, or a hypervisor specific URI. */
3425 if (migrateuri != NULL) {
3426 vshError(ctl, "%s", _("migrate: Unexpected migrateuri for peer2peer/direct migration"));
3427 goto done;
3430 if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0)
3431 ret = TRUE;
3432 } else {
3433 /* For traditional live migration, connect to the destination host directly. */
3434 virConnectPtr dconn = NULL;
3435 virDomainPtr ddom = NULL;
3437 dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
3438 if (!dconn) goto done;
3440 ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
3441 if (ddom) {
3442 virDomainFree(ddom);
3443 ret = TRUE;
3445 virConnectClose (dconn);
3448 done:
3449 if (dom) virDomainFree (dom);
3450 return ret;
3454 * "migrate-setmaxdowntime" command
3456 static const vshCmdInfo info_migrate_setmaxdowntime[] = {
3457 {"help", N_("set maximum tolerable downtime")},
3458 {"desc", N_("Set maximum tolerable downtime of a domain which is being live-migrated to another host.")},
3459 {NULL, NULL}
3462 static const vshCmdOptDef opts_migrate_setmaxdowntime[] = {
3463 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
3464 {"downtime", VSH_OT_INT, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in milliseconds) for migration")},
3465 {NULL, 0, 0, NULL}
3468 static int
3469 cmdMigrateSetMaxDowntime(vshControl *ctl, const vshCmd *cmd)
3471 virDomainPtr dom = NULL;
3472 long long downtime;
3473 int found;
3474 int ret = FALSE;
3476 if (!vshConnectionUsability(ctl, ctl->conn))
3477 return FALSE;
3479 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
3480 return FALSE;
3482 downtime = vshCommandOptLongLong(cmd, "downtime", &found);
3483 if (!found || downtime < 1) {
3484 vshError(ctl, "%s", _("migrate: Invalid downtime"));
3485 goto done;
3488 if (virDomainMigrateSetMaxDowntime(dom, downtime, 0))
3489 goto done;
3491 ret = TRUE;
3493 done:
3494 virDomainFree(dom);
3495 return ret;
3499 * "net-autostart" command
3501 static const vshCmdInfo info_network_autostart[] = {
3502 {"help", N_("autostart a network")},
3503 {"desc",
3504 N_("Configure a network to be automatically started at boot.")},
3505 {NULL, NULL}
3508 static const vshCmdOptDef opts_network_autostart[] = {
3509 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
3510 {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
3511 {NULL, 0, 0, NULL}
3514 static int
3515 cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd)
3517 virNetworkPtr network;
3518 char *name;
3519 int autostart;
3521 if (!vshConnectionUsability(ctl, ctl->conn))
3522 return FALSE;
3524 if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
3525 return FALSE;
3527 autostart = !vshCommandOptBool(cmd, "disable");
3529 if (virNetworkSetAutostart(network, autostart) < 0) {
3530 if (autostart)
3531 vshError(ctl, _("failed to mark network %s as autostarted"), name);
3532 else
3533 vshError(ctl, _("failed to unmark network %s as autostarted"), name);
3534 virNetworkFree(network);
3535 return FALSE;
3538 if (autostart)
3539 vshPrint(ctl, _("Network %s marked as autostarted\n"), name);
3540 else
3541 vshPrint(ctl, _("Network %s unmarked as autostarted\n"), name);
3543 virNetworkFree(network);
3544 return TRUE;
3548 * "net-create" command
3550 static const vshCmdInfo info_network_create[] = {
3551 {"help", N_("create a network from an XML file")},
3552 {"desc", N_("Create a network.")},
3553 {NULL, NULL}
3556 static const vshCmdOptDef opts_network_create[] = {
3557 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
3558 {NULL, 0, 0, NULL}
3561 static int
3562 cmdNetworkCreate(vshControl *ctl, const vshCmd *cmd)
3564 virNetworkPtr network;
3565 char *from;
3566 int found;
3567 int ret = TRUE;
3568 char *buffer;
3570 if (!vshConnectionUsability(ctl, ctl->conn))
3571 return FALSE;
3573 from = vshCommandOptString(cmd, "file", &found);
3574 if (!found)
3575 return FALSE;
3577 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
3578 return FALSE;
3580 network = virNetworkCreateXML(ctl->conn, buffer);
3581 VIR_FREE(buffer);
3583 if (network != NULL) {
3584 vshPrint(ctl, _("Network %s created from %s\n"),
3585 virNetworkGetName(network), from);
3586 virNetworkFree(network);
3587 } else {
3588 vshError(ctl, _("Failed to create network from %s"), from);
3589 ret = FALSE;
3591 return ret;
3596 * "net-define" command
3598 static const vshCmdInfo info_network_define[] = {
3599 {"help", N_("define (but don't start) a network from an XML file")},
3600 {"desc", N_("Define a network.")},
3601 {NULL, NULL}
3604 static const vshCmdOptDef opts_network_define[] = {
3605 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")},
3606 {NULL, 0, 0, NULL}
3609 static int
3610 cmdNetworkDefine(vshControl *ctl, const vshCmd *cmd)
3612 virNetworkPtr network;
3613 char *from;
3614 int found;
3615 int ret = TRUE;
3616 char *buffer;
3618 if (!vshConnectionUsability(ctl, ctl->conn))
3619 return FALSE;
3621 from = vshCommandOptString(cmd, "file", &found);
3622 if (!found)
3623 return FALSE;
3625 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
3626 return FALSE;
3628 network = virNetworkDefineXML(ctl->conn, buffer);
3629 VIR_FREE(buffer);
3631 if (network != NULL) {
3632 vshPrint(ctl, _("Network %s defined from %s\n"),
3633 virNetworkGetName(network), from);
3634 virNetworkFree(network);
3635 } else {
3636 vshError(ctl, _("Failed to define network from %s"), from);
3637 ret = FALSE;
3639 return ret;
3644 * "net-destroy" command
3646 static const vshCmdInfo info_network_destroy[] = {
3647 {"help", N_("destroy a network")},
3648 {"desc", N_("Destroy a given network.")},
3649 {NULL, NULL}
3652 static const vshCmdOptDef opts_network_destroy[] = {
3653 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name, id or uuid")},
3654 {NULL, 0, 0, NULL}
3657 static int
3658 cmdNetworkDestroy(vshControl *ctl, const vshCmd *cmd)
3660 virNetworkPtr network;
3661 int ret = TRUE;
3662 char *name;
3664 if (!vshConnectionUsability(ctl, ctl->conn))
3665 return FALSE;
3667 if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
3668 return FALSE;
3670 if (virNetworkDestroy(network) == 0) {
3671 vshPrint(ctl, _("Network %s destroyed\n"), name);
3672 } else {
3673 vshError(ctl, _("Failed to destroy network %s"), name);
3674 ret = FALSE;
3677 virNetworkFree(network);
3678 return ret;
3683 * "net-dumpxml" command
3685 static const vshCmdInfo info_network_dumpxml[] = {
3686 {"help", N_("network information in XML")},
3687 {"desc", N_("Output the network information as an XML dump to stdout.")},
3688 {NULL, NULL}
3691 static const vshCmdOptDef opts_network_dumpxml[] = {
3692 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name, id or uuid")},
3693 {NULL, 0, 0, NULL}
3696 static int
3697 cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd)
3699 virNetworkPtr network;
3700 int ret = TRUE;
3701 char *dump;
3703 if (!vshConnectionUsability(ctl, ctl->conn))
3704 return FALSE;
3706 if (!(network = vshCommandOptNetwork(ctl, cmd, NULL)))
3707 return FALSE;
3709 dump = virNetworkGetXMLDesc(network, 0);
3710 if (dump != NULL) {
3711 vshPrint(ctl, "%s", dump);
3712 VIR_FREE(dump);
3713 } else {
3714 ret = FALSE;
3717 virNetworkFree(network);
3718 return ret;
3723 * "iface-edit" command
3725 static const vshCmdInfo info_interface_edit[] = {
3726 {"help", N_("edit XML configuration for a physical host interface")},
3727 {"desc", N_("Edit the XML configuration for a physical host interface.")},
3728 {NULL, NULL}
3731 static const vshCmdOptDef opts_interface_edit[] = {
3732 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
3733 {NULL, 0, 0, NULL}
3736 static int
3737 cmdInterfaceEdit (vshControl *ctl, const vshCmd *cmd)
3739 int ret = FALSE;
3740 virInterfacePtr iface = NULL;
3741 char *tmp = NULL;
3742 char *doc = NULL;
3743 char *doc_edited = NULL;
3744 char *doc_reread = NULL;
3745 int flags = VIR_INTERFACE_XML_INACTIVE;
3747 if (!vshConnectionUsability(ctl, ctl->conn))
3748 goto cleanup;
3750 iface = vshCommandOptInterface (ctl, cmd, NULL);
3751 if (iface == NULL)
3752 goto cleanup;
3754 /* Get the XML configuration of the interface. */
3755 doc = virInterfaceGetXMLDesc (iface, flags);
3756 if (!doc)
3757 goto cleanup;
3759 /* Create and open the temporary file. */
3760 tmp = editWriteToTempFile (ctl, doc);
3761 if (!tmp) goto cleanup;
3763 /* Start the editor. */
3764 if (editFile (ctl, tmp) == -1) goto cleanup;
3766 /* Read back the edited file. */
3767 doc_edited = editReadBackFile (ctl, tmp);
3768 if (!doc_edited) goto cleanup;
3770 /* Compare original XML with edited. Has it changed at all? */
3771 if (STREQ (doc, doc_edited)) {
3772 vshPrint (ctl, _("Interface %s XML configuration not changed.\n"),
3773 virInterfaceGetName (iface));
3774 ret = TRUE;
3775 goto cleanup;
3778 /* Now re-read the interface XML. Did someone else change it while
3779 * it was being edited? This also catches problems such as us
3780 * losing a connection or the interface going away.
3782 doc_reread = virInterfaceGetXMLDesc (iface, flags);
3783 if (!doc_reread)
3784 goto cleanup;
3786 if (STRNEQ (doc, doc_reread)) {
3787 vshError(ctl, "%s",
3788 _("ERROR: the XML configuration was changed by another user"));
3789 goto cleanup;
3792 /* Everything checks out, so redefine the interface. */
3793 virInterfaceFree (iface);
3794 iface = virInterfaceDefineXML (ctl->conn, doc_edited, 0);
3795 if (!iface)
3796 goto cleanup;
3798 vshPrint (ctl, _("Interface %s XML configuration edited.\n"),
3799 virInterfaceGetName(iface));
3801 ret = TRUE;
3803 cleanup:
3804 if (iface)
3805 virInterfaceFree (iface);
3807 VIR_FREE(doc);
3808 VIR_FREE(doc_edited);
3809 VIR_FREE(doc_reread);
3811 if (tmp) {
3812 unlink (tmp);
3813 VIR_FREE(tmp);
3816 return ret;
3820 * "net-list" command
3822 static const vshCmdInfo info_network_list[] = {
3823 {"help", N_("list networks")},
3824 {"desc", N_("Returns list of networks.")},
3825 {NULL, NULL}
3828 static const vshCmdOptDef opts_network_list[] = {
3829 {"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")},
3830 {"all", VSH_OT_BOOL, 0, N_("list inactive & active networks")},
3831 {NULL, 0, 0, NULL}
3834 static int
3835 cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
3837 int inactive = vshCommandOptBool(cmd, "inactive");
3838 int all = vshCommandOptBool(cmd, "all");
3839 int active = !inactive || all ? 1 : 0;
3840 int maxactive = 0, maxinactive = 0, i;
3841 char **activeNames = NULL, **inactiveNames = NULL;
3842 inactive |= all;
3844 if (!vshConnectionUsability(ctl, ctl->conn))
3845 return FALSE;
3847 if (active) {
3848 maxactive = virConnectNumOfNetworks(ctl->conn);
3849 if (maxactive < 0) {
3850 vshError(ctl, "%s", _("Failed to list active networks"));
3851 return FALSE;
3853 if (maxactive) {
3854 activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
3856 if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
3857 maxactive)) < 0) {
3858 vshError(ctl, "%s", _("Failed to list active networks"));
3859 VIR_FREE(activeNames);
3860 return FALSE;
3863 qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
3866 if (inactive) {
3867 maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
3868 if (maxinactive < 0) {
3869 vshError(ctl, "%s", _("Failed to list inactive networks"));
3870 VIR_FREE(activeNames);
3871 return FALSE;
3873 if (maxinactive) {
3874 inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
3876 if ((maxinactive =
3877 virConnectListDefinedNetworks(ctl->conn, inactiveNames,
3878 maxinactive)) < 0) {
3879 vshError(ctl, "%s", _("Failed to list inactive networks"));
3880 VIR_FREE(activeNames);
3881 VIR_FREE(inactiveNames);
3882 return FALSE;
3885 qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
3888 vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
3889 _("Autostart"));
3890 vshPrintExtra(ctl, "-----------------------------------------\n");
3892 for (i = 0; i < maxactive; i++) {
3893 virNetworkPtr network =
3894 virNetworkLookupByName(ctl->conn, activeNames[i]);
3895 const char *autostartStr;
3896 int autostart = 0;
3898 /* this kind of work with networks is not atomic operation */
3899 if (!network) {
3900 VIR_FREE(activeNames[i]);
3901 continue;
3904 if (virNetworkGetAutostart(network, &autostart) < 0)
3905 autostartStr = _("no autostart");
3906 else
3907 autostartStr = autostart ? _("yes") : _("no");
3909 vshPrint(ctl, "%-20s %-10s %-10s\n",
3910 virNetworkGetName(network),
3911 _("active"),
3912 autostartStr);
3913 virNetworkFree(network);
3914 VIR_FREE(activeNames[i]);
3916 for (i = 0; i < maxinactive; i++) {
3917 virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
3918 const char *autostartStr;
3919 int autostart = 0;
3921 /* this kind of work with networks is not atomic operation */
3922 if (!network) {
3923 VIR_FREE(inactiveNames[i]);
3924 continue;
3927 if (virNetworkGetAutostart(network, &autostart) < 0)
3928 autostartStr = _("no autostart");
3929 else
3930 autostartStr = autostart ? _("yes") : _("no");
3932 vshPrint(ctl, "%-20s %-10s %-10s\n",
3933 inactiveNames[i],
3934 _("inactive"),
3935 autostartStr);
3937 virNetworkFree(network);
3938 VIR_FREE(inactiveNames[i]);
3940 VIR_FREE(activeNames);
3941 VIR_FREE(inactiveNames);
3942 return TRUE;
3947 * "net-name" command
3949 static const vshCmdInfo info_network_name[] = {
3950 {"help", N_("convert a network UUID to network name")},
3951 {"desc", ""},
3952 {NULL, NULL}
3955 static const vshCmdOptDef opts_network_name[] = {
3956 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network uuid")},
3957 {NULL, 0, 0, NULL}
3960 static int
3961 cmdNetworkName(vshControl *ctl, const vshCmd *cmd)
3963 virNetworkPtr network;
3965 if (!vshConnectionUsability(ctl, ctl->conn))
3966 return FALSE;
3967 if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
3968 VSH_BYUUID)))
3969 return FALSE;
3971 vshPrint(ctl, "%s\n", virNetworkGetName(network));
3972 virNetworkFree(network);
3973 return TRUE;
3978 * "net-start" command
3980 static const vshCmdInfo info_network_start[] = {
3981 {"help", N_("start a (previously defined) inactive network")},
3982 {"desc", N_("Start a network.")},
3983 {NULL, NULL}
3986 static const vshCmdOptDef opts_network_start[] = {
3987 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive network")},
3988 {NULL, 0, 0, NULL}
3991 static int
3992 cmdNetworkStart(vshControl *ctl, const vshCmd *cmd)
3994 virNetworkPtr network;
3995 int ret = TRUE;
3997 if (!vshConnectionUsability(ctl, ctl->conn))
3998 return FALSE;
4000 if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, VSH_BYNAME)))
4001 return FALSE;
4003 if (virNetworkCreate(network) == 0) {
4004 vshPrint(ctl, _("Network %s started\n"),
4005 virNetworkGetName(network));
4006 } else {
4007 vshError(ctl, _("Failed to start network %s"),
4008 virNetworkGetName(network));
4009 ret = FALSE;
4011 virNetworkFree(network);
4012 return ret;
4017 * "net-undefine" command
4019 static const vshCmdInfo info_network_undefine[] = {
4020 {"help", N_("undefine an inactive network")},
4021 {"desc", N_("Undefine the configuration for an inactive network.")},
4022 {NULL, NULL}
4025 static const vshCmdOptDef opts_network_undefine[] = {
4026 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")},
4027 {NULL, 0, 0, NULL}
4030 static int
4031 cmdNetworkUndefine(vshControl *ctl, const vshCmd *cmd)
4033 virNetworkPtr network;
4034 int ret = TRUE;
4035 char *name;
4037 if (!vshConnectionUsability(ctl, ctl->conn))
4038 return FALSE;
4040 if (!(network = vshCommandOptNetwork(ctl, cmd, &name)))
4041 return FALSE;
4043 if (virNetworkUndefine(network) == 0) {
4044 vshPrint(ctl, _("Network %s has been undefined\n"), name);
4045 } else {
4046 vshError(ctl, _("Failed to undefine network %s"), name);
4047 ret = FALSE;
4050 virNetworkFree(network);
4051 return ret;
4056 * "net-uuid" command
4058 static const vshCmdInfo info_network_uuid[] = {
4059 {"help", N_("convert a network name to network UUID")},
4060 {"desc", ""},
4061 {NULL, NULL}
4064 static const vshCmdOptDef opts_network_uuid[] = {
4065 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")},
4066 {NULL, 0, 0, NULL}
4069 static int
4070 cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd)
4072 virNetworkPtr network;
4073 char uuid[VIR_UUID_STRING_BUFLEN];
4075 if (!vshConnectionUsability(ctl, ctl->conn))
4076 return FALSE;
4078 if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL,
4079 VSH_BYNAME)))
4080 return FALSE;
4082 if (virNetworkGetUUIDString(network, uuid) != -1)
4083 vshPrint(ctl, "%s\n", uuid);
4084 else
4085 vshError(ctl, "%s", _("failed to get network UUID"));
4087 virNetworkFree(network);
4088 return TRUE;
4092 /**************************************************************************/
4094 * "iface-list" command
4096 static const vshCmdInfo info_interface_list[] = {
4097 {"help", N_("list physical host interfaces")},
4098 {"desc", N_("Returns list of physical host interfaces.")},
4099 {NULL, NULL}
4102 static const vshCmdOptDef opts_interface_list[] = {
4103 {"inactive", VSH_OT_BOOL, 0, N_("list inactive interfaces")},
4104 {"all", VSH_OT_BOOL, 0, N_("list inactive & active interfaces")},
4105 {NULL, 0, 0, NULL}
4107 static int
4108 cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
4110 int inactive = vshCommandOptBool(cmd, "inactive");
4111 int all = vshCommandOptBool(cmd, "all");
4112 int active = !inactive || all ? 1 : 0;
4113 int maxactive = 0, maxinactive = 0, i;
4114 char **activeNames = NULL, **inactiveNames = NULL;
4115 inactive |= all;
4117 if (!vshConnectionUsability(ctl, ctl->conn))
4118 return FALSE;
4120 if (active) {
4121 maxactive = virConnectNumOfInterfaces(ctl->conn);
4122 if (maxactive < 0) {
4123 vshError(ctl, "%s", _("Failed to list active interfaces"));
4124 return FALSE;
4126 if (maxactive) {
4127 activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
4129 if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames,
4130 maxactive)) < 0) {
4131 vshError(ctl, "%s", _("Failed to list active interfaces"));
4132 VIR_FREE(activeNames);
4133 return FALSE;
4136 qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
4139 if (inactive) {
4140 maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn);
4141 if (maxinactive < 0) {
4142 vshError(ctl, "%s", _("Failed to list inactive interfaces"));
4143 VIR_FREE(activeNames);
4144 return FALSE;
4146 if (maxinactive) {
4147 inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
4149 if ((maxinactive =
4150 virConnectListDefinedInterfaces(ctl->conn, inactiveNames,
4151 maxinactive)) < 0) {
4152 vshError(ctl, "%s", _("Failed to list inactive interfaces"));
4153 VIR_FREE(activeNames);
4154 VIR_FREE(inactiveNames);
4155 return FALSE;
4158 qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
4161 vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
4162 _("MAC Address"));
4163 vshPrintExtra(ctl, "--------------------------------------------\n");
4165 for (i = 0; i < maxactive; i++) {
4166 virInterfacePtr iface =
4167 virInterfaceLookupByName(ctl->conn, activeNames[i]);
4169 /* this kind of work with interfaces is not atomic */
4170 if (!iface) {
4171 VIR_FREE(activeNames[i]);
4172 continue;
4175 vshPrint(ctl, "%-20s %-10s %s\n",
4176 virInterfaceGetName(iface),
4177 _("active"),
4178 virInterfaceGetMACString(iface));
4179 virInterfaceFree(iface);
4180 VIR_FREE(activeNames[i]);
4182 for (i = 0; i < maxinactive; i++) {
4183 virInterfacePtr iface =
4184 virInterfaceLookupByName(ctl->conn, inactiveNames[i]);
4186 /* this kind of work with interfaces is not atomic */
4187 if (!iface) {
4188 VIR_FREE(inactiveNames[i]);
4189 continue;
4192 vshPrint(ctl, "%-20s %-10s %s\n",
4193 virInterfaceGetName(iface),
4194 _("inactive"),
4195 virInterfaceGetMACString(iface));
4196 virInterfaceFree(iface);
4197 VIR_FREE(inactiveNames[i]);
4199 VIR_FREE(activeNames);
4200 VIR_FREE(inactiveNames);
4201 return TRUE;
4206 * "iface-name" command
4208 static const vshCmdInfo info_interface_name[] = {
4209 {"help", N_("convert an interface MAC address to interface name")},
4210 {"desc", ""},
4211 {NULL, NULL}
4214 static const vshCmdOptDef opts_interface_name[] = {
4215 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface mac")},
4216 {NULL, 0, 0, NULL}
4219 static int
4220 cmdInterfaceName(vshControl *ctl, const vshCmd *cmd)
4222 virInterfacePtr iface;
4224 if (!vshConnectionUsability(ctl, ctl->conn))
4225 return FALSE;
4226 if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
4227 VSH_BYMAC)))
4228 return FALSE;
4230 vshPrint(ctl, "%s\n", virInterfaceGetName(iface));
4231 virInterfaceFree(iface);
4232 return TRUE;
4236 * "iface-mac" command
4238 static const vshCmdInfo info_interface_mac[] = {
4239 {"help", N_("convert an interface name to interface MAC address")},
4240 {"desc", ""},
4241 {NULL, NULL}
4244 static const vshCmdOptDef opts_interface_mac[] = {
4245 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name")},
4246 {NULL, 0, 0, NULL}
4249 static int
4250 cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd)
4252 virInterfacePtr iface;
4254 if (!vshConnectionUsability(ctl, ctl->conn))
4255 return FALSE;
4256 if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
4257 VSH_BYNAME)))
4258 return FALSE;
4260 vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface));
4261 virInterfaceFree(iface);
4262 return TRUE;
4266 * "iface-dumpxml" command
4268 static const vshCmdInfo info_interface_dumpxml[] = {
4269 {"help", N_("interface information in XML")},
4270 {"desc", N_("Output the physical host interface information as an XML dump to stdout.")},
4271 {NULL, NULL}
4274 static const vshCmdOptDef opts_interface_dumpxml[] = {
4275 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4276 {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")},
4277 {NULL, 0, 0, NULL}
4280 static int
4281 cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd)
4283 virInterfacePtr iface;
4284 int ret = TRUE;
4285 char *dump;
4286 int flags = 0;
4287 int inactive = vshCommandOptBool(cmd, "inactive");
4289 if (inactive)
4290 flags |= VIR_INTERFACE_XML_INACTIVE;
4292 if (!vshConnectionUsability(ctl, ctl->conn))
4293 return FALSE;
4295 if (!(iface = vshCommandOptInterface(ctl, cmd, NULL)))
4296 return FALSE;
4298 dump = virInterfaceGetXMLDesc(iface, flags);
4299 if (dump != NULL) {
4300 vshPrint(ctl, "%s", dump);
4301 VIR_FREE(dump);
4302 } else {
4303 ret = FALSE;
4306 virInterfaceFree(iface);
4307 return ret;
4311 * "iface-define" command
4313 static const vshCmdInfo info_interface_define[] = {
4314 {"help", N_("define (but don't start) a physical host interface from an XML file")},
4315 {"desc", N_("Define a physical host interface.")},
4316 {NULL, NULL}
4319 static const vshCmdOptDef opts_interface_define[] = {
4320 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML interface description")},
4321 {NULL, 0, 0, NULL}
4324 static int
4325 cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd)
4327 virInterfacePtr iface;
4328 char *from;
4329 int found;
4330 int ret = TRUE;
4331 char *buffer;
4333 if (!vshConnectionUsability(ctl, ctl->conn))
4334 return FALSE;
4336 from = vshCommandOptString(cmd, "file", &found);
4337 if (!found)
4338 return FALSE;
4340 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4341 return FALSE;
4343 iface = virInterfaceDefineXML(ctl->conn, buffer, 0);
4344 VIR_FREE(buffer);
4346 if (iface != NULL) {
4347 vshPrint(ctl, _("Interface %s defined from %s\n"),
4348 virInterfaceGetName(iface), from);
4349 virInterfaceFree (iface);
4350 } else {
4351 vshError(ctl, _("Failed to define interface from %s"), from);
4352 ret = FALSE;
4354 return ret;
4358 * "iface-undefine" command
4360 static const vshCmdInfo info_interface_undefine[] = {
4361 {"help", N_("undefine a physical host interface (remove it from configuration)")},
4362 {"desc", N_("undefine an interface.")},
4363 {NULL, NULL}
4366 static const vshCmdOptDef opts_interface_undefine[] = {
4367 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4368 {NULL, 0, 0, NULL}
4371 static int
4372 cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd)
4374 virInterfacePtr iface;
4375 int ret = TRUE;
4376 char *name;
4378 if (!vshConnectionUsability(ctl, ctl->conn))
4379 return FALSE;
4381 if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
4382 return FALSE;
4384 if (virInterfaceUndefine(iface) == 0) {
4385 vshPrint(ctl, _("Interface %s undefined\n"), name);
4386 } else {
4387 vshError(ctl, _("Failed to undefine interface %s"), name);
4388 ret = FALSE;
4391 virInterfaceFree(iface);
4392 return ret;
4396 * "iface-start" command
4398 static const vshCmdInfo info_interface_start[] = {
4399 {"help", N_("start a physical host interface (enable it / \"if-up\")")},
4400 {"desc", N_("start a physical host interface.")},
4401 {NULL, NULL}
4404 static const vshCmdOptDef opts_interface_start[] = {
4405 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4406 {NULL, 0, 0, NULL}
4409 static int
4410 cmdInterfaceStart(vshControl *ctl, const vshCmd *cmd)
4412 virInterfacePtr iface;
4413 int ret = TRUE;
4414 char *name;
4416 if (!vshConnectionUsability(ctl, ctl->conn))
4417 return FALSE;
4419 if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
4420 return FALSE;
4422 if (virInterfaceCreate(iface, 0) == 0) {
4423 vshPrint(ctl, _("Interface %s started\n"), name);
4424 } else {
4425 vshError(ctl, _("Failed to start interface %s"), name);
4426 ret = FALSE;
4429 virInterfaceFree(iface);
4430 return ret;
4434 * "iface-destroy" command
4436 static const vshCmdInfo info_interface_destroy[] = {
4437 {"help", N_("destroy a physical host interface (disable it / \"if-down\")")},
4438 {"desc", N_("destroy a physical host interface.")},
4439 {NULL, NULL}
4442 static const vshCmdOptDef opts_interface_destroy[] = {
4443 {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")},
4444 {NULL, 0, 0, NULL}
4447 static int
4448 cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd)
4450 virInterfacePtr iface;
4451 int ret = TRUE;
4452 char *name;
4454 if (!vshConnectionUsability(ctl, ctl->conn))
4455 return FALSE;
4457 if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
4458 return FALSE;
4460 if (virInterfaceDestroy(iface, 0) == 0) {
4461 vshPrint(ctl, _("Interface %s destroyed\n"), name);
4462 } else {
4463 vshError(ctl, _("Failed to destroy interface %s"), name);
4464 ret = FALSE;
4467 virInterfaceFree(iface);
4468 return ret;
4473 * "nwfilter-define" command
4475 static const vshCmdInfo info_nwfilter_define[] = {
4476 {"help", N_("define or update a network filter from an XML file")},
4477 {"desc", N_("Define a new network filter or update an existing one.")},
4478 {NULL, NULL}
4481 static const vshCmdOptDef opts_nwfilter_define[] = {
4482 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network filter description")},
4483 {NULL, 0, 0, NULL}
4486 static int
4487 cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd)
4489 virNWFilterPtr nwfilter;
4490 char *from;
4491 int found;
4492 int ret = TRUE;
4493 char *buffer;
4495 if (!vshConnectionUsability(ctl, ctl->conn))
4496 return FALSE;
4498 from = vshCommandOptString(cmd, "file", &found);
4499 if (!found)
4500 return FALSE;
4502 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4503 return FALSE;
4505 nwfilter = virNWFilterDefineXML(ctl->conn, buffer);
4506 VIR_FREE(buffer);
4508 if (nwfilter != NULL) {
4509 vshPrint(ctl, _("Network filter %s defined from %s\n"),
4510 virNWFilterGetName(nwfilter), from);
4511 virNWFilterFree(nwfilter);
4512 } else {
4513 vshError(ctl, _("Failed to define network filter from %s"), from);
4514 ret = FALSE;
4516 return ret;
4521 * "nwfilter-undefine" command
4523 static const vshCmdInfo info_nwfilter_undefine[] = {
4524 {"help", N_("undefine a network filter")},
4525 {"desc", N_("Undefine a given network filter.")},
4526 {NULL, NULL}
4529 static const vshCmdOptDef opts_nwfilter_undefine[] = {
4530 {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
4531 {NULL, 0, 0, NULL}
4534 static int
4535 cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd)
4537 virNWFilterPtr nwfilter;
4538 int ret = TRUE;
4539 char *name;
4541 if (!vshConnectionUsability(ctl, ctl->conn))
4542 return FALSE;
4544 if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, &name)))
4545 return FALSE;
4547 if (virNWFilterUndefine(nwfilter) == 0) {
4548 vshPrint(ctl, _("Network filter %s undefined\n"), name);
4549 } else {
4550 vshError(ctl, _("Failed to undefine network filter %s"), name);
4551 ret = FALSE;
4554 virNWFilterFree(nwfilter);
4555 return ret;
4560 * "nwfilter-dumpxml" command
4562 static const vshCmdInfo info_nwfilter_dumpxml[] = {
4563 {"help", N_("network filter information in XML")},
4564 {"desc", N_("Output the network filter information as an XML dump to stdout.")},
4565 {NULL, NULL}
4568 static const vshCmdOptDef opts_nwfilter_dumpxml[] = {
4569 {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
4570 {NULL, 0, 0, NULL}
4573 static int
4574 cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd)
4576 virNWFilterPtr nwfilter;
4577 int ret = TRUE;
4578 char *dump;
4580 if (!vshConnectionUsability(ctl, ctl->conn))
4581 return FALSE;
4583 if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL)))
4584 return FALSE;
4586 dump = virNWFilterGetXMLDesc(nwfilter, 0);
4587 if (dump != NULL) {
4588 vshPrint(ctl, "%s", dump);
4589 VIR_FREE(dump);
4590 } else {
4591 ret = FALSE;
4594 virNWFilterFree(nwfilter);
4595 return ret;
4599 * "nwfilter-list" command
4601 static const vshCmdInfo info_nwfilter_list[] = {
4602 {"help", N_("list network filters")},
4603 {"desc", N_("Returns list of network filters.")},
4604 {NULL, NULL}
4607 static const vshCmdOptDef opts_nwfilter_list[] = {
4608 {NULL, 0, 0, NULL}
4611 static int
4612 cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
4614 int numfilters, i;
4615 char **names;
4616 char uuid[VIR_UUID_STRING_BUFLEN];
4618 if (!vshConnectionUsability(ctl, ctl->conn))
4619 return FALSE;
4621 numfilters = virConnectNumOfNWFilters(ctl->conn);
4622 if (numfilters < 0) {
4623 vshError(ctl, "%s", _("Failed to list network filters"));
4624 return FALSE;
4627 names = vshMalloc(ctl, sizeof(char *) * numfilters);
4629 if ((numfilters = virConnectListNWFilters(ctl->conn, names,
4630 numfilters)) < 0) {
4631 vshError(ctl, "%s", _("Failed to list network filters"));
4632 VIR_FREE(names);
4633 return FALSE;
4636 qsort(&names[0], numfilters, sizeof(char *), namesorter);
4638 vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name"));
4639 vshPrintExtra(ctl,
4640 "----------------------------------------------------------------\n");
4642 for (i = 0; i < numfilters; i++) {
4643 virNWFilterPtr nwfilter =
4644 virNWFilterLookupByName(ctl->conn, names[i]);
4646 /* this kind of work with networks is not atomic operation */
4647 if (!nwfilter) {
4648 VIR_FREE(names[i]);
4649 continue;
4652 virNWFilterGetUUIDString(nwfilter, uuid);
4653 vshPrint(ctl, "%-36s %-20s\n",
4654 uuid,
4655 virNWFilterGetName(nwfilter));
4656 virNWFilterFree(nwfilter);
4657 VIR_FREE(names[i]);
4660 VIR_FREE(names);
4661 return TRUE;
4666 * "nwfilter-edit" command
4668 static const vshCmdInfo info_nwfilter_edit[] = {
4669 {"help", N_("edit XML configuration for a network filter")},
4670 {"desc", N_("Edit the XML configuration for a network filter.")},
4671 {NULL, NULL}
4674 static const vshCmdOptDef opts_nwfilter_edit[] = {
4675 {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")},
4676 {NULL, 0, 0, NULL}
4679 static int
4680 cmdNWFilterEdit (vshControl *ctl, const vshCmd *cmd)
4682 int ret = FALSE;
4683 virNWFilterPtr nwfilter = NULL;
4684 char *tmp = NULL;
4685 char *doc = NULL;
4686 char *doc_edited = NULL;
4687 char *doc_reread = NULL;
4689 if (!vshConnectionUsability(ctl, ctl->conn))
4690 goto cleanup;
4692 nwfilter = vshCommandOptNWFilter (ctl, cmd, NULL);
4693 if (nwfilter == NULL)
4694 goto cleanup;
4696 /* Get the XML configuration of the interface. */
4697 doc = virNWFilterGetXMLDesc (nwfilter, 0);
4698 if (!doc)
4699 goto cleanup;
4701 /* Create and open the temporary file. */
4702 tmp = editWriteToTempFile (ctl, doc);
4703 if (!tmp) goto cleanup;
4705 /* Start the editor. */
4706 if (editFile (ctl, tmp) == -1) goto cleanup;
4708 /* Read back the edited file. */
4709 doc_edited = editReadBackFile (ctl, tmp);
4710 if (!doc_edited) goto cleanup;
4712 /* Compare original XML with edited. Has it changed at all? */
4713 if (STREQ (doc, doc_edited)) {
4714 vshPrint (ctl, _("Network filter %s XML configuration not changed.\n"),
4715 virNWFilterGetName (nwfilter));
4716 ret = TRUE;
4717 goto cleanup;
4720 /* Now re-read the network filter XML. Did someone else change it while
4721 * it was being edited? This also catches problems such as us
4722 * losing a connection or the interface going away.
4724 doc_reread = virNWFilterGetXMLDesc (nwfilter, 0);
4725 if (!doc_reread)
4726 goto cleanup;
4728 if (STRNEQ (doc, doc_reread)) {
4729 vshError(ctl, "%s",
4730 _("ERROR: the XML configuration was changed by another user"));
4731 goto cleanup;
4734 /* Everything checks out, so redefine the interface. */
4735 virNWFilterFree (nwfilter);
4736 nwfilter = virNWFilterDefineXML (ctl->conn, doc_edited);
4737 if (!nwfilter)
4738 goto cleanup;
4740 vshPrint (ctl, _("Network filter %s XML configuration edited.\n"),
4741 virNWFilterGetName(nwfilter));
4743 ret = TRUE;
4745 cleanup:
4746 if (nwfilter)
4747 virNWFilterFree (nwfilter);
4749 VIR_FREE(doc);
4750 VIR_FREE(doc_edited);
4751 VIR_FREE(doc_reread);
4753 if (tmp) {
4754 unlink (tmp);
4755 VIR_FREE(tmp);
4758 return ret;
4762 /**************************************************************************/
4764 * "pool-autostart" command
4766 static const vshCmdInfo info_pool_autostart[] = {
4767 {"help", N_("autostart a pool")},
4768 {"desc",
4769 N_("Configure a pool to be automatically started at boot.")},
4770 {NULL, NULL}
4773 static const vshCmdOptDef opts_pool_autostart[] = {
4774 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
4775 {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")},
4776 {NULL, 0, 0, NULL}
4779 static int
4780 cmdPoolAutostart(vshControl *ctl, const vshCmd *cmd)
4782 virStoragePoolPtr pool;
4783 char *name;
4784 int autostart;
4786 if (!vshConnectionUsability(ctl, ctl->conn))
4787 return FALSE;
4789 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
4790 return FALSE;
4792 autostart = !vshCommandOptBool(cmd, "disable");
4794 if (virStoragePoolSetAutostart(pool, autostart) < 0) {
4795 if (autostart)
4796 vshError(ctl, _("failed to mark pool %s as autostarted"), name);
4797 else
4798 vshError(ctl, _("failed to unmark pool %s as autostarted"), name);
4799 virStoragePoolFree(pool);
4800 return FALSE;
4803 if (autostart)
4804 vshPrint(ctl, _("Pool %s marked as autostarted\n"), name);
4805 else
4806 vshPrint(ctl, _("Pool %s unmarked as autostarted\n"), name);
4808 virStoragePoolFree(pool);
4809 return TRUE;
4813 * "pool-create" command
4815 static const vshCmdInfo info_pool_create[] = {
4816 {"help", N_("create a pool from an XML file")},
4817 {"desc", N_("Create a pool.")},
4818 {NULL, NULL}
4821 static const vshCmdOptDef opts_pool_create[] = {
4822 {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
4823 N_("file containing an XML pool description")},
4824 {NULL, 0, 0, NULL}
4827 static int
4828 cmdPoolCreate(vshControl *ctl, const vshCmd *cmd)
4830 virStoragePoolPtr pool;
4831 char *from;
4832 int found;
4833 int ret = TRUE;
4834 char *buffer;
4836 if (!vshConnectionUsability(ctl, ctl->conn))
4837 return FALSE;
4839 from = vshCommandOptString(cmd, "file", &found);
4840 if (!found)
4841 return FALSE;
4843 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4844 return FALSE;
4846 pool = virStoragePoolCreateXML(ctl->conn, buffer, 0);
4847 VIR_FREE(buffer);
4849 if (pool != NULL) {
4850 vshPrint(ctl, _("Pool %s created from %s\n"),
4851 virStoragePoolGetName(pool), from);
4852 virStoragePoolFree(pool);
4853 } else {
4854 vshError(ctl, _("Failed to create pool from %s"), from);
4855 ret = FALSE;
4857 return ret;
4862 * "nodedev-create" command
4864 static const vshCmdInfo info_node_device_create[] = {
4865 {"help", N_("create a device defined "
4866 "by an XML file on the node")},
4867 {"desc", N_("Create a device on the node. Note that this "
4868 "command creates devices on the physical host "
4869 "that can then be assigned to a virtual machine.")},
4870 {NULL, NULL}
4873 static const vshCmdOptDef opts_node_device_create[] = {
4874 {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
4875 N_("file containing an XML description of the device")},
4876 {NULL, 0, 0, NULL}
4879 static int
4880 cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
4882 virNodeDevicePtr dev = NULL;
4883 char *from;
4884 int found = 0;
4885 int ret = TRUE;
4886 char *buffer;
4888 if (!vshConnectionUsability(ctl, ctl->conn))
4889 return FALSE;
4891 from = vshCommandOptString(cmd, "file", &found);
4892 if (!found) {
4893 return FALSE;
4896 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
4897 return FALSE;
4899 dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0);
4900 VIR_FREE(buffer);
4902 if (dev != NULL) {
4903 vshPrint(ctl, _("Node device %s created from %s\n"),
4904 virNodeDeviceGetName(dev), from);
4905 virNodeDeviceFree(dev);
4906 } else {
4907 vshError(ctl, _("Failed to create node device from %s"), from);
4908 ret = FALSE;
4911 return ret;
4916 * "nodedev-destroy" command
4918 static const vshCmdInfo info_node_device_destroy[] = {
4919 {"help", N_("destroy a device on the node")},
4920 {"desc", N_("Destroy a device on the node. Note that this "
4921 "command destroys devices on the physical host ")},
4922 {NULL, NULL}
4925 static const vshCmdOptDef opts_node_device_destroy[] = {
4926 {"name", VSH_OT_DATA, VSH_OFLAG_REQ,
4927 N_("name of the device to be destroyed")},
4928 {NULL, 0, 0, NULL}
4931 static int
4932 cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
4934 virNodeDevicePtr dev = NULL;
4935 int ret = TRUE;
4936 int found = 0;
4937 char *name;
4939 if (!vshConnectionUsability(ctl, ctl->conn)) {
4940 return FALSE;
4943 name = vshCommandOptString(cmd, "name", &found);
4944 if (!found) {
4945 return FALSE;
4948 dev = virNodeDeviceLookupByName(ctl->conn, name);
4950 if (virNodeDeviceDestroy(dev) == 0) {
4951 vshPrint(ctl, _("Destroyed node device '%s'\n"), name);
4952 } else {
4953 vshError(ctl, _("Failed to destroy node device '%s'"), name);
4954 ret = FALSE;
4957 virNodeDeviceFree(dev);
4958 return ret;
4963 * XML Building helper for pool-define-as and pool-create-as
4965 static const vshCmdOptDef opts_pool_X_as[] = {
4966 {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the pool")},
4967 {"print-xml", VSH_OT_BOOL, 0, N_("print XML document, but don't define/create")},
4968 {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("type of the pool")},
4969 {"source-host", VSH_OT_DATA, 0, N_("source-host for underlying storage")},
4970 {"source-path", VSH_OT_DATA, 0, N_("source path for underlying storage")},
4971 {"source-dev", VSH_OT_DATA, 0, N_("source device for underlying storage")},
4972 {"source-name", VSH_OT_DATA, 0, N_("source name for underlying storage")},
4973 {"target", VSH_OT_DATA, 0, N_("target for underlying storage")},
4974 {"source-format", VSH_OT_STRING, 0, N_("format for underlying storage")},
4975 {NULL, 0, 0, NULL}
4978 static int buildPoolXML(const vshCmd *cmd, char **retname, char **xml) {
4980 int found;
4981 char *name, *type, *srcHost, *srcPath, *srcDev, *srcName, *srcFormat, *target;
4982 virBuffer buf = VIR_BUFFER_INITIALIZER;
4984 name = vshCommandOptString(cmd, "name", &found);
4985 if (!found)
4986 goto cleanup;
4987 type = vshCommandOptString(cmd, "type", &found);
4988 if (!found)
4989 goto cleanup;
4991 srcHost = vshCommandOptString(cmd, "source-host", &found);
4992 srcPath = vshCommandOptString(cmd, "source-path", &found);
4993 srcDev = vshCommandOptString(cmd, "source-dev", &found);
4994 srcName = vshCommandOptString(cmd, "source-name", &found);
4995 srcFormat = vshCommandOptString(cmd, "source-format", &found);
4996 target = vshCommandOptString(cmd, "target", &found);
4998 virBufferVSprintf(&buf, "<pool type='%s'>\n", type);
4999 virBufferVSprintf(&buf, " <name>%s</name>\n", name);
5000 if (srcHost || srcPath || srcDev) {
5001 virBufferAddLit(&buf, " <source>\n");
5003 if (srcHost)
5004 virBufferVSprintf(&buf, " <host name='%s'/>\n", srcHost);
5005 if (srcPath)
5006 virBufferVSprintf(&buf, " <dir path='%s'/>\n", srcPath);
5007 if (srcDev)
5008 virBufferVSprintf(&buf, " <device path='%s'/>\n", srcDev);
5009 if (srcFormat)
5010 virBufferVSprintf(&buf, " <format type='%s'/>\n", srcFormat);
5011 if (srcName)
5012 virBufferVSprintf(&buf, " <name>%s</name>\n", srcName);
5014 virBufferAddLit(&buf, " </source>\n");
5016 if (target) {
5017 virBufferAddLit(&buf, " <target>\n");
5018 virBufferVSprintf(&buf, " <path>%s</path>\n", target);
5019 virBufferAddLit(&buf, " </target>\n");
5021 virBufferAddLit(&buf, "</pool>\n");
5023 if (virBufferError(&buf)) {
5024 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
5025 return FALSE;
5028 *xml = virBufferContentAndReset(&buf);
5029 *retname = name;
5030 return TRUE;
5032 cleanup:
5033 virBufferFreeAndReset(&buf);
5034 return FALSE;
5038 * "pool-create-as" command
5040 static const vshCmdInfo info_pool_create_as[] = {
5041 {"help", N_("create a pool from a set of args")},
5042 {"desc", N_("Create a pool.")},
5043 {NULL, NULL}
5046 static int
5047 cmdPoolCreateAs(vshControl *ctl, const vshCmd *cmd)
5049 virStoragePoolPtr pool;
5050 char *xml, *name;
5051 int printXML = vshCommandOptBool(cmd, "print-xml");
5053 if (!vshConnectionUsability(ctl, ctl->conn))
5054 return FALSE;
5056 if (!buildPoolXML(cmd, &name, &xml))
5057 return FALSE;
5059 if (printXML) {
5060 vshPrint(ctl, "%s", xml);
5061 VIR_FREE(xml);
5062 } else {
5063 pool = virStoragePoolCreateXML(ctl->conn, xml, 0);
5064 VIR_FREE(xml);
5066 if (pool != NULL) {
5067 vshPrint(ctl, _("Pool %s created\n"), name);
5068 virStoragePoolFree(pool);
5069 } else {
5070 vshError(ctl, _("Failed to create pool %s"), name);
5071 return FALSE;
5074 return TRUE;
5079 * "pool-define" command
5081 static const vshCmdInfo info_pool_define[] = {
5082 {"help", N_("define (but don't start) a pool from an XML file")},
5083 {"desc", N_("Define a pool.")},
5084 {NULL, NULL}
5087 static const vshCmdOptDef opts_pool_define[] = {
5088 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML pool description")},
5089 {NULL, 0, 0, NULL}
5092 static int
5093 cmdPoolDefine(vshControl *ctl, const vshCmd *cmd)
5095 virStoragePoolPtr pool;
5096 char *from;
5097 int found;
5098 int ret = TRUE;
5099 char *buffer;
5101 if (!vshConnectionUsability(ctl, ctl->conn))
5102 return FALSE;
5104 from = vshCommandOptString(cmd, "file", &found);
5105 if (!found)
5106 return FALSE;
5108 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
5109 return FALSE;
5111 pool = virStoragePoolDefineXML(ctl->conn, buffer, 0);
5112 VIR_FREE(buffer);
5114 if (pool != NULL) {
5115 vshPrint(ctl, _("Pool %s defined from %s\n"),
5116 virStoragePoolGetName(pool), from);
5117 virStoragePoolFree(pool);
5118 } else {
5119 vshError(ctl, _("Failed to define pool from %s"), from);
5120 ret = FALSE;
5122 return ret;
5127 * "pool-define-as" command
5129 static const vshCmdInfo info_pool_define_as[] = {
5130 {"help", N_("define a pool from a set of args")},
5131 {"desc", N_("Define a pool.")},
5132 {NULL, NULL}
5135 static int
5136 cmdPoolDefineAs(vshControl *ctl, const vshCmd *cmd)
5138 virStoragePoolPtr pool;
5139 char *xml, *name;
5140 int printXML = vshCommandOptBool(cmd, "print-xml");
5142 if (!vshConnectionUsability(ctl, ctl->conn))
5143 return FALSE;
5145 if (!buildPoolXML(cmd, &name, &xml))
5146 return FALSE;
5148 if (printXML) {
5149 vshPrint(ctl, "%s", xml);
5150 VIR_FREE(xml);
5151 } else {
5152 pool = virStoragePoolDefineXML(ctl->conn, xml, 0);
5153 VIR_FREE(xml);
5155 if (pool != NULL) {
5156 vshPrint(ctl, _("Pool %s defined\n"), name);
5157 virStoragePoolFree(pool);
5158 } else {
5159 vshError(ctl, _("Failed to define pool %s"), name);
5160 return FALSE;
5163 return TRUE;
5168 * "pool-build" command
5170 static const vshCmdInfo info_pool_build[] = {
5171 {"help", N_("build a pool")},
5172 {"desc", N_("Build a given pool.")},
5173 {NULL, NULL}
5176 static const vshCmdOptDef opts_pool_build[] = {
5177 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5178 {NULL, 0, 0, NULL}
5181 static int
5182 cmdPoolBuild(vshControl *ctl, const vshCmd *cmd)
5184 virStoragePoolPtr pool;
5185 int ret = TRUE;
5186 char *name;
5188 if (!vshConnectionUsability(ctl, ctl->conn))
5189 return FALSE;
5191 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5192 return FALSE;
5194 if (virStoragePoolBuild(pool, 0) == 0) {
5195 vshPrint(ctl, _("Pool %s built\n"), name);
5196 } else {
5197 vshError(ctl, _("Failed to build pool %s"), name);
5198 ret = FALSE;
5201 virStoragePoolFree(pool);
5203 return ret;
5208 * "pool-destroy" command
5210 static const vshCmdInfo info_pool_destroy[] = {
5211 {"help", N_("destroy a pool")},
5212 {"desc", N_("Destroy a given pool.")},
5213 {NULL, NULL}
5216 static const vshCmdOptDef opts_pool_destroy[] = {
5217 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5218 {NULL, 0, 0, NULL}
5221 static int
5222 cmdPoolDestroy(vshControl *ctl, const vshCmd *cmd)
5224 virStoragePoolPtr pool;
5225 int ret = TRUE;
5226 char *name;
5228 if (!vshConnectionUsability(ctl, ctl->conn))
5229 return FALSE;
5231 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5232 return FALSE;
5234 if (virStoragePoolDestroy(pool) == 0) {
5235 vshPrint(ctl, _("Pool %s destroyed\n"), name);
5236 } else {
5237 vshError(ctl, _("Failed to destroy pool %s"), name);
5238 ret = FALSE;
5241 virStoragePoolFree(pool);
5242 return ret;
5247 * "pool-delete" command
5249 static const vshCmdInfo info_pool_delete[] = {
5250 {"help", N_("delete a pool")},
5251 {"desc", N_("Delete a given pool.")},
5252 {NULL, NULL}
5255 static const vshCmdOptDef opts_pool_delete[] = {
5256 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5257 {NULL, 0, 0, NULL}
5260 static int
5261 cmdPoolDelete(vshControl *ctl, const vshCmd *cmd)
5263 virStoragePoolPtr pool;
5264 int ret = TRUE;
5265 char *name;
5267 if (!vshConnectionUsability(ctl, ctl->conn))
5268 return FALSE;
5270 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5271 return FALSE;
5273 if (virStoragePoolDelete(pool, 0) == 0) {
5274 vshPrint(ctl, _("Pool %s deleted\n"), name);
5275 } else {
5276 vshError(ctl, _("Failed to delete pool %s"), name);
5277 ret = FALSE;
5280 virStoragePoolFree(pool);
5281 return ret;
5286 * "pool-refresh" command
5288 static const vshCmdInfo info_pool_refresh[] = {
5289 {"help", N_("refresh a pool")},
5290 {"desc", N_("Refresh a given pool.")},
5291 {NULL, NULL}
5294 static const vshCmdOptDef opts_pool_refresh[] = {
5295 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5296 {NULL, 0, 0, NULL}
5299 static int
5300 cmdPoolRefresh(vshControl *ctl, const vshCmd *cmd)
5302 virStoragePoolPtr pool;
5303 int ret = TRUE;
5304 char *name;
5306 if (!vshConnectionUsability(ctl, ctl->conn))
5307 return FALSE;
5309 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
5310 return FALSE;
5312 if (virStoragePoolRefresh(pool, 0) == 0) {
5313 vshPrint(ctl, _("Pool %s refreshed\n"), name);
5314 } else {
5315 vshError(ctl, _("Failed to refresh pool %s"), name);
5316 ret = FALSE;
5318 virStoragePoolFree(pool);
5320 return ret;
5325 * "pool-dumpxml" command
5327 static const vshCmdInfo info_pool_dumpxml[] = {
5328 {"help", N_("pool information in XML")},
5329 {"desc", N_("Output the pool information as an XML dump to stdout.")},
5330 {NULL, NULL}
5333 static const vshCmdOptDef opts_pool_dumpxml[] = {
5334 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5335 {NULL, 0, 0, NULL}
5338 static int
5339 cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd)
5341 virStoragePoolPtr pool;
5342 int ret = TRUE;
5343 char *dump;
5345 if (!vshConnectionUsability(ctl, ctl->conn))
5346 return FALSE;
5348 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
5349 return FALSE;
5351 dump = virStoragePoolGetXMLDesc(pool, 0);
5352 if (dump != NULL) {
5353 vshPrint(ctl, "%s", dump);
5354 VIR_FREE(dump);
5355 } else {
5356 ret = FALSE;
5359 virStoragePoolFree(pool);
5360 return ret;
5365 * "pool-list" command
5367 static const vshCmdInfo info_pool_list[] = {
5368 {"help", N_("list pools")},
5369 {"desc", N_("Returns list of pools.")},
5370 {NULL, NULL}
5373 static const vshCmdOptDef opts_pool_list[] = {
5374 {"inactive", VSH_OT_BOOL, 0, N_("list inactive pools")},
5375 {"all", VSH_OT_BOOL, 0, N_("list inactive & active pools")},
5376 {"details", VSH_OT_BOOL, 0, N_("display extended details for pools")},
5377 {NULL, 0, 0, NULL}
5380 static int
5381 cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
5383 virStoragePoolInfo info;
5384 char **poolNames = NULL;
5385 int i, functionReturn, ret;
5386 int numActivePools = 0, numInactivePools = 0, numAllPools = 0;
5387 size_t stringLength = 0, nameStrLength = 0;
5388 size_t autostartStrLength = 0, persistStrLength = 0;
5389 size_t stateStrLength = 0, capStrLength = 0;
5390 size_t allocStrLength = 0, availStrLength = 0;
5391 struct poolInfoText {
5392 char *state;
5393 char *autostart;
5394 char *persistent;
5395 char *capacity;
5396 char *allocation;
5397 char *available;
5399 struct poolInfoText *poolInfoTexts = NULL;
5401 /* Determine the options passed by the user */
5402 int all = vshCommandOptBool(cmd, "all");
5403 int details = vshCommandOptBool(cmd, "details");
5404 int inactive = vshCommandOptBool(cmd, "inactive");
5405 int active = !inactive || all ? 1 : 0;
5406 inactive |= all;
5408 /* Check the connection to libvirtd daemon is still working */
5409 if (!vshConnectionUsability(ctl, ctl->conn))
5410 return FALSE;
5412 /* Retrieve the number of active storage pools */
5413 if (active) {
5414 numActivePools = virConnectNumOfStoragePools(ctl->conn);
5415 if (numActivePools < 0) {
5416 vshError(ctl, "%s", _("Failed to list active pools"));
5417 return FALSE;
5421 /* Retrieve the number of inactive storage pools */
5422 if (inactive) {
5423 numInactivePools = virConnectNumOfDefinedStoragePools(ctl->conn);
5424 if (numInactivePools < 0) {
5425 vshError(ctl, "%s", _("Failed to list inactive pools"));
5426 return FALSE;
5430 /* Determine the total number of pools to list */
5431 numAllPools = numActivePools + numInactivePools;
5433 /* Allocate memory for arrays of storage pool names and info */
5434 poolNames = vshCalloc(ctl, numAllPools, sizeof(*poolNames));
5435 poolInfoTexts =
5436 vshCalloc(ctl, numAllPools, sizeof(*poolInfoTexts));
5438 /* Retrieve a list of active storage pool names */
5439 if (active) {
5440 if ((virConnectListStoragePools(ctl->conn,
5441 poolNames, numActivePools)) < 0) {
5442 vshError(ctl, "%s", _("Failed to list active pools"));
5443 VIR_FREE(poolInfoTexts);
5444 VIR_FREE(poolNames);
5445 return FALSE;
5449 /* Add the inactive storage pools to the end of the name list */
5450 if (inactive) {
5451 if ((virConnectListDefinedStoragePools(ctl->conn,
5452 &poolNames[numActivePools],
5453 numInactivePools)) < 0) {
5454 vshError(ctl, "%s", _("Failed to list inactive pools"));
5455 VIR_FREE(poolInfoTexts);
5456 VIR_FREE(poolNames);
5457 return FALSE;
5461 /* Sort the storage pool names */
5462 qsort(poolNames, numAllPools, sizeof(*poolNames), namesorter);
5464 /* Collect the storage pool information for display */
5465 for (i = 0; i < numAllPools; i++) {
5466 int autostart = 0, persistent = 0;
5468 /* Retrieve a pool object, looking it up by name */
5469 virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn,
5470 poolNames[i]);
5471 if (!pool) {
5472 VIR_FREE(poolNames[i]);
5473 continue;
5476 /* Retrieve the autostart status of the pool */
5477 if (virStoragePoolGetAutostart(pool, &autostart) < 0)
5478 poolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart"));
5479 else
5480 poolInfoTexts[i].autostart = vshStrdup(ctl, autostart ?
5481 _("yes") : _("no"));
5483 /* Retrieve the persistence status of the pool */
5484 if (details) {
5485 persistent = virStoragePoolIsPersistent(pool);
5486 vshDebug(ctl, 5, "Persistent flag value: %d\n", persistent);
5487 if (persistent < 0)
5488 poolInfoTexts[i].persistent = vshStrdup(ctl, _("unknown"));
5489 else
5490 poolInfoTexts[i].persistent = vshStrdup(ctl, persistent ?
5491 _("yes") : _("no"));
5493 /* Keep the length of persistent string if longest so far */
5494 stringLength = strlen(poolInfoTexts[i].persistent);
5495 if (stringLength > persistStrLength)
5496 persistStrLength = stringLength;
5499 /* Collect further extended information about the pool */
5500 if (virStoragePoolGetInfo(pool, &info) != 0) {
5501 /* Something went wrong retrieving pool info, cope with it */
5502 vshError(ctl, "%s", _("Could not retrieve pool information"));
5503 poolInfoTexts[i].state = vshStrdup(ctl, _("unknown"));
5504 if (details) {
5505 poolInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
5506 poolInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
5507 poolInfoTexts[i].available = vshStrdup(ctl, _("unknown"));
5509 } else {
5510 /* Decide which state string to display */
5511 if (details) {
5512 /* --details option was specified, we're using detailed state
5513 * strings */
5514 switch (info.state) {
5515 case VIR_STORAGE_POOL_INACTIVE:
5516 poolInfoTexts[i].state = vshStrdup(ctl, _("inactive"));
5517 break;
5518 case VIR_STORAGE_POOL_BUILDING:
5519 poolInfoTexts[i].state = vshStrdup(ctl, _("building"));
5520 break;
5521 case VIR_STORAGE_POOL_RUNNING:
5522 poolInfoTexts[i].state = vshStrdup(ctl, _("running"));
5523 break;
5524 case VIR_STORAGE_POOL_DEGRADED:
5525 poolInfoTexts[i].state = vshStrdup(ctl, _("degraded"));
5526 break;
5527 case VIR_STORAGE_POOL_INACCESSIBLE:
5528 poolInfoTexts[i].state = vshStrdup(ctl, _("inaccessible"));
5529 break;
5532 /* Create the pool size related strings */
5533 if (info.state == VIR_STORAGE_POOL_RUNNING ||
5534 info.state == VIR_STORAGE_POOL_DEGRADED) {
5535 double val;
5536 const char *unit;
5538 /* Create the capacity output string */
5539 val = prettyCapacity(info.capacity, &unit);
5540 ret = virAsprintf(&poolInfoTexts[i].capacity,
5541 "%.2lf %s", val, unit);
5542 if (ret < 0) {
5543 /* An error occurred creating the string, return */
5544 goto asprintf_failure;
5547 /* Create the allocation output string */
5548 val = prettyCapacity(info.allocation, &unit);
5549 ret = virAsprintf(&poolInfoTexts[i].allocation,
5550 "%.2lf %s", val, unit);
5551 if (ret < 0) {
5552 /* An error occurred creating the string, return */
5553 goto asprintf_failure;
5556 /* Create the available space output string */
5557 val = prettyCapacity(info.available, &unit);
5558 ret = virAsprintf(&poolInfoTexts[i].available,
5559 "%.2lf %s", val, unit);
5560 if (ret < 0) {
5561 /* An error occurred creating the string, return */
5562 goto asprintf_failure;
5564 } else {
5565 /* Capacity related information isn't available */
5566 poolInfoTexts[i].capacity = vshStrdup(ctl, _("-"));
5567 poolInfoTexts[i].allocation = vshStrdup(ctl, _("-"));
5568 poolInfoTexts[i].available = vshStrdup(ctl, _("-"));
5571 /* Keep the length of capacity string if longest so far */
5572 stringLength = strlen(poolInfoTexts[i].capacity);
5573 if (stringLength > capStrLength)
5574 capStrLength = stringLength;
5576 /* Keep the length of allocation string if longest so far */
5577 stringLength = strlen(poolInfoTexts[i].allocation);
5578 if (stringLength > allocStrLength)
5579 allocStrLength = stringLength;
5581 /* Keep the length of available string if longest so far */
5582 stringLength = strlen(poolInfoTexts[i].available);
5583 if (stringLength > availStrLength)
5584 availStrLength = stringLength;
5585 } else {
5586 /* --details option was not specified, only active/inactive
5587 * state strings are used */
5588 if (info.state == VIR_STORAGE_POOL_INACTIVE)
5589 poolInfoTexts[i].state = vshStrdup(ctl, _("inactive"));
5590 else
5591 poolInfoTexts[i].state = vshStrdup(ctl, _("active"));
5595 /* Keep the length of name string if longest so far */
5596 stringLength = strlen(poolNames[i]);
5597 if (stringLength > nameStrLength)
5598 nameStrLength = stringLength;
5600 /* Keep the length of state string if longest so far */
5601 stringLength = strlen(poolInfoTexts[i].state);
5602 if (stringLength > stateStrLength)
5603 stateStrLength = stringLength;
5605 /* Keep the length of autostart string if longest so far */
5606 stringLength = strlen(poolInfoTexts[i].autostart);
5607 if (stringLength > autostartStrLength)
5608 autostartStrLength = stringLength;
5610 /* Free the pool object */
5611 virStoragePoolFree(pool);
5614 /* If the --details option wasn't selected, we output the pool
5615 * info using the fixed string format from previous versions to
5616 * maintain backward compatibility.
5619 /* Output basic info then return if --details option not selected */
5620 if (!details) {
5621 /* Output old style header */
5622 vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("State"),
5623 _("Autostart"));
5624 vshPrintExtra(ctl, "-----------------------------------------\n");
5626 /* Output old style pool info */
5627 for (i = 0; i < numAllPools; i++) {
5628 vshPrint(ctl, "%-20s %-10s %-10s\n",
5629 poolNames[i],
5630 poolInfoTexts[i].state,
5631 poolInfoTexts[i].autostart);
5634 /* Cleanup and return */
5635 functionReturn = TRUE;
5636 goto cleanup;
5639 /* We only get here if the --details option was selected. */
5641 /* Use the length of name header string if it's longest */
5642 stringLength = strlen(_("Name"));
5643 if (stringLength > nameStrLength)
5644 nameStrLength = stringLength;
5646 /* Use the length of state header string if it's longest */
5647 stringLength = strlen(_("State"));
5648 if (stringLength > stateStrLength)
5649 stateStrLength = stringLength;
5651 /* Use the length of autostart header string if it's longest */
5652 stringLength = strlen(_("Autostart"));
5653 if (stringLength > autostartStrLength)
5654 autostartStrLength = stringLength;
5656 /* Use the length of persistent header string if it's longest */
5657 stringLength = strlen(_("Persistent"));
5658 if (stringLength > persistStrLength)
5659 persistStrLength = stringLength;
5661 /* Use the length of capacity header string if it's longest */
5662 stringLength = strlen(_("Capacity"));
5663 if (stringLength > capStrLength)
5664 capStrLength = stringLength;
5666 /* Use the length of allocation header string if it's longest */
5667 stringLength = strlen(_("Allocation"));
5668 if (stringLength > allocStrLength)
5669 allocStrLength = stringLength;
5671 /* Use the length of available header string if it's longest */
5672 stringLength = strlen(_("Available"));
5673 if (stringLength > availStrLength)
5674 availStrLength = stringLength;
5676 /* Display the string lengths for debugging. */
5677 vshDebug(ctl, 5, "Longest name string = %lu chars\n",
5678 (unsigned long) nameStrLength);
5679 vshDebug(ctl, 5, "Longest state string = %lu chars\n",
5680 (unsigned long) stateStrLength);
5681 vshDebug(ctl, 5, "Longest autostart string = %lu chars\n",
5682 (unsigned long) autostartStrLength);
5683 vshDebug(ctl, 5, "Longest persistent string = %lu chars\n",
5684 (unsigned long) persistStrLength);
5685 vshDebug(ctl, 5, "Longest capacity string = %lu chars\n",
5686 (unsigned long) capStrLength);
5687 vshDebug(ctl, 5, "Longest allocation string = %lu chars\n",
5688 (unsigned long) allocStrLength);
5689 vshDebug(ctl, 5, "Longest available string = %lu chars\n",
5690 (unsigned long) availStrLength);
5692 /* Create the output template. Each column is sized according to
5693 * the longest string.
5695 char *outputStr;
5696 ret = virAsprintf(&outputStr,
5697 "%%-%lus %%-%lus %%-%lus %%-%lus %%%lus %%%lus %%%lus\n",
5698 (unsigned long) nameStrLength,
5699 (unsigned long) stateStrLength,
5700 (unsigned long) autostartStrLength,
5701 (unsigned long) persistStrLength,
5702 (unsigned long) capStrLength,
5703 (unsigned long) allocStrLength,
5704 (unsigned long) availStrLength);
5705 if (ret < 0) {
5706 /* An error occurred creating the string, return */
5707 goto asprintf_failure;
5710 /* Display the header */
5711 vshPrint(ctl, outputStr, _("Name"), _("State"), _("Autostart"),
5712 _("Persistent"), _("Capacity"), _("Allocation"), _("Available"));
5713 for (i = nameStrLength + stateStrLength + autostartStrLength
5714 + persistStrLength + capStrLength
5715 + allocStrLength + availStrLength
5716 + 12; i > 0; i--)
5717 vshPrintExtra(ctl, "-");
5718 vshPrintExtra(ctl, "\n");
5720 /* Display the pool info rows */
5721 for (i = 0; i < numAllPools; i++) {
5722 vshPrint(ctl, outputStr,
5723 poolNames[i],
5724 poolInfoTexts[i].state,
5725 poolInfoTexts[i].autostart,
5726 poolInfoTexts[i].persistent,
5727 poolInfoTexts[i].capacity,
5728 poolInfoTexts[i].allocation,
5729 poolInfoTexts[i].available);
5732 /* Cleanup and return */
5733 functionReturn = TRUE;
5734 goto cleanup;
5736 asprintf_failure:
5738 /* Display an appropriate error message then cleanup and return */
5739 switch (errno) {
5740 case ENOMEM:
5741 /* Couldn't allocate memory */
5742 vshError(ctl, "%s", _("Out of memory"));
5743 break;
5744 default:
5745 /* Some other error */
5746 vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
5748 functionReturn = FALSE;
5750 cleanup:
5752 /* Safely free the memory allocated in this function */
5753 for (i = 0; i < numAllPools; i++) {
5754 /* Cleanup the memory for one pool info structure */
5755 VIR_FREE(poolInfoTexts[i].state);
5756 VIR_FREE(poolInfoTexts[i].autostart);
5757 VIR_FREE(poolInfoTexts[i].persistent);
5758 VIR_FREE(poolInfoTexts[i].capacity);
5759 VIR_FREE(poolInfoTexts[i].allocation);
5760 VIR_FREE(poolInfoTexts[i].available);
5761 VIR_FREE(poolNames[i]);
5764 /* Cleanup the memory for the initial arrays*/
5765 VIR_FREE(poolInfoTexts);
5766 VIR_FREE(poolNames);
5768 /* Return the desired value */
5769 return functionReturn;
5773 * "find-storage-pool-sources-as" command
5775 static const vshCmdInfo info_find_storage_pool_sources_as[] = {
5776 {"help", N_("find potential storage pool sources")},
5777 {"desc", N_("Returns XML <sources> document.")},
5778 {NULL, NULL}
5781 static const vshCmdOptDef opts_find_storage_pool_sources_as[] = {
5782 {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
5783 N_("type of storage pool sources to find")},
5784 {"host", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional host to query")},
5785 {"port", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional port to query")},
5786 {NULL, 0, 0, NULL}
5789 static int
5790 cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
5792 char *type, *host;
5793 char *srcSpec = NULL;
5794 char *srcList;
5795 int found;
5797 type = vshCommandOptString(cmd, "type", &found);
5798 if (!found)
5799 return FALSE;
5800 host = vshCommandOptString(cmd, "host", &found);
5801 if (!found)
5802 host = NULL;
5804 if (!vshConnectionUsability(ctl, ctl->conn))
5805 return FALSE;
5807 if (host) {
5808 size_t hostlen = strlen(host);
5809 char *port = vshCommandOptString(cmd, "port", &found);
5810 int ret;
5811 if (!found) {
5812 port = strrchr(host, ':');
5813 if (port) {
5814 if (*(++port))
5815 hostlen = port - host - 1;
5816 else
5817 port = NULL;
5820 ret = port ?
5821 virAsprintf(&srcSpec,
5822 "<source><host name='%.*s' port='%s'/></source>",
5823 (int)hostlen, host, port) :
5824 virAsprintf(&srcSpec,
5825 "<source><host name='%.*s'/></source>",
5826 (int)hostlen, host);
5827 if (ret < 0) {
5828 switch (errno) {
5829 case ENOMEM:
5830 vshError(ctl, "%s", _("Out of memory"));
5831 break;
5832 default:
5833 vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
5835 return FALSE;
5839 srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
5840 VIR_FREE(srcSpec);
5841 if (srcList == NULL) {
5842 vshError(ctl, _("Failed to find any %s pool sources"), type);
5843 return FALSE;
5845 vshPrint(ctl, "%s", srcList);
5846 VIR_FREE(srcList);
5848 return TRUE;
5853 * "find-storage-pool-sources" command
5855 static const vshCmdInfo info_find_storage_pool_sources[] = {
5856 {"help", N_("discover potential storage pool sources")},
5857 {"desc", N_("Returns XML <sources> document.")},
5858 {NULL, NULL}
5861 static const vshCmdOptDef opts_find_storage_pool_sources[] = {
5862 {"type", VSH_OT_DATA, VSH_OFLAG_REQ,
5863 N_("type of storage pool sources to discover")},
5864 {"srcSpec", VSH_OT_DATA, VSH_OFLAG_NONE,
5865 N_("optional file of source xml to query for pools")},
5866 {NULL, 0, 0, NULL}
5869 static int
5870 cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
5872 char *type, *srcSpecFile, *srcList;
5873 char *srcSpec = NULL;
5874 int found;
5876 type = vshCommandOptString(cmd, "type", &found);
5877 if (!found)
5878 return FALSE;
5879 srcSpecFile = vshCommandOptString(cmd, "srcSpec", &found);
5880 if (!found)
5881 srcSpecFile = NULL;
5883 if (!vshConnectionUsability(ctl, ctl->conn))
5884 return FALSE;
5886 if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0)
5887 return FALSE;
5889 srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0);
5890 VIR_FREE(srcSpec);
5891 if (srcList == NULL) {
5892 vshError(ctl, _("Failed to find any %s pool sources"), type);
5893 return FALSE;
5895 vshPrint(ctl, "%s", srcList);
5896 VIR_FREE(srcList);
5898 return TRUE;
5903 * "pool-info" command
5905 static const vshCmdInfo info_pool_info[] = {
5906 {"help", N_("storage pool information")},
5907 {"desc", N_("Returns basic information about the storage pool.")},
5908 {NULL, NULL}
5911 static const vshCmdOptDef opts_pool_info[] = {
5912 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
5913 {NULL, 0, 0, NULL}
5916 static int
5917 cmdPoolInfo(vshControl *ctl, const vshCmd *cmd)
5919 virStoragePoolInfo info;
5920 virStoragePoolPtr pool;
5921 int autostart = 0;
5922 int persistent = 0;
5923 int ret = TRUE;
5924 char uuid[VIR_UUID_STRING_BUFLEN];
5926 if (!vshConnectionUsability(ctl, ctl->conn))
5927 return FALSE;
5929 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
5930 return FALSE;
5932 vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool));
5934 if (virStoragePoolGetUUIDString(pool, &uuid[0])==0)
5935 vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
5937 if (virStoragePoolGetInfo(pool, &info) == 0) {
5938 double val;
5939 const char *unit;
5940 switch (info.state) {
5941 case VIR_STORAGE_POOL_INACTIVE:
5942 vshPrint(ctl, "%-15s %s\n", _("State:"),
5943 _("inactive"));
5944 break;
5945 case VIR_STORAGE_POOL_BUILDING:
5946 vshPrint(ctl, "%-15s %s\n", _("State:"),
5947 _("building"));
5948 break;
5949 case VIR_STORAGE_POOL_RUNNING:
5950 vshPrint(ctl, "%-15s %s\n", _("State:"),
5951 _("running"));
5952 break;
5953 case VIR_STORAGE_POOL_DEGRADED:
5954 vshPrint(ctl, "%-15s %s\n", _("State:"),
5955 _("degraded"));
5956 break;
5957 case VIR_STORAGE_POOL_INACCESSIBLE:
5958 vshPrint(ctl, "%-15s %s\n", _("State:"),
5959 _("inaccessible"));
5960 break;
5963 /* Check and display whether the pool is persistent or not */
5964 persistent = virStoragePoolIsPersistent(pool);
5965 vshDebug(ctl, 5, "Pool persistent flag value: %d\n", persistent);
5966 if (persistent < 0)
5967 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
5968 else
5969 vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));
5971 /* Check and display whether the pool is autostarted or not */
5972 virStoragePoolGetAutostart(pool, &autostart);
5973 vshDebug(ctl, 5, "Pool autostart flag value: %d\n", autostart);
5974 if (autostart < 0)
5975 vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart"));
5976 else
5977 vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));
5979 if (info.state == VIR_STORAGE_POOL_RUNNING ||
5980 info.state == VIR_STORAGE_POOL_DEGRADED) {
5981 val = prettyCapacity(info.capacity, &unit);
5982 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);
5984 val = prettyCapacity(info.allocation, &unit);
5985 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
5987 val = prettyCapacity(info.available, &unit);
5988 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit);
5990 } else {
5991 ret = FALSE;
5994 virStoragePoolFree(pool);
5995 return ret;
6000 * "pool-name" command
6002 static const vshCmdInfo info_pool_name[] = {
6003 {"help", N_("convert a pool UUID to pool name")},
6004 {"desc", ""},
6005 {NULL, NULL}
6008 static const vshCmdOptDef opts_pool_name[] = {
6009 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")},
6010 {NULL, 0, 0, NULL}
6013 static int
6014 cmdPoolName(vshControl *ctl, const vshCmd *cmd)
6016 virStoragePoolPtr pool;
6018 if (!vshConnectionUsability(ctl, ctl->conn))
6019 return FALSE;
6020 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6021 VSH_BYUUID)))
6022 return FALSE;
6024 vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
6025 virStoragePoolFree(pool);
6026 return TRUE;
6031 * "pool-start" command
6033 static const vshCmdInfo info_pool_start[] = {
6034 {"help", N_("start a (previously defined) inactive pool")},
6035 {"desc", N_("Start a pool.")},
6036 {NULL, NULL}
6039 static const vshCmdOptDef opts_pool_start[] = {
6040 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the inactive pool")},
6041 {NULL, 0, 0, NULL}
6044 static int
6045 cmdPoolStart(vshControl *ctl, const vshCmd *cmd)
6047 virStoragePoolPtr pool;
6048 int ret = TRUE;
6050 if (!vshConnectionUsability(ctl, ctl->conn))
6051 return FALSE;
6053 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
6054 return FALSE;
6056 if (virStoragePoolCreate(pool, 0) == 0) {
6057 vshPrint(ctl, _("Pool %s started\n"),
6058 virStoragePoolGetName(pool));
6059 } else {
6060 vshError(ctl, _("Failed to start pool %s"), virStoragePoolGetName(pool));
6061 ret = FALSE;
6064 virStoragePoolFree(pool);
6065 return ret;
6070 * "vol-create-as" command
6072 static const vshCmdInfo info_vol_create_as[] = {
6073 {"help", N_("create a volume from a set of args")},
6074 {"desc", N_("Create a vol.")},
6075 {NULL, NULL}
6078 static const vshCmdOptDef opts_vol_create_as[] = {
6079 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6080 {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")},
6081 {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, N_("size of the vol with optional k,M,G,T suffix")},
6082 {"allocation", VSH_OT_STRING, 0, N_("initial allocation size with optional k,M,G,T suffix")},
6083 {"format", VSH_OT_STRING, 0, N_("file format type raw,bochs,qcow,qcow2,vmdk")},
6084 {"backing-vol", VSH_OT_STRING, 0, N_("the backing volume if taking a snapshot")},
6085 {"backing-vol-format", VSH_OT_STRING, 0, N_("format of backing volume if taking a snapshot")},
6086 {NULL, 0, 0, NULL}
6089 static int cmdVolSize(const char *data, unsigned long long *val)
6091 char *end;
6092 if (virStrToLong_ull(data, &end, 10, val) < 0)
6093 return -1;
6095 if (end && *end) {
6096 /* Deliberate fallthrough cases here :-) */
6097 switch (*end) {
6098 case 'T':
6099 *val *= 1024;
6100 case 'G':
6101 *val *= 1024;
6102 case 'M':
6103 *val *= 1024;
6104 case 'k':
6105 *val *= 1024;
6106 break;
6107 default:
6108 return -1;
6110 end++;
6111 if (*end)
6112 return -1;
6114 return 0;
6117 static int
6118 cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd)
6120 virStoragePoolPtr pool;
6121 virStorageVolPtr vol;
6122 int found;
6123 char *xml;
6124 char *name, *capacityStr, *allocationStr, *format;
6125 char *snapshotStrVol, *snapshotStrFormat;
6126 unsigned long long capacity, allocation = 0;
6127 virBuffer buf = VIR_BUFFER_INITIALIZER;
6129 if (!vshConnectionUsability(ctl, ctl->conn))
6130 return FALSE;
6132 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6133 VSH_BYNAME)))
6134 return FALSE;
6136 name = vshCommandOptString(cmd, "name", &found);
6137 if (!found)
6138 goto cleanup;
6140 capacityStr = vshCommandOptString(cmd, "capacity", &found);
6141 if (!found)
6142 goto cleanup;
6143 if (cmdVolSize(capacityStr, &capacity) < 0)
6144 vshError(ctl, _("Malformed size %s"), capacityStr);
6146 allocationStr = vshCommandOptString(cmd, "allocation", &found);
6147 if (allocationStr &&
6148 cmdVolSize(allocationStr, &allocation) < 0)
6149 vshError(ctl, _("Malformed size %s"), allocationStr);
6151 format = vshCommandOptString(cmd, "format", &found);
6152 snapshotStrVol = vshCommandOptString(cmd, "backing-vol", &found);
6153 snapshotStrFormat = vshCommandOptString(cmd, "backing-vol-format", &found);
6155 virBufferAddLit(&buf, "<volume>\n");
6156 virBufferVSprintf(&buf, " <name>%s</name>\n", name);
6157 virBufferVSprintf(&buf, " <capacity>%llu</capacity>\n", capacity);
6158 if (allocationStr)
6159 virBufferVSprintf(&buf, " <allocation>%llu</allocation>\n", allocation);
6161 if (format) {
6162 virBufferAddLit(&buf, " <target>\n");
6163 virBufferVSprintf(&buf, " <format type='%s'/>\n",format);
6164 virBufferAddLit(&buf, " </target>\n");
6167 /* Convert the snapshot parameters into backingStore XML */
6168 if (snapshotStrVol) {
6169 /* Lookup snapshot backing volume. Try the backing-vol
6170 * parameter as a name */
6171 vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as name\n",
6172 cmd->def->name, snapshotStrVol);
6173 virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol);
6174 if (snapVol)
6175 vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as name\n",
6176 cmd->def->name, snapshotStrVol);
6178 if (snapVol == NULL) {
6179 /* Snapshot backing volume not found by name. Try the
6180 * backing-vol parameter as a key */
6181 vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as key\n",
6182 cmd->def->name, snapshotStrVol);
6183 snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol);
6184 if (snapVol)
6185 vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as key\n",
6186 cmd->def->name, snapshotStrVol);
6188 if (snapVol == NULL) {
6189 /* Snapshot backing volume not found by key. Try the
6190 * backing-vol parameter as a path */
6191 vshDebug(ctl, 5, "%s: Look up backing store volume '%s' as path\n",
6192 cmd->def->name, snapshotStrVol);
6193 snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol);
6194 if (snapVol)
6195 vshDebug(ctl, 5, "%s: Backing store volume found using '%s' as path\n",
6196 cmd->def->name, snapshotStrVol);
6198 if (snapVol == NULL) {
6199 vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol);
6200 return FALSE;
6203 char *snapshotStrVolPath;
6204 if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) {
6205 virStorageVolFree(snapVol);
6206 return FALSE;
6209 /* Create XML for the backing store */
6210 virBufferAddLit(&buf, " <backingStore>\n");
6211 virBufferVSprintf(&buf, " <path>%s</path>\n",snapshotStrVolPath);
6212 if (snapshotStrFormat)
6213 virBufferVSprintf(&buf, " <format type='%s'/>\n",snapshotStrFormat);
6214 virBufferAddLit(&buf, " </backingStore>\n");
6216 /* Cleanup snapshot allocations */
6217 VIR_FREE(snapshotStrVolPath);
6218 virStorageVolFree(snapVol);
6221 virBufferAddLit(&buf, "</volume>\n");
6223 if (virBufferError(&buf)) {
6224 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
6225 return FALSE;
6227 xml = virBufferContentAndReset(&buf);
6228 vol = virStorageVolCreateXML(pool, xml, 0);
6229 VIR_FREE(xml);
6230 virStoragePoolFree(pool);
6232 if (vol != NULL) {
6233 vshPrint(ctl, _("Vol %s created\n"), name);
6234 virStorageVolFree(vol);
6235 return TRUE;
6236 } else {
6237 vshError(ctl, _("Failed to create vol %s"), name);
6238 return FALSE;
6241 cleanup:
6242 virBufferFreeAndReset(&buf);
6243 virStoragePoolFree(pool);
6244 return FALSE;
6249 * "pool-undefine" command
6251 static const vshCmdInfo info_pool_undefine[] = {
6252 {"help", N_("undefine an inactive pool")},
6253 {"desc", N_("Undefine the configuration for an inactive pool.")},
6254 {NULL, NULL}
6257 static const vshCmdOptDef opts_pool_undefine[] = {
6258 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
6259 {NULL, 0, 0, NULL}
6262 static int
6263 cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd)
6265 virStoragePoolPtr pool;
6266 int ret = TRUE;
6267 char *name;
6269 if (!vshConnectionUsability(ctl, ctl->conn))
6270 return FALSE;
6272 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
6273 return FALSE;
6275 if (virStoragePoolUndefine(pool) == 0) {
6276 vshPrint(ctl, _("Pool %s has been undefined\n"), name);
6277 } else {
6278 vshError(ctl, _("Failed to undefine pool %s"), name);
6279 ret = FALSE;
6282 virStoragePoolFree(pool);
6283 return ret;
6288 * "pool-uuid" command
6290 static const vshCmdInfo info_pool_uuid[] = {
6291 {"help", N_("convert a pool name to pool UUID")},
6292 {"desc", ""},
6293 {NULL, NULL}
6296 static const vshCmdOptDef opts_pool_uuid[] = {
6297 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6298 {NULL, 0, 0, NULL}
6301 static int
6302 cmdPoolUuid(vshControl *ctl, const vshCmd *cmd)
6304 virStoragePoolPtr pool;
6305 char uuid[VIR_UUID_STRING_BUFLEN];
6307 if (!vshConnectionUsability(ctl, ctl->conn))
6308 return FALSE;
6310 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6311 VSH_BYNAME)))
6312 return FALSE;
6314 if (virStoragePoolGetUUIDString(pool, uuid) != -1)
6315 vshPrint(ctl, "%s\n", uuid);
6316 else
6317 vshError(ctl, "%s", _("failed to get pool UUID"));
6319 virStoragePoolFree(pool);
6320 return TRUE;
6325 * "vol-create" command
6327 static const vshCmdInfo info_vol_create[] = {
6328 {"help", N_("create a vol from an XML file")},
6329 {"desc", N_("Create a vol.")},
6330 {NULL, NULL}
6333 static const vshCmdOptDef opts_vol_create[] = {
6334 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6335 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
6336 {NULL, 0, 0, NULL}
6339 static int
6340 cmdVolCreate(vshControl *ctl, const vshCmd *cmd)
6342 virStoragePoolPtr pool;
6343 virStorageVolPtr vol;
6344 char *from;
6345 int found;
6346 int ret = TRUE;
6347 char *buffer;
6349 if (!vshConnectionUsability(ctl, ctl->conn))
6350 return FALSE;
6352 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL,
6353 VSH_BYNAME)))
6354 return FALSE;
6356 from = vshCommandOptString(cmd, "file", &found);
6357 if (!found) {
6358 virStoragePoolFree(pool);
6359 return FALSE;
6362 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
6363 virshReportError(ctl);
6364 virStoragePoolFree(pool);
6365 return FALSE;
6368 vol = virStorageVolCreateXML(pool, buffer, 0);
6369 VIR_FREE(buffer);
6370 virStoragePoolFree(pool);
6372 if (vol != NULL) {
6373 vshPrint(ctl, _("Vol %s created from %s\n"),
6374 virStorageVolGetName(vol), from);
6375 virStorageVolFree(vol);
6376 } else {
6377 vshError(ctl, _("Failed to create vol from %s"), from);
6378 ret = FALSE;
6380 return ret;
6384 * "vol-create-from" command
6386 static const vshCmdInfo info_vol_create_from[] = {
6387 {"help", N_("create a vol, using another volume as input")},
6388 {"desc", N_("Create a vol from an existing volume.")},
6389 {NULL, NULL}
6392 static const vshCmdOptDef opts_vol_create_from[] = {
6393 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")},
6394 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")},
6395 {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")},
6396 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")},
6397 {NULL, 0, 0, NULL}
6400 static int
6401 cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd)
6403 virStoragePoolPtr pool = NULL;
6404 virStorageVolPtr newvol = NULL, inputvol = NULL;
6405 char *from;
6406 int found;
6407 int ret = FALSE;
6408 char *buffer = NULL;
6410 if (!vshConnectionUsability(ctl, ctl->conn))
6411 goto cleanup;
6413 if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
6414 goto cleanup;
6416 from = vshCommandOptString(cmd, "file", &found);
6417 if (!found) {
6418 goto cleanup;
6421 if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL)))
6422 goto cleanup;
6424 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
6425 virshReportError(ctl);
6426 goto cleanup;
6429 newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0);
6431 if (newvol != NULL) {
6432 vshPrint(ctl, _("Vol %s created from input vol %s\n"),
6433 virStorageVolGetName(newvol), virStorageVolGetName(inputvol));
6434 } else {
6435 vshError(ctl, _("Failed to create vol from %s"), from);
6436 goto cleanup;
6439 ret = TRUE;
6440 cleanup:
6441 VIR_FREE(buffer);
6442 if (pool)
6443 virStoragePoolFree(pool);
6444 if (inputvol)
6445 virStorageVolFree(inputvol);
6446 if (newvol)
6447 virStorageVolFree(newvol);
6448 return ret;
6451 static xmlChar *
6452 makeCloneXML(char *origxml, char *newname) {
6454 xmlDocPtr doc = NULL;
6455 xmlXPathContextPtr ctxt = NULL;
6456 xmlXPathObjectPtr obj = NULL;
6457 xmlChar *newxml = NULL;
6458 int size;
6460 doc = xmlReadDoc((const xmlChar *) origxml, "domain.xml", NULL,
6461 XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOWARNING);
6462 if (!doc)
6463 goto cleanup;
6464 ctxt = xmlXPathNewContext(doc);
6465 if (!ctxt)
6466 goto cleanup;
6468 obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt);
6469 if ((obj == NULL) || (obj->nodesetval == NULL) ||
6470 (obj->nodesetval->nodeTab == NULL))
6471 goto cleanup;
6473 xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname);
6474 xmlDocDumpMemory(doc, &newxml, &size);
6476 cleanup:
6477 xmlXPathFreeObject(obj);
6478 xmlXPathFreeContext(ctxt);
6479 xmlFreeDoc(doc);
6480 return newxml;
6484 * "vol-clone" command
6486 static const vshCmdInfo info_vol_clone[] = {
6487 {"help", N_("clone a volume.")},
6488 {"desc", N_("Clone an existing volume.")},
6489 {NULL, NULL}
6492 static const vshCmdOptDef opts_vol_clone[] = {
6493 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6494 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")},
6495 {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")},
6496 {NULL, 0, 0, NULL}
6499 static int
6500 cmdVolClone(vshControl *ctl, const vshCmd *cmd)
6502 virStoragePoolPtr origpool = NULL;
6503 virStorageVolPtr origvol = NULL, newvol = NULL;
6504 char *name, *origxml = NULL;
6505 xmlChar *newxml = NULL;
6506 int found;
6507 int ret = FALSE;
6509 if (!vshConnectionUsability(ctl, ctl->conn))
6510 goto cleanup;
6512 if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
6513 goto cleanup;
6515 origpool = virStoragePoolLookupByVolume(origvol);
6516 if (!origpool) {
6517 vshError(ctl, "%s", _("failed to get parent pool"));
6518 goto cleanup;
6521 name = vshCommandOptString(cmd, "newname", &found);
6522 if (!found)
6523 goto cleanup;
6525 origxml = virStorageVolGetXMLDesc(origvol, 0);
6526 if (!origxml)
6527 goto cleanup;
6529 newxml = makeCloneXML(origxml, name);
6530 if (!newxml) {
6531 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
6532 goto cleanup;
6535 newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0);
6537 if (newvol != NULL) {
6538 vshPrint(ctl, _("Vol %s cloned from %s\n"),
6539 virStorageVolGetName(newvol), virStorageVolGetName(origvol));
6540 } else {
6541 vshError(ctl, _("Failed to clone vol from %s"),
6542 virStorageVolGetName(origvol));
6543 goto cleanup;
6546 ret = TRUE;
6548 cleanup:
6549 VIR_FREE(origxml);
6550 xmlFree(newxml);
6551 if (origvol)
6552 virStorageVolFree(origvol);
6553 if (newvol)
6554 virStorageVolFree(newvol);
6555 if (origpool)
6556 virStoragePoolFree(origpool);
6557 return ret;
6561 * "vol-delete" command
6563 static const vshCmdInfo info_vol_delete[] = {
6564 {"help", N_("delete a vol")},
6565 {"desc", N_("Delete a given vol.")},
6566 {NULL, NULL}
6569 static const vshCmdOptDef opts_vol_delete[] = {
6570 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6571 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6572 {NULL, 0, 0, NULL}
6575 static int
6576 cmdVolDelete(vshControl *ctl, const vshCmd *cmd)
6578 virStorageVolPtr vol;
6579 int ret = TRUE;
6580 char *name;
6582 if (!vshConnectionUsability(ctl, ctl->conn))
6583 return FALSE;
6585 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
6586 return FALSE;
6589 if (virStorageVolDelete(vol, 0) == 0) {
6590 vshPrint(ctl, _("Vol %s deleted\n"), name);
6591 } else {
6592 vshError(ctl, _("Failed to delete vol %s"), name);
6593 ret = FALSE;
6596 virStorageVolFree(vol);
6597 return ret;
6602 * "vol-wipe" command
6604 static const vshCmdInfo info_vol_wipe[] = {
6605 {"help", N_("wipe a vol")},
6606 {"desc", N_("Ensure data previously on a volume is not accessible to future reads")},
6607 {NULL, NULL}
6610 static const vshCmdOptDef opts_vol_wipe[] = {
6611 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6612 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6613 {NULL, 0, 0, NULL}
6616 static int
6617 cmdVolWipe(vshControl *ctl, const vshCmd *cmd)
6619 virStorageVolPtr vol;
6620 int ret = TRUE;
6621 char *name;
6623 if (!vshConnectionUsability(ctl, ctl->conn))
6624 return FALSE;
6626 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
6627 return FALSE;
6630 if (virStorageVolWipe(vol, 0) == 0) {
6631 vshPrint(ctl, _("Vol %s wiped\n"), name);
6632 } else {
6633 vshError(ctl, _("Failed to wipe vol %s"), name);
6634 ret = FALSE;
6637 virStorageVolFree(vol);
6638 return ret;
6643 * "vol-info" command
6645 static const vshCmdInfo info_vol_info[] = {
6646 {"help", N_("storage vol information")},
6647 {"desc", N_("Returns basic information about the storage vol.")},
6648 {NULL, NULL}
6651 static const vshCmdOptDef opts_vol_info[] = {
6652 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6653 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6654 {NULL, 0, 0, NULL}
6657 static int
6658 cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
6660 virStorageVolInfo info;
6661 virStorageVolPtr vol;
6662 int ret = TRUE;
6664 if (!vshConnectionUsability(ctl, ctl->conn))
6665 return FALSE;
6667 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
6668 return FALSE;
6670 vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol));
6672 if (virStorageVolGetInfo(vol, &info) == 0) {
6673 double val;
6674 const char *unit;
6675 vshPrint(ctl, "%-15s %s\n", _("Type:"),
6676 info.type == VIR_STORAGE_VOL_FILE ?
6677 _("file") : _("block"));
6679 val = prettyCapacity(info.capacity, &unit);
6680 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);
6682 val = prettyCapacity(info.allocation, &unit);
6683 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
6684 } else {
6685 ret = FALSE;
6688 virStorageVolFree(vol);
6689 return ret;
6694 * "vol-dumpxml" command
6696 static const vshCmdInfo info_vol_dumpxml[] = {
6697 {"help", N_("vol information in XML")},
6698 {"desc", N_("Output the vol information as an XML dump to stdout.")},
6699 {NULL, NULL}
6702 static const vshCmdOptDef opts_vol_dumpxml[] = {
6703 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
6704 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
6705 {NULL, 0, 0, NULL}
6708 static int
6709 cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd)
6711 virStorageVolPtr vol;
6712 int ret = TRUE;
6713 char *dump;
6715 if (!vshConnectionUsability(ctl, ctl->conn))
6716 return FALSE;
6718 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
6719 return FALSE;
6721 dump = virStorageVolGetXMLDesc(vol, 0);
6722 if (dump != NULL) {
6723 vshPrint(ctl, "%s", dump);
6724 VIR_FREE(dump);
6725 } else {
6726 ret = FALSE;
6729 virStorageVolFree(vol);
6730 return ret;
6735 * "vol-list" command
6737 static const vshCmdInfo info_vol_list[] = {
6738 {"help", N_("list vols")},
6739 {"desc", N_("Returns list of vols by pool.")},
6740 {NULL, NULL}
6743 static const vshCmdOptDef opts_vol_list[] = {
6744 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
6745 {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")},
6746 {NULL, 0, 0, NULL}
6749 static int
6750 cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
6752 virStorageVolInfo volumeInfo;
6753 virStoragePoolPtr pool;
6754 char **activeNames = NULL;
6755 char *outputStr = NULL;
6756 const char *unit;
6757 double val;
6758 int details = vshCommandOptBool(cmd, "details");
6759 int numVolumes = 0, i;
6760 int ret, functionReturn;
6761 int stringLength = 0;
6762 size_t allocStrLength = 0, capStrLength = 0;
6763 size_t nameStrLength = 0, pathStrLength = 0;
6764 size_t typeStrLength = 0;
6765 struct volInfoText {
6766 char *allocation;
6767 char *capacity;
6768 char *path;
6769 char *type;
6771 struct volInfoText *volInfoTexts = NULL;
6773 /* Check the connection to libvirtd daemon is still working */
6774 if (!vshConnectionUsability(ctl, ctl->conn))
6775 return FALSE;
6777 /* Look up the pool information given to us by the user */
6778 if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
6779 return FALSE;
6781 /* Determine the number of volumes in the pool */
6782 numVolumes = virStoragePoolNumOfVolumes(pool);
6784 /* Retrieve the list of volume names in the pool */
6785 if (numVolumes > 0) {
6786 activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames));
6787 if ((numVolumes = virStoragePoolListVolumes(pool, activeNames,
6788 numVolumes)) < 0) {
6789 vshError(ctl, "%s", _("Failed to list active vols"));
6790 VIR_FREE(activeNames);
6791 virStoragePoolFree(pool);
6792 return FALSE;
6795 /* Sort the volume names */
6796 qsort(&activeNames[0], numVolumes, sizeof(*activeNames), namesorter);
6798 /* Set aside memory for volume information pointers */
6799 volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts));
6802 /* Collect the rest of the volume information for display */
6803 for (i = 0; i < numVolumes; i++) {
6804 /* Retrieve volume info */
6805 virStorageVolPtr vol = virStorageVolLookupByName(pool,
6806 activeNames[i]);
6808 /* Retrieve the volume path */
6809 if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) {
6810 /* Something went wrong retrieving a volume path, cope with it */
6811 volInfoTexts[i].path = vshStrdup(ctl, _("unknown"));
6814 /* If requested, retrieve volume type and sizing information */
6815 if (details) {
6816 if (virStorageVolGetInfo(vol, &volumeInfo) != 0) {
6817 /* Something went wrong retrieving volume info, cope with it */
6818 volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
6819 volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
6820 volInfoTexts[i].type = vshStrdup(ctl, _("unknown"));
6821 } else {
6822 /* Convert the returned volume info into output strings */
6824 /* Volume type */
6825 if (volumeInfo.type == VIR_STORAGE_VOL_FILE)
6826 volInfoTexts[i].type = vshStrdup(ctl, _("file"));
6827 else
6828 volInfoTexts[i].type = vshStrdup(ctl, _("block"));
6830 /* Create the capacity output string */
6831 val = prettyCapacity(volumeInfo.capacity, &unit);
6832 ret = virAsprintf(&volInfoTexts[i].capacity,
6833 "%.2lf %s", val, unit);
6834 if (ret < 0) {
6835 /* An error occurred creating the string, return */
6836 goto asprintf_failure;
6839 /* Create the allocation output string */
6840 val = prettyCapacity(volumeInfo.allocation, &unit);
6841 ret = virAsprintf(&volInfoTexts[i].allocation,
6842 "%.2lf %s", val, unit);
6843 if (ret < 0) {
6844 /* An error occurred creating the string, return */
6845 goto asprintf_failure;
6849 /* Remember the largest length for each output string.
6850 * This lets us displaying header and volume information rows
6851 * using a single, properly sized, printf style output string.
6854 /* Keep the length of name string if longest so far */
6855 stringLength = strlen(activeNames[i]);
6856 if (stringLength > nameStrLength)
6857 nameStrLength = stringLength;
6859 /* Keep the length of path string if longest so far */
6860 stringLength = strlen(volInfoTexts[i].path);
6861 if (stringLength > pathStrLength)
6862 pathStrLength = stringLength;
6864 /* Keep the length of type string if longest so far */
6865 stringLength = strlen(volInfoTexts[i].type);
6866 if (stringLength > typeStrLength)
6867 typeStrLength = stringLength;
6869 /* Keep the length of capacity string if longest so far */
6870 stringLength = strlen(volInfoTexts[i].capacity);
6871 if (stringLength > capStrLength)
6872 capStrLength = stringLength;
6874 /* Keep the length of allocation string if longest so far */
6875 stringLength = strlen(volInfoTexts[i].allocation);
6876 if (stringLength > allocStrLength)
6877 allocStrLength = stringLength;
6880 /* Cleanup memory allocation */
6881 virStorageVolFree(vol);
6884 /* If the --details option wasn't selected, we output the volume
6885 * info using the fixed string format from previous versions to
6886 * maintain backward compatibility.
6889 /* Output basic info then return if --details option not selected */
6890 if (!details) {
6891 /* The old output format */
6892 vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path"));
6893 vshPrintExtra(ctl, "-----------------------------------------\n");
6894 for (i = 0; i < numVolumes; i++) {
6895 vshPrint(ctl, "%-20s %-40s\n", activeNames[i],
6896 volInfoTexts[i].path);
6899 /* Cleanup and return */
6900 functionReturn = TRUE;
6901 goto cleanup;
6904 /* We only get here if the --details option was selected. */
6906 /* Use the length of name header string if it's longest */
6907 stringLength = strlen(_("Name"));
6908 if (stringLength > nameStrLength)
6909 nameStrLength = stringLength;
6911 /* Use the length of path header string if it's longest */
6912 stringLength = strlen(_("Path"));
6913 if (stringLength > pathStrLength)
6914 pathStrLength = stringLength;
6916 /* Use the length of type header string if it's longest */
6917 stringLength = strlen(_("Type"));
6918 if (stringLength > typeStrLength)
6919 typeStrLength = stringLength;
6921 /* Use the length of capacity header string if it's longest */
6922 stringLength = strlen(_("Capacity"));
6923 if (stringLength > capStrLength)
6924 capStrLength = stringLength;
6926 /* Use the length of allocation header string if it's longest */
6927 stringLength = strlen(_("Allocation"));
6928 if (stringLength > allocStrLength)
6929 allocStrLength = stringLength;
6931 /* Display the string lengths for debugging */
6932 vshDebug(ctl, 5, "Longest name string = %zu chars\n", nameStrLength);
6933 vshDebug(ctl, 5, "Longest path string = %zu chars\n", pathStrLength);
6934 vshDebug(ctl, 5, "Longest type string = %zu chars\n", typeStrLength);
6935 vshDebug(ctl, 5, "Longest capacity string = %zu chars\n", capStrLength);
6936 vshDebug(ctl, 5, "Longest allocation string = %zu chars\n", allocStrLength);
6938 /* Create the output template */
6939 ret = virAsprintf(&outputStr,
6940 "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n",
6941 (unsigned long) nameStrLength,
6942 (unsigned long) pathStrLength,
6943 (unsigned long) typeStrLength,
6944 (unsigned long) capStrLength,
6945 (unsigned long) allocStrLength);
6946 if (ret < 0) {
6947 /* An error occurred creating the string, return */
6948 goto asprintf_failure;
6951 /* Display the header */
6952 vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"),
6953 ("Capacity"), _("Allocation"));
6954 for (i = nameStrLength + pathStrLength + typeStrLength
6955 + capStrLength + allocStrLength
6956 + 8; i > 0; i--)
6957 vshPrintExtra(ctl, "-");
6958 vshPrintExtra(ctl, "\n");
6960 /* Display the volume info rows */
6961 for (i = 0; i < numVolumes; i++) {
6962 vshPrint(ctl, outputStr,
6963 activeNames[i],
6964 volInfoTexts[i].path,
6965 volInfoTexts[i].type,
6966 volInfoTexts[i].capacity,
6967 volInfoTexts[i].allocation);
6970 /* Cleanup and return */
6971 functionReturn = TRUE;
6972 goto cleanup;
6974 asprintf_failure:
6976 /* Display an appropriate error message then cleanup and return */
6977 switch (errno) {
6978 case ENOMEM:
6979 /* Couldn't allocate memory */
6980 vshError(ctl, "%s", _("Out of memory"));
6981 break;
6982 default:
6983 /* Some other error */
6984 vshError(ctl, _("virAsprintf failed (errno %d)"), errno);
6986 functionReturn = FALSE;
6988 cleanup:
6990 /* Safely free the memory allocated in this function */
6991 for (i = 0; i < numVolumes; i++) {
6992 /* Cleanup the memory for one volume info structure per loop */
6993 VIR_FREE(volInfoTexts[i].path);
6994 VIR_FREE(volInfoTexts[i].type);
6995 VIR_FREE(volInfoTexts[i].capacity);
6996 VIR_FREE(volInfoTexts[i].allocation);
6997 VIR_FREE(activeNames[i]);
7000 /* Cleanup remaining memory */
7001 VIR_FREE(outputStr);
7002 VIR_FREE(volInfoTexts);
7003 VIR_FREE(activeNames);
7004 virStoragePoolFree(pool);
7006 /* Return the desired value */
7007 return functionReturn;
7012 * "vol-name" command
7014 static const vshCmdInfo info_vol_name[] = {
7015 {"help", N_("returns the volume name for a given volume key or path")},
7016 {"desc", ""},
7017 {NULL, NULL}
7020 static const vshCmdOptDef opts_vol_name[] = {
7021 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")},
7022 {NULL, 0, 0, NULL}
7025 static int
7026 cmdVolName(vshControl *ctl, const vshCmd *cmd)
7028 virStorageVolPtr vol;
7030 if (!vshConnectionUsability(ctl, ctl->conn))
7031 return FALSE;
7033 if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
7034 VSH_BYUUID)))
7035 return FALSE;
7037 vshPrint(ctl, "%s\n", virStorageVolGetName(vol));
7038 virStorageVolFree(vol);
7039 return TRUE;
7044 * "vol-pool" command
7046 static const vshCmdInfo info_vol_pool[] = {
7047 {"help", N_("returns the storage pool for a given volume key or path")},
7048 {"desc", ""},
7049 {NULL, NULL}
7052 static const vshCmdOptDef opts_vol_pool[] = {
7053 {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")},
7054 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")},
7055 {NULL, 0, 0, NULL}
7058 static int
7059 cmdVolPool(vshControl *ctl, const vshCmd *cmd)
7061 virStoragePoolPtr pool;
7062 virStorageVolPtr vol;
7063 char uuid[VIR_UUID_STRING_BUFLEN];
7065 /* Check the connection to libvirtd daemon is still working */
7066 if (!vshConnectionUsability(ctl, ctl->conn))
7067 return FALSE;
7069 /* Use the supplied string to locate the volume */
7070 if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", "pool", NULL,
7071 VSH_BYUUID))) {
7072 return FALSE;
7075 /* Look up the parent storage pool for the volume */
7076 pool = virStoragePoolLookupByVolume(vol);
7077 if (pool == NULL) {
7078 vshError(ctl, "%s", _("failed to get parent pool"));
7079 virStorageVolFree(vol);
7080 return FALSE;
7083 /* Return the requested details of the parent storage pool */
7084 if (vshCommandOptBool(cmd, "uuid")) {
7085 /* Retrieve and return pool UUID string */
7086 if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0)
7087 vshPrint(ctl, "%s\n", uuid);
7088 } else {
7089 /* Return the storage pool name */
7090 vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
7093 /* Cleanup */
7094 virStorageVolFree(vol);
7095 virStoragePoolFree(pool);
7096 return TRUE;
7101 * "vol-key" command
7103 static const vshCmdInfo info_vol_key[] = {
7104 {"help", N_("returns the volume key for a given volume name or path")},
7105 {"desc", ""},
7106 {NULL, NULL}
7109 static const vshCmdOptDef opts_vol_key[] = {
7110 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7111 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")},
7112 {NULL, 0, 0, NULL}
7115 static int
7116 cmdVolKey(vshControl *ctl, const vshCmd *cmd)
7118 virStorageVolPtr vol;
7120 if (!vshConnectionUsability(ctl, ctl->conn))
7121 return FALSE;
7123 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
7124 return FALSE;
7126 vshPrint(ctl, "%s\n", virStorageVolGetKey(vol));
7127 virStorageVolFree(vol);
7128 return TRUE;
7134 * "vol-path" command
7136 static const vshCmdInfo info_vol_path[] = {
7137 {"help", N_("returns the volume path for a given volume name or key")},
7138 {"desc", ""},
7139 {NULL, NULL}
7142 static const vshCmdOptDef opts_vol_path[] = {
7143 {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
7144 {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")},
7145 {NULL, 0, 0, NULL}
7148 static int
7149 cmdVolPath(vshControl *ctl, const vshCmd *cmd)
7151 virStorageVolPtr vol;
7152 char *name = NULL;
7154 if (!vshConnectionUsability(ctl, ctl->conn))
7155 return FALSE;
7157 if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) {
7158 return FALSE;
7161 vshPrint(ctl, "%s\n", virStorageVolGetPath(vol));
7162 virStorageVolFree(vol);
7163 return TRUE;
7168 * "secret-define" command
7170 static const vshCmdInfo info_secret_define[] = {
7171 {"help", N_("define or modify a secret from an XML file")},
7172 {"desc", N_("Define or modify a secret.")},
7173 {NULL, NULL}
7176 static const vshCmdOptDef opts_secret_define[] = {
7177 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")},
7178 {NULL, 0, 0, NULL}
7181 static int
7182 cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
7184 char *from, *buffer;
7185 virSecretPtr res;
7186 char uuid[VIR_UUID_STRING_BUFLEN];
7188 if (!vshConnectionUsability(ctl, ctl->conn))
7189 return FALSE;
7191 from = vshCommandOptString(cmd, "file", NULL);
7192 if (!from)
7193 return FALSE;
7195 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
7196 return FALSE;
7198 res = virSecretDefineXML(ctl->conn, buffer, 0);
7199 VIR_FREE(buffer);
7201 if (res == NULL) {
7202 vshError(ctl, _("Failed to set attributes from %s"), from);
7203 return FALSE;
7205 if (virSecretGetUUIDString(res, &(uuid[0])) < 0) {
7206 vshError(ctl, "%s", _("Failed to get UUID of created secret"));
7207 virSecretFree(res);
7208 return FALSE;
7210 vshPrint(ctl, _("Secret %s created\n"), uuid);
7211 virSecretFree(res);
7212 return TRUE;
7216 * "secret-dumpxml" command
7218 static const vshCmdInfo info_secret_dumpxml[] = {
7219 {"help", N_("secret attributes in XML")},
7220 {"desc", N_("Output attributes of a secret as an XML dump to stdout.")},
7221 {NULL, NULL}
7224 static const vshCmdOptDef opts_secret_dumpxml[] = {
7225 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7226 {NULL, 0, 0, NULL}
7229 static int
7230 cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
7232 virSecretPtr secret;
7233 int ret = FALSE;
7234 char *xml;
7236 if (!vshConnectionUsability(ctl, ctl->conn))
7237 return FALSE;
7239 secret = vshCommandOptSecret(ctl, cmd, NULL);
7240 if (secret == NULL)
7241 return FALSE;
7243 xml = virSecretGetXMLDesc(secret, 0);
7244 if (xml == NULL)
7245 goto cleanup;
7246 vshPrint(ctl, "%s", xml);
7247 VIR_FREE(xml);
7248 ret = TRUE;
7250 cleanup:
7251 virSecretFree(secret);
7252 return ret;
7256 * "secret-set-value" command
7258 static const vshCmdInfo info_secret_set_value[] = {
7259 {"help", N_("set a secret value")},
7260 {"desc", N_("Set a secret value.")},
7261 {NULL, NULL}
7264 static const vshCmdOptDef opts_secret_set_value[] = {
7265 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7266 {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")},
7267 {NULL, 0, 0, NULL}
7270 static int
7271 cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
7273 virSecretPtr secret;
7274 size_t value_size;
7275 char *base64, *value;
7276 int found, res, ret = FALSE;
7278 if (!vshConnectionUsability(ctl, ctl->conn))
7279 return FALSE;
7281 secret = vshCommandOptSecret(ctl, cmd, NULL);
7282 if (secret == NULL)
7283 return FALSE;
7285 base64 = vshCommandOptString(cmd, "base64", &found);
7286 if (!base64)
7287 goto cleanup;
7289 if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
7290 vshError(ctl, "%s", _("Invalid base64 data"));
7291 goto cleanup;
7293 if (value == NULL) {
7294 vshError(ctl, "%s", _("Failed to allocate memory"));
7295 return FALSE;
7298 res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
7299 memset(value, 0, value_size);
7300 VIR_FREE(value);
7302 if (res != 0) {
7303 vshError(ctl, "%s", _("Failed to set secret value"));
7304 goto cleanup;
7306 vshPrint(ctl, "%s", _("Secret value set\n"));
7307 ret = TRUE;
7309 cleanup:
7310 virSecretFree(secret);
7311 return ret;
7315 * "secret-get-value" command
7317 static const vshCmdInfo info_secret_get_value[] = {
7318 {"help", N_("Output a secret value")},
7319 {"desc", N_("Output a secret value to stdout.")},
7320 {NULL, NULL}
7323 static const vshCmdOptDef opts_secret_get_value[] = {
7324 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7325 {NULL, 0, 0, NULL}
7328 static int
7329 cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
7331 virSecretPtr secret;
7332 char *base64;
7333 unsigned char *value;
7334 size_t value_size;
7335 int ret = FALSE;
7337 if (!vshConnectionUsability(ctl, ctl->conn))
7338 return FALSE;
7340 secret = vshCommandOptSecret(ctl, cmd, NULL);
7341 if (secret == NULL)
7342 return FALSE;
7344 value = virSecretGetValue(secret, &value_size, 0);
7345 if (value == NULL)
7346 goto cleanup;
7348 base64_encode_alloc((char *)value, value_size, &base64);
7349 memset(value, 0, value_size);
7350 VIR_FREE(value);
7352 if (base64 == NULL) {
7353 vshError(ctl, "%s", _("Failed to allocate memory"));
7354 goto cleanup;
7356 vshPrint(ctl, "%s", base64);
7357 memset(base64, 0, strlen(base64));
7358 VIR_FREE(base64);
7359 ret = TRUE;
7361 cleanup:
7362 virSecretFree(secret);
7363 return ret;
7367 * "secret-undefine" command
7369 static const vshCmdInfo info_secret_undefine[] = {
7370 {"help", N_("undefine a secret")},
7371 {"desc", N_("Undefine a secret.")},
7372 {NULL, NULL}
7375 static const vshCmdOptDef opts_secret_undefine[] = {
7376 {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
7377 {NULL, 0, 0, NULL}
7380 static int
7381 cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
7383 virSecretPtr secret;
7384 int ret = FALSE;
7385 char *uuid;
7387 if (!vshConnectionUsability(ctl, ctl->conn))
7388 return FALSE;
7390 secret = vshCommandOptSecret(ctl, cmd, &uuid);
7391 if (secret == NULL)
7392 return FALSE;
7394 if (virSecretUndefine(secret) < 0) {
7395 vshError(ctl, _("Failed to delete secret %s"), uuid);
7396 goto cleanup;
7398 vshPrint(ctl, _("Secret %s deleted\n"), uuid);
7399 ret = TRUE;
7401 cleanup:
7402 virSecretFree(secret);
7403 return ret;
7407 * "secret-list" command
7409 static const vshCmdInfo info_secret_list[] = {
7410 {"help", N_("list secrets")},
7411 {"desc", N_("Returns a list of secrets")},
7412 {NULL, NULL}
7415 static int
7416 cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7418 int maxuuids = 0, i;
7419 char **uuids = NULL;
7421 if (!vshConnectionUsability(ctl, ctl->conn))
7422 return FALSE;
7424 maxuuids = virConnectNumOfSecrets(ctl->conn);
7425 if (maxuuids < 0) {
7426 vshError(ctl, "%s", _("Failed to list secrets"));
7427 return FALSE;
7429 uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);
7431 maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
7432 if (maxuuids < 0) {
7433 vshError(ctl, "%s", _("Failed to list secrets"));
7434 VIR_FREE(uuids);
7435 return FALSE;
7438 qsort(uuids, maxuuids, sizeof(char *), namesorter);
7440 vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage"));
7441 vshPrintExtra(ctl, "-----------------------------------------------------------\n");
7443 for (i = 0; i < maxuuids; i++) {
7444 virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]);
7445 const char *usageType = NULL;
7447 if (!sec) {
7448 VIR_FREE(uuids[i]);
7449 continue;
7452 switch (virSecretGetUsageType(sec)) {
7453 case VIR_SECRET_USAGE_TYPE_VOLUME:
7454 usageType = _("Volume");
7455 break;
7458 if (usageType) {
7459 vshPrint(ctl, "%-36s %s %s\n",
7460 uuids[i], usageType,
7461 virSecretGetUsageID(sec));
7462 } else {
7463 vshPrint(ctl, "%-36s %s\n",
7464 uuids[i], _("Unused"));
7466 virSecretFree(sec);
7467 VIR_FREE(uuids[i]);
7469 VIR_FREE(uuids);
7470 return TRUE;
7475 * "version" command
7477 static const vshCmdInfo info_version[] = {
7478 {"help", N_("show version")},
7479 {"desc", N_("Display the system version information.")},
7480 {NULL, NULL}
7484 static int
7485 cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7487 unsigned long hvVersion;
7488 const char *hvType;
7489 unsigned long libVersion;
7490 unsigned long includeVersion;
7491 unsigned long apiVersion;
7492 int ret;
7493 unsigned int major;
7494 unsigned int minor;
7495 unsigned int rel;
7497 if (!vshConnectionUsability(ctl, ctl->conn))
7498 return FALSE;
7500 hvType = virConnectGetType(ctl->conn);
7501 if (hvType == NULL) {
7502 vshError(ctl, "%s", _("failed to get hypervisor type"));
7503 return FALSE;
7506 includeVersion = LIBVIR_VERSION_NUMBER;
7507 major = includeVersion / 1000000;
7508 includeVersion %= 1000000;
7509 minor = includeVersion / 1000;
7510 rel = includeVersion % 1000;
7511 vshPrint(ctl, _("Compiled against library: libvir %d.%d.%d\n"),
7512 major, minor, rel);
7514 ret = virGetVersion(&libVersion, hvType, &apiVersion);
7515 if (ret < 0) {
7516 vshError(ctl, "%s", _("failed to get the library version"));
7517 return FALSE;
7519 major = libVersion / 1000000;
7520 libVersion %= 1000000;
7521 minor = libVersion / 1000;
7522 rel = libVersion % 1000;
7523 vshPrint(ctl, _("Using library: libvir %d.%d.%d\n"),
7524 major, minor, rel);
7526 major = apiVersion / 1000000;
7527 apiVersion %= 1000000;
7528 minor = apiVersion / 1000;
7529 rel = apiVersion % 1000;
7530 vshPrint(ctl, _("Using API: %s %d.%d.%d\n"), hvType,
7531 major, minor, rel);
7533 ret = virConnectGetVersion(ctl->conn, &hvVersion);
7534 if (ret < 0) {
7535 vshError(ctl, "%s", _("failed to get the hypervisor version"));
7536 return FALSE;
7538 if (hvVersion == 0) {
7539 vshPrint(ctl,
7540 _("Cannot extract running %s hypervisor version\n"), hvType);
7541 } else {
7542 major = hvVersion / 1000000;
7543 hvVersion %= 1000000;
7544 minor = hvVersion / 1000;
7545 rel = hvVersion % 1000;
7547 vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"),
7548 hvType, major, minor, rel);
7550 return TRUE;
7554 * "nodedev-list" command
7556 static const vshCmdInfo info_node_list_devices[] = {
7557 {"help", N_("enumerate devices on this host")},
7558 {"desc", ""},
7559 {NULL, NULL}
7562 static const vshCmdOptDef opts_node_list_devices[] = {
7563 {"tree", VSH_OT_BOOL, 0, N_("list devices in a tree")},
7564 {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability name")},
7565 {NULL, 0, 0, NULL}
7568 #define MAX_DEPTH 100
7569 #define INDENT_SIZE 4
7570 #define INDENT_BUFLEN ((MAX_DEPTH * INDENT_SIZE) + 1)
7572 static void
7573 cmdNodeListDevicesPrint(vshControl *ctl,
7574 char **devices,
7575 char **parents,
7576 int num_devices,
7577 int devid,
7578 int lastdev,
7579 unsigned int depth,
7580 unsigned int indentIdx,
7581 char *indentBuf)
7583 int i;
7584 int nextlastdev = -1;
7586 /* Prepare indent for this device, but not if at root */
7587 if (depth && depth < MAX_DEPTH) {
7588 indentBuf[indentIdx] = '+';
7589 indentBuf[indentIdx+1] = '-';
7590 indentBuf[indentIdx+2] = ' ';
7591 indentBuf[indentIdx+3] = '\0';
7594 /* Print this device */
7595 vshPrint(ctl, "%s", indentBuf);
7596 vshPrint(ctl, "%s\n", devices[devid]);
7599 /* Update indent to show '|' or ' ' for child devices */
7600 if (depth && depth < MAX_DEPTH) {
7601 if (devid == lastdev)
7602 indentBuf[indentIdx] = ' ';
7603 else
7604 indentBuf[indentIdx] = '|';
7605 indentBuf[indentIdx+1] = ' ';
7606 indentIdx+=2;
7609 /* Determine the index of the last child device */
7610 for (i = 0 ; i < num_devices ; i++) {
7611 if (parents[i] &&
7612 STREQ(parents[i], devices[devid])) {
7613 nextlastdev = i;
7617 /* If there is a child device, then print another blank line */
7618 if (nextlastdev != -1) {
7619 vshPrint(ctl, "%s", indentBuf);
7620 vshPrint(ctl, " |\n");
7623 /* Finally print all children */
7624 if (depth < MAX_DEPTH)
7625 indentBuf[indentIdx] = ' ';
7626 for (i = 0 ; i < num_devices ; i++) {
7627 if (depth < MAX_DEPTH) {
7628 indentBuf[indentIdx] = ' ';
7629 indentBuf[indentIdx+1] = ' ';
7631 if (parents[i] &&
7632 STREQ(parents[i], devices[devid]))
7633 cmdNodeListDevicesPrint(ctl, devices, parents,
7634 num_devices, i, nextlastdev,
7635 depth + 1, indentIdx + 2, indentBuf);
7636 if (depth < MAX_DEPTH)
7637 indentBuf[indentIdx] = '\0';
7640 /* If there was no child device, and we're the last in
7641 * a list of devices, then print another blank line */
7642 if (nextlastdev == -1 && devid == lastdev) {
7643 vshPrint(ctl, "%s", indentBuf);
7644 vshPrint(ctl, "\n");
7648 static int
7649 cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7651 char *cap;
7652 char **devices;
7653 int found, num_devices, i;
7654 int tree = vshCommandOptBool(cmd, "tree");
7656 if (!vshConnectionUsability(ctl, ctl->conn))
7657 return FALSE;
7659 cap = vshCommandOptString(cmd, "cap", &found);
7660 if (!found)
7661 cap = NULL;
7663 num_devices = virNodeNumOfDevices(ctl->conn, cap, 0);
7664 if (num_devices < 0) {
7665 vshError(ctl, "%s", _("Failed to count node devices"));
7666 return FALSE;
7667 } else if (num_devices == 0) {
7668 return TRUE;
7671 devices = vshMalloc(ctl, sizeof(char *) * num_devices);
7672 num_devices =
7673 virNodeListDevices(ctl->conn, cap, devices, num_devices, 0);
7674 if (num_devices < 0) {
7675 vshError(ctl, "%s", _("Failed to list node devices"));
7676 VIR_FREE(devices);
7677 return FALSE;
7679 qsort(&devices[0], num_devices, sizeof(char*), namesorter);
7680 if (tree) {
7681 char indentBuf[INDENT_BUFLEN];
7682 char **parents = vshMalloc(ctl, sizeof(char *) * num_devices);
7683 for (i = 0; i < num_devices; i++) {
7684 virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]);
7685 if (dev && STRNEQ(devices[i], "computer")) {
7686 const char *parent = virNodeDeviceGetParent(dev);
7687 parents[i] = parent ? vshStrdup(ctl, parent) : NULL;
7688 } else {
7689 parents[i] = NULL;
7691 virNodeDeviceFree(dev);
7693 for (i = 0 ; i < num_devices ; i++) {
7694 memset(indentBuf, '\0', sizeof indentBuf);
7695 if (parents[i] == NULL)
7696 cmdNodeListDevicesPrint(ctl,
7697 devices,
7698 parents,
7699 num_devices,
7704 indentBuf);
7706 for (i = 0 ; i < num_devices ; i++) {
7707 VIR_FREE(devices[i]);
7708 VIR_FREE(parents[i]);
7710 VIR_FREE(parents);
7711 } else {
7712 for (i = 0; i < num_devices; i++) {
7713 vshPrint(ctl, "%s\n", devices[i]);
7714 VIR_FREE(devices[i]);
7717 VIR_FREE(devices);
7718 return TRUE;
7722 * "nodedev-dumpxml" command
7724 static const vshCmdInfo info_node_device_dumpxml[] = {
7725 {"help", N_("node device details in XML")},
7726 {"desc", N_("Output the node device details as an XML dump to stdout.")},
7727 {NULL, NULL}
7731 static const vshCmdOptDef opts_node_device_dumpxml[] = {
7732 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7733 {NULL, 0, 0, NULL}
7736 static int
7737 cmdNodeDeviceDumpXML (vshControl *ctl, const vshCmd *cmd)
7739 const char *name;
7740 virNodeDevicePtr device;
7741 char *xml;
7743 if (!vshConnectionUsability(ctl, ctl->conn))
7744 return FALSE;
7745 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7746 return FALSE;
7747 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7748 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7749 return FALSE;
7752 xml = virNodeDeviceGetXMLDesc(device, 0);
7753 if (!xml) {
7754 virNodeDeviceFree(device);
7755 return FALSE;
7758 vshPrint(ctl, "%s\n", xml);
7759 VIR_FREE(xml);
7760 virNodeDeviceFree(device);
7761 return TRUE;
7765 * "nodedev-dettach" command
7767 static const vshCmdInfo info_node_device_dettach[] = {
7768 {"help", N_("dettach node device from its device driver")},
7769 {"desc", N_("Dettach node device from its device driver before assigning to a domain.")},
7770 {NULL, NULL}
7774 static const vshCmdOptDef opts_node_device_dettach[] = {
7775 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7776 {NULL, 0, 0, NULL}
7779 static int
7780 cmdNodeDeviceDettach (vshControl *ctl, const vshCmd *cmd)
7782 const char *name;
7783 virNodeDevicePtr device;
7784 int ret = TRUE;
7786 if (!vshConnectionUsability(ctl, ctl->conn))
7787 return FALSE;
7788 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7789 return FALSE;
7790 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7791 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7792 return FALSE;
7795 if (virNodeDeviceDettach(device) == 0) {
7796 vshPrint(ctl, _("Device %s dettached\n"), name);
7797 } else {
7798 vshError(ctl, _("Failed to dettach device %s"), name);
7799 ret = FALSE;
7801 virNodeDeviceFree(device);
7802 return ret;
7806 * "nodedev-reattach" command
7808 static const vshCmdInfo info_node_device_reattach[] = {
7809 {"help", N_("reattach node device to its device driver")},
7810 {"desc", N_("Reattach node device to its device driver once released by the domain.")},
7811 {NULL, NULL}
7815 static const vshCmdOptDef opts_node_device_reattach[] = {
7816 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7817 {NULL, 0, 0, NULL}
7820 static int
7821 cmdNodeDeviceReAttach (vshControl *ctl, const vshCmd *cmd)
7823 const char *name;
7824 virNodeDevicePtr device;
7825 int ret = TRUE;
7827 if (!vshConnectionUsability(ctl, ctl->conn))
7828 return FALSE;
7829 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7830 return FALSE;
7831 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7832 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7833 return FALSE;
7836 if (virNodeDeviceReAttach(device) == 0) {
7837 vshPrint(ctl, _("Device %s re-attached\n"), name);
7838 } else {
7839 vshError(ctl, _("Failed to re-attach device %s"), name);
7840 ret = FALSE;
7842 virNodeDeviceFree(device);
7843 return ret;
7847 * "nodedev-reset" command
7849 static const vshCmdInfo info_node_device_reset[] = {
7850 {"help", N_("reset node device")},
7851 {"desc", N_("Reset node device before or after assigning to a domain.")},
7852 {NULL, NULL}
7856 static const vshCmdOptDef opts_node_device_reset[] = {
7857 {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")},
7858 {NULL, 0, 0, NULL}
7861 static int
7862 cmdNodeDeviceReset (vshControl *ctl, const vshCmd *cmd)
7864 const char *name;
7865 virNodeDevicePtr device;
7866 int ret = TRUE;
7868 if (!vshConnectionUsability(ctl, ctl->conn))
7869 return FALSE;
7870 if (!(name = vshCommandOptString(cmd, "device", NULL)))
7871 return FALSE;
7872 if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) {
7873 vshError(ctl, "%s '%s'", _("Could not find matching device"), name);
7874 return FALSE;
7877 if (virNodeDeviceReset(device) == 0) {
7878 vshPrint(ctl, _("Device %s reset\n"), name);
7879 } else {
7880 vshError(ctl, _("Failed to reset device %s"), name);
7881 ret = FALSE;
7883 virNodeDeviceFree(device);
7884 return ret;
7888 * "hostkey" command
7890 static const vshCmdInfo info_hostname[] = {
7891 {"help", N_("print the hypervisor hostname")},
7892 {"desc", ""},
7893 {NULL, NULL}
7896 static int
7897 cmdHostname (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7899 char *hostname;
7901 if (!vshConnectionUsability(ctl, ctl->conn))
7902 return FALSE;
7904 hostname = virConnectGetHostname (ctl->conn);
7905 if (hostname == NULL) {
7906 vshError(ctl, "%s", _("failed to get hostname"));
7907 return FALSE;
7910 vshPrint (ctl, "%s\n", hostname);
7911 VIR_FREE(hostname);
7913 return TRUE;
7917 * "uri" command
7919 static const vshCmdInfo info_uri[] = {
7920 {"help", N_("print the hypervisor canonical URI")},
7921 {"desc", ""},
7922 {NULL, NULL}
7925 static int
7926 cmdURI (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
7928 char *uri;
7930 if (!vshConnectionUsability(ctl, ctl->conn))
7931 return FALSE;
7933 uri = virConnectGetURI (ctl->conn);
7934 if (uri == NULL) {
7935 vshError(ctl, "%s", _("failed to get URI"));
7936 return FALSE;
7939 vshPrint (ctl, "%s\n", uri);
7940 VIR_FREE(uri);
7942 return TRUE;
7946 * "vncdisplay" command
7948 static const vshCmdInfo info_vncdisplay[] = {
7949 {"help", N_("vnc display")},
7950 {"desc", N_("Output the IP address and port number for the VNC display.")},
7951 {NULL, NULL}
7954 static const vshCmdOptDef opts_vncdisplay[] = {
7955 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
7956 {NULL, 0, 0, NULL}
7959 static int
7960 cmdVNCDisplay(vshControl *ctl, const vshCmd *cmd)
7962 xmlDocPtr xml = NULL;
7963 xmlXPathObjectPtr obj = NULL;
7964 xmlXPathContextPtr ctxt = NULL;
7965 virDomainPtr dom;
7966 int ret = FALSE;
7967 int port = 0;
7968 char *doc;
7970 if (!vshConnectionUsability(ctl, ctl->conn))
7971 return FALSE;
7973 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
7974 return FALSE;
7976 doc = virDomainGetXMLDesc(dom, 0);
7977 if (!doc)
7978 goto cleanup;
7980 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
7981 XML_PARSE_NOENT | XML_PARSE_NONET |
7982 XML_PARSE_NOWARNING);
7983 VIR_FREE(doc);
7984 if (!xml)
7985 goto cleanup;
7986 ctxt = xmlXPathNewContext(xml);
7987 if (!ctxt)
7988 goto cleanup;
7990 obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@port)", ctxt);
7991 if ((obj == NULL) || (obj->type != XPATH_STRING) ||
7992 (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
7993 goto cleanup;
7995 if (virStrToLong_i((const char *)obj->stringval, NULL, 10, &port) || port < 0)
7996 goto cleanup;
7997 xmlXPathFreeObject(obj);
7999 obj = xmlXPathEval(BAD_CAST "string(/domain/devices/graphics[@type='vnc']/@listen)", ctxt);
8000 if ((obj == NULL) || (obj->type != XPATH_STRING) ||
8001 (obj->stringval == NULL) || (obj->stringval[0] == 0) ||
8002 STREQ((const char*)obj->stringval, "0.0.0.0")) {
8003 vshPrint(ctl, ":%d\n", port-5900);
8004 } else {
8005 vshPrint(ctl, "%s:%d\n", (const char *)obj->stringval, port-5900);
8007 xmlXPathFreeObject(obj);
8008 obj = NULL;
8009 ret = TRUE;
8011 cleanup:
8012 xmlXPathFreeObject(obj);
8013 xmlXPathFreeContext(ctxt);
8014 if (xml)
8015 xmlFreeDoc(xml);
8016 virDomainFree(dom);
8017 return ret;
8021 * "ttyconsole" command
8023 static const vshCmdInfo info_ttyconsole[] = {
8024 {"help", N_("tty console")},
8025 {"desc", N_("Output the device for the TTY console.")},
8026 {NULL, NULL}
8029 static const vshCmdOptDef opts_ttyconsole[] = {
8030 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8031 {NULL, 0, 0, NULL}
8034 static int
8035 cmdTTYConsole(vshControl *ctl, const vshCmd *cmd)
8037 xmlDocPtr xml = NULL;
8038 xmlXPathObjectPtr obj = NULL;
8039 xmlXPathContextPtr ctxt = NULL;
8040 virDomainPtr dom;
8041 int ret = FALSE;
8042 char *doc;
8044 if (!vshConnectionUsability(ctl, ctl->conn))
8045 return FALSE;
8047 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8048 return FALSE;
8050 doc = virDomainGetXMLDesc(dom, 0);
8051 if (!doc)
8052 goto cleanup;
8054 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
8055 XML_PARSE_NOENT | XML_PARSE_NONET |
8056 XML_PARSE_NOWARNING);
8057 VIR_FREE(doc);
8058 if (!xml)
8059 goto cleanup;
8060 ctxt = xmlXPathNewContext(xml);
8061 if (!ctxt)
8062 goto cleanup;
8064 obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt);
8065 if ((obj == NULL) || (obj->type != XPATH_STRING) ||
8066 (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
8067 goto cleanup;
8069 vshPrint(ctl, "%s\n", (const char *)obj->stringval);
8070 ret = TRUE;
8072 cleanup:
8073 xmlXPathFreeObject(obj);
8074 xmlXPathFreeContext(ctxt);
8075 if (xml)
8076 xmlFreeDoc(xml);
8077 virDomainFree(dom);
8078 return ret;
8082 * "attach-device" command
8084 static const vshCmdInfo info_attach_device[] = {
8085 {"help", N_("attach device from an XML file")},
8086 {"desc", N_("Attach device from an XML <file>.")},
8087 {NULL, NULL}
8090 static const vshCmdOptDef opts_attach_device[] = {
8091 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8092 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
8093 {"persistent", VSH_OT_BOOL, 0, N_("persist device attachment")},
8094 {NULL, 0, 0, NULL}
8097 static int
8098 cmdAttachDevice(vshControl *ctl, const vshCmd *cmd)
8100 virDomainPtr dom;
8101 char *from;
8102 char *buffer;
8103 int ret = TRUE;
8104 int found;
8105 unsigned int flags;
8107 if (!vshConnectionUsability(ctl, ctl->conn))
8108 return FALSE;
8110 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8111 return FALSE;
8113 from = vshCommandOptString(cmd, "file", &found);
8114 if (!found) {
8115 virDomainFree(dom);
8116 return FALSE;
8119 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
8120 virshReportError(ctl);
8121 virDomainFree(dom);
8122 return FALSE;
8125 if (vshCommandOptBool(cmd, "persistent")) {
8126 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8127 if (virDomainIsActive(dom) == 1)
8128 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8129 ret = virDomainAttachDeviceFlags(dom, buffer, flags);
8130 } else {
8131 ret = virDomainAttachDevice(dom, buffer);
8133 VIR_FREE(buffer);
8135 if (ret < 0) {
8136 vshError(ctl, _("Failed to attach device from %s"), from);
8137 virDomainFree(dom);
8138 return FALSE;
8139 } else {
8140 vshPrint(ctl, "%s", _("Device attached successfully\n"));
8143 virDomainFree(dom);
8144 return TRUE;
8149 * "detach-device" command
8151 static const vshCmdInfo info_detach_device[] = {
8152 {"help", N_("detach device from an XML file")},
8153 {"desc", N_("Detach device from an XML <file>")},
8154 {NULL, NULL}
8157 static const vshCmdOptDef opts_detach_device[] = {
8158 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8159 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
8160 {"persistent", VSH_OT_BOOL, 0, N_("persist device detachment")},
8161 {NULL, 0, 0, NULL}
8164 static int
8165 cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
8167 virDomainPtr dom;
8168 char *from;
8169 char *buffer;
8170 int ret = TRUE;
8171 int found;
8172 unsigned int flags;
8174 if (!vshConnectionUsability(ctl, ctl->conn))
8175 return FALSE;
8177 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8178 return FALSE;
8180 from = vshCommandOptString(cmd, "file", &found);
8181 if (!found) {
8182 virDomainFree(dom);
8183 return FALSE;
8186 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
8187 virshReportError(ctl);
8188 virDomainFree(dom);
8189 return FALSE;
8192 if (vshCommandOptBool(cmd, "persistent")) {
8193 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8194 if (virDomainIsActive(dom) == 1)
8195 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8196 ret = virDomainDetachDeviceFlags(dom, buffer, flags);
8197 } else {
8198 ret = virDomainDetachDevice(dom, buffer);
8200 VIR_FREE(buffer);
8202 if (ret < 0) {
8203 vshError(ctl, _("Failed to detach device from %s"), from);
8204 virDomainFree(dom);
8205 return FALSE;
8206 } else {
8207 vshPrint(ctl, "%s", _("Device detached successfully\n"));
8210 virDomainFree(dom);
8211 return TRUE;
8216 * "update-device" command
8218 static const vshCmdInfo info_update_device[] = {
8219 {"help", N_("update device from an XML file")},
8220 {"desc", N_("Update device from an XML <file>.")},
8221 {NULL, NULL}
8224 static const vshCmdOptDef opts_update_device[] = {
8225 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8226 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("XML file")},
8227 {"persistent", VSH_OT_BOOL, 0, N_("persist device update")},
8228 {NULL, 0, 0, NULL}
8231 static int
8232 cmdUpdateDevice(vshControl *ctl, const vshCmd *cmd)
8234 virDomainPtr dom;
8235 char *from;
8236 char *buffer;
8237 int ret = TRUE;
8238 int found;
8239 unsigned int flags;
8241 if (!vshConnectionUsability(ctl, ctl->conn))
8242 return FALSE;
8244 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8245 return FALSE;
8247 from = vshCommandOptString(cmd, "file", &found);
8248 if (!found) {
8249 virDomainFree(dom);
8250 return FALSE;
8253 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
8254 virshReportError(ctl);
8255 virDomainFree(dom);
8256 return FALSE;
8259 if (vshCommandOptBool(cmd, "persistent")) {
8260 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8261 if (virDomainIsActive(dom) == 1)
8262 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8263 } else {
8264 flags = VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8266 ret = virDomainUpdateDeviceFlags(dom, buffer, flags);
8267 VIR_FREE(buffer);
8269 if (ret < 0) {
8270 vshError(ctl, _("Failed to update device from %s"), from);
8271 virDomainFree(dom);
8272 return FALSE;
8273 } else {
8274 vshPrint(ctl, "%s", _("Device updated successfully\n"));
8277 virDomainFree(dom);
8278 return TRUE;
8283 * "attach-interface" command
8285 static const vshCmdInfo info_attach_interface[] = {
8286 {"help", N_("attach network interface")},
8287 {"desc", N_("Attach new network interface.")},
8288 {NULL, NULL}
8291 static const vshCmdOptDef opts_attach_interface[] = {
8292 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8293 {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface type")},
8294 {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of network interface")},
8295 {"target", VSH_OT_DATA, 0, N_("target network name")},
8296 {"mac", VSH_OT_DATA, 0, N_("MAC address")},
8297 {"script", VSH_OT_DATA, 0, N_("script used to bridge network interface")},
8298 {"model", VSH_OT_DATA, 0, N_("model type")},
8299 {"persistent", VSH_OT_BOOL, 0, N_("persist interface attachment")},
8300 {NULL, 0, 0, NULL}
8303 static int
8304 cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
8306 virDomainPtr dom = NULL;
8307 char *mac, *target, *script, *type, *source, *model;
8308 int typ, ret = FALSE;
8309 unsigned int flags;
8310 virBuffer buf = VIR_BUFFER_INITIALIZER;
8311 char *xml;
8313 if (!vshConnectionUsability(ctl, ctl->conn))
8314 goto cleanup;
8316 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8317 goto cleanup;
8319 if (!(type = vshCommandOptString(cmd, "type", NULL)))
8320 goto cleanup;
8322 source = vshCommandOptString(cmd, "source", NULL);
8323 target = vshCommandOptString(cmd, "target", NULL);
8324 mac = vshCommandOptString(cmd, "mac", NULL);
8325 script = vshCommandOptString(cmd, "script", NULL);
8326 model = vshCommandOptString(cmd, "model", NULL);
8328 /* check interface type */
8329 if (STREQ(type, "network")) {
8330 typ = 1;
8331 } else if (STREQ(type, "bridge")) {
8332 typ = 2;
8333 } else {
8334 vshError(ctl, _("No support for %s in command 'attach-interface'"),
8335 type);
8336 goto cleanup;
8339 /* Make XML of interface */
8340 virBufferVSprintf(&buf, "<interface type='%s'>\n", type);
8342 if (typ == 1)
8343 virBufferVSprintf(&buf, " <source network='%s'/>\n", source);
8344 else if (typ == 2)
8345 virBufferVSprintf(&buf, " <source bridge='%s'/>\n", source);
8347 if (target != NULL)
8348 virBufferVSprintf(&buf, " <target dev='%s'/>\n", target);
8349 if (mac != NULL)
8350 virBufferVSprintf(&buf, " <mac address='%s'/>\n", mac);
8351 if (script != NULL)
8352 virBufferVSprintf(&buf, " <script path='%s'/>\n", script);
8353 if (model != NULL)
8354 virBufferVSprintf(&buf, " <model type='%s'/>\n", model);
8356 virBufferAddLit(&buf, "</interface>\n");
8358 if (virBufferError(&buf)) {
8359 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
8360 return FALSE;
8363 xml = virBufferContentAndReset(&buf);
8365 if (vshCommandOptBool(cmd, "persistent")) {
8366 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8367 if (virDomainIsActive(dom) == 1)
8368 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8369 ret = virDomainAttachDeviceFlags(dom, xml, flags);
8370 } else {
8371 ret = virDomainAttachDevice(dom, xml);
8374 VIR_FREE(xml);
8376 if (ret != 0) {
8377 vshError(ctl, "%s", _("Failed to attach interface"));
8378 ret = FALSE;
8379 } else {
8380 vshPrint(ctl, "%s", _("Interface attached successfully\n"));
8381 ret = TRUE;
8384 cleanup:
8385 if (dom)
8386 virDomainFree(dom);
8387 virBufferFreeAndReset(&buf);
8388 return ret;
8392 * "detach-interface" command
8394 static const vshCmdInfo info_detach_interface[] = {
8395 {"help", N_("detach network interface")},
8396 {"desc", N_("Detach network interface.")},
8397 {NULL, NULL}
8400 static const vshCmdOptDef opts_detach_interface[] = {
8401 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8402 {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network interface type")},
8403 {"mac", VSH_OT_STRING, 0, N_("MAC address")},
8404 {"persistent", VSH_OT_BOOL, 0, N_("persist interface detachment")},
8405 {NULL, 0, 0, NULL}
8408 static int
8409 cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
8411 virDomainPtr dom = NULL;
8412 xmlDocPtr xml = NULL;
8413 xmlXPathObjectPtr obj=NULL;
8414 xmlXPathContextPtr ctxt = NULL;
8415 xmlNodePtr cur = NULL;
8416 xmlChar *tmp_mac = NULL;
8417 xmlBufferPtr xml_buf = NULL;
8418 char *doc, *mac =NULL, *type;
8419 char buf[64];
8420 int i = 0, diff_mac, ret = FALSE;
8421 unsigned int flags;
8423 if (!vshConnectionUsability(ctl, ctl->conn))
8424 goto cleanup;
8426 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8427 goto cleanup;
8429 if (!(type = vshCommandOptString(cmd, "type", NULL)))
8430 goto cleanup;
8432 mac = vshCommandOptString(cmd, "mac", NULL);
8434 doc = virDomainGetXMLDesc(dom, 0);
8435 if (!doc)
8436 goto cleanup;
8438 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
8439 XML_PARSE_NOENT | XML_PARSE_NONET |
8440 XML_PARSE_NOWARNING);
8441 VIR_FREE(doc);
8442 if (!xml) {
8443 vshError(ctl, "%s", _("Failed to get interface information"));
8444 goto cleanup;
8446 ctxt = xmlXPathNewContext(xml);
8447 if (!ctxt) {
8448 vshError(ctl, "%s", _("Failed to get interface information"));
8449 goto cleanup;
8452 sprintf(buf, "/domain/devices/interface[@type='%s']", type);
8453 obj = xmlXPathEval(BAD_CAST buf, ctxt);
8454 if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
8455 (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
8456 vshError(ctl, _("No found interface whose type is %s"), type);
8457 goto cleanup;
8460 if (!mac)
8461 goto hit;
8463 /* search mac */
8464 for (; i < obj->nodesetval->nodeNr; i++) {
8465 cur = obj->nodesetval->nodeTab[i]->children;
8466 while (cur != NULL) {
8467 if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, BAD_CAST "mac")) {
8468 tmp_mac = xmlGetProp(cur, BAD_CAST "address");
8469 diff_mac = virMacAddrCompare ((char *) tmp_mac, mac);
8470 xmlFree(tmp_mac);
8471 if (!diff_mac) {
8472 goto hit;
8475 cur = cur->next;
8478 vshError(ctl, _("No found interface whose MAC address is %s"), mac);
8479 goto cleanup;
8481 hit:
8482 xml_buf = xmlBufferCreate();
8483 if (!xml_buf) {
8484 vshError(ctl, "%s", _("Failed to allocate memory"));
8485 goto cleanup;
8488 if(xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0){
8489 vshError(ctl, "%s", _("Failed to create XML"));
8490 goto cleanup;
8493 if (vshCommandOptBool(cmd, "persistent")) {
8494 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8495 if (virDomainIsActive(dom) == 1)
8496 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8497 ret = virDomainDetachDeviceFlags(dom,
8498 (char *)xmlBufferContent(xml_buf),
8499 flags);
8500 } else {
8501 ret = virDomainDetachDevice(dom, (char *)xmlBufferContent(xml_buf));
8504 if (ret != 0) {
8505 vshError(ctl, "%s", _("Failed to detach interface"));
8506 ret = FALSE;
8507 } else {
8508 vshPrint(ctl, "%s", _("Interface detached successfully\n"));
8509 ret = TRUE;
8512 cleanup:
8513 if (dom)
8514 virDomainFree(dom);
8515 xmlXPathFreeObject(obj);
8516 xmlXPathFreeContext(ctxt);
8517 if (xml)
8518 xmlFreeDoc(xml);
8519 if (xml_buf)
8520 xmlBufferFree(xml_buf);
8521 return ret;
8525 * "attach-disk" command
8527 static const vshCmdInfo info_attach_disk[] = {
8528 {"help", N_("attach disk device")},
8529 {"desc", N_("Attach new disk device.")},
8530 {NULL, NULL}
8533 static const vshCmdOptDef opts_attach_disk[] = {
8534 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8535 {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of disk device")},
8536 {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
8537 {"driver", VSH_OT_STRING, 0, N_("driver of disk device")},
8538 {"subdriver", VSH_OT_STRING, 0, N_("subdriver of disk device")},
8539 {"type", VSH_OT_STRING, 0, N_("target device type")},
8540 {"mode", VSH_OT_STRING, 0, N_("mode of device reading and writing")},
8541 {"persistent", VSH_OT_BOOL, 0, N_("persist disk attachment")},
8542 {"sourcetype", VSH_OT_STRING, 0, N_("type of source (block|file)")},
8543 {NULL, 0, 0, NULL}
8546 static int
8547 cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
8549 virDomainPtr dom = NULL;
8550 char *source, *target, *driver, *subdriver, *type, *mode;
8551 int isFile = 0, ret = FALSE;
8552 unsigned int flags;
8553 char *stype;
8554 virBuffer buf = VIR_BUFFER_INITIALIZER;
8555 char *xml;
8557 if (!vshConnectionUsability(ctl, ctl->conn))
8558 goto cleanup;
8560 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8561 goto cleanup;
8563 if (!(source = vshCommandOptString(cmd, "source", NULL)))
8564 goto cleanup;
8566 if (!(target = vshCommandOptString(cmd, "target", NULL)))
8567 goto cleanup;
8569 driver = vshCommandOptString(cmd, "driver", NULL);
8570 subdriver = vshCommandOptString(cmd, "subdriver", NULL);
8571 type = vshCommandOptString(cmd, "type", NULL);
8572 mode = vshCommandOptString(cmd, "mode", NULL);
8573 stype = vshCommandOptString(cmd, "sourcetype", NULL);
8575 if (!stype) {
8576 if (driver && (STREQ(driver, "file") || STREQ(driver, "tap")))
8577 isFile = 1;
8578 } else if (STREQ(stype, "file")) {
8579 isFile = 1;
8580 } else if (STRNEQ(stype, "block")) {
8581 vshError(ctl, _("Unknown source type: '%s'"), stype);
8582 goto cleanup;
8585 if (mode) {
8586 if (STRNEQ(mode, "readonly") && STRNEQ(mode, "shareable")) {
8587 vshError(ctl, _("No support for %s in command 'attach-disk'"),
8588 mode);
8589 goto cleanup;
8593 /* Make XML of disk */
8594 virBufferVSprintf(&buf, "<disk type='%s'",
8595 (isFile) ? "file" : "block");
8596 if (type)
8597 virBufferVSprintf(&buf, " device='%s'", type);
8598 virBufferAddLit(&buf, ">\n");
8600 virBufferVSprintf(&buf, " <driver name='%s'",
8601 (driver) ? driver : "phy");
8602 if (subdriver)
8603 virBufferVSprintf(&buf, " type='%s'", subdriver);
8604 virBufferAddLit(&buf, "/>\n");
8606 virBufferVSprintf(&buf, " <source %s='%s'/>\n",
8607 (isFile) ? "file" : "dev",
8608 source);
8609 virBufferVSprintf(&buf, " <target dev='%s'/>\n", target);
8610 if (mode)
8611 virBufferVSprintf(&buf, " <%s/>\n", mode);
8613 virBufferAddLit(&buf, "</disk>\n");
8615 if (virBufferError(&buf)) {
8616 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
8617 return FALSE;
8620 xml = virBufferContentAndReset(&buf);
8622 if (vshCommandOptBool(cmd, "persistent")) {
8623 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8624 if (virDomainIsActive(dom) == 1)
8625 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8626 ret = virDomainAttachDeviceFlags(dom, xml, flags);
8627 } else {
8628 ret = virDomainAttachDevice(dom, xml);
8631 VIR_FREE(xml);
8633 if (ret != 0) {
8634 vshError(ctl, "%s", _("Failed to attach disk"));
8635 ret = FALSE;
8636 } else {
8637 vshPrint(ctl, "%s", _("Disk attached successfully\n"));
8638 ret = TRUE;
8641 cleanup:
8642 if (dom)
8643 virDomainFree(dom);
8644 virBufferFreeAndReset(&buf);
8645 return ret;
8649 * "detach-disk" command
8651 static const vshCmdInfo info_detach_disk[] = {
8652 {"help", N_("detach disk device")},
8653 {"desc", N_("Detach disk device.")},
8654 {NULL, NULL}
8657 static const vshCmdOptDef opts_detach_disk[] = {
8658 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
8659 {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
8660 {"persistent", VSH_OT_BOOL, 0, N_("persist disk detachment")},
8661 {NULL, 0, 0, NULL}
8664 static int
8665 cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
8667 xmlDocPtr xml = NULL;
8668 xmlXPathObjectPtr obj=NULL;
8669 xmlXPathContextPtr ctxt = NULL;
8670 xmlNodePtr cur = NULL;
8671 xmlChar *tmp_tgt = NULL;
8672 xmlBufferPtr xml_buf = NULL;
8673 virDomainPtr dom = NULL;
8674 char *doc, *target;
8675 int i = 0, diff_tgt, ret = FALSE;
8676 unsigned int flags;
8678 if (!vshConnectionUsability(ctl, ctl->conn))
8679 goto cleanup;
8681 if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
8682 goto cleanup;
8684 if (!(target = vshCommandOptString(cmd, "target", NULL)))
8685 goto cleanup;
8687 doc = virDomainGetXMLDesc(dom, 0);
8688 if (!doc)
8689 goto cleanup;
8691 xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
8692 XML_PARSE_NOENT | XML_PARSE_NONET |
8693 XML_PARSE_NOWARNING);
8694 VIR_FREE(doc);
8695 if (!xml) {
8696 vshError(ctl, "%s", _("Failed to get disk information"));
8697 goto cleanup;
8699 ctxt = xmlXPathNewContext(xml);
8700 if (!ctxt) {
8701 vshError(ctl, "%s", _("Failed to get disk information"));
8702 goto cleanup;
8705 obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
8706 if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
8707 (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
8708 vshError(ctl, "%s", _("Failed to get disk information"));
8709 goto cleanup;
8712 /* search target */
8713 for (; i < obj->nodesetval->nodeNr; i++) {
8714 cur = obj->nodesetval->nodeTab[i]->children;
8715 while (cur != NULL) {
8716 if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, BAD_CAST "target")) {
8717 tmp_tgt = xmlGetProp(cur, BAD_CAST "dev");
8718 diff_tgt = xmlStrEqual(tmp_tgt, BAD_CAST target);
8719 xmlFree(tmp_tgt);
8720 if (diff_tgt) {
8721 goto hit;
8724 cur = cur->next;
8727 vshError(ctl, _("No found disk whose target is %s"), target);
8728 goto cleanup;
8730 hit:
8731 xml_buf = xmlBufferCreate();
8732 if (!xml_buf) {
8733 vshError(ctl, "%s", _("Failed to allocate memory"));
8734 goto cleanup;
8737 if(xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0){
8738 vshError(ctl, "%s", _("Failed to create XML"));
8739 goto cleanup;
8742 if (vshCommandOptBool(cmd, "persistent")) {
8743 flags = VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
8744 if (virDomainIsActive(dom) == 1)
8745 flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
8746 ret = virDomainDetachDeviceFlags(dom,
8747 (char *)xmlBufferContent(xml_buf),
8748 flags);
8749 } else {
8750 ret = virDomainDetachDevice(dom, (char *)xmlBufferContent(xml_buf));
8753 if (ret != 0) {
8754 vshError(ctl, "%s", _("Failed to detach disk"));
8755 ret = FALSE;
8756 } else {
8757 vshPrint(ctl, "%s", _("Disk detached successfully\n"));
8758 ret = TRUE;
8761 cleanup:
8762 xmlXPathFreeObject(obj);
8763 xmlXPathFreeContext(ctxt);
8764 if (xml)
8765 xmlFreeDoc(xml);
8766 if (xml_buf)
8767 xmlBufferFree(xml_buf);
8768 if (dom)
8769 virDomainFree(dom);
8770 return ret;
8774 * "cpu-compare" command
8776 static const vshCmdInfo info_cpu_compare[] = {
8777 {"help", N_("compare host CPU with a CPU described by an XML file")},
8778 {"desc", N_("compare CPU with host CPU")},
8779 {NULL, NULL}
8782 static const vshCmdOptDef opts_cpu_compare[] = {
8783 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML CPU description")},
8784 {NULL, 0, 0, NULL}
8787 static int
8788 cmdCPUCompare(vshControl *ctl, const vshCmd *cmd)
8790 char *from;
8791 int found;
8792 int ret = TRUE;
8793 char *buffer;
8794 int result;
8796 if (!vshConnectionUsability(ctl, ctl->conn))
8797 return FALSE;
8799 from = vshCommandOptString(cmd, "file", &found);
8800 if (!found)
8801 return FALSE;
8803 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
8804 return FALSE;
8806 result = virConnectCompareCPU(ctl->conn, buffer, 0);
8807 VIR_FREE(buffer);
8809 switch (result) {
8810 case VIR_CPU_COMPARE_INCOMPATIBLE:
8811 vshPrint(ctl, _("CPU described in %s is incompatible with host CPU\n"),
8812 from);
8813 ret = FALSE;
8814 break;
8816 case VIR_CPU_COMPARE_IDENTICAL:
8817 vshPrint(ctl, _("CPU described in %s is identical to host CPU\n"),
8818 from);
8819 ret = TRUE;
8820 break;
8822 case VIR_CPU_COMPARE_SUPERSET:
8823 vshPrint(ctl, _("Host CPU is a superset of CPU described in %s\n"),
8824 from);
8825 ret = TRUE;
8826 break;
8828 case VIR_CPU_COMPARE_ERROR:
8829 default:
8830 vshError(ctl, _("Failed to compare host CPU with %s"), from);
8831 ret = FALSE;
8834 return ret;
8838 * "cpu-baseline" command
8840 static const vshCmdInfo info_cpu_baseline[] = {
8841 {"help", N_("compute baseline CPU")},
8842 {"desc", N_("Compute baseline CPU for a set of given CPUs.")},
8843 {NULL, NULL}
8846 static const vshCmdOptDef opts_cpu_baseline[] = {
8847 {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing XML CPU descriptions")},
8848 {NULL, 0, 0, NULL}
8851 static int
8852 cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
8854 char *from;
8855 int found;
8856 int ret = TRUE;
8857 char *buffer;
8858 char *result = NULL;
8859 const char **list = NULL;
8860 unsigned int count = 0;
8861 xmlDocPtr doc = NULL;
8862 xmlNodePtr node_list;
8863 xmlXPathContextPtr ctxt = NULL;
8864 xmlSaveCtxtPtr sctxt = NULL;
8865 xmlBufferPtr buf = NULL;
8866 xmlXPathObjectPtr obj = NULL;
8867 int res, i;
8869 if (!vshConnectionUsability(ctl, ctl->conn))
8870 return FALSE;
8872 from = vshCommandOptString(cmd, "file", &found);
8873 if (!found)
8874 return FALSE;
8876 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
8877 return FALSE;
8879 doc = xmlNewDoc(NULL);
8880 if (doc == NULL)
8881 goto no_memory;
8883 res = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
8884 (const xmlChar *)buffer, &node_list);
8885 if (res != 0) {
8886 vshError(ctl, _("Failed to parse XML fragment %s"), from);
8887 ret = FALSE;
8888 goto cleanup;
8891 xmlAddChildList((xmlNodePtr) doc, node_list);
8893 ctxt = xmlXPathNewContext(doc);
8894 if (!ctxt)
8895 goto no_memory;
8897 obj = xmlXPathEval(BAD_CAST "//cpu[not(ancestor::cpu)]", ctxt);
8898 if ((obj == NULL) || (obj->nodesetval == NULL) ||
8899 (obj->nodesetval->nodeTab == NULL))
8900 goto cleanup;
8902 for (i = 0;i < obj->nodesetval->nodeNr;i++) {
8903 buf = xmlBufferCreate();
8904 if (buf == NULL)
8905 goto no_memory;
8906 sctxt = xmlSaveToBuffer(buf, NULL, 0);
8907 if (sctxt == NULL) {
8908 xmlBufferFree(buf);
8909 goto no_memory;
8912 xmlSaveTree(sctxt, obj->nodesetval->nodeTab[i]);
8913 xmlSaveClose(sctxt);
8915 list = vshRealloc(ctl, list, sizeof(char *) * (count + 1));
8916 list[count++] = (char *) buf->content;
8917 buf->content = NULL;
8918 xmlBufferFree(buf);
8919 buf = NULL;
8922 if (count == 0) {
8923 vshError(ctl, _("No host CPU specified in '%s'"), from);
8924 ret = FALSE;
8925 goto cleanup;
8928 result = virConnectBaselineCPU(ctl->conn, list, count, 0);
8930 if (result)
8931 vshPrint(ctl, "%s", result);
8932 else
8933 ret = FALSE;
8935 cleanup:
8936 xmlXPathFreeObject(obj);
8937 xmlXPathFreeContext(ctxt);
8938 xmlFreeDoc(doc);
8939 VIR_FREE(result);
8940 if ((list != NULL) && (count > 0)) {
8941 for (i = 0;i < count;i++)
8942 VIR_FREE(list[i]);
8944 VIR_FREE(list);
8945 VIR_FREE(buffer);
8947 return ret;
8949 no_memory:
8950 vshError(ctl, "%s", _("Out of memory"));
8951 ret = FALSE;
8952 goto cleanup;
8955 /* Common code for the edit / net-edit / pool-edit functions which follow. */
8956 static char *
8957 editWriteToTempFile (vshControl *ctl, const char *doc)
8959 char *ret;
8960 const char *tmpdir;
8961 int fd;
8963 ret = vshMalloc(ctl, PATH_MAX);
8965 tmpdir = getenv ("TMPDIR");
8966 if (!tmpdir) tmpdir = "/tmp";
8967 snprintf (ret, PATH_MAX, "%s/virshXXXXXX", tmpdir);
8968 fd = mkstemp (ret);
8969 if (fd == -1) {
8970 vshError(ctl, _("mkstemp: failed to create temporary file: %s"),
8971 strerror(errno));
8972 VIR_FREE(ret);
8973 return NULL;
8976 if (safewrite (fd, doc, strlen (doc)) == -1) {
8977 vshError(ctl, _("write: %s: failed to write to temporary file: %s"),
8978 ret, strerror(errno));
8979 close (fd);
8980 unlink (ret);
8981 VIR_FREE(ret);
8982 return NULL;
8984 if (close (fd) == -1) {
8985 vshError(ctl, _("close: %s: failed to write or close temporary file: %s"),
8986 ret, strerror(errno));
8987 unlink (ret);
8988 VIR_FREE(ret);
8989 return NULL;
8992 /* Temporary filename: caller frees. */
8993 return ret;
8996 /* Characters permitted in $EDITOR environment variable and temp filename. */
8997 #define ACCEPTED_CHARS \
8998 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/_.:@"
9000 static int
9001 editFile (vshControl *ctl, const char *filename)
9003 const char *editor;
9004 char *command;
9005 int command_ret;
9007 editor = getenv ("VISUAL");
9008 if (!editor) editor = getenv ("EDITOR");
9009 if (!editor) editor = "vi"; /* could be cruel & default to ed(1) here */
9011 /* Check that filename doesn't contain shell meta-characters, and
9012 * if it does, refuse to run. Follow the Unix conventions for
9013 * EDITOR: the user can intentionally specify command options, so
9014 * we don't protect any shell metacharacters there. Lots more
9015 * than virsh will misbehave if EDITOR has bogus contents (which
9016 * is why sudo scrubs it by default).
9018 if (strspn (filename, ACCEPTED_CHARS) != strlen (filename)) {
9019 vshError(ctl,
9020 _("%s: temporary filename contains shell meta or other "
9021 "unacceptable characters (is $TMPDIR wrong?)"),
9022 filename);
9023 return -1;
9026 if (virAsprintf(&command, "%s %s", editor, filename) == -1) {
9027 vshError(ctl,
9028 _("virAsprintf: could not create editing command: %s"),
9029 strerror(errno));
9030 return -1;
9033 command_ret = system (command);
9034 if (command_ret == -1) {
9035 vshError(ctl,
9036 _("%s: edit command failed: %s"), command, strerror(errno));
9037 VIR_FREE(command);
9038 return -1;
9040 if (WEXITSTATUS(command_ret) != 0) {
9041 vshError(ctl,
9042 _("%s: command exited with non-zero status"), command);
9043 VIR_FREE(command);
9044 return -1;
9046 VIR_FREE(command);
9047 return 0;
9050 static char *
9051 editReadBackFile (vshControl *ctl, const char *filename)
9053 char *ret;
9055 if (virFileReadAll (filename, VIRSH_MAX_XML_FILE, &ret) == -1) {
9056 vshError(ctl,
9057 _("%s: failed to read temporary file: %s"),
9058 filename, strerror(errno));
9059 return NULL;
9061 return ret;
9065 #ifndef WIN32
9067 * "cd" command
9069 static const vshCmdInfo info_cd[] = {
9070 {"help", N_("change the current directory")},
9071 {"desc", N_("Change the current directory.")},
9072 {NULL, NULL}
9075 static const vshCmdOptDef opts_cd[] = {
9076 {"dir", VSH_OT_DATA, 0, N_("directory to switch to (default: home or else root)")},
9077 {NULL, 0, 0, NULL}
9080 static int
9081 cmdCd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
9083 const char *dir;
9084 int found;
9086 if (!ctl->imode) {
9087 vshError(ctl, "%s", _("cd: command valid only in interactive mode"));
9088 return FALSE;
9091 dir = vshCommandOptString(cmd, "dir", &found);
9092 if (!found) {
9093 uid_t uid = geteuid();
9094 dir = virGetUserDirectory(uid);
9096 if (!dir)
9097 dir = "/";
9099 if (chdir (dir) == -1) {
9100 vshError(ctl, _("cd: %s: %s"), strerror(errno), dir);
9101 return FALSE;
9104 return TRUE;
9107 #endif
9109 #ifndef WIN32
9111 * "pwd" command
9113 static const vshCmdInfo info_pwd[] = {
9114 {"help", N_("print the current directory")},
9115 {"desc", N_("Print the current directory.")},
9116 {NULL, NULL}
9119 static int
9120 cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
9122 char *cwd;
9123 size_t path_max;
9124 int err = TRUE;
9126 path_max = (size_t) PATH_MAX + 2;
9127 cwd = vshMalloc (ctl, path_max);
9128 while (cwd) {
9129 err = getcwd (cwd, path_max) == NULL;
9130 if (!err || errno != ERANGE)
9131 break;
9133 path_max *= 2;
9134 cwd = vshRealloc (ctl, cwd, path_max);
9137 if (err)
9138 vshError(ctl, _("pwd: cannot get current directory: %s"),
9139 strerror(errno));
9140 else
9141 vshPrint (ctl, _("%s\n"), cwd);
9143 VIR_FREE(cwd);
9144 return !err;
9146 #endif
9149 * "echo" command
9151 static const vshCmdInfo info_echo[] = {
9152 {"help", N_("echo arguments")},
9153 {"desc", N_("Echo back arguments, possibly with quoting.")},
9154 {NULL, NULL}
9157 static const vshCmdOptDef opts_echo[] = {
9158 {"shell", VSH_OT_BOOL, 0, N_("escape for shell use")},
9159 {"xml", VSH_OT_BOOL, 0, N_("escape for XML use")},
9160 {"", VSH_OT_ARGV, 0, N_("arguments to echo")},
9161 {NULL, 0, 0, NULL}
9164 /* Exists mainly for debugging virsh, but also handy for adding back
9165 * quotes for later evaluation.
9167 static int
9168 cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd)
9170 bool shell = false;
9171 bool xml = false;
9172 int count = 0;
9173 char *arg;
9174 virBuffer buf = VIR_BUFFER_INITIALIZER;
9176 if (vshCommandOptBool(cmd, "shell"))
9177 shell = true;
9178 if (vshCommandOptBool(cmd, "xml"))
9179 xml = true;
9181 while ((arg = vshCommandOptArgv(cmd, count)) != NULL) {
9182 bool close_quote = false;
9183 char *q;
9185 if (count)
9186 virBufferAddChar(&buf, ' ');
9187 /* Add outer '' only if arg included shell metacharacters. */
9188 if (shell &&
9189 (strpbrk(arg, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") || !*arg)) {
9190 virBufferAddChar(&buf, '\'');
9191 close_quote = true;
9193 if (xml) {
9194 virBufferEscapeString(&buf, "%s", arg);
9195 } else {
9196 if (shell && (q = strchr(arg, '\''))) {
9197 do {
9198 virBufferAdd(&buf, arg, q - arg);
9199 virBufferAddLit(&buf, "'\\''");
9200 arg = q + 1;
9201 q = strchr(arg, '\'');
9202 } while (q);
9204 virBufferAdd(&buf, arg, strlen(arg));
9206 if (close_quote)
9207 virBufferAddChar(&buf, '\'');
9208 count++;
9211 if (virBufferError(&buf)) {
9212 vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
9213 return FALSE;
9215 arg = virBufferContentAndReset(&buf);
9216 if (arg)
9217 vshPrint(ctl, "%s", arg);
9218 VIR_FREE(arg);
9219 return TRUE;
9223 * "edit" command
9225 static const vshCmdInfo info_edit[] = {
9226 {"help", N_("edit XML configuration for a domain")},
9227 {"desc", N_("Edit the XML configuration for a domain.")},
9228 {NULL, NULL}
9231 static const vshCmdOptDef opts_edit[] = {
9232 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9233 {NULL, 0, 0, NULL}
9236 /* This function also acts as a template to generate cmdNetworkEdit
9237 * and cmdPoolEdit functions (below) using a sed script in the Makefile.
9239 static int
9240 cmdEdit (vshControl *ctl, const vshCmd *cmd)
9242 int ret = FALSE;
9243 virDomainPtr dom = NULL;
9244 char *tmp = NULL;
9245 char *doc = NULL;
9246 char *doc_edited = NULL;
9247 char *doc_reread = NULL;
9248 int flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_INACTIVE;
9250 if (!vshConnectionUsability(ctl, ctl->conn))
9251 goto cleanup;
9253 dom = vshCommandOptDomain (ctl, cmd, NULL);
9254 if (dom == NULL)
9255 goto cleanup;
9257 /* Get the XML configuration of the domain. */
9258 doc = virDomainGetXMLDesc (dom, flags);
9259 if (!doc)
9260 goto cleanup;
9262 /* Create and open the temporary file. */
9263 tmp = editWriteToTempFile (ctl, doc);
9264 if (!tmp) goto cleanup;
9266 /* Start the editor. */
9267 if (editFile (ctl, tmp) == -1) goto cleanup;
9269 /* Read back the edited file. */
9270 doc_edited = editReadBackFile (ctl, tmp);
9271 if (!doc_edited) goto cleanup;
9273 /* Compare original XML with edited. Has it changed at all? */
9274 if (STREQ (doc, doc_edited)) {
9275 vshPrint (ctl, _("Domain %s XML configuration not changed.\n"),
9276 virDomainGetName (dom));
9277 ret = TRUE;
9278 goto cleanup;
9281 /* Now re-read the domain XML. Did someone else change it while
9282 * it was being edited? This also catches problems such as us
9283 * losing a connection or the domain going away.
9285 doc_reread = virDomainGetXMLDesc (dom, flags);
9286 if (!doc_reread)
9287 goto cleanup;
9289 if (STRNEQ (doc, doc_reread)) {
9290 vshError(ctl,
9291 "%s", _("ERROR: the XML configuration was changed by another user"));
9292 goto cleanup;
9295 /* Everything checks out, so redefine the domain. */
9296 virDomainFree (dom);
9297 dom = virDomainDefineXML (ctl->conn, doc_edited);
9298 if (!dom)
9299 goto cleanup;
9301 vshPrint (ctl, _("Domain %s XML configuration edited.\n"),
9302 virDomainGetName(dom));
9304 ret = TRUE;
9306 cleanup:
9307 if (dom)
9308 virDomainFree (dom);
9310 VIR_FREE(doc);
9311 VIR_FREE(doc_edited);
9312 VIR_FREE(doc_reread);
9314 if (tmp) {
9315 unlink (tmp);
9316 VIR_FREE(tmp);
9319 return ret;
9323 * "net-edit" command
9325 static const vshCmdInfo info_network_edit[] = {
9326 {"help", N_("edit XML configuration for a network")},
9327 {"desc", N_("Edit the XML configuration for a network.")},
9328 {NULL, NULL}
9331 static const vshCmdOptDef opts_network_edit[] = {
9332 {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name, id or uuid")},
9333 {NULL, 0, 0, NULL}
9336 /* This is generated from this file by a sed script in the Makefile. */
9337 #include "virsh-net-edit.c"
9340 * "pool-edit" command
9342 static const vshCmdInfo info_pool_edit[] = {
9343 {"help", N_("edit XML configuration for a storage pool")},
9344 {"desc", N_("Edit the XML configuration for a storage pool.")},
9345 {NULL, NULL}
9348 static const vshCmdOptDef opts_pool_edit[] = {
9349 {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
9350 {NULL, 0, 0, NULL}
9353 /* This is generated from this file by a sed script in the Makefile. */
9354 #include "virsh-pool-edit.c"
9357 * "quit" command
9359 static const vshCmdInfo info_quit[] = {
9360 {"help", N_("quit this interactive terminal")},
9361 {"desc", ""},
9362 {NULL, NULL}
9365 static int
9366 cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
9368 ctl->imode = FALSE;
9369 return TRUE;
9373 * "snapshot-create" command
9375 static const vshCmdInfo info_snapshot_create[] = {
9376 {"help", N_("Create a snapshot")},
9377 {"desc", N_("Snapshot create")},
9378 {NULL, NULL}
9381 static const vshCmdOptDef opts_snapshot_create[] = {
9382 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9383 {"xmlfile", VSH_OT_DATA, 0, N_("domain snapshot XML")},
9384 {NULL, 0, 0, NULL}
9387 static int
9388 cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
9390 virDomainPtr dom = NULL;
9391 int ret = FALSE;
9392 char *from;
9393 char *buffer = NULL;
9394 virDomainSnapshotPtr snapshot = NULL;
9395 xmlDocPtr xml = NULL;
9396 xmlXPathContextPtr ctxt = NULL;
9397 char *doc = NULL;
9398 char *name = NULL;
9400 if (!vshConnectionUsability(ctl, ctl->conn))
9401 goto cleanup;
9403 dom = vshCommandOptDomain(ctl, cmd, NULL);
9404 if (dom == NULL)
9405 goto cleanup;
9407 from = vshCommandOptString(cmd, "xmlfile", NULL);
9408 if (from == NULL)
9409 buffer = vshStrdup(ctl, "<domainsnapshot/>");
9410 else {
9411 if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
9412 /* we have to report the error here because during cleanup
9413 * we'll run through virDomainFree(), which loses the
9414 * last error
9416 virshReportError(ctl);
9417 goto cleanup;
9420 if (buffer == NULL) {
9421 vshError(ctl, "%s", _("Out of memory"));
9422 goto cleanup;
9425 snapshot = virDomainSnapshotCreateXML(dom, buffer, 0);
9426 if (snapshot == NULL)
9427 goto cleanup;
9429 doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
9430 if (!doc)
9431 goto cleanup;
9433 xml = xmlReadDoc((const xmlChar *) doc, "domainsnapshot.xml", NULL,
9434 XML_PARSE_NOENT | XML_PARSE_NONET |
9435 XML_PARSE_NOWARNING);
9436 if (!xml)
9437 goto cleanup;
9438 ctxt = xmlXPathNewContext(xml);
9439 if (!ctxt)
9440 goto cleanup;
9442 name = virXPathString("string(/domainsnapshot/name)", ctxt);
9443 if (!name) {
9444 vshError(ctl, "%s",
9445 _("Could not find 'name' element in domain snapshot XML"));
9446 goto cleanup;
9449 vshPrint(ctl, _("Domain snapshot %s created"), name);
9450 if (from)
9451 vshPrint(ctl, _(" from '%s'"), from);
9452 vshPrint(ctl, "\n");
9454 ret = TRUE;
9456 cleanup:
9457 VIR_FREE(name);
9458 xmlXPathFreeContext(ctxt);
9459 if (xml)
9460 xmlFreeDoc(xml);
9461 if (snapshot)
9462 virDomainSnapshotFree(snapshot);
9463 VIR_FREE(doc);
9464 VIR_FREE(buffer);
9465 if (dom)
9466 virDomainFree(dom);
9468 return ret;
9472 * "snapshot-current" command
9474 static const vshCmdInfo info_snapshot_current[] = {
9475 {"help", N_("Get the current snapshot")},
9476 {"desc", N_("Get the current snapshot")},
9477 {NULL, NULL}
9480 static const vshCmdOptDef opts_snapshot_current[] = {
9481 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9482 {NULL, 0, 0, NULL}
9485 static int
9486 cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
9488 virDomainPtr dom = NULL;
9489 int ret = FALSE;
9490 int current;
9491 virDomainSnapshotPtr snapshot = NULL;
9493 if (!vshConnectionUsability(ctl, ctl->conn))
9494 goto cleanup;
9496 dom = vshCommandOptDomain(ctl, cmd, NULL);
9497 if (dom == NULL)
9498 goto cleanup;
9500 current = virDomainHasCurrentSnapshot(dom, 0);
9501 if (current < 0)
9502 goto cleanup;
9503 else if (current) {
9504 char *xml;
9506 if (!(snapshot = virDomainSnapshotCurrent(dom, 0)))
9507 goto cleanup;
9509 xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
9510 if (!xml)
9511 goto cleanup;
9513 vshPrint(ctl, "%s", xml);
9514 VIR_FREE(xml);
9517 ret = TRUE;
9519 cleanup:
9520 if (snapshot)
9521 virDomainSnapshotFree(snapshot);
9522 if (dom)
9523 virDomainFree(dom);
9525 return ret;
9529 * "snapshot-list" command
9531 static const vshCmdInfo info_snapshot_list[] = {
9532 {"help", N_("List snapshots for a domain")},
9533 {"desc", N_("Snapshot List")},
9534 {NULL, NULL}
9537 static const vshCmdOptDef opts_snapshot_list[] = {
9538 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9539 {NULL, 0, 0, NULL}
9542 static int
9543 cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
9545 virDomainPtr dom = NULL;
9546 int ret = FALSE;
9547 int numsnaps;
9548 char **names = NULL;
9549 int actual = 0;
9550 int i;
9551 xmlDocPtr xml = NULL;
9552 xmlXPathContextPtr ctxt = NULL;
9553 char *doc = NULL;
9554 virDomainSnapshotPtr snapshot = NULL;
9555 char *state = NULL;
9556 long creation;
9557 char timestr[100];
9558 struct tm time_info;
9560 if (!vshConnectionUsability(ctl, ctl->conn))
9561 goto cleanup;
9563 dom = vshCommandOptDomain(ctl, cmd, NULL);
9564 if (dom == NULL)
9565 goto cleanup;
9567 numsnaps = virDomainSnapshotNum(dom, 0);
9569 if (numsnaps < 0)
9570 goto cleanup;
9572 vshPrint(ctl, " %-20s %-25s %s\n", _("Name"), _("Creation Time"), _("State"));
9573 vshPrint(ctl, "---------------------------------------------------\n");
9575 if (numsnaps) {
9576 if (VIR_ALLOC_N(names, numsnaps) < 0)
9577 goto cleanup;
9579 actual = virDomainSnapshotListNames(dom, names, numsnaps, 0);
9580 if (actual < 0)
9581 goto cleanup;
9583 qsort(&names[0], actual, sizeof(char*), namesorter);
9585 for (i = 0; i < actual; i++) {
9586 /* free up memory from previous iterations of the loop */
9587 VIR_FREE(state);
9588 if (snapshot)
9589 virDomainSnapshotFree(snapshot);
9590 xmlXPathFreeContext(ctxt);
9591 if (xml)
9592 xmlFreeDoc(xml);
9593 VIR_FREE(doc);
9595 snapshot = virDomainSnapshotLookupByName(dom, names[i], 0);
9596 if (snapshot == NULL)
9597 continue;
9599 doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
9600 if (!doc)
9601 continue;
9603 xml = xmlReadDoc((const xmlChar *) doc, "domainsnapshot.xml", NULL,
9604 XML_PARSE_NOENT | XML_PARSE_NONET |
9605 XML_PARSE_NOWARNING);
9606 if (!xml)
9607 continue;
9608 ctxt = xmlXPathNewContext(xml);
9609 if (!ctxt)
9610 continue;
9612 state = virXPathString("string(/domainsnapshot/state)", ctxt);
9613 if (state == NULL)
9614 continue;
9615 if (virXPathLong("string(/domainsnapshot/creationTime)", ctxt,
9616 &creation) < 0)
9617 continue;
9618 localtime_r(&creation, &time_info);
9619 strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", &time_info);
9621 vshPrint(ctl, " %-20s %-25s %s\n", names[i], timestr, state);
9625 ret = TRUE;
9627 cleanup:
9628 /* this frees up memory from the last iteration of the loop */
9629 VIR_FREE(state);
9630 if (snapshot)
9631 virDomainSnapshotFree(snapshot);
9632 xmlXPathFreeContext(ctxt);
9633 if (xml)
9634 xmlFreeDoc(xml);
9635 VIR_FREE(doc);
9636 for (i = 0; i < actual; i++)
9637 VIR_FREE(names[i]);
9638 VIR_FREE(names);
9639 if (dom)
9640 virDomainFree(dom);
9642 return ret;
9646 * "snapshot-dumpxml" command
9648 static const vshCmdInfo info_snapshot_dumpxml[] = {
9649 {"help", N_("Dump XML for a domain snapshot")},
9650 {"desc", N_("Snapshot Dump XML")},
9651 {NULL, NULL}
9654 static const vshCmdOptDef opts_snapshot_dumpxml[] = {
9655 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9656 {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
9657 {NULL, 0, 0, NULL}
9660 static int
9661 cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd)
9663 virDomainPtr dom = NULL;
9664 int ret = FALSE;
9665 char *name;
9666 virDomainSnapshotPtr snapshot = NULL;
9667 char *xml = NULL;
9669 if (!vshConnectionUsability(ctl, ctl->conn))
9670 goto cleanup;
9672 dom = vshCommandOptDomain(ctl, cmd, NULL);
9673 if (dom == NULL)
9674 goto cleanup;
9676 name = vshCommandOptString(cmd, "snapshotname", NULL);
9677 if (name == NULL)
9678 goto cleanup;
9680 snapshot = virDomainSnapshotLookupByName(dom, name, 0);
9681 if (snapshot == NULL)
9682 goto cleanup;
9684 xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
9685 if (!xml)
9686 goto cleanup;
9688 vshPrint(ctl, "%s", xml);
9690 ret = TRUE;
9692 cleanup:
9693 VIR_FREE(xml);
9694 if (snapshot)
9695 virDomainSnapshotFree(snapshot);
9696 if (dom)
9697 virDomainFree(dom);
9699 return ret;
9703 * "snapshot-revert" command
9705 static const vshCmdInfo info_snapshot_revert[] = {
9706 {"help", N_("Revert a domain to a snapshot")},
9707 {"desc", N_("Revert domain to snapshot")},
9708 {NULL, NULL}
9711 static const vshCmdOptDef opts_snapshot_revert[] = {
9712 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9713 {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
9714 {NULL, 0, 0, NULL}
9717 static int
9718 cmdDomainSnapshotRevert(vshControl *ctl, const vshCmd *cmd)
9720 virDomainPtr dom = NULL;
9721 int ret = FALSE;
9722 char *name;
9723 virDomainSnapshotPtr snapshot = NULL;
9725 if (!vshConnectionUsability(ctl, ctl->conn))
9726 goto cleanup;
9728 dom = vshCommandOptDomain(ctl, cmd, NULL);
9729 if (dom == NULL)
9730 goto cleanup;
9732 name = vshCommandOptString(cmd, "snapshotname", NULL);
9733 if (name == NULL)
9734 goto cleanup;
9736 snapshot = virDomainSnapshotLookupByName(dom, name, 0);
9737 if (snapshot == NULL)
9738 goto cleanup;
9740 if (virDomainRevertToSnapshot(snapshot, 0) < 0)
9741 goto cleanup;
9743 ret = TRUE;
9745 cleanup:
9746 if (snapshot)
9747 virDomainSnapshotFree(snapshot);
9748 if (dom)
9749 virDomainFree(dom);
9751 return ret;
9755 * "snapshot-delete" command
9757 static const vshCmdInfo info_snapshot_delete[] = {
9758 {"help", N_("Delete a domain snapshot")},
9759 {"desc", N_("Snapshot Delete")},
9760 {NULL, NULL}
9763 static const vshCmdOptDef opts_snapshot_delete[] = {
9764 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9765 {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
9766 {"children", VSH_OT_BOOL, 0, N_("delete snapshot and all children")},
9767 {NULL, 0, 0, NULL}
9770 static int
9771 cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd)
9773 virDomainPtr dom = NULL;
9774 int ret = FALSE;
9775 char *name;
9776 virDomainSnapshotPtr snapshot = NULL;
9777 unsigned int flags = 0;
9779 if (!vshConnectionUsability(ctl, ctl->conn))
9780 goto cleanup;
9782 dom = vshCommandOptDomain(ctl, cmd, NULL);
9783 if (dom == NULL)
9784 goto cleanup;
9786 name = vshCommandOptString(cmd, "snapshotname", NULL);
9787 if (name == NULL)
9788 goto cleanup;
9790 if (vshCommandOptBool(cmd, "children"))
9791 flags |= VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN;
9793 snapshot = virDomainSnapshotLookupByName(dom, name, 0);
9794 if (snapshot == NULL)
9795 goto cleanup;
9797 if (virDomainSnapshotDelete(snapshot, flags) < 0)
9798 goto cleanup;
9800 ret = TRUE;
9802 cleanup:
9803 if (snapshot)
9804 virDomainSnapshotFree(snapshot);
9805 if (dom)
9806 virDomainFree(dom);
9808 return ret;
9812 * "qemu-monitor-command" command
9814 static const vshCmdInfo info_qemu_monitor_command[] = {
9815 {"help", N_("Qemu Monitor Command")},
9816 {"desc", N_("Qemu Monitor Command")},
9817 {NULL, NULL}
9820 static const vshCmdOptDef opts_qemu_monitor_command[] = {
9821 {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
9822 {"cmd", VSH_OT_DATA, VSH_OFLAG_REQ, N_("command")},
9823 {NULL, 0, 0, NULL}
9826 static int
9827 cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
9829 virDomainPtr dom = NULL;
9830 int ret = FALSE;
9831 char *monitor_cmd;
9832 char *result = NULL;
9834 if (!vshConnectionUsability(ctl, ctl->conn))
9835 goto cleanup;
9837 dom = vshCommandOptDomain(ctl, cmd, NULL);
9838 if (dom == NULL)
9839 goto cleanup;
9841 monitor_cmd = vshCommandOptString(cmd, "cmd", NULL);
9842 if (monitor_cmd == NULL) {
9843 vshError(ctl, "%s", _("missing monitor command"));
9844 goto cleanup;
9847 if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, 0) < 0)
9848 goto cleanup;
9850 printf("%s\n", result);
9852 ret = TRUE;
9854 cleanup:
9855 VIR_FREE(result);
9856 if (dom)
9857 virDomainFree(dom);
9859 return ret;
9864 * Commands
9866 static const vshCmdDef commands[] = {
9867 {"help", cmdHelp, opts_help, info_help},
9868 {"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device},
9869 {"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk},
9870 {"attach-interface", cmdAttachInterface, opts_attach_interface, info_attach_interface},
9871 {"autostart", cmdAutostart, opts_autostart, info_autostart},
9872 {"capabilities", cmdCapabilities, NULL, info_capabilities},
9873 #ifndef WIN32
9874 {"cd", cmdCd, opts_cd, info_cd},
9875 #endif
9876 {"connect", cmdConnect, opts_connect, info_connect},
9877 #ifndef WIN32
9878 {"console", cmdConsole, opts_console, info_console},
9879 #endif
9880 {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline},
9881 {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare},
9882 {"create", cmdCreate, opts_create, info_create},
9883 {"start", cmdStart, opts_start, info_start},
9884 {"destroy", cmdDestroy, opts_destroy, info_destroy},
9885 {"detach-device", cmdDetachDevice, opts_detach_device, info_detach_device},
9886 {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk},
9887 {"detach-interface", cmdDetachInterface, opts_detach_interface, info_detach_interface},
9888 {"define", cmdDefine, opts_define, info_define},
9889 {"domid", cmdDomid, opts_domid, info_domid},
9890 {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
9891 {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
9892 {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo},
9893 {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort},
9894 {"domname", cmdDomname, opts_domname, info_domname},
9895 {"domstate", cmdDomstate, opts_domstate, info_domstate},
9896 {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
9897 {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat},
9898 {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat},
9899 {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo},
9900 {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, info_domxmlfromnative},
9901 {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, info_domxmltonative},
9902 {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
9903 {"echo", cmdEcho, opts_echo, info_echo},
9904 {"edit", cmdEdit, opts_edit, info_edit},
9905 {"find-storage-pool-sources", cmdPoolDiscoverSources,
9906 opts_find_storage_pool_sources, info_find_storage_pool_sources},
9907 {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs,
9908 opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as},
9909 {"freecell", cmdFreecell, opts_freecell, info_freecell},
9910 {"hostname", cmdHostname, NULL, info_hostname},
9911 {"list", cmdList, opts_list, info_list},
9912 {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus},
9913 {"migrate", cmdMigrate, opts_migrate, info_migrate},
9914 {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime},
9916 {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart},
9917 {"net-create", cmdNetworkCreate, opts_network_create, info_network_create},
9918 {"net-define", cmdNetworkDefine, opts_network_define, info_network_define},
9919 {"net-destroy", cmdNetworkDestroy, opts_network_destroy, info_network_destroy},
9920 {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, info_network_dumpxml},
9921 {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit},
9922 {"net-list", cmdNetworkList, opts_network_list, info_network_list},
9923 {"net-name", cmdNetworkName, opts_network_name, info_network_name},
9924 {"net-start", cmdNetworkStart, opts_network_start, info_network_start},
9925 {"net-undefine", cmdNetworkUndefine, opts_network_undefine, info_network_undefine},
9926 {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid},
9928 {"iface-list", cmdInterfaceList, opts_interface_list, info_interface_list},
9929 {"iface-name", cmdInterfaceName, opts_interface_name, info_interface_name},
9930 {"iface-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac},
9931 {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, info_interface_dumpxml},
9932 {"iface-define", cmdInterfaceDefine, opts_interface_define, info_interface_define},
9933 {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, info_interface_undefine},
9934 {"iface-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit},
9935 {"iface-start", cmdInterfaceStart, opts_interface_start, info_interface_start},
9936 {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, info_interface_destroy},
9938 {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave},
9939 {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, info_managedsaveremove},
9941 {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
9943 {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices},
9944 {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml},
9945 {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach},
9946 {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach},
9947 {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset},
9948 {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
9949 {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},
9951 {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, info_nwfilter_define},
9952 {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, info_nwfilter_undefine},
9953 {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, info_nwfilter_dumpxml},
9954 {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, info_nwfilter_list},
9955 {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, info_nwfilter_edit},
9957 {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
9958 {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
9959 {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create},
9960 {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as},
9961 {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define},
9962 {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as},
9963 {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy},
9964 {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete},
9965 {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml},
9966 {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit},
9967 {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info},
9968 {"pool-list", cmdPoolList, opts_pool_list, info_pool_list},
9969 {"pool-name", cmdPoolName, opts_pool_name, info_pool_name},
9970 {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh},
9971 {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start},
9972 {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine},
9973 {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid},
9975 {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define},
9976 {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml},
9977 {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value},
9978 {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value},
9979 {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine},
9980 {"secret-list", cmdSecretList, NULL, info_secret_list},
9983 #ifndef WIN32
9984 {"pwd", cmdPwd, NULL, info_pwd},
9985 #endif
9986 {"quit", cmdQuit, NULL, info_quit},
9987 {"exit", cmdQuit, NULL, info_quit},
9988 {"reboot", cmdReboot, opts_reboot, info_reboot},
9989 {"restore", cmdRestore, opts_restore, info_restore},
9990 {"resume", cmdResume, opts_resume, info_resume},
9991 {"save", cmdSave, opts_save, info_save},
9992 {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo},
9993 {"dump", cmdDump, opts_dump, info_dump},
9994 {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
9995 {"setmem", cmdSetmem, opts_setmem, info_setmem},
9996 {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
9997 {"memtune", cmdMemtune, opts_memtune, info_memtune},
9998 {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
9999 {"suspend", cmdSuspend, opts_suspend, info_suspend},
10000 {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},
10001 {"undefine", cmdUndefine, opts_undefine, info_undefine},
10002 {"update-device", cmdUpdateDevice, opts_update_device, info_update_device},
10003 {"uri", cmdURI, NULL, info_uri},
10005 {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
10006 {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from},
10007 {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
10008 {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone},
10009 {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete},
10010 {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe},
10011 {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml},
10012 {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info},
10013 {"vol-list", cmdVolList, opts_vol_list, info_vol_list},
10014 {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool},
10015 {"vol-path", cmdVolPath, opts_vol_path, info_vol_path},
10016 {"vol-name", cmdVolName, opts_vol_name, info_vol_name},
10017 {"vol-key", cmdVolKey, opts_vol_key, info_vol_key},
10019 {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount},
10020 {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
10021 {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
10022 {"version", cmdVersion, NULL, info_version},
10023 {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
10025 {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create},
10026 {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, info_snapshot_current},
10027 {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete},
10028 {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, info_snapshot_dumpxml},
10029 {"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list},
10030 {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, info_snapshot_revert},
10032 {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, info_qemu_monitor_command},
10034 {NULL, NULL, NULL, NULL}
10037 /* ---------------
10038 * Utils for work with command definition
10039 * ---------------
10041 static const char *
10042 vshCmddefGetInfo(const vshCmdDef * cmd, const char *name)
10044 const vshCmdInfo *info;
10046 for (info = cmd->info; info && info->name; info++) {
10047 if (STREQ(info->name, name))
10048 return info->data;
10050 return NULL;
10053 static const vshCmdOptDef *
10054 vshCmddefGetOption(const vshCmdDef * cmd, const char *name)
10056 const vshCmdOptDef *opt;
10058 for (opt = cmd->opts; opt && opt->name; opt++)
10059 if (STREQ(opt->name, name))
10060 return opt;
10061 return NULL;
10064 static const vshCmdOptDef *
10065 vshCmddefGetData(const vshCmdDef * cmd, int data_ct)
10067 const vshCmdOptDef *opt;
10069 for (opt = cmd->opts; opt && opt->name; opt++) {
10070 if (opt->type >= VSH_OT_DATA ||
10071 (opt->type == VSH_OT_INT && (opt->flag & VSH_OFLAG_REQ))) {
10072 if (data_ct == 0 || opt->type == VSH_OT_ARGV)
10073 return opt;
10074 else
10075 data_ct--;
10078 return NULL;
10082 * Checks for required options
10084 static int
10085 vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd)
10087 const vshCmdDef *def = cmd->def;
10088 const vshCmdOptDef *d;
10089 int err = 0;
10091 for (d = def->opts; d && d->name; d++) {
10092 if (d->flag & VSH_OFLAG_REQ) {
10093 vshCmdOpt *o = cmd->opts;
10094 int ok = 0;
10096 while (o && ok == 0) {
10097 if (o->def == d)
10098 ok = 1;
10099 o = o->next;
10101 if (!ok) {
10102 vshError(ctl,
10103 d->type == VSH_OT_DATA ?
10104 _("command '%s' requires <%s> option") :
10105 _("command '%s' requires --%s option"),
10106 def->name, d->name);
10107 err = 1;
10112 return !err;
10115 static const vshCmdDef *
10116 vshCmddefSearch(const char *cmdname)
10118 const vshCmdDef *c;
10120 for (c = commands; c->name; c++)
10121 if (STREQ(c->name, cmdname))
10122 return c;
10123 return NULL;
10126 static int
10127 vshCmddefHelp(vshControl *ctl, const char *cmdname)
10129 const vshCmdDef *def = vshCmddefSearch(cmdname);
10131 if (!def) {
10132 vshError(ctl, _("command '%s' doesn't exist"), cmdname);
10133 return FALSE;
10134 } else {
10135 const char *desc = _(vshCmddefGetInfo(def, "desc"));
10136 const char *help = _(vshCmddefGetInfo(def, "help"));
10137 char buf[256];
10139 fputs(_(" NAME\n"), stdout);
10140 fprintf(stdout, " %s - %s\n", def->name, help);
10142 fputs(_("\n SYNOPSIS\n"), stdout);
10143 fprintf(stdout, " %s", def->name);
10144 if (def->opts) {
10145 const vshCmdOptDef *opt;
10146 for (opt = def->opts; opt->name; opt++) {
10147 const char *fmt;
10148 switch (opt->type) {
10149 case VSH_OT_BOOL:
10150 fmt = "[--%s]";
10151 break;
10152 case VSH_OT_INT:
10153 /* xgettext:c-format */
10154 fmt = ((opt->flag & VSH_OFLAG_REQ) ? "<%s>"
10155 : _("[--%s <number>]"));
10156 break;
10157 case VSH_OT_STRING:
10158 /* xgettext:c-format */
10159 fmt = _("[--%s <string>]");
10160 break;
10161 case VSH_OT_DATA:
10162 fmt = ((opt->flag & VSH_OFLAG_REQ) ? "<%s>" : "[<%s>]");
10163 break;
10164 case VSH_OT_ARGV:
10165 /* xgettext:c-format */
10166 fmt = _("[<string>]...");
10167 break;
10168 default:
10169 assert(0);
10171 fputc(' ', stdout);
10172 fprintf(stdout, fmt, opt->name);
10175 fputc('\n', stdout);
10177 if (desc[0]) {
10178 /* Print the description only if it's not empty. */
10179 fputs(_("\n DESCRIPTION\n"), stdout);
10180 fprintf(stdout, " %s\n", desc);
10183 if (def->opts) {
10184 const vshCmdOptDef *opt;
10185 fputs(_("\n OPTIONS\n"), stdout);
10186 for (opt = def->opts; opt->name; opt++) {
10187 switch (opt->type) {
10188 case VSH_OT_BOOL:
10189 snprintf(buf, sizeof(buf), "--%s", opt->name);
10190 break;
10191 case VSH_OT_INT:
10192 snprintf(buf, sizeof(buf),
10193 (opt->flag & VSH_OFLAG_REQ) ? _("[--%s] <number>")
10194 : _("--%s <number>"), opt->name);
10195 break;
10196 case VSH_OT_STRING:
10197 /* OT_STRING should never be VSH_OFLAG_REQ */
10198 snprintf(buf, sizeof(buf), _("--%s <string>"), opt->name);
10199 break;
10200 case VSH_OT_DATA:
10201 snprintf(buf, sizeof(buf), _("[--%s] <string>"),
10202 opt->name);
10203 break;
10204 case VSH_OT_ARGV:
10205 /* Not really an option. */
10206 continue;
10207 default:
10208 assert(0);
10211 fprintf(stdout, " %-15s %s\n", buf, _(opt->help));
10214 fputc('\n', stdout);
10216 return TRUE;
10219 /* ---------------
10220 * Utils for work with runtime commands data
10221 * ---------------
10223 static void
10224 vshCommandOptFree(vshCmdOpt * arg)
10226 vshCmdOpt *a = arg;
10228 while (a) {
10229 vshCmdOpt *tmp = a;
10231 a = a->next;
10233 VIR_FREE(tmp->data);
10234 VIR_FREE(tmp);
10238 static void
10239 vshCommandFree(vshCmd *cmd)
10241 vshCmd *c = cmd;
10243 while (c) {
10244 vshCmd *tmp = c;
10246 c = c->next;
10248 if (tmp->opts)
10249 vshCommandOptFree(tmp->opts);
10250 VIR_FREE(tmp);
10255 * Returns option by name
10257 static vshCmdOpt *
10258 vshCommandOpt(const vshCmd *cmd, const char *name)
10260 vshCmdOpt *opt = cmd->opts;
10262 while (opt) {
10263 if (opt->def && STREQ(opt->def->name, name))
10264 return opt;
10265 opt = opt->next;
10267 return NULL;
10271 * Returns option as INT
10273 static int
10274 vshCommandOptInt(const vshCmd *cmd, const char *name, int *found)
10276 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10277 int res = 0, num_found = FALSE;
10278 char *end_p = NULL;
10280 if ((arg != NULL) && (arg->data != NULL)) {
10281 res = strtol(arg->data, &end_p, 10);
10282 if ((arg->data == end_p) || (*end_p!= 0))
10283 num_found = FALSE;
10284 else
10285 num_found = TRUE;
10287 if (found)
10288 *found = num_found;
10289 return res;
10292 static unsigned long
10293 vshCommandOptUL(const vshCmd *cmd, const char *name, int *found)
10295 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10296 unsigned long res = 0;
10297 int num_found = FALSE;
10298 char *end_p = NULL;
10300 if ((arg != NULL) && (arg->data != NULL)) {
10301 res = strtoul(arg->data, &end_p, 10);
10302 if ((arg->data == end_p) || (*end_p!= 0))
10303 num_found = FALSE;
10304 else
10305 num_found = TRUE;
10307 if (found)
10308 *found = num_found;
10309 return res;
10313 * Returns option as STRING
10315 static char *
10316 vshCommandOptString(const vshCmd *cmd, const char *name, int *found)
10318 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10320 if (found)
10321 *found = arg ? TRUE : FALSE;
10323 if (arg && arg->data && *arg->data)
10324 return arg->data;
10326 if (arg && arg->def && ((arg->def->flag) & VSH_OFLAG_REQ))
10327 vshError(NULL, _("Missing required option '%s'"), name);
10329 return NULL;
10333 * Returns option as long long
10335 static long long
10336 vshCommandOptLongLong(const vshCmd *cmd, const char *name, int *found)
10338 vshCmdOpt *arg = vshCommandOpt(cmd, name);
10339 int num_found = FALSE;
10340 long long res = 0;
10341 char *end_p = NULL;
10343 if ((arg != NULL) && (arg->data != NULL))
10344 num_found = !virStrToLong_ll(arg->data, &end_p, 10, &res);
10345 if (found)
10346 *found = num_found;
10347 return res;
10351 * Returns TRUE/FALSE if the option exists
10353 static int
10354 vshCommandOptBool(const vshCmd *cmd, const char *name)
10356 return vshCommandOpt(cmd, name) ? TRUE : FALSE;
10360 * Returns the COUNT argv argument, or NULL after last argument.
10362 * Requires that a VSH_OT_ARGV option with the name "" be last in the
10363 * list of supported options in CMD->def->opts.
10365 static char *
10366 vshCommandOptArgv(const vshCmd *cmd, int count)
10368 vshCmdOpt *opt = cmd->opts;
10370 while (opt) {
10371 if (opt->def && opt->def->type == VSH_OT_ARGV) {
10372 if (count-- == 0)
10373 return opt->data;
10375 opt = opt->next;
10377 return NULL;
10380 /* Determine whether CMD->opts includes an option with name OPTNAME.
10381 If not, give a diagnostic and return false.
10382 If so, return true. */
10383 static bool
10384 cmd_has_option (vshControl *ctl, const vshCmd *cmd, const char *optname)
10386 /* Iterate through cmd->opts, to ensure that there is an entry
10387 with name OPTNAME and type VSH_OT_DATA. */
10388 bool found = false;
10389 const vshCmdOpt *opt;
10390 for (opt = cmd->opts; opt; opt = opt->next) {
10391 if (STREQ (opt->def->name, optname) && opt->def->type == VSH_OT_DATA) {
10392 found = true;
10393 break;
10397 if (!found)
10398 vshError(ctl, _("internal error: virsh %s: no %s VSH_OT_DATA option"),
10399 cmd->def->name, optname);
10400 return found;
10403 static virDomainPtr
10404 vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
10405 char **name, int flag)
10407 virDomainPtr dom = NULL;
10408 char *n;
10409 int id;
10410 const char *optname = "domain";
10411 if (!cmd_has_option (ctl, cmd, optname))
10412 return NULL;
10414 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10415 return NULL;
10417 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10418 cmd->def->name, optname, n);
10420 if (name)
10421 *name = n;
10423 /* try it by ID */
10424 if (flag & VSH_BYID) {
10425 if (virStrToLong_i(n, NULL, 10, &id) == 0 && id >= 0) {
10426 vshDebug(ctl, 5, "%s: <%s> seems like domain ID\n",
10427 cmd->def->name, optname);
10428 dom = virDomainLookupByID(ctl->conn, id);
10431 /* try it by UUID */
10432 if (dom==NULL && (flag & VSH_BYUUID) && strlen(n)==VIR_UUID_STRING_BUFLEN-1) {
10433 vshDebug(ctl, 5, "%s: <%s> trying as domain UUID\n",
10434 cmd->def->name, optname);
10435 dom = virDomainLookupByUUIDString(ctl->conn, n);
10437 /* try it by NAME */
10438 if (dom==NULL && (flag & VSH_BYNAME)) {
10439 vshDebug(ctl, 5, "%s: <%s> trying as domain NAME\n",
10440 cmd->def->name, optname);
10441 dom = virDomainLookupByName(ctl->conn, n);
10444 if (!dom)
10445 vshError(ctl, _("failed to get domain '%s'"), n);
10447 return dom;
10450 static virNetworkPtr
10451 vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
10452 char **name, int flag)
10454 virNetworkPtr network = NULL;
10455 char *n;
10456 const char *optname = "network";
10457 if (!cmd_has_option (ctl, cmd, optname))
10458 return NULL;
10460 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10461 return NULL;
10463 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10464 cmd->def->name, optname, n);
10466 if (name)
10467 *name = n;
10469 /* try it by UUID */
10470 if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
10471 vshDebug(ctl, 5, "%s: <%s> trying as network UUID\n",
10472 cmd->def->name, optname);
10473 network = virNetworkLookupByUUIDString(ctl->conn, n);
10475 /* try it by NAME */
10476 if (network==NULL && (flag & VSH_BYNAME)) {
10477 vshDebug(ctl, 5, "%s: <%s> trying as network NAME\n",
10478 cmd->def->name, optname);
10479 network = virNetworkLookupByName(ctl->conn, n);
10482 if (!network)
10483 vshError(ctl, _("failed to get network '%s'"), n);
10485 return network;
10489 static virNWFilterPtr
10490 vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
10491 char **name, int flag)
10493 virNWFilterPtr nwfilter = NULL;
10494 char *n;
10495 const char *optname = "nwfilter";
10496 if (!cmd_has_option (ctl, cmd, optname))
10497 return NULL;
10499 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10500 return NULL;
10502 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10503 cmd->def->name, optname, n);
10505 if (name)
10506 *name = n;
10508 /* try it by UUID */
10509 if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
10510 vshDebug(ctl, 5, "%s: <%s> trying as nwfilter UUID\n",
10511 cmd->def->name, optname);
10512 nwfilter = virNWFilterLookupByUUIDString(ctl->conn, n);
10514 /* try it by NAME */
10515 if (nwfilter == NULL && (flag & VSH_BYNAME)) {
10516 vshDebug(ctl, 5, "%s: <%s> trying as nwfilter NAME\n",
10517 cmd->def->name, optname);
10518 nwfilter = virNWFilterLookupByName(ctl->conn, n);
10521 if (!nwfilter)
10522 vshError(ctl, _("failed to get nwfilter '%s'"), n);
10524 return nwfilter;
10527 static virInterfacePtr
10528 vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
10529 char **name, int flag)
10531 virInterfacePtr iface = NULL;
10532 char *n;
10533 const char *optname = "interface";
10534 if (!cmd_has_option (ctl, cmd, optname))
10535 return NULL;
10537 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10538 return NULL;
10540 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10541 cmd->def->name, optname, n);
10543 if (name)
10544 *name = n;
10546 /* try it by NAME */
10547 if ((flag & VSH_BYNAME)) {
10548 vshDebug(ctl, 5, "%s: <%s> trying as interface NAME\n",
10549 cmd->def->name, optname);
10550 iface = virInterfaceLookupByName(ctl->conn, n);
10552 /* try it by MAC */
10553 if ((iface == NULL) && (flag & VSH_BYMAC)) {
10554 vshDebug(ctl, 5, "%s: <%s> trying as interface MAC\n",
10555 cmd->def->name, optname);
10556 iface = virInterfaceLookupByMACString(ctl->conn, n);
10559 if (!iface)
10560 vshError(ctl, _("failed to get interface '%s'"), n);
10562 return iface;
10565 static virStoragePoolPtr
10566 vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
10567 char **name, int flag)
10569 virStoragePoolPtr pool = NULL;
10570 char *n;
10572 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10573 return NULL;
10575 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10576 cmd->def->name, optname, n);
10578 if (name)
10579 *name = n;
10581 /* try it by UUID */
10582 if ((flag & VSH_BYUUID) && (strlen(n) == VIR_UUID_STRING_BUFLEN-1)) {
10583 vshDebug(ctl, 5, "%s: <%s> trying as pool UUID\n",
10584 cmd->def->name, optname);
10585 pool = virStoragePoolLookupByUUIDString(ctl->conn, n);
10587 /* try it by NAME */
10588 if (pool == NULL && (flag & VSH_BYNAME)) {
10589 vshDebug(ctl, 5, "%s: <%s> trying as pool NAME\n",
10590 cmd->def->name, optname);
10591 pool = virStoragePoolLookupByName(ctl->conn, n);
10594 if (!pool)
10595 vshError(ctl, _("failed to get pool '%s'"), n);
10597 return pool;
10600 static virStorageVolPtr
10601 vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
10602 const char *optname,
10603 const char *pooloptname,
10604 char **name, int flag)
10606 virStorageVolPtr vol = NULL;
10607 virStoragePoolPtr pool = NULL;
10608 char *n, *p;
10609 int found;
10611 if (!(n = vshCommandOptString(cmd, optname, NULL)))
10612 return NULL;
10614 if (!(p = vshCommandOptString(cmd, pooloptname, &found)) && found)
10615 return NULL;
10617 if (p)
10618 pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag);
10620 vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
10621 cmd->def->name, optname, n);
10623 if (name)
10624 *name = n;
10626 /* try it by name */
10627 if (pool && (flag & VSH_BYNAME)) {
10628 vshDebug(ctl, 5, "%s: <%s> trying as vol name\n",
10629 cmd->def->name, optname);
10630 vol = virStorageVolLookupByName(pool, n);
10632 /* try it by key */
10633 if (vol == NULL && (flag & VSH_BYUUID)) {
10634 vshDebug(ctl, 5, "%s: <%s> trying as vol key\n",
10635 cmd->def->name, optname);
10636 vol = virStorageVolLookupByKey(ctl->conn, n);
10638 /* try it by path */
10639 if (vol == NULL && (flag & VSH_BYUUID)) {
10640 vshDebug(ctl, 5, "%s: <%s> trying as vol path\n",
10641 cmd->def->name, optname);
10642 vol = virStorageVolLookupByPath(ctl->conn, n);
10645 if (!vol)
10646 vshError(ctl, _("failed to get vol '%s'"), n);
10648 if (pool)
10649 virStoragePoolFree(pool);
10651 return vol;
10654 static virSecretPtr
10655 vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, char **name)
10657 virSecretPtr secret = NULL;
10658 char *n;
10659 const char *optname = "secret";
10661 if (!cmd_has_option (ctl, cmd, optname))
10662 return NULL;
10664 n = vshCommandOptString(cmd, optname, NULL);
10665 if (n == NULL)
10666 return NULL;
10668 vshDebug(ctl, 5, "%s: found option <%s>: %s\n", cmd->def->name, optname, n);
10670 if (name != NULL)
10671 *name = n;
10673 secret = virSecretLookupByUUIDString(ctl->conn, n);
10675 if (secret == NULL)
10676 vshError(ctl, _("failed to get secret '%s'"), n);
10678 return secret;
10682 * Executes command(s) and returns return code from last command
10684 static int
10685 vshCommandRun(vshControl *ctl, const vshCmd *cmd)
10687 int ret = TRUE;
10689 while (cmd) {
10690 struct timeval before, after;
10691 bool enable_timing = ctl->timing;
10693 if ((ctl->conn == NULL) || (disconnected != 0))
10694 vshReconnect(ctl);
10696 if (enable_timing)
10697 GETTIMEOFDAY(&before);
10699 ret = cmd->def->handler(ctl, cmd);
10701 if (enable_timing)
10702 GETTIMEOFDAY(&after);
10704 if (ret == FALSE)
10705 virshReportError(ctl);
10707 /* try to automatically catch disconnections */
10708 if ((ret == FALSE) &&
10709 ((disconnected != 0) ||
10710 ((last_error != NULL) &&
10711 (((last_error->code == VIR_ERR_SYSTEM_ERROR) &&
10712 (last_error->domain == VIR_FROM_REMOTE)) ||
10713 (last_error->code == VIR_ERR_RPC) ||
10714 (last_error->code == VIR_ERR_NO_CONNECT) ||
10715 (last_error->code == VIR_ERR_INVALID_CONN)))))
10716 vshReconnect(ctl);
10718 if (STREQ(cmd->def->name, "quit")) /* hack ... */
10719 return ret;
10721 if (enable_timing)
10722 vshPrint(ctl, _("\n(Time: %.3f ms)\n\n"),
10723 DIFF_MSEC(&after, &before));
10724 else
10725 vshPrintExtra(ctl, "\n");
10726 cmd = cmd->next;
10728 return ret;
10731 /* ---------------
10732 * Command parsing
10733 * ---------------
10736 typedef enum {
10737 VSH_TK_ERROR, /* Failed to parse a token */
10738 VSH_TK_ARG, /* Arbitrary argument, might be option or empty */
10739 VSH_TK_SUBCMD_END, /* Separation between commands */
10740 VSH_TK_END /* No more commands */
10741 } vshCommandToken;
10743 typedef struct __vshCommandParser {
10744 vshCommandToken (*getNextArg)(vshControl *, struct __vshCommandParser *,
10745 char **);
10746 /* vshCommandStringGetArg() */
10747 char *pos;
10748 /* vshCommandArgvGetArg() */
10749 char **arg_pos;
10750 char **arg_end;
10751 } vshCommandParser;
10753 static int
10754 vshCommandParse(vshControl *ctl, vshCommandParser *parser)
10756 char *tkdata = NULL;
10757 vshCmd *clast = NULL;
10758 vshCmdOpt *first = NULL;
10760 if (ctl->cmd) {
10761 vshCommandFree(ctl->cmd);
10762 ctl->cmd = NULL;
10765 while (1) {
10766 vshCmdOpt *last = NULL;
10767 const vshCmdDef *cmd = NULL;
10768 vshCommandToken tk;
10769 bool data_only = false;
10770 int data_ct = 0;
10772 first = NULL;
10774 while (1) {
10775 const vshCmdOptDef *opt = NULL;
10777 tkdata = NULL;
10778 tk = parser->getNextArg(ctl, parser, &tkdata);
10780 if (tk == VSH_TK_ERROR)
10781 goto syntaxError;
10782 if (tk != VSH_TK_ARG)
10783 break;
10785 if (cmd == NULL) {
10786 /* first token must be command name */
10787 if (!(cmd = vshCmddefSearch(tkdata))) {
10788 vshError(ctl, _("unknown command: '%s'"), tkdata);
10789 goto syntaxError; /* ... or ignore this command only? */
10791 VIR_FREE(tkdata);
10792 } else if (data_only) {
10793 goto get_data;
10794 } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
10795 c_isalnum(tkdata[2])) {
10796 char *optstr = strchr(tkdata + 2, '=');
10797 if (optstr) {
10798 *optstr = '\0'; /* convert the '=' to '\0' */
10799 optstr = vshStrdup(ctl, optstr + 1);
10801 if (!(opt = vshCmddefGetOption(cmd, tkdata + 2))) {
10802 vshError(ctl,
10803 _("command '%s' doesn't support option --%s"),
10804 cmd->name, tkdata + 2);
10805 VIR_FREE(optstr);
10806 goto syntaxError;
10808 VIR_FREE(tkdata);
10810 if (opt->type != VSH_OT_BOOL) {
10811 /* option data */
10812 if (optstr)
10813 tkdata = optstr;
10814 else
10815 tk = parser->getNextArg(ctl, parser, &tkdata);
10816 if (tk == VSH_TK_ERROR)
10817 goto syntaxError;
10818 if (tk != VSH_TK_ARG) {
10819 vshError(ctl,
10820 _("expected syntax: --%s <%s>"),
10821 opt->name,
10822 opt->type ==
10823 VSH_OT_INT ? _("number") : _("string"));
10824 goto syntaxError;
10826 } else {
10827 tkdata = NULL;
10828 if (optstr) {
10829 vshError(ctl, _("invalid '=' after option --%s"),
10830 opt->name);
10831 VIR_FREE(optstr);
10832 goto syntaxError;
10835 } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
10836 tkdata[2] == '\0') {
10837 data_only = true;
10838 continue;
10839 } else {
10840 get_data:
10841 if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
10842 vshError(ctl, _("unexpected data '%s'"), tkdata);
10843 goto syntaxError;
10846 if (opt) {
10847 /* save option */
10848 vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
10850 arg->def = opt;
10851 arg->data = tkdata;
10852 arg->next = NULL;
10853 tkdata = NULL;
10855 if (!first)
10856 first = arg;
10857 if (last)
10858 last->next = arg;
10859 last = arg;
10861 vshDebug(ctl, 4, "%s: %s(%s): %s\n",
10862 cmd->name,
10863 opt->name,
10864 opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
10865 opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
10869 /* command parsed -- allocate new struct for the command */
10870 if (cmd) {
10871 vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
10873 c->opts = first;
10874 c->def = cmd;
10875 c->next = NULL;
10877 if (!vshCommandCheckOpts(ctl, c)) {
10878 VIR_FREE(c);
10879 goto syntaxError;
10882 if (!ctl->cmd)
10883 ctl->cmd = c;
10884 if (clast)
10885 clast->next = c;
10886 clast = c;
10889 if (tk == VSH_TK_END)
10890 break;
10893 return TRUE;
10895 syntaxError:
10896 if (ctl->cmd) {
10897 vshCommandFree(ctl->cmd);
10898 ctl->cmd = NULL;
10900 if (first)
10901 vshCommandOptFree(first);
10902 VIR_FREE(tkdata);
10903 return FALSE;
10906 /* --------------------
10907 * Command argv parsing
10908 * --------------------
10911 static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
10912 vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
10914 if (parser->arg_pos == parser->arg_end) {
10915 *res = NULL;
10916 return VSH_TK_END;
10919 *res = vshStrdup(ctl, *parser->arg_pos);
10920 parser->arg_pos++;
10921 return VSH_TK_ARG;
10924 static int vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
10926 vshCommandParser parser;
10928 if (nargs <= 0)
10929 return FALSE;
10931 parser.arg_pos = argv;
10932 parser.arg_end = argv + nargs;
10933 parser.getNextArg = vshCommandArgvGetArg;
10934 return vshCommandParse(ctl, &parser);
10937 /* ----------------------
10938 * Command string parsing
10939 * ----------------------
10942 static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
10943 vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
10945 bool single_quote = false;
10946 bool double_quote = false;
10947 int sz = 0;
10948 char *p = parser->pos;
10949 char *q = vshStrdup(ctl, p);
10951 *res = q;
10953 while (*p && (*p == ' ' || *p == '\t'))
10954 p++;
10956 if (*p == '\0')
10957 return VSH_TK_END;
10958 if (*p == ';') {
10959 parser->pos = ++p; /* = \0 or begin of next command */
10960 return VSH_TK_SUBCMD_END;
10963 while (*p) {
10964 /* end of token is blank space or ';' */
10965 if (!double_quote && !single_quote &&
10966 (*p == ' ' || *p == '\t' || *p == ';'))
10967 break;
10969 if (!double_quote && *p == '\'') { /* single quote */
10970 single_quote = !single_quote;
10971 p++;
10972 continue;
10973 } else if (!single_quote && *p == '\\') { /* escape */
10975 * The same as the bash, a \ in "" is an escaper,
10976 * but a \ in '' is not an escaper.
10978 p++;
10979 if (*p == '\0') {
10980 vshError(ctl, "%s", _("dangling \\"));
10981 return VSH_TK_ERROR;
10983 } else if (!single_quote && *p == '"') { /* double quote */
10984 double_quote = !double_quote;
10985 p++;
10986 continue;
10989 *q++ = *p++;
10990 sz++;
10992 if (double_quote) {
10993 vshError(ctl, "%s", _("missing \""));
10994 return VSH_TK_ERROR;
10997 *q = '\0';
10998 parser->pos = p;
10999 return VSH_TK_ARG;
11002 static int vshCommandStringParse(vshControl *ctl, char *cmdstr)
11004 vshCommandParser parser;
11006 if (cmdstr == NULL || *cmdstr == '\0')
11007 return FALSE;
11009 parser.pos = cmdstr;
11010 parser.getNextArg = vshCommandStringGetArg;
11011 return vshCommandParse(ctl, &parser);
11014 /* ---------------
11015 * Misc utils
11016 * ---------------
11018 static const char *
11019 vshDomainStateToString(int state)
11021 switch (state) {
11022 case VIR_DOMAIN_RUNNING:
11023 return N_("running");
11024 case VIR_DOMAIN_BLOCKED:
11025 return N_("idle");
11026 case VIR_DOMAIN_PAUSED:
11027 return N_("paused");
11028 case VIR_DOMAIN_SHUTDOWN:
11029 return N_("in shutdown");
11030 case VIR_DOMAIN_SHUTOFF:
11031 return N_("shut off");
11032 case VIR_DOMAIN_CRASHED:
11033 return N_("crashed");
11034 default:
11035 ;/*FALLTHROUGH*/
11037 return N_("no state"); /* = dom0 state */
11040 static const char *
11041 vshDomainVcpuStateToString(int state)
11043 switch (state) {
11044 case VIR_VCPU_OFFLINE:
11045 return N_("offline");
11046 case VIR_VCPU_BLOCKED:
11047 return N_("idle");
11048 case VIR_VCPU_RUNNING:
11049 return N_("running");
11050 default:
11051 ;/*FALLTHROUGH*/
11053 return N_("no state");
11056 static int
11057 vshConnectionUsability(vshControl *ctl, virConnectPtr conn)
11059 /* TODO: use something like virConnectionState() to
11060 * check usability of the connection
11062 if (!conn) {
11063 vshError(ctl, "%s", _("no valid connection"));
11064 return FALSE;
11066 return TRUE;
11069 static void
11070 vshDebug(vshControl *ctl, int level, const char *format, ...)
11072 va_list ap;
11074 va_start(ap, format);
11075 vshOutputLogFile(ctl, VSH_ERR_DEBUG, format, ap);
11076 va_end(ap);
11078 if (level > ctl->debug)
11079 return;
11081 va_start(ap, format);
11082 vfprintf(stdout, format, ap);
11083 va_end(ap);
11086 static void
11087 vshPrintExtra(vshControl *ctl, const char *format, ...)
11089 va_list ap;
11091 if (ctl->quiet == TRUE)
11092 return;
11094 va_start(ap, format);
11095 vfprintf(stdout, format, ap);
11096 va_end(ap);
11100 static void
11101 vshError(vshControl *ctl, const char *format, ...)
11103 va_list ap;
11105 if (ctl != NULL) {
11106 va_start(ap, format);
11107 vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
11108 va_end(ap);
11111 fputs(_("error: "), stderr);
11113 va_start(ap, format);
11114 vfprintf(stderr, format, ap);
11115 va_end(ap);
11117 fputc('\n', stderr);
11121 * Initialize connection.
11123 static int
11124 vshInit(vshControl *ctl)
11126 if (ctl->conn)
11127 return FALSE;
11129 vshOpenLogFile(ctl);
11131 /* set up the library error handler */
11132 virSetErrorFunc(NULL, virshErrorHandler);
11134 /* set up the signals handlers to catch disconnections */
11135 vshSetupSignals();
11137 ctl->conn = virConnectOpenAuth(ctl->name,
11138 virConnectAuthPtrDefault,
11139 ctl->readonly ? VIR_CONNECT_RO : 0);
11142 /* This is not necessarily fatal. All the individual commands check
11143 * vshConnectionUsability, except ones which don't need a connection
11144 * such as "help".
11146 if (!ctl->conn) {
11147 virshReportError(ctl);
11148 vshError(ctl, "%s", _("failed to connect to the hypervisor"));
11149 return FALSE;
11152 return TRUE;
11155 #define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT | O_SYNC)
11158 * vshOpenLogFile:
11160 * Open log file.
11162 static void
11163 vshOpenLogFile(vshControl *ctl)
11165 struct stat st;
11167 if (ctl->logfile == NULL)
11168 return;
11170 /* check log file */
11171 if (stat(ctl->logfile, &st) == -1) {
11172 switch (errno) {
11173 case ENOENT:
11174 break;
11175 default:
11176 vshError(ctl, "%s",
11177 _("failed to get the log file information"));
11178 exit(EXIT_FAILURE);
11180 } else {
11181 if (!S_ISREG(st.st_mode)) {
11182 vshError(ctl, "%s", _("the log path is not a file"));
11183 exit(EXIT_FAILURE);
11187 /* log file open */
11188 if ((ctl->log_fd = open(ctl->logfile, LOGFILE_FLAGS, FILE_MODE)) < 0) {
11189 vshError(ctl, "%s",
11190 _("failed to open the log file. check the log file path"));
11191 exit(EXIT_FAILURE);
11196 * vshOutputLogFile:
11198 * Outputting an error to log file.
11200 static void
11201 vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format, va_list ap)
11203 char msg_buf[MSG_BUFFER];
11204 const char *lvl = "";
11205 struct timeval stTimeval;
11206 struct tm *stTm;
11208 if (ctl->log_fd == -1)
11209 return;
11212 * create log format
11214 * [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message
11216 gettimeofday(&stTimeval, NULL);
11217 stTm = localtime(&stTimeval.tv_sec);
11218 snprintf(msg_buf, sizeof(msg_buf),
11219 "[%d.%02d.%02d %02d:%02d:%02d ",
11220 (1900 + stTm->tm_year),
11221 (1 + stTm->tm_mon),
11222 (stTm->tm_mday),
11223 (stTm->tm_hour),
11224 (stTm->tm_min),
11225 (stTm->tm_sec));
11226 snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
11227 "%s] ", SIGN_NAME);
11228 switch (log_level) {
11229 case VSH_ERR_DEBUG:
11230 lvl = LVL_DEBUG;
11231 break;
11232 case VSH_ERR_INFO:
11233 lvl = LVL_INFO;
11234 break;
11235 case VSH_ERR_NOTICE:
11236 lvl = LVL_INFO;
11237 break;
11238 case VSH_ERR_WARNING:
11239 lvl = LVL_WARNING;
11240 break;
11241 case VSH_ERR_ERROR:
11242 lvl = LVL_ERROR;
11243 break;
11244 default:
11245 lvl = LVL_DEBUG;
11246 break;
11248 snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
11249 "%s ", lvl);
11250 vsnprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf),
11251 msg_format, ap);
11253 if (msg_buf[strlen(msg_buf) - 1] != '\n')
11254 snprintf(msg_buf + strlen(msg_buf), sizeof(msg_buf) - strlen(msg_buf), "\n");
11256 /* write log */
11257 if (safewrite(ctl->log_fd, msg_buf, strlen(msg_buf)) < 0) {
11258 vshCloseLogFile(ctl);
11259 vshError(ctl, "%s", _("failed to write the log file"));
11264 * vshCloseLogFile:
11266 * Close log file.
11268 static void
11269 vshCloseLogFile(vshControl *ctl)
11271 /* log file close */
11272 if (ctl->log_fd >= 0) {
11273 if (close(ctl->log_fd) < 0)
11274 vshError(ctl, _("%s: failed to write log file: %s"),
11275 ctl->logfile ? ctl->logfile : "?", strerror (errno));
11276 ctl->log_fd = -1;
11279 if (ctl->logfile) {
11280 VIR_FREE(ctl->logfile);
11281 ctl->logfile = NULL;
11285 #ifdef USE_READLINE
11287 /* -----------------
11288 * Readline stuff
11289 * -----------------
11293 * Generator function for command completion. STATE lets us
11294 * know whether to start from scratch; without any state
11295 * (i.e. STATE == 0), then we start at the top of the list.
11297 static char *
11298 vshReadlineCommandGenerator(const char *text, int state)
11300 static int list_index, len;
11301 const char *name;
11303 /* If this is a new word to complete, initialize now. This
11304 * includes saving the length of TEXT for efficiency, and
11305 * initializing the index variable to 0.
11307 if (!state) {
11308 list_index = 0;
11309 len = strlen(text);
11312 /* Return the next name which partially matches from the
11313 * command list.
11315 while ((name = commands[list_index].name)) {
11316 list_index++;
11317 if (STREQLEN(name, text, len))
11318 return vshStrdup(NULL, name);
11321 /* If no names matched, then return NULL. */
11322 return NULL;
11325 static char *
11326 vshReadlineOptionsGenerator(const char *text, int state)
11328 static int list_index, len;
11329 static const vshCmdDef *cmd = NULL;
11330 const char *name;
11332 if (!state) {
11333 /* determine command name */
11334 char *p;
11335 char *cmdname;
11337 if (!(p = strchr(rl_line_buffer, ' ')))
11338 return NULL;
11340 cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
11341 memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
11343 cmd = vshCmddefSearch(cmdname);
11344 list_index = 0;
11345 len = strlen(text);
11346 VIR_FREE(cmdname);
11349 if (!cmd)
11350 return NULL;
11352 if (!cmd->opts)
11353 return NULL;
11355 while ((name = cmd->opts[list_index].name)) {
11356 const vshCmdOptDef *opt = &cmd->opts[list_index];
11357 char *res;
11359 list_index++;
11361 if (opt->type == VSH_OT_DATA)
11362 /* ignore non --option */
11363 continue;
11365 if (len > 2) {
11366 if (STRNEQLEN(name, text + 2, len - 2))
11367 continue;
11369 res = vshMalloc(NULL, strlen(name) + 3);
11370 snprintf(res, strlen(name) + 3, "--%s", name);
11371 return res;
11374 /* If no names matched, then return NULL. */
11375 return NULL;
11378 static char **
11379 vshReadlineCompletion(const char *text, int start,
11380 int end ATTRIBUTE_UNUSED)
11382 char **matches = (char **) NULL;
11384 if (start == 0)
11385 /* command name generator */
11386 matches = rl_completion_matches(text, vshReadlineCommandGenerator);
11387 else
11388 /* commands options */
11389 matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
11390 return matches;
11394 static int
11395 vshReadlineInit(vshControl *ctl)
11397 char *userdir = NULL;
11399 /* Allow conditional parsing of the ~/.inputrc file. */
11400 rl_readline_name = "virsh";
11402 /* Tell the completer that we want a crack first. */
11403 rl_attempted_completion_function = vshReadlineCompletion;
11405 /* Limit the total size of the history buffer */
11406 stifle_history(500);
11408 /* Prepare to read/write history from/to the ~/.virsh/history file */
11409 userdir = virGetUserDirectory(getuid());
11411 if (userdir == NULL)
11412 return -1;
11414 if (virAsprintf(&ctl->historydir, "%s/.virsh", userdir) < 0) {
11415 vshError(ctl, "%s", _("Out of memory"));
11416 VIR_FREE(userdir);
11417 return -1;
11420 if (virAsprintf(&ctl->historyfile, "%s/history", ctl->historydir) < 0) {
11421 vshError(ctl, "%s", _("Out of memory"));
11422 VIR_FREE(userdir);
11423 return -1;
11426 VIR_FREE(userdir);
11428 read_history(ctl->historyfile);
11430 return 0;
11433 static void
11434 vshReadlineDeinit (vshControl *ctl)
11436 if (ctl->historyfile != NULL) {
11437 if (mkdir(ctl->historydir, 0755) < 0 && errno != EEXIST) {
11438 char ebuf[1024];
11439 vshError(ctl, _("Failed to create '%s': %s"),
11440 ctl->historydir, virStrerror(errno, ebuf, sizeof ebuf));
11441 } else
11442 write_history(ctl->historyfile);
11445 VIR_FREE(ctl->historydir);
11446 VIR_FREE(ctl->historyfile);
11449 static char *
11450 vshReadline (vshControl *ctl ATTRIBUTE_UNUSED, const char *prompt)
11452 return readline (prompt);
11455 #else /* !USE_READLINE */
11457 static int
11458 vshReadlineInit (vshControl *ctl ATTRIBUTE_UNUSED)
11460 /* empty */
11461 return 0;
11464 static void
11465 vshReadlineDeinit (vshControl *ctl ATTRIBUTE_UNUSED)
11467 /* empty */
11470 static char *
11471 vshReadline (vshControl *ctl, const char *prompt)
11473 char line[1024];
11474 char *r;
11475 int len;
11477 fputs (prompt, stdout);
11478 r = fgets (line, sizeof line, stdin);
11479 if (r == NULL) return NULL; /* EOF */
11481 /* Chomp trailing \n */
11482 len = strlen (r);
11483 if (len > 0 && r[len-1] == '\n')
11484 r[len-1] = '\0';
11486 return vshStrdup (ctl, r);
11489 #endif /* !USE_READLINE */
11492 * Deinitialize virsh
11494 static int
11495 vshDeinit(vshControl *ctl)
11497 vshReadlineDeinit(ctl);
11498 vshCloseLogFile(ctl);
11499 VIR_FREE(ctl->name);
11500 if (ctl->conn) {
11501 if (virConnectClose(ctl->conn) != 0) {
11502 vshError(ctl, "%s", _("failed to disconnect from the hypervisor"));
11505 virResetLastError();
11507 return TRUE;
11511 * Print usage
11513 static void
11514 vshUsage(void)
11516 const vshCmdDef *cmd;
11517 fprintf(stdout, _("\n%s [options]... [<command_string>]"
11518 "\n%s [options]... <command> [args...]\n\n"
11519 " options:\n"
11520 " -c | --connect <uri> hypervisor connection URI\n"
11521 " -r | --readonly connect readonly\n"
11522 " -d | --debug <num> debug level [0-5]\n"
11523 " -h | --help this help\n"
11524 " -q | --quiet quiet mode\n"
11525 " -t | --timing print timing information\n"
11526 " -l | --log <file> output logging to file\n"
11527 " -v | --version program version\n\n"
11528 " commands (non interactive mode):\n"), progname, progname);
11530 for (cmd = commands; cmd->name; cmd++)
11531 fprintf(stdout,
11532 " %-15s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help")));
11534 fprintf(stdout, "%s",
11535 _("\n (specify help <command> for details about the command)\n\n"));
11536 return;
11540 * argv[]: virsh [options] [command]
11543 static int
11544 vshParseArgv(vshControl *ctl, int argc, char **argv)
11546 bool help = false;
11547 int arg;
11548 struct option opt[] = {
11549 {"debug", 1, 0, 'd'},
11550 {"help", 0, 0, 'h'},
11551 {"quiet", 0, 0, 'q'},
11552 {"timing", 0, 0, 't'},
11553 {"version", 0, 0, 'v'},
11554 {"connect", 1, 0, 'c'},
11555 {"readonly", 0, 0, 'r'},
11556 {"log", 1, 0, 'l'},
11557 {0, 0, 0, 0}
11560 /* Standard (non-command) options. The leading + ensures that no
11561 * argument reordering takes place, so that command options are
11562 * not confused with top-level virsh options. */
11563 while ((arg = getopt_long(argc, argv, "+d:hqtc:vrl:", opt, NULL)) != -1) {
11564 switch (arg) {
11565 case 'd':
11566 if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) {
11567 vshError(ctl, "%s", _("option -d takes a numeric argument"));
11568 exit(EXIT_FAILURE);
11570 break;
11571 case 'h':
11572 help = true;
11573 break;
11574 case 'q':
11575 ctl->quiet = TRUE;
11576 break;
11577 case 't':
11578 ctl->timing = TRUE;
11579 break;
11580 case 'c':
11581 ctl->name = vshStrdup(ctl, optarg);
11582 break;
11583 case 'v':
11584 /* FIXME - list a copyright blurb, as in GNU programs? */
11585 puts(VERSION);
11586 exit(EXIT_SUCCESS);
11587 case 'r':
11588 ctl->readonly = TRUE;
11589 break;
11590 case 'l':
11591 ctl->logfile = vshStrdup(ctl, optarg);
11592 break;
11593 default:
11594 vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
11595 exit(EXIT_FAILURE);
11599 if (help) {
11600 if (optind < argc) {
11601 vshError(ctl, _("extra argument '%s'. See --help."), argv[optind]);
11602 exit(EXIT_FAILURE);
11605 /* list all command */
11606 vshUsage();
11607 exit(EXIT_SUCCESS);
11610 if (argc > optind) {
11611 /* parse command */
11612 ctl->imode = FALSE;
11613 if (argc - optind == 1) {
11614 vshDebug(ctl, 2, "commands: \"%s\"\n", argv[optind]);
11615 return vshCommandStringParse(ctl, argv[optind]);
11616 } else {
11617 return vshCommandArgvParse(ctl, argc - optind, argv + optind);
11620 return TRUE;
11624 main(int argc, char **argv)
11626 vshControl _ctl, *ctl = &_ctl;
11627 char *defaultConn;
11628 int ret = TRUE;
11630 if (!setlocale(LC_ALL, "")) {
11631 perror("setlocale");
11632 /* failure to setup locale is not fatal */
11634 if (!bindtextdomain(GETTEXT_PACKAGE, LOCALEBASEDIR)) {
11635 perror("bindtextdomain");
11636 return -1;
11638 if (!textdomain(GETTEXT_PACKAGE)) {
11639 perror("textdomain");
11640 return -1;
11643 if (!(progname = strrchr(argv[0], '/')))
11644 progname = argv[0];
11645 else
11646 progname++;
11648 memset(ctl, 0, sizeof(vshControl));
11649 ctl->imode = TRUE; /* default is interactive mode */
11650 ctl->log_fd = -1; /* Initialize log file descriptor */
11652 if ((defaultConn = getenv("VIRSH_DEFAULT_CONNECT_URI"))) {
11653 ctl->name = vshStrdup(ctl, defaultConn);
11656 if (!vshParseArgv(ctl, argc, argv)) {
11657 vshDeinit(ctl);
11658 exit(EXIT_FAILURE);
11661 if (!vshInit(ctl)) {
11662 vshDeinit(ctl);
11663 exit(EXIT_FAILURE);
11666 if (!ctl->imode) {
11667 ret = vshCommandRun(ctl, ctl->cmd);
11668 } else {
11669 /* interactive mode */
11670 if (!ctl->quiet) {
11671 vshPrint(ctl,
11672 _("Welcome to %s, the virtualization interactive terminal.\n\n"),
11673 progname);
11674 vshPrint(ctl, "%s",
11675 _("Type: 'help' for help with commands\n"
11676 " 'quit' to quit\n\n"));
11679 if (vshReadlineInit(ctl) < 0) {
11680 vshDeinit(ctl);
11681 exit(EXIT_FAILURE);
11684 do {
11685 const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW;
11686 ctl->cmdstr =
11687 vshReadline(ctl, prompt);
11688 if (ctl->cmdstr == NULL)
11689 break; /* EOF */
11690 if (*ctl->cmdstr) {
11691 #if USE_READLINE
11692 add_history(ctl->cmdstr);
11693 #endif
11694 if (vshCommandStringParse(ctl, ctl->cmdstr))
11695 vshCommandRun(ctl, ctl->cmd);
11697 VIR_FREE(ctl->cmdstr);
11698 } while (ctl->imode);
11700 if (ctl->cmdstr == NULL)
11701 fputc('\n', stdout); /* line break after alone prompt */
11704 vshDeinit(ctl);
11705 exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);