2005-11-10 16:12:31 +00:00
|
|
|
/*
|
2010-06-09 09:00:30 +00:00
|
|
|
* virsh.c: a shell to exercise the libvirt API
|
2005-11-10 16:12:31 +00:00
|
|
|
*
|
2012-01-09 18:57:46 +00:00
|
|
|
* Copyright (C) 2005, 2007-2012 Red Hat, Inc.
|
2005-11-10 16:12:31 +00:00
|
|
|
*
|
2012-07-27 09:39:53 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
2005-11-10 16:12:31 +00:00
|
|
|
*
|
|
|
|
* Daniel Veillard <veillard@redhat.com>
|
2005-12-08 14:22:52 +00:00
|
|
|
* Karel Zak <kzak@redhat.com>
|
2006-05-29 15:39:31 +00:00
|
|
|
* Daniel P. Berrange <berrange@redhat.com>
|
2005-11-10 16:12:31 +00:00
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-12-04 18:27:52 +00:00
|
|
|
|
2005-11-10 16:12:31 +00:00
|
|
|
#include <stdio.h>
|
2005-12-08 10:23:34 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
2005-12-01 16:35:42 +00:00
|
|
|
#include <unistd.h>
|
2007-05-23 15:09:19 +00:00
|
|
|
#include <errno.h>
|
2005-12-08 10:23:34 +00:00
|
|
|
#include <getopt.h>
|
2005-12-01 16:35:42 +00:00
|
|
|
#include <sys/types.h>
|
2005-12-08 14:22:52 +00:00
|
|
|
#include <sys/time.h>
|
2010-05-11 15:32:19 +00:00
|
|
|
#include <sys/wait.h>
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
#include "c-ctype.h"
|
2006-03-30 16:08:13 +00:00
|
|
|
#include <fcntl.h>
|
2006-09-29 16:23:27 +00:00
|
|
|
#include <locale.h>
|
2007-11-29 09:18:04 +00:00
|
|
|
#include <time.h>
|
2007-06-15 15:24:20 +00:00
|
|
|
#include <limits.h>
|
2007-06-05 12:06:08 +00:00
|
|
|
#include <assert.h>
|
2007-06-06 12:24:31 +00:00
|
|
|
#include <sys/stat.h>
|
2007-08-21 10:08:12 +00:00
|
|
|
#include <inttypes.h>
|
2010-03-05 09:59:52 +00:00
|
|
|
#include <signal.h>
|
2011-01-25 10:14:28 +00:00
|
|
|
#include <poll.h>
|
2011-07-15 21:49:37 +00:00
|
|
|
#include <strings.h>
|
2012-05-18 10:21:06 +00:00
|
|
|
#include <termios.h>
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2007-01-26 11:54:29 +00:00
|
|
|
#include <libxml/parser.h>
|
|
|
|
#include <libxml/tree.h>
|
|
|
|
#include <libxml/xpath.h>
|
2010-02-17 13:52:07 +00:00
|
|
|
#include <libxml/xmlsave.h>
|
2007-01-26 11:54:29 +00:00
|
|
|
|
2007-12-04 18:27:52 +00:00
|
|
|
#ifdef HAVE_READLINE_READLINE_H
|
2010-03-09 18:22:22 +00:00
|
|
|
# include <readline/readline.h>
|
|
|
|
# include <readline/history.h>
|
2007-12-04 18:27:52 +00:00
|
|
|
#endif
|
2005-12-08 10:23:34 +00:00
|
|
|
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
#include "internal.h"
|
2010-01-03 14:45:10 +00:00
|
|
|
#include "virterror_internal.h"
|
2009-07-28 10:27:25 +00:00
|
|
|
#include "base64.h"
|
Use safewrite in place of write, in many cases.
Also add "make syntax-check" rules to ensure no new uses sneak in.
There are many uses of write like this:
if (write (fd, xml, towrite) != towrite)
return -1;
The problem is that the syscall can succeed, yet write less than
the requested number of bytes, so the caller should retry
rather than simply failing.
This patch changes most of them to use util.c's safewrite wrapper,
which encapsulates the process. Also, there were a few cases in
which the retry loop was open-coded, and I replaced those, too.
* Makefile.maint (sc_avoid_write): New rule, to avoid recurrence.
* .x-sc_avoid_write: New file. Record two legitimate exemptions.
* qemud/qemud.c (sig_handler, qemudClientWriteBuf): Use safewrite, not write.
* src/conf.c (__virConfWriteFile): Likewise.
* src/qemu_conf.c (qemudSaveConfig, qemudSaveNetworkConfig): Likewise.
* src/qemu_driver.c (qemudWaitForMonitor, qemudStartVMDaemon)
(qemudVMData, PROC_IP_FORWARD): Likewise.
* proxy/libvirt_proxy.c: Include "util.h".
(proxyWriteClientSocket): Use safewrite.
* src/test.c (testDomainSave, testDomainCoreDump): Likewise.
* src/proxy_internal.c (virProxyWriteClientSocket): Likewise.
* src/virsh.c: Include "util-lib.h".
(vshOutputLogFile): Use safewrite.
* src/console.c: Include "util-lib.h".
(vshRunConsole): Use safewrite.
2008-02-22 15:55:04 +00:00
|
|
|
#include "buf.h"
|
2007-01-26 11:54:29 +00:00
|
|
|
#include "console.h"
|
2008-01-21 15:27:14 +00:00
|
|
|
#include "util.h"
|
2010-01-03 16:13:27 +00:00
|
|
|
#include "memory.h"
|
2010-03-31 20:28:00 +00:00
|
|
|
#include "xml.h"
|
2010-04-13 18:08:59 +00:00
|
|
|
#include "libvirt/libvirt-qemu.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2011-02-24 17:58:04 +00:00
|
|
|
#include "event_poll.h"
|
2010-11-16 14:54:17 +00:00
|
|
|
#include "configmake.h"
|
2011-01-25 10:14:28 +00:00
|
|
|
#include "threads.h"
|
2011-01-28 21:22:39 +00:00
|
|
|
#include "command.h"
|
2011-07-21 07:49:10 +00:00
|
|
|
#include "virkeycode.h"
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
#include "virnetdevbandwidth.h"
|
2011-06-06 10:20:11 +00:00
|
|
|
#include "util/bitmap.h"
|
2011-12-20 08:35:03 +00:00
|
|
|
#include "conf/domain_conf.h"
|
2012-01-02 22:03:19 +00:00
|
|
|
#include "virtypedparam.h"
|
2012-06-19 13:18:16 +00:00
|
|
|
#include "conf/virdomainlist.h"
|
2005-12-08 10:23:34 +00:00
|
|
|
|
|
|
|
static char *progname;
|
|
|
|
|
2008-01-21 15:27:14 +00:00
|
|
|
#define VIRSH_MAX_XML_FILE 10*1024*1024
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
#define VSH_PROMPT_RW "virsh # "
|
|
|
|
#define VSH_PROMPT_RO "virsh > "
|
|
|
|
|
2011-08-18 21:37:14 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
#define GETTIMEOFDAY(T) gettimeofday(T, NULL)
|
|
|
|
#define DIFF_MSEC(T, U) \
|
|
|
|
((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
|
|
|
|
((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
|
|
|
|
|
2011-11-22 16:08:05 +00:00
|
|
|
/* Default escape char Ctrl-] as per telnet */
|
|
|
|
#define CTRL_CLOSE_BRACKET "^]"
|
|
|
|
|
2007-06-06 12:24:31 +00:00
|
|
|
/**
|
|
|
|
* The log configuration
|
|
|
|
*/
|
|
|
|
#define MSG_BUFFER 4096
|
|
|
|
#define SIGN_NAME "virsh"
|
|
|
|
#define DIR_MODE (S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) /* 0755 */
|
|
|
|
#define FILE_MODE (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) /* 0644 */
|
|
|
|
#define LOCK_MODE (S_IWUSR | S_IRUSR) /* 0600 */
|
|
|
|
#define LVL_DEBUG "DEBUG"
|
|
|
|
#define LVL_INFO "INFO"
|
|
|
|
#define LVL_NOTICE "NOTICE"
|
|
|
|
#define LVL_WARNING "WARNING"
|
|
|
|
#define LVL_ERROR "ERROR"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vshErrorLevel:
|
|
|
|
*
|
2010-05-11 14:02:28 +00:00
|
|
|
* Indicates the level of a log message
|
2007-06-06 12:24:31 +00:00
|
|
|
*/
|
|
|
|
typedef enum {
|
|
|
|
VSH_ERR_DEBUG = 0,
|
|
|
|
VSH_ERR_INFO,
|
|
|
|
VSH_ERR_NOTICE,
|
|
|
|
VSH_ERR_WARNING,
|
|
|
|
VSH_ERR_ERROR
|
|
|
|
} vshErrorLevel;
|
|
|
|
|
2011-07-14 11:58:02 +00:00
|
|
|
#define VSH_DEBUG_DEFAULT VSH_ERR_ERROR
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
|
|
|
* virsh command line grammar:
|
|
|
|
*
|
|
|
|
* command_line = <command>\n | <command>; <command>; ...
|
|
|
|
*
|
2010-10-12 22:23:18 +00:00
|
|
|
* command = <keyword> <option> [--] <data>
|
2005-12-08 10:23:34 +00:00
|
|
|
*
|
|
|
|
* option = <bool_option> | <int_option> | <string_option>
|
|
|
|
* data = <string>
|
|
|
|
*
|
|
|
|
* bool_option = --optionname
|
2010-10-12 22:23:18 +00:00
|
|
|
* int_option = --optionname <number> | --optionname=<number>
|
|
|
|
* string_option = --optionname <string> | --optionname=<string>
|
2007-02-07 13:50:18 +00:00
|
|
|
*
|
2010-10-12 22:23:18 +00:00
|
|
|
* keyword = [a-zA-Z][a-zA-Z-]*
|
2006-01-25 09:46:22 +00:00
|
|
|
* number = [0-9]+
|
2010-10-12 22:23:18 +00:00
|
|
|
* string = ('[^']*'|"([^\\"]|\\.)*"|([^ \t\n\\'"]|\\.))+
|
2005-12-08 10:23:34 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2007-02-07 13:50:18 +00:00
|
|
|
* vshCmdOptType - command option type
|
2006-03-15 12:13:25 +00:00
|
|
|
*/
|
2005-12-08 10:23:34 +00:00
|
|
|
typedef enum {
|
2010-10-19 16:27:02 +00:00
|
|
|
VSH_OT_BOOL, /* optional boolean option */
|
|
|
|
VSH_OT_STRING, /* optional string option */
|
|
|
|
VSH_OT_INT, /* optional or mandatory int option */
|
2010-10-15 13:38:49 +00:00
|
|
|
VSH_OT_DATA, /* string data (as non-option) */
|
2012-03-02 18:01:15 +00:00
|
|
|
VSH_OT_ARGV, /* remaining arguments */
|
|
|
|
VSH_OT_ALIAS, /* alternate spelling for a later argument */
|
2005-12-08 10:23:34 +00:00
|
|
|
} vshCmdOptType;
|
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
/*
|
|
|
|
* Command group types
|
|
|
|
*/
|
|
|
|
#define VSH_CMD_GRP_DOM_MANAGEMENT "Domain Management"
|
|
|
|
#define VSH_CMD_GRP_DOM_MONITORING "Domain Monitoring"
|
|
|
|
#define VSH_CMD_GRP_STORAGE_POOL "Storage Pool"
|
|
|
|
#define VSH_CMD_GRP_STORAGE_VOL "Storage Volume"
|
|
|
|
#define VSH_CMD_GRP_NETWORK "Networking"
|
|
|
|
#define VSH_CMD_GRP_NODEDEV "Node Device"
|
|
|
|
#define VSH_CMD_GRP_IFACE "Interface"
|
|
|
|
#define VSH_CMD_GRP_NWFILTER "Network Filter"
|
|
|
|
#define VSH_CMD_GRP_SECRET "Secret"
|
|
|
|
#define VSH_CMD_GRP_SNAPSHOT "Snapshot"
|
|
|
|
#define VSH_CMD_GRP_HOST_AND_HV "Host and Hypervisor"
|
|
|
|
#define VSH_CMD_GRP_VIRSH "Virsh itself"
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
|
|
|
* Command Option Flags
|
|
|
|
*/
|
2011-03-14 16:44:37 +00:00
|
|
|
enum {
|
|
|
|
VSH_OFLAG_NONE = 0, /* without flags */
|
|
|
|
VSH_OFLAG_REQ = (1 << 0), /* option required */
|
|
|
|
VSH_OFLAG_EMPTY_OK = (1 << 1), /* empty string option allowed */
|
2011-06-07 09:11:10 +00:00
|
|
|
VSH_OFLAG_REQ_OPT = (1 << 2), /* --optionname required */
|
2011-03-14 16:44:37 +00:00
|
|
|
};
|
2005-12-08 10:23:34 +00:00
|
|
|
|
|
|
|
/* dummy */
|
|
|
|
typedef struct __vshControl vshControl;
|
|
|
|
typedef struct __vshCmd vshCmd;
|
|
|
|
|
|
|
|
/*
|
2011-07-15 17:23:17 +00:00
|
|
|
* vshCmdInfo -- name/value pair for information about command
|
|
|
|
*
|
|
|
|
* Commands should have at least the following names:
|
|
|
|
* "name" - command name
|
|
|
|
* "desc" - description of command, or empty string
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2006-03-15 12:13:25 +00:00
|
|
|
typedef struct {
|
2011-07-15 17:23:17 +00:00
|
|
|
const char *name; /* name of information, or NULL for list end */
|
|
|
|
const char *data; /* non-NULL information */
|
2005-12-08 10:23:34 +00:00
|
|
|
} vshCmdInfo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vshCmdOptDef - command option definition
|
|
|
|
*/
|
2006-03-15 12:13:25 +00:00
|
|
|
typedef struct {
|
2011-07-15 17:23:17 +00:00
|
|
|
const char *name; /* the name of option, or NULL for list end */
|
2006-03-15 12:13:25 +00:00
|
|
|
vshCmdOptType type; /* option type */
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
unsigned int flags; /* flags */
|
2012-03-02 18:01:15 +00:00
|
|
|
const char *help; /* non-NULL help string; or for VSH_OT_ALIAS
|
|
|
|
* the name of a later public option */
|
2005-12-08 10:23:34 +00:00
|
|
|
} vshCmdOptDef;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vshCmdOpt - command options
|
2011-07-15 17:23:17 +00:00
|
|
|
*
|
|
|
|
* After parsing a command, all arguments to the command have been
|
|
|
|
* collected into a list of these objects.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
|
|
|
typedef struct vshCmdOpt {
|
2011-07-15 17:23:17 +00:00
|
|
|
const vshCmdOptDef *def; /* non-NULL pointer to option definition */
|
|
|
|
char *data; /* allocated data, or NULL for bool option */
|
2006-03-15 12:13:25 +00:00
|
|
|
struct vshCmdOpt *next;
|
2005-12-08 10:23:34 +00:00
|
|
|
} vshCmdOpt;
|
|
|
|
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
/*
|
|
|
|
* Command Usage Flags
|
|
|
|
*/
|
|
|
|
enum {
|
|
|
|
VSH_CMD_FLAG_NOCONNECT = (1 << 0), /* no prior connection needed */
|
2012-03-02 19:01:06 +00:00
|
|
|
VSH_CMD_FLAG_ALIAS = (1 << 1), /* command is an alias */
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
};
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
|
|
|
* vshCmdDef - command definition
|
|
|
|
*/
|
2006-03-15 12:13:25 +00:00
|
|
|
typedef struct {
|
2011-07-15 17:23:17 +00:00
|
|
|
const char *name; /* name of command, or NULL for list end */
|
2011-04-18 22:37:42 +00:00
|
|
|
bool (*handler) (vshControl *, const vshCmd *); /* command handler */
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdOptDef *opts; /* definition of command options */
|
|
|
|
const vshCmdInfo *info; /* details about command */
|
2011-07-07 17:53:04 +00:00
|
|
|
unsigned int flags; /* bitwise OR of VSH_CMD_FLAG */
|
2005-12-08 10:23:34 +00:00
|
|
|
} vshCmdDef;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vshCmd - parsed command
|
|
|
|
*/
|
|
|
|
typedef struct __vshCmd {
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdDef *def; /* command definition */
|
2006-03-15 12:13:25 +00:00
|
|
|
vshCmdOpt *opts; /* list of command arguments */
|
|
|
|
struct __vshCmd *next; /* next command */
|
2005-12-08 10:23:34 +00:00
|
|
|
} __vshCmd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vshControl
|
|
|
|
*/
|
|
|
|
typedef struct __vshControl {
|
2006-05-29 15:39:31 +00:00
|
|
|
char *name; /* connection name */
|
2007-06-20 17:22:09 +00:00
|
|
|
virConnectPtr conn; /* connection to hypervisor (MAY BE NULL) */
|
2006-03-15 12:13:25 +00:00
|
|
|
vshCmd *cmd; /* the current command */
|
|
|
|
char *cmdstr; /* string with command */
|
2011-04-18 22:37:42 +00:00
|
|
|
bool imode; /* interactive mode? */
|
|
|
|
bool quiet; /* quiet mode */
|
2006-03-15 12:13:25 +00:00
|
|
|
int debug; /* print debug messages? */
|
2011-04-18 22:37:42 +00:00
|
|
|
bool timing; /* print timing info? */
|
|
|
|
bool readonly; /* connect readonly (first time only, not
|
2007-03-08 13:48:22 +00:00
|
|
|
* during explicit connect command)
|
|
|
|
*/
|
2007-06-06 12:24:31 +00:00
|
|
|
char *logfile; /* log file name */
|
|
|
|
int log_fd; /* log file descriptor */
|
2010-01-03 14:45:10 +00:00
|
|
|
char *historydir; /* readline history directory name */
|
|
|
|
char *historyfile; /* readline history file name */
|
2011-04-29 08:20:49 +00:00
|
|
|
bool useGetInfo; /* must use virDomainGetInfo, since
|
|
|
|
virDomainGetState is not supported */
|
2011-09-29 21:18:50 +00:00
|
|
|
bool useSnapshotOld; /* cannot use virDomainSnapshotGetParent or
|
|
|
|
virDomainSnapshotNumChildren */
|
2011-10-11 13:05:52 +00:00
|
|
|
virThread eventLoop;
|
2011-11-30 19:42:20 +00:00
|
|
|
virMutex lock;
|
2011-10-11 13:05:52 +00:00
|
|
|
bool eventLoopStarted;
|
|
|
|
bool quit;
|
2011-11-22 16:08:05 +00:00
|
|
|
|
|
|
|
const char *escapeChar; /* String representation of
|
|
|
|
console escape character */
|
2005-12-08 10:23:34 +00:00
|
|
|
} __vshControl;
|
2005-11-10 16:12:31 +00:00
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
typedef struct vshCmdGrp {
|
2011-07-15 17:23:17 +00:00
|
|
|
const char *name; /* name of group, or NULL for list end */
|
2010-11-30 06:37:04 +00:00
|
|
|
const char *keyword; /* help keyword */
|
|
|
|
const vshCmdDef *commands;
|
|
|
|
} vshCmdGrp;
|
2005-12-02 14:16:21 +00:00
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
static const vshCmdGrp cmdGroups[];
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2009-09-29 11:42:42 +00:00
|
|
|
static void vshError(vshControl *ctl, const char *format, ...)
|
|
|
|
ATTRIBUTE_FMT_PRINTF(2, 3);
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool vshInit(vshControl *ctl);
|
|
|
|
static bool vshDeinit(vshControl *ctl);
|
2008-12-08 13:14:48 +00:00
|
|
|
static void vshUsage(void);
|
2007-06-06 12:24:31 +00:00
|
|
|
static void vshOpenLogFile(vshControl *ctl);
|
2010-07-16 15:38:10 +00:00
|
|
|
static void vshOutputLogFile(vshControl *ctl, int log_level, const char *format, va_list ap)
|
|
|
|
ATTRIBUTE_FMT_PRINTF(3, 0);
|
2007-06-06 12:24:31 +00:00
|
|
|
static void vshCloseLogFile(vshControl *ctl);
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool vshParseArgv(vshControl *ctl, int argc, char **argv);
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2008-08-01 13:51:18 +00:00
|
|
|
static const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info);
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdDef *vshCmddefSearch(const char *cmdname);
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool vshCmddefHelp(vshControl *ctl, const char *name);
|
2010-11-30 06:37:04 +00:00
|
|
|
static const vshCmdGrp *vshCmdGrpSearch(const char *grpname);
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool vshCmdGrpHelp(vshControl *ctl, const char *name);
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
static int vshCommandOpt(const vshCmd *cmd, const char *name, vshCmdOpt **opt)
|
|
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
|
|
ATTRIBUTE_RETURN_CHECK;
|
2011-03-08 16:29:31 +00:00
|
|
|
static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *value)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
2011-05-12 16:29:12 +00:00
|
|
|
static int vshCommandOptUInt(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned int *value)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
2011-03-08 16:29:31 +00:00
|
|
|
static int vshCommandOptUL(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned long *value)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
|
|
|
static int vshCommandOptString(const vshCmd *cmd, const char *name,
|
|
|
|
const char **value)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
|
|
|
static int vshCommandOptLongLong(const vshCmd *cmd, const char *name,
|
|
|
|
long long *value)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
2009-07-14 13:24:53 +00:00
|
|
|
static int vshCommandOptULongLong(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned long long *value)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
2012-03-08 01:10:30 +00:00
|
|
|
static int vshCommandOptScaledInt(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned long long *value, int scale,
|
|
|
|
unsigned long long max)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool vshCommandOptBool(const vshCmd *cmd, const char *name);
|
2011-06-14 17:26:20 +00:00
|
|
|
static const vshCmdOpt *vshCommandOptArgv(const vshCmd *cmd,
|
|
|
|
const vshCmdOpt *opt);
|
2012-02-01 13:03:51 +00:00
|
|
|
static char *vshGetDomainDescription(vshControl *ctl, virDomainPtr dom,
|
|
|
|
bool title, unsigned int flags)
|
|
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
2006-05-29 15:39:31 +00:00
|
|
|
|
2007-02-14 15:44:58 +00:00
|
|
|
#define VSH_BYID (1 << 1)
|
|
|
|
#define VSH_BYUUID (1 << 2)
|
|
|
|
#define VSH_BYNAME (1 << 3)
|
2009-07-16 19:44:10 +00:00
|
|
|
#define VSH_BYMAC (1 << 4)
|
2006-05-29 15:39:31 +00:00
|
|
|
|
2008-08-01 13:51:18 +00:00
|
|
|
static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
|
2011-03-08 16:29:30 +00:00
|
|
|
const char **name, int flag);
|
2006-05-29 15:39:31 +00:00
|
|
|
|
|
|
|
/* default is lookup by Id, Name and UUID */
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
#define vshCommandOptDomain(_ctl, _cmd, _name) \
|
|
|
|
vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME)
|
2007-02-14 15:44:58 +00:00
|
|
|
|
2008-08-01 13:51:18 +00:00
|
|
|
static void vshPrintExtra(vshControl *ctl, const char *format, ...)
|
Fix misc Win32 compile warnings
GCC >= 4.4 assumes the 'printf' attribute refers to the native
runtime libraries format specifiers. Thanks to gnulib, libvirt
has GNU format specifiers everywhere. This means we need to
use 'gnu_printf' with GCC >= 4.4 to get correct compiler
checking of printf format specifiers.
* HACKING: Document new rules for ATTRIBUTE_FMT_PRINTF
* autobuild.sh, mingw32-libvirt.spec.in: Disable OpenNebula
driver on mingw32 builds
* qemud/dispatch.h, qemud/qemu.h, src/buf.h src/internal.h,
src/logging.h, src/security.h, src/sexpr.h, src/util.h,
src/virterror_internal.h, src/xend_internal.c: Change
over to ATTRIBUTE_FMT_PRINTF.
* src/virsh.c: Disable 'cd' and 'pwd' commands on Win32
since they don't compile
* src/threads-win32.c: Add missing return value check
2009-07-23 15:07:32 +00:00
|
|
|
ATTRIBUTE_FMT_PRINTF(2, 3);
|
2008-08-01 13:51:18 +00:00
|
|
|
static void vshDebug(vshControl *ctl, int level, const char *format, ...)
|
Fix misc Win32 compile warnings
GCC >= 4.4 assumes the 'printf' attribute refers to the native
runtime libraries format specifiers. Thanks to gnulib, libvirt
has GNU format specifiers everywhere. This means we need to
use 'gnu_printf' with GCC >= 4.4 to get correct compiler
checking of printf format specifiers.
* HACKING: Document new rules for ATTRIBUTE_FMT_PRINTF
* autobuild.sh, mingw32-libvirt.spec.in: Disable OpenNebula
driver on mingw32 builds
* qemud/dispatch.h, qemud/qemu.h, src/buf.h src/internal.h,
src/logging.h, src/security.h, src/sexpr.h, src/util.h,
src/virterror_internal.h, src/xend_internal.c: Change
over to ATTRIBUTE_FMT_PRINTF.
* src/virsh.c: Disable 'cd' and 'pwd' commands on Win32
since they don't compile
* src/threads-win32.c: Add missing return value check
2009-07-23 15:07:32 +00:00
|
|
|
ATTRIBUTE_FMT_PRINTF(3, 4);
|
2006-05-29 15:39:31 +00:00
|
|
|
|
|
|
|
/* XXX: add batch support */
|
2011-02-12 00:17:12 +00:00
|
|
|
#define vshPrint(_ctl, ...) vshPrintExtra(NULL, __VA_ARGS__)
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2011-04-29 08:20:49 +00:00
|
|
|
static int vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason);
|
2005-12-08 14:22:52 +00:00
|
|
|
static const char *vshDomainStateToString(int state);
|
2011-04-29 08:20:49 +00:00
|
|
|
static const char *vshDomainStateReasonToString(int state, int reason);
|
2011-05-31 16:21:58 +00:00
|
|
|
static const char *vshDomainControlStateToString(int state);
|
2006-08-07 14:35:20 +00:00
|
|
|
static const char *vshDomainVcpuStateToString(int state);
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool vshConnectionUsability(vshControl *ctl, virConnectPtr conn);
|
2011-09-19 12:23:12 +00:00
|
|
|
static virTypedParameterPtr vshFindTypedParamByName(const char *name,
|
|
|
|
virTypedParameterPtr list,
|
|
|
|
int count);
|
2011-12-19 23:06:08 +00:00
|
|
|
static char *vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
|
|
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2012-04-14 22:35:22 +00:00
|
|
|
static char *editWriteToTempFile(vshControl *ctl, const char *doc);
|
|
|
|
static int editFile(vshControl *ctl, const char *filename);
|
|
|
|
static char *editReadBackFile(vshControl *ctl, const char *filename);
|
2009-07-16 19:44:10 +00:00
|
|
|
|
2011-12-20 13:04:28 +00:00
|
|
|
/* Typedefs, function prototypes for job progress reporting.
|
|
|
|
* There are used by some long lingering commands like
|
|
|
|
* migrate, dump, save, managedsave.
|
|
|
|
*/
|
|
|
|
typedef struct __vshCtrlData {
|
|
|
|
vshControl *ctl;
|
|
|
|
const vshCmd *cmd;
|
|
|
|
int writefd;
|
|
|
|
} vshCtrlData;
|
|
|
|
|
|
|
|
typedef void (*jobWatchTimeoutFunc) (vshControl *ctl, virDomainPtr dom,
|
|
|
|
void *opaque);
|
|
|
|
|
|
|
|
static bool
|
|
|
|
vshWatchJob(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
bool verbose,
|
|
|
|
int pipe_fd,
|
|
|
|
int timeout,
|
|
|
|
jobWatchTimeoutFunc timeout_func,
|
|
|
|
void *opaque,
|
|
|
|
const char *label);
|
|
|
|
|
2008-08-01 13:51:18 +00:00
|
|
|
static void *_vshMalloc(vshControl *ctl, size_t sz, const char *filename, int line);
|
2006-04-06 10:33:06 +00:00
|
|
|
#define vshMalloc(_ctl, _sz) _vshMalloc(_ctl, _sz, __FILE__, __LINE__)
|
|
|
|
|
2008-08-01 13:51:18 +00:00
|
|
|
static void *_vshCalloc(vshControl *ctl, size_t nmemb, size_t sz, const char *filename, int line);
|
2006-04-06 10:33:06 +00:00
|
|
|
#define vshCalloc(_ctl, _nmemb, _sz) _vshCalloc(_ctl, _nmemb, _sz, __FILE__, __LINE__)
|
|
|
|
|
2008-08-01 13:51:18 +00:00
|
|
|
static char *_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line);
|
2006-04-06 10:33:06 +00:00
|
|
|
#define vshStrdup(_ctl, _s) _vshStrdup(_ctl, _s, __FILE__, __LINE__)
|
|
|
|
|
2011-12-29 07:33:21 +00:00
|
|
|
static int parseRateStr(const char *rateStr, virNetDevBandwidthRatePtr rate);
|
|
|
|
|
2010-10-12 17:24:00 +00:00
|
|
|
static void *
|
|
|
|
_vshMalloc(vshControl *ctl, size_t size, const char *filename, int line)
|
|
|
|
{
|
2012-02-02 22:47:04 +00:00
|
|
|
char *x;
|
2010-10-12 17:24:00 +00:00
|
|
|
|
2012-02-02 22:47:04 +00:00
|
|
|
if (VIR_ALLOC_N(x, size) == 0)
|
2010-10-12 17:24:00 +00:00
|
|
|
return x;
|
|
|
|
vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
|
|
|
|
filename, line, (int) size);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_vshCalloc(vshControl *ctl, size_t nmemb, size_t size, const char *filename, int line)
|
|
|
|
{
|
2012-02-02 22:47:04 +00:00
|
|
|
char *x;
|
2010-10-12 17:24:00 +00:00
|
|
|
|
2012-02-02 22:47:04 +00:00
|
|
|
if (!xalloc_oversized(nmemb, size) &&
|
|
|
|
VIR_ALLOC_N(x, nmemb * size) == 0)
|
2010-10-12 17:24:00 +00:00
|
|
|
return x;
|
|
|
|
vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
|
|
|
|
filename, line, (int) (size*nmemb));
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line)
|
|
|
|
{
|
|
|
|
char *x;
|
|
|
|
|
|
|
|
if (s == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2010-10-12 17:24:00 +00:00
|
|
|
if ((x = strdup(s)))
|
|
|
|
return x;
|
|
|
|
vshError(ctl, _("%s: %d: failed to allocate %lu bytes"),
|
|
|
|
filename, line, (unsigned long)strlen(s));
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Poison the raw allocating identifiers in favor of our vsh variants. */
|
|
|
|
#undef malloc
|
|
|
|
#undef calloc
|
|
|
|
#undef realloc
|
|
|
|
#undef strdup
|
|
|
|
#define malloc use_vshMalloc_instead_of_malloc
|
|
|
|
#define calloc use_vshCalloc_instead_of_calloc
|
|
|
|
#define realloc use_vshRealloc_instead_of_realloc
|
|
|
|
#define strdup use_vshStrdup_instead_of_strdup
|
2007-02-14 15:44:58 +00:00
|
|
|
|
2012-06-19 13:13:47 +00:00
|
|
|
static int
|
|
|
|
vshNameSorter(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const char **sa = (const char**)a;
|
|
|
|
const char **sb = (const char**)b;
|
2007-02-14 15:44:58 +00:00
|
|
|
|
2012-06-19 13:13:47 +00:00
|
|
|
/* User visible sort, so we want locale-specific case comparison. */
|
|
|
|
return strcasecmp(*sa, *sb);
|
2007-02-14 15:44:58 +00:00
|
|
|
}
|
|
|
|
|
2010-02-03 16:45:05 +00:00
|
|
|
static double
|
|
|
|
prettyCapacity(unsigned long long val,
|
|
|
|
const char **unit) {
|
|
|
|
if (val < 1024) {
|
|
|
|
*unit = "";
|
|
|
|
return (double)val;
|
|
|
|
} else if (val < (1024.0l * 1024.0l)) {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "KiB";
|
2010-02-03 16:45:05 +00:00
|
|
|
return (((double)val / 1024.0l));
|
|
|
|
} else if (val < (1024.0l * 1024.0l * 1024.0l)) {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "MiB";
|
2012-03-22 11:33:35 +00:00
|
|
|
return (double)val / (1024.0l * 1024.0l);
|
2010-02-03 16:45:05 +00:00
|
|
|
} else if (val < (1024.0l * 1024.0l * 1024.0l * 1024.0l)) {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "GiB";
|
2012-03-22 11:33:35 +00:00
|
|
|
return (double)val / (1024.0l * 1024.0l * 1024.0l);
|
2010-02-03 16:45:05 +00:00
|
|
|
} else {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "TiB";
|
2012-03-22 11:33:35 +00:00
|
|
|
return (double)val / (1024.0l * 1024.0l * 1024.0l * 1024.0l);
|
2010-02-03 16:45:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-09 14:24:06 +00:00
|
|
|
static virErrorPtr last_error;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Quieten libvirt until we're done with the command.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
virshErrorHandler(void *unused ATTRIBUTE_UNUSED, virErrorPtr error)
|
|
|
|
{
|
|
|
|
virFreeError(last_error);
|
|
|
|
last_error = virSaveLastError();
|
|
|
|
if (getenv("VIRSH_DEBUG") != NULL)
|
|
|
|
virDefaultErrorFunc(error);
|
|
|
|
}
|
|
|
|
|
2012-07-25 11:41:49 +00:00
|
|
|
/*
|
|
|
|
* Reset libvirt error on graceful fallback paths
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
vshResetLibvirtError(void)
|
|
|
|
{
|
|
|
|
virFreeError(last_error);
|
|
|
|
last_error = NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-09 14:24:06 +00:00
|
|
|
/*
|
|
|
|
* Report an error when a command finishes. This is better than before
|
|
|
|
* (when correct operation would report errors), but it has some
|
|
|
|
* problems: we lose the smarter formatting of virDefaultErrorFunc(),
|
|
|
|
* and it can become harder to debug problems, if errors get reported
|
|
|
|
* twice during one command. This case shouldn't really happen anyway,
|
|
|
|
* and it's IMHO a bug that libvirt does that sometimes.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
virshReportError(vshControl *ctl)
|
|
|
|
{
|
2010-02-24 16:13:00 +00:00
|
|
|
if (last_error == NULL) {
|
|
|
|
/* Calling directly into libvirt util functions won't trigger the
|
|
|
|
* error callback (which sets last_error), so check it ourselves.
|
|
|
|
*
|
|
|
|
* If the returned error has CODE_OK, this most likely means that
|
|
|
|
* no error was ever raised, so just ignore */
|
|
|
|
last_error = virSaveLastError();
|
|
|
|
if (!last_error || last_error->code == VIR_ERR_OK)
|
2010-06-18 14:14:04 +00:00
|
|
|
goto out;
|
2010-02-24 16:13:00 +00:00
|
|
|
}
|
2009-02-09 14:24:06 +00:00
|
|
|
|
|
|
|
if (last_error->code == VIR_ERR_OK) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, "%s", _("unknown error"));
|
2009-02-09 14:24:06 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, "%s", last_error->message);
|
2009-02-09 14:24:06 +00:00
|
|
|
|
|
|
|
out:
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2009-02-09 14:24:06 +00:00
|
|
|
}
|
|
|
|
|
2011-01-25 10:14:28 +00:00
|
|
|
static volatile sig_atomic_t intCaught = 0;
|
|
|
|
|
|
|
|
static void vshCatchInt(int sig ATTRIBUTE_UNUSED,
|
|
|
|
siginfo_t *siginfo ATTRIBUTE_UNUSED,
|
|
|
|
void *context ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
intCaught = 1;
|
|
|
|
}
|
|
|
|
|
2010-03-05 09:59:52 +00:00
|
|
|
/*
|
|
|
|
* Detection of disconnections and automatic reconnection support
|
|
|
|
*/
|
|
|
|
static int disconnected = 0; /* we may have been disconnected */
|
|
|
|
|
2010-12-24 02:26:15 +00:00
|
|
|
/* Gnulib doesn't guarantee SA_SIGINFO support. */
|
|
|
|
#ifndef SA_SIGINFO
|
|
|
|
# define SA_SIGINFO 0
|
|
|
|
#endif
|
|
|
|
|
2010-03-05 09:59:52 +00:00
|
|
|
/*
|
|
|
|
* vshCatchDisconnect:
|
|
|
|
*
|
2012-08-02 17:15:16 +00:00
|
|
|
* We get here when the connection was closed. We can't do much in the
|
|
|
|
* handler, just save the fact it was raised.
|
2010-03-05 09:59:52 +00:00
|
|
|
*/
|
2010-03-12 10:39:24 +00:00
|
|
|
static void
|
2012-08-02 17:15:16 +00:00
|
|
|
vshCatchDisconnect(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
int reason,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
if (reason != VIR_CONNECT_CLOSE_REASON_CLIENT)
|
|
|
|
disconnected++;
|
2010-03-05 09:59:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vshReconnect:
|
|
|
|
*
|
2010-03-12 10:39:24 +00:00
|
|
|
* Reconnect after a disconnect from libvirtd
|
2010-03-05 09:59:52 +00:00
|
|
|
*
|
|
|
|
*/
|
2010-03-12 10:39:24 +00:00
|
|
|
static void
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
vshReconnect(vshControl *ctl)
|
|
|
|
{
|
|
|
|
bool connected = false;
|
|
|
|
|
|
|
|
if (ctl->conn != NULL) {
|
|
|
|
connected = true;
|
2010-03-05 09:59:52 +00:00
|
|
|
virConnectClose(ctl->conn);
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
}
|
2010-03-05 09:59:52 +00:00
|
|
|
|
|
|
|
ctl->conn = virConnectOpenAuth(ctl->name,
|
|
|
|
virConnectAuthPtrDefault,
|
|
|
|
ctl->readonly ? VIR_CONNECT_RO : 0);
|
2012-08-02 17:15:16 +00:00
|
|
|
if (!ctl->conn) {
|
2010-03-05 09:59:52 +00:00
|
|
|
vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
|
2012-08-02 17:15:16 +00:00
|
|
|
} else {
|
|
|
|
if (virConnectRegisterCloseCallback(ctl->conn, vshCatchDisconnect,
|
|
|
|
NULL, NULL) < 0)
|
|
|
|
vshError(ctl, "%s", _("Unable to register disconnect callback"));
|
|
|
|
if (connected)
|
|
|
|
vshError(ctl, "%s", _("Reconnected to the hypervisor"));
|
|
|
|
}
|
2010-03-05 09:59:52 +00:00
|
|
|
disconnected = 0;
|
2011-04-29 08:20:49 +00:00
|
|
|
ctl->useGetInfo = false;
|
2011-09-29 21:18:50 +00:00
|
|
|
ctl->useSnapshotOld = false;
|
2010-03-05 09:59:52 +00:00
|
|
|
}
|
2007-02-14 15:44:58 +00:00
|
|
|
|
2012-06-21 13:46:03 +00:00
|
|
|
#ifndef WIN32
|
2012-06-13 09:11:27 +00:00
|
|
|
static void
|
|
|
|
vshPrintRaw(vshControl *ctl, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
char *key;
|
|
|
|
|
|
|
|
va_start(ap, ctl);
|
|
|
|
while ((key = va_arg(ap, char *)) != NULL) {
|
|
|
|
vshPrint(ctl, "%s\r\n", key);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2012-05-18 10:21:06 +00:00
|
|
|
/**
|
|
|
|
* vshAskReedit:
|
|
|
|
* @msg: Question to ask user
|
|
|
|
*
|
|
|
|
* Ask user if he wants to return to previously
|
|
|
|
* edited file.
|
|
|
|
*
|
|
|
|
* Returns 'y' if he wants to
|
|
|
|
* 'f' if he forcibly wants to
|
|
|
|
* 'n' if he doesn't want to
|
|
|
|
* -1 on error
|
|
|
|
* 0 otherwise
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
vshAskReedit(vshControl *ctl, const char *msg)
|
|
|
|
{
|
|
|
|
int c = -1;
|
|
|
|
struct termios ttyattr;
|
|
|
|
|
|
|
|
if (!isatty(STDIN_FILENO))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virshReportError(ctl);
|
|
|
|
|
|
|
|
if (vshMakeStdinRaw(&ttyattr, false) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
/* TRANSLATORS: For now, we aren't using LC_MESSAGES, and the user
|
|
|
|
* choices really are limited to just 'y', 'n', 'f' and '?' */
|
|
|
|
vshPrint(ctl, "\r%s %s", msg, _("Try again? [y,n,f,?]:"));
|
|
|
|
c = c_tolower(getchar());
|
|
|
|
|
|
|
|
if (c == '?') {
|
2012-06-13 09:11:27 +00:00
|
|
|
vshPrintRaw(ctl,
|
|
|
|
"",
|
|
|
|
_("y - yes, start editor again"),
|
|
|
|
_("n - no, throw away my changes"),
|
|
|
|
_("f - force, try to redefine again"),
|
|
|
|
_("? - print this help"),
|
|
|
|
NULL);
|
2012-05-18 10:21:06 +00:00
|
|
|
continue;
|
|
|
|
} else if (c == 'y' || c == 'n' || c == 'f') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr);
|
|
|
|
|
|
|
|
vshPrint(ctl, "\r\n");
|
|
|
|
return c;
|
2012-06-21 13:46:03 +00:00
|
|
|
}
|
|
|
|
#else /* WIN32 */
|
|
|
|
static int
|
|
|
|
vshAskReedit(vshControl *ctl, const char *msg ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2012-05-18 10:21:06 +00:00
|
|
|
vshDebug(ctl, VSH_ERR_WARNING, "%s", _("This function is not "
|
|
|
|
"supported on WIN32 platform"));
|
|
|
|
return 0;
|
|
|
|
}
|
2012-06-21 13:46:03 +00:00
|
|
|
#endif /* WIN32 */
|
2012-05-18 10:21:06 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static int vshStreamSink(virStreamPtr st ATTRIBUTE_UNUSED,
|
|
|
|
const char *bytes, size_t nbytes, void *opaque)
|
|
|
|
{
|
|
|
|
int *fd = opaque;
|
|
|
|
|
|
|
|
return safewrite(*fd, bytes, nbytes);
|
|
|
|
}
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/* ---------------
|
|
|
|
* Commands
|
|
|
|
* ---------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2007-02-07 13:50:18 +00:00
|
|
|
* "help" command
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdInfo info_help[] = {
|
2010-03-09 17:05:02 +00:00
|
|
|
{"help", N_("print help")},
|
2010-12-01 12:24:58 +00:00
|
|
|
{"desc", N_("Prints global help, command specific help, or help for a\n"
|
|
|
|
" group of related commands")},
|
2006-09-21 15:24:37 +00:00
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
{NULL, NULL}
|
2005-12-08 10:23:34 +00:00
|
|
|
};
|
|
|
|
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdOptDef opts_help[] = {
|
2010-12-03 07:34:23 +00:00
|
|
|
{"command", VSH_OT_DATA, 0, N_("Prints global help, command specific help, or help for a group of related commands")},
|
2006-03-15 12:13:25 +00:00
|
|
|
{NULL, 0, 0, NULL}
|
2005-12-08 10:23:34 +00:00
|
|
|
};
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2008-08-01 13:51:18 +00:00
|
|
|
cmdHelp(vshControl *ctl, const vshCmd *cmd)
|
2010-11-30 06:37:04 +00:00
|
|
|
{
|
2011-03-08 16:29:31 +00:00
|
|
|
const char *name = NULL;
|
2010-12-01 12:24:58 +00:00
|
|
|
|
2011-03-08 16:29:31 +00:00
|
|
|
if (vshCommandOptString(cmd, "command", &name) <= 0) {
|
2010-11-30 06:37:04 +00:00
|
|
|
const vshCmdGrp *grp;
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdDef *def;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
vshPrint(ctl, "%s", _("Grouped commands:\n\n"));
|
|
|
|
|
|
|
|
for (grp = cmdGroups; grp->name; grp++) {
|
|
|
|
vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
|
|
|
|
grp->keyword);
|
|
|
|
|
2012-03-02 19:01:06 +00:00
|
|
|
for (def = grp->commands; def->name; def++) {
|
|
|
|
if (def->flags & VSH_CMD_FLAG_ALIAS)
|
|
|
|
continue;
|
2010-11-30 06:37:04 +00:00
|
|
|
vshPrint(ctl, " %-30s %s\n", def->name,
|
|
|
|
_(vshCmddefGetInfo(def, "help")));
|
2012-03-02 19:01:06 +00:00
|
|
|
}
|
2010-11-30 06:37:04 +00:00
|
|
|
|
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
}
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2010-12-01 12:24:58 +00:00
|
|
|
}
|
2010-11-30 06:37:04 +00:00
|
|
|
|
2011-02-14 23:06:31 +00:00
|
|
|
if (vshCmddefSearch(name)) {
|
2010-11-30 06:37:04 +00:00
|
|
|
return vshCmddefHelp(ctl, name);
|
2011-02-14 23:06:31 +00:00
|
|
|
} else if (vshCmdGrpSearch(name)) {
|
2010-11-30 06:37:04 +00:00
|
|
|
return vshCmdGrpHelp(ctl, name);
|
|
|
|
} else {
|
|
|
|
vshError(ctl, _("command or command group '%s' doesn't exist"), name);
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* Tree listing helpers. */
|
|
|
|
|
|
|
|
/* Given an index, return either the name of that device (non-NULL) or
|
|
|
|
* of its parent (NULL if a root). */
|
|
|
|
typedef const char * (*vshTreeLookup)(int devid, bool parent, void *opaque);
|
|
|
|
|
|
|
|
static int
|
|
|
|
vshTreePrintInternal(vshControl *ctl,
|
|
|
|
vshTreeLookup lookup,
|
|
|
|
void *opaque,
|
|
|
|
int num_devices,
|
|
|
|
int devid,
|
|
|
|
int lastdev,
|
|
|
|
bool root,
|
|
|
|
virBufferPtr indent)
|
2012-02-28 06:38:03 +00:00
|
|
|
{
|
2012-07-25 15:37:18 +00:00
|
|
|
int i;
|
|
|
|
int nextlastdev = -1;
|
|
|
|
int ret = -1;
|
|
|
|
const char *dev = (lookup)(devid, false, opaque);
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (virBufferError(indent))
|
2012-02-28 06:38:03 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* Print this device, with indent if not at root */
|
|
|
|
vshPrint(ctl, "%s%s%s\n", virBufferCurrentContent(indent),
|
|
|
|
root ? "" : "+- ", dev);
|
|
|
|
|
|
|
|
/* Update indent to show '|' or ' ' for child devices */
|
|
|
|
if (!root) {
|
|
|
|
virBufferAddChar(indent, devid == lastdev ? ' ' : '|');
|
|
|
|
virBufferAddChar(indent, ' ');
|
|
|
|
if (virBufferError(indent))
|
|
|
|
goto cleanup;
|
2012-02-28 06:38:03 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* Determine the index of the last child device */
|
|
|
|
for (i = 0 ; i < num_devices ; i++) {
|
|
|
|
const char *parent = (lookup)(i, true, opaque);
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (parent && STREQ(parent, dev))
|
|
|
|
nextlastdev = i;
|
|
|
|
}
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* If there is a child device, then print another blank line */
|
|
|
|
if (nextlastdev != -1)
|
|
|
|
vshPrint(ctl, "%s |\n", virBufferCurrentContent(indent));
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* Finally print all children */
|
|
|
|
virBufferAddLit(indent, " ");
|
|
|
|
for (i = 0 ; i < num_devices ; i++) {
|
|
|
|
const char *parent = (lookup)(i, true, opaque);
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (parent && STREQ(parent, dev) &&
|
|
|
|
vshTreePrintInternal(ctl, lookup, opaque,
|
|
|
|
num_devices, i, nextlastdev,
|
|
|
|
false, indent) < 0)
|
|
|
|
goto cleanup;
|
2012-02-28 06:38:03 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
virBufferTrim(indent, " ", -1);
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* If there was no child device, and we're the last in
|
|
|
|
* a list of devices, then print another blank line */
|
|
|
|
if (nextlastdev == -1 && devid == lastdev)
|
|
|
|
vshPrint(ctl, "%s\n", virBufferCurrentContent(indent));
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (!root)
|
|
|
|
virBufferTrim(indent, NULL, 2);
|
|
|
|
ret = 0;
|
2012-02-28 06:38:03 +00:00
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static int
|
|
|
|
vshTreePrint(vshControl *ctl, vshTreeLookup lookup, void *opaque,
|
|
|
|
int num_devices, int devid)
|
2012-02-28 06:38:03 +00:00
|
|
|
{
|
2012-07-25 15:37:18 +00:00
|
|
|
int ret;
|
|
|
|
virBuffer indent = VIR_BUFFER_INITIALIZER;
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = vshTreePrintInternal(ctl, lookup, opaque, num_devices,
|
|
|
|
devid, devid, true, &indent);
|
|
|
|
if (ret < 0)
|
|
|
|
vshError(ctl, "%s", _("Failed to complete tree listing"));
|
|
|
|
virBufferFreeAndReset(&indent);
|
2012-02-28 06:38:03 +00:00
|
|
|
return ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2012-02-28 06:38:03 +00:00
|
|
|
|
2008-08-01 14:30:41 +00:00
|
|
|
/* Common code for the edit / net-edit / pool-edit functions which follow. */
|
|
|
|
static char *
|
2012-07-11 06:17:28 +00:00
|
|
|
editWriteToTempFile(vshControl *ctl, const char *doc)
|
2008-08-01 14:30:41 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
const char *tmpdir;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
tmpdir = getenv ("TMPDIR");
|
|
|
|
if (!tmpdir) tmpdir = "/tmp";
|
2012-05-25 13:14:07 +00:00
|
|
|
if (virAsprintf(&ret, "%s/virshXXXXXX.xml", tmpdir) < 0) {
|
|
|
|
vshError(ctl, "%s", _("out of memory"));
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-09 09:27:09 +00:00
|
|
|
fd = mkstemps(ret, 4);
|
2008-08-01 14:30:41 +00:00
|
|
|
if (fd == -1) {
|
2010-11-09 09:27:09 +00:00
|
|
|
vshError(ctl, _("mkstemps: failed to create temporary file: %s"),
|
2009-09-29 11:42:42 +00:00
|
|
|
strerror(errno));
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(ret);
|
2008-08-01 14:30:41 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-07-11 06:17:28 +00:00
|
|
|
if (safewrite(fd, doc, strlen(doc)) == -1) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("write: %s: failed to write to temporary file: %s"),
|
|
|
|
ret, strerror(errno));
|
2010-11-17 15:19:13 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2012-07-11 06:17:28 +00:00
|
|
|
unlink(ret);
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(ret);
|
2008-08-01 14:30:41 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-17 15:19:13 +00:00
|
|
|
if (VIR_CLOSE(fd) < 0) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("close: %s: failed to write or close temporary file: %s"),
|
|
|
|
ret, strerror(errno));
|
2012-07-11 06:17:28 +00:00
|
|
|
unlink(ret);
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(ret);
|
2008-08-01 14:30:41 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Temporary filename: caller frees. */
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Characters permitted in $EDITOR environment variable and temp filename. */
|
|
|
|
#define ACCEPTED_CHARS \
|
|
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/_.:@"
|
|
|
|
|
|
|
|
static int
|
2012-07-11 06:17:28 +00:00
|
|
|
editFile(vshControl *ctl, const char *filename)
|
2008-08-01 14:30:41 +00:00
|
|
|
{
|
|
|
|
const char *editor;
|
2011-01-28 21:22:39 +00:00
|
|
|
virCommandPtr cmd;
|
|
|
|
int ret = -1;
|
|
|
|
int outfd = STDOUT_FILENO;
|
|
|
|
int errfd = STDERR_FILENO;
|
2008-08-01 14:30:41 +00:00
|
|
|
|
2012-07-11 06:17:28 +00:00
|
|
|
editor = getenv("VISUAL");
|
2011-01-28 21:22:39 +00:00
|
|
|
if (!editor)
|
2012-07-11 06:17:28 +00:00
|
|
|
editor = getenv("EDITOR");
|
2011-01-28 21:22:39 +00:00
|
|
|
if (!editor)
|
|
|
|
editor = "vi"; /* could be cruel & default to ed(1) here */
|
2008-08-01 14:30:41 +00:00
|
|
|
|
2010-03-12 16:33:22 +00:00
|
|
|
/* Check that filename doesn't contain shell meta-characters, and
|
|
|
|
* if it does, refuse to run. Follow the Unix conventions for
|
|
|
|
* EDITOR: the user can intentionally specify command options, so
|
|
|
|
* we don't protect any shell metacharacters there. Lots more
|
|
|
|
* than virsh will misbehave if EDITOR has bogus contents (which
|
2011-01-28 21:22:39 +00:00
|
|
|
* is why sudo scrubs it by default). Conversely, if the editor
|
|
|
|
* is safe, we can run it directly rather than wasting a shell.
|
2008-08-01 14:30:41 +00:00
|
|
|
*/
|
2012-07-11 06:17:28 +00:00
|
|
|
if (strspn(editor, ACCEPTED_CHARS) != strlen(editor)) {
|
|
|
|
if (strspn(filename, ACCEPTED_CHARS) != strlen(filename)) {
|
2011-01-28 21:22:39 +00:00
|
|
|
vshError(ctl,
|
|
|
|
_("%s: temporary filename contains shell meta or other "
|
|
|
|
"unacceptable characters (is $TMPDIR wrong?)"),
|
|
|
|
filename);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
cmd = virCommandNewArgList("sh", "-c", NULL);
|
|
|
|
virCommandAddArgFormat(cmd, "%s %s", editor, filename);
|
|
|
|
} else {
|
|
|
|
cmd = virCommandNewArgList(editor, filename, NULL);
|
2008-08-01 14:30:41 +00:00
|
|
|
}
|
|
|
|
|
2011-01-28 21:22:39 +00:00
|
|
|
virCommandSetInputFD(cmd, STDIN_FILENO);
|
|
|
|
virCommandSetOutputFD(cmd, &outfd);
|
|
|
|
virCommandSetErrorFD(cmd, &errfd);
|
|
|
|
if (virCommandRunAsync(cmd, NULL) < 0 ||
|
|
|
|
virCommandWait(cmd, NULL) < 0) {
|
|
|
|
virshReportError(ctl);
|
|
|
|
goto cleanup;
|
2008-08-01 14:30:41 +00:00
|
|
|
}
|
2011-01-28 21:22:39 +00:00
|
|
|
ret = 0;
|
2008-08-01 14:30:41 +00:00
|
|
|
|
2011-01-28 21:22:39 +00:00
|
|
|
cleanup:
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
2008-08-01 14:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2012-07-11 06:17:28 +00:00
|
|
|
editReadBackFile(vshControl *ctl, const char *filename)
|
2008-08-01 14:30:41 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
2012-04-14 22:35:22 +00:00
|
|
|
if (virFileReadAll(filename, VIRSH_MAX_XML_FILE, &ret) == -1) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl,
|
2008-08-01 14:30:41 +00:00
|
|
|
_("%s: failed to read temporary file: %s"),
|
2009-09-29 11:42:42 +00:00
|
|
|
filename, strerror(errno));
|
2008-08-01 14:30:41 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
Fix misc Win32 compile warnings
GCC >= 4.4 assumes the 'printf' attribute refers to the native
runtime libraries format specifiers. Thanks to gnulib, libvirt
has GNU format specifiers everywhere. This means we need to
use 'gnu_printf' with GCC >= 4.4 to get correct compiler
checking of printf format specifiers.
* HACKING: Document new rules for ATTRIBUTE_FMT_PRINTF
* autobuild.sh, mingw32-libvirt.spec.in: Disable OpenNebula
driver on mingw32 builds
* qemud/dispatch.h, qemud/qemu.h, src/buf.h src/internal.h,
src/logging.h, src/security.h, src/sexpr.h, src/util.h,
src/virterror_internal.h, src/xend_internal.c: Change
over to ATTRIBUTE_FMT_PRINTF.
* src/virsh.c: Disable 'cd' and 'pwd' commands on Win32
since they don't compile
* src/threads-win32.c: Add missing return value check
2009-07-23 15:07:32 +00:00
|
|
|
|
2009-07-16 14:40:08 +00:00
|
|
|
/*
|
|
|
|
* "cd" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_cd[] = {
|
2010-03-09 17:05:02 +00:00
|
|
|
{"help", N_("change the current directory")},
|
|
|
|
{"desc", N_("Change the current directory.")},
|
2009-07-16 14:40:08 +00:00
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_cd[] = {
|
2010-03-09 17:05:02 +00:00
|
|
|
{"dir", VSH_OT_DATA, 0, N_("directory to switch to (default: home or else root)")},
|
2009-07-16 14:40:08 +00:00
|
|
|
{NULL, 0, 0, NULL}
|
|
|
|
};
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
cmdCd(vshControl *ctl, const vshCmd *cmd)
|
2009-07-16 14:40:08 +00:00
|
|
|
{
|
2011-03-08 16:29:31 +00:00
|
|
|
const char *dir = NULL;
|
2011-03-08 16:29:30 +00:00
|
|
|
char *dir_malloced = NULL;
|
2011-04-18 22:37:42 +00:00
|
|
|
bool ret = true;
|
2009-07-16 14:40:08 +00:00
|
|
|
|
|
|
|
if (!ctl->imode) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, "%s", _("cd: command valid only in interactive mode"));
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2009-07-16 14:40:08 +00:00
|
|
|
}
|
|
|
|
|
2011-03-08 16:29:31 +00:00
|
|
|
if (vshCommandOptString(cmd, "dir", &dir) <= 0) {
|
2012-05-24 12:29:42 +00:00
|
|
|
dir = dir_malloced = virGetUserDirectory();
|
2009-07-16 14:40:08 +00:00
|
|
|
}
|
|
|
|
if (!dir)
|
|
|
|
dir = "/";
|
|
|
|
|
2011-03-04 16:52:12 +00:00
|
|
|
if (chdir(dir) == -1) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("cd: %s: %s"), strerror(errno), dir);
|
2011-04-18 22:37:42 +00:00
|
|
|
ret = false;
|
2009-07-16 14:40:08 +00:00
|
|
|
}
|
|
|
|
|
2011-03-08 16:29:30 +00:00
|
|
|
VIR_FREE(dir_malloced);
|
2011-03-04 16:52:12 +00:00
|
|
|
return ret;
|
2009-07-16 14:40:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "pwd" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_pwd[] = {
|
2010-03-09 17:05:02 +00:00
|
|
|
{"help", N_("print the current directory")},
|
|
|
|
{"desc", N_("Print the current directory.")},
|
2009-07-16 14:40:08 +00:00
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2009-07-16 14:40:08 +00:00
|
|
|
cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
char *cwd;
|
2011-04-29 17:14:23 +00:00
|
|
|
bool ret = true;
|
2009-07-16 14:40:08 +00:00
|
|
|
|
2011-04-29 17:14:23 +00:00
|
|
|
cwd = getcwd(NULL, 0);
|
|
|
|
if (!cwd) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("pwd: cannot get current directory: %s"),
|
|
|
|
strerror(errno));
|
2011-04-29 17:14:23 +00:00
|
|
|
ret = false;
|
|
|
|
} else {
|
2012-07-11 06:17:28 +00:00
|
|
|
vshPrint(ctl, _("%s\n"), cwd);
|
2011-04-29 17:14:23 +00:00
|
|
|
VIR_FREE(cwd);
|
|
|
|
}
|
2009-07-16 14:40:08 +00:00
|
|
|
|
2011-04-29 17:14:23 +00:00
|
|
|
return ret;
|
2009-07-16 14:40:08 +00:00
|
|
|
}
|
|
|
|
|
2010-10-15 13:39:34 +00:00
|
|
|
/*
|
|
|
|
* "echo" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_echo[] = {
|
|
|
|
{"help", N_("echo arguments")},
|
|
|
|
{"desc", N_("Echo back arguments, possibly with quoting.")},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_echo[] = {
|
|
|
|
{"shell", VSH_OT_BOOL, 0, N_("escape for shell use")},
|
|
|
|
{"xml", VSH_OT_BOOL, 0, N_("escape for XML use")},
|
2012-03-02 18:01:15 +00:00
|
|
|
{"str", VSH_OT_ALIAS, 0, "string"},
|
2011-06-07 09:11:08 +00:00
|
|
|
{"string", VSH_OT_ARGV, 0, N_("arguments to echo")},
|
2010-10-15 13:39:34 +00:00
|
|
|
{NULL, 0, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Exists mainly for debugging virsh, but also handy for adding back
|
|
|
|
* quotes for later evaluation.
|
|
|
|
*/
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2012-07-11 06:17:28 +00:00
|
|
|
cmdEcho(vshControl *ctl, const vshCmd *cmd)
|
2010-10-15 13:39:34 +00:00
|
|
|
{
|
|
|
|
bool shell = false;
|
|
|
|
bool xml = false;
|
|
|
|
int count = 0;
|
2011-06-14 17:26:20 +00:00
|
|
|
const vshCmdOpt *opt = NULL;
|
2010-10-15 13:39:34 +00:00
|
|
|
char *arg;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "shell"))
|
|
|
|
shell = true;
|
|
|
|
if (vshCommandOptBool(cmd, "xml"))
|
|
|
|
xml = true;
|
|
|
|
|
2011-06-14 17:26:20 +00:00
|
|
|
while ((opt = vshCommandOptArgv(cmd, opt))) {
|
2011-10-13 20:49:15 +00:00
|
|
|
char *str;
|
|
|
|
virBuffer xmlbuf = VIR_BUFFER_INITIALIZER;
|
2010-10-15 13:39:34 +00:00
|
|
|
|
2011-06-14 17:26:20 +00:00
|
|
|
arg = opt->data;
|
2011-10-13 20:49:15 +00:00
|
|
|
|
2010-10-15 13:39:34 +00:00
|
|
|
if (count)
|
|
|
|
virBufferAddChar(&buf, ' ');
|
2011-10-13 20:49:15 +00:00
|
|
|
|
2010-10-15 13:39:34 +00:00
|
|
|
if (xml) {
|
2011-10-13 20:49:15 +00:00
|
|
|
virBufferEscapeString(&xmlbuf, "%s", arg);
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
|
|
|
|
return false;
|
2010-10-15 13:39:34 +00:00
|
|
|
}
|
2011-10-13 20:49:15 +00:00
|
|
|
str = virBufferContentAndReset(&xmlbuf);
|
|
|
|
} else {
|
|
|
|
str = vshStrdup(ctl, arg);
|
2010-10-15 13:39:34 +00:00
|
|
|
}
|
2011-10-13 20:49:15 +00:00
|
|
|
|
|
|
|
if (shell)
|
|
|
|
virBufferEscapeShell(&buf, str);
|
|
|
|
else
|
|
|
|
virBufferAdd(&buf, str, -1);
|
2010-10-15 13:39:34 +00:00
|
|
|
count++;
|
2011-10-13 20:49:15 +00:00
|
|
|
VIR_FREE(str);
|
2010-10-15 13:39:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2010-10-15 13:39:34 +00:00
|
|
|
}
|
|
|
|
arg = virBufferContentAndReset(&buf);
|
|
|
|
if (arg)
|
|
|
|
vshPrint(ctl, "%s", arg);
|
|
|
|
VIR_FREE(arg);
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2010-10-15 13:39:34 +00:00
|
|
|
}
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
|
|
|
* "quit" command
|
|
|
|
*/
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdInfo info_quit[] = {
|
2010-03-09 17:05:02 +00:00
|
|
|
{"help", N_("quit this interactive terminal")},
|
2009-01-05 13:27:43 +00:00
|
|
|
{"desc", ""},
|
2006-03-15 12:13:25 +00:00
|
|
|
{NULL, NULL}
|
2005-12-08 10:23:34 +00:00
|
|
|
};
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2008-08-01 13:51:18 +00:00
|
|
|
cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-04-18 22:37:42 +00:00
|
|
|
ctl->imode = false;
|
|
|
|
return true;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
/* ---------------
|
|
|
|
* Utils for work with command definition
|
|
|
|
* ---------------
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
vshCmddefGetInfo(const vshCmdDef * cmd, const char *name)
|
|
|
|
{
|
|
|
|
const vshCmdInfo *info;
|
2010-11-30 06:37:04 +00:00
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
for (info = cmd->info; info && info->name; info++) {
|
|
|
|
if (STREQ(info->name, name))
|
|
|
|
return info->data;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-30 06:37:04 +00:00
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
/* Validate that the options associated with cmd can be parsed. */
|
|
|
|
static int
|
|
|
|
vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg,
|
|
|
|
uint32_t *opts_required)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
bool optional = false;
|
2008-02-20 15:27:08 +00:00
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
*opts_need_arg = 0;
|
|
|
|
*opts_required = 0;
|
2009-07-16 19:44:10 +00:00
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
if (!cmd->opts)
|
|
|
|
return 0;
|
2010-11-30 06:37:04 +00:00
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
for (i = 0; cmd->opts[i].name; i++) {
|
|
|
|
const vshCmdOptDef *opt = &cmd->opts[i];
|
2011-04-12 20:42:59 +00:00
|
|
|
|
|
|
|
if (i > 31)
|
|
|
|
return -1; /* too many options */
|
|
|
|
if (opt->type == VSH_OT_BOOL) {
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
if (opt->flags & VSH_OFLAG_REQ)
|
2011-04-12 20:42:59 +00:00
|
|
|
return -1; /* bool options can't be mandatory */
|
|
|
|
continue;
|
|
|
|
}
|
2012-03-02 18:01:15 +00:00
|
|
|
if (opt->type == VSH_OT_ALIAS) {
|
|
|
|
int j;
|
|
|
|
if (opt->flags || !opt->help)
|
|
|
|
return -1; /* alias options are tracked by the original name */
|
|
|
|
for (j = i + 1; cmd->opts[j].name; j++) {
|
|
|
|
if (STREQ(opt->help, cmd->opts[j].name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!cmd->opts[j].name)
|
|
|
|
return -1; /* alias option must map to a later option name */
|
|
|
|
continue;
|
|
|
|
}
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
if (opt->flags & VSH_OFLAG_REQ_OPT) {
|
|
|
|
if (opt->flags & VSH_OFLAG_REQ)
|
2011-06-07 09:11:10 +00:00
|
|
|
*opts_required |= 1 << i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-04-12 20:42:59 +00:00
|
|
|
*opts_need_arg |= 1 << i;
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
if (opt->flags & VSH_OFLAG_REQ) {
|
2011-04-12 20:42:59 +00:00
|
|
|
if (optional)
|
|
|
|
return -1; /* mandatory options must be listed first */
|
|
|
|
*opts_required |= 1 << i;
|
|
|
|
} else {
|
|
|
|
optional = true;
|
|
|
|
}
|
2011-09-21 14:54:47 +00:00
|
|
|
|
|
|
|
if (opt->type == VSH_OT_ARGV && cmd->opts[i + 1].name)
|
|
|
|
return -1; /* argv option must be listed last */
|
2011-04-12 20:42:59 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdOptDef *
|
2011-04-12 20:42:59 +00:00
|
|
|
vshCmddefGetOption(vshControl *ctl, const vshCmdDef *cmd, const char *name,
|
2011-09-21 14:54:47 +00:00
|
|
|
uint32_t *opts_seen, int *opt_index)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-04-12 20:42:59 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; cmd->opts && cmd->opts[i].name; i++) {
|
|
|
|
const vshCmdOptDef *opt = &cmd->opts[i];
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-04-12 20:42:59 +00:00
|
|
|
if (STREQ(opt->name, name)) {
|
2012-03-02 18:01:15 +00:00
|
|
|
if (opt->type == VSH_OT_ALIAS) {
|
|
|
|
name = opt->help;
|
|
|
|
continue;
|
|
|
|
}
|
2011-09-21 14:54:47 +00:00
|
|
|
if ((*opts_seen & (1 << i)) && opt->type != VSH_OT_ARGV) {
|
2011-04-12 20:42:59 +00:00
|
|
|
vshError(ctl, _("option --%s already seen"), name);
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-09-21 14:54:47 +00:00
|
|
|
*opts_seen |= 1 << i;
|
|
|
|
*opt_index = i;
|
2005-12-08 10:23:34 +00:00
|
|
|
return opt;
|
2011-04-12 20:42:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vshError(ctl, _("command '%s' doesn't support option --%s"),
|
|
|
|
cmd->name, name);
|
2005-12-08 10:23:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdOptDef *
|
2011-04-12 20:42:59 +00:00
|
|
|
vshCmddefGetData(const vshCmdDef *cmd, uint32_t *opts_need_arg,
|
|
|
|
uint32_t *opts_seen)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-04-12 20:42:59 +00:00
|
|
|
int i;
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdOptDef *opt;
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2011-04-12 20:42:59 +00:00
|
|
|
if (!*opts_need_arg)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Grab least-significant set bit */
|
2011-07-15 21:49:37 +00:00
|
|
|
i = ffs(*opts_need_arg) - 1;
|
2011-04-12 20:42:59 +00:00
|
|
|
opt = &cmd->opts[i];
|
2011-09-21 14:54:47 +00:00
|
|
|
if (opt->type != VSH_OT_ARGV)
|
2011-04-12 20:42:59 +00:00
|
|
|
*opts_need_arg &= ~(1 << i);
|
2011-09-21 14:54:47 +00:00
|
|
|
*opts_seen |= 1 << i;
|
2011-04-12 20:42:59 +00:00
|
|
|
return opt;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2006-01-25 09:46:22 +00:00
|
|
|
/*
|
|
|
|
* Checks for required options
|
|
|
|
*/
|
2006-03-15 12:13:25 +00:00
|
|
|
static int
|
2011-04-12 20:42:59 +00:00
|
|
|
vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd, uint32_t opts_required,
|
|
|
|
uint32_t opts_seen)
|
2006-01-25 09:46:22 +00:00
|
|
|
{
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdDef *def = cmd->def;
|
2011-04-12 20:42:59 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
opts_required &= ~opts_seen;
|
|
|
|
if (!opts_required)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; def->opts[i].name; i++) {
|
|
|
|
if (opts_required & (1 << i)) {
|
|
|
|
const vshCmdOptDef *opt = &def->opts[i];
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-04-12 20:42:59 +00:00
|
|
|
vshError(ctl,
|
2011-06-07 09:11:08 +00:00
|
|
|
opt->type == VSH_OT_DATA || opt->type == VSH_OT_ARGV ?
|
2011-04-12 20:42:59 +00:00
|
|
|
_("command '%s' requires <%s> option") :
|
|
|
|
_("command '%s' requires --%s option"),
|
|
|
|
def->name, opt->name);
|
2006-01-25 09:46:22 +00:00
|
|
|
}
|
|
|
|
}
|
2011-04-12 20:42:59 +00:00
|
|
|
return -1;
|
2006-01-25 09:46:22 +00:00
|
|
|
}
|
|
|
|
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdDef *
|
2006-03-15 12:13:25 +00:00
|
|
|
vshCmddefSearch(const char *cmdname)
|
|
|
|
{
|
2010-11-30 06:37:04 +00:00
|
|
|
const vshCmdGrp *g;
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdDef *c;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
for (g = cmdGroups; g->name; g++) {
|
|
|
|
for (c = g->commands; c->name; c++) {
|
2011-04-08 05:08:52 +00:00
|
|
|
if (STREQ(c->name, cmdname))
|
2010-11-30 06:37:04 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
static const vshCmdGrp *
|
|
|
|
vshCmdGrpSearch(const char *grpname)
|
|
|
|
{
|
|
|
|
const vshCmdGrp *g;
|
|
|
|
|
|
|
|
for (g = cmdGroups; g->name; g++) {
|
2011-04-08 05:08:52 +00:00
|
|
|
if (STREQ(g->name, grpname) || STREQ(g->keyword, grpname))
|
2010-11-30 06:37:04 +00:00
|
|
|
return g;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2010-11-30 06:37:04 +00:00
|
|
|
vshCmdGrpHelp(vshControl *ctl, const char *grpname)
|
|
|
|
{
|
|
|
|
const vshCmdGrp *grp = vshCmdGrpSearch(grpname);
|
|
|
|
const vshCmdDef *cmd = NULL;
|
|
|
|
|
|
|
|
if (!grp) {
|
|
|
|
vshError(ctl, _("command group '%s' doesn't exist"), grpname);
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2010-11-30 06:37:04 +00:00
|
|
|
} else {
|
|
|
|
vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
|
|
|
|
grp->keyword);
|
|
|
|
|
|
|
|
for (cmd = grp->commands; cmd->name; cmd++) {
|
|
|
|
vshPrint(ctl, " %-30s %s\n", cmd->name,
|
|
|
|
_(vshCmddefGetInfo(cmd, "help")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2010-11-30 06:37:04 +00:00
|
|
|
}
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2008-12-08 13:14:48 +00:00
|
|
|
vshCmddefHelp(vshControl *ctl, const char *cmdname)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdDef *def = vshCmddefSearch(cmdname);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (!def) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("command '%s' doesn't exist"), cmdname);
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2006-03-15 12:13:25 +00:00
|
|
|
} else {
|
2011-06-20 20:25:08 +00:00
|
|
|
/* Don't translate desc if it is "". */
|
|
|
|
const char *desc = vshCmddefGetInfo(def, "desc");
|
2010-03-09 17:05:01 +00:00
|
|
|
const char *help = _(vshCmddefGetInfo(def, "help"));
|
2008-12-08 13:14:48 +00:00
|
|
|
char buf[256];
|
2011-04-12 20:42:59 +00:00
|
|
|
uint32_t opts_need_arg;
|
|
|
|
uint32_t opts_required;
|
2011-09-14 21:20:08 +00:00
|
|
|
bool shortopt = false; /* true if 'arg' works instead of '--opt arg' */
|
2011-04-12 20:42:59 +00:00
|
|
|
|
|
|
|
if (vshCmddefOptParse(def, &opts_need_arg, &opts_required)) {
|
|
|
|
vshError(ctl, _("internal error: bad options in command: '%s'"),
|
|
|
|
def->name);
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2011-04-12 20:42:59 +00:00
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2006-09-21 15:24:37 +00:00
|
|
|
fputs(_(" NAME\n"), stdout);
|
2006-03-15 12:13:25 +00:00
|
|
|
fprintf(stdout, " %s - %s\n", def->name, help);
|
|
|
|
|
2008-12-08 13:14:48 +00:00
|
|
|
fputs(_("\n SYNOPSIS\n"), stdout);
|
|
|
|
fprintf(stdout, " %s", def->name);
|
|
|
|
if (def->opts) {
|
|
|
|
const vshCmdOptDef *opt;
|
|
|
|
for (opt = def->opts; opt->name; opt++) {
|
2011-05-13 06:27:59 +00:00
|
|
|
const char *fmt = "%s";
|
2010-10-15 13:38:49 +00:00
|
|
|
switch (opt->type) {
|
|
|
|
case VSH_OT_BOOL:
|
2008-12-08 13:14:48 +00:00
|
|
|
fmt = "[--%s]";
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_INT:
|
2010-03-09 17:05:01 +00:00
|
|
|
/* xgettext:c-format */
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
fmt = ((opt->flags & VSH_OFLAG_REQ) ? "<%s>"
|
2010-10-19 16:27:02 +00:00
|
|
|
: _("[--%s <number>]"));
|
2011-09-14 21:20:08 +00:00
|
|
|
if (!(opt->flags & VSH_OFLAG_REQ_OPT))
|
|
|
|
shortopt = true;
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_STRING:
|
2010-03-09 17:05:01 +00:00
|
|
|
/* xgettext:c-format */
|
|
|
|
fmt = _("[--%s <string>]");
|
2011-09-14 21:20:08 +00:00
|
|
|
if (!(opt->flags & VSH_OFLAG_REQ_OPT))
|
|
|
|
shortopt = true;
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_DATA:
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
fmt = ((opt->flags & VSH_OFLAG_REQ) ? "<%s>" : "[<%s>]");
|
2011-09-14 21:20:08 +00:00
|
|
|
if (!(opt->flags & VSH_OFLAG_REQ_OPT))
|
|
|
|
shortopt = true;
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_ARGV:
|
|
|
|
/* xgettext:c-format */
|
2011-09-14 21:20:08 +00:00
|
|
|
if (shortopt) {
|
|
|
|
fmt = (opt->flags & VSH_OFLAG_REQ)
|
|
|
|
? _("{[--%s] <string>}...")
|
|
|
|
: _("[[--%s] <string>]...");
|
|
|
|
} else {
|
|
|
|
fmt = (opt->flags & VSH_OFLAG_REQ) ? _("<%s>...")
|
|
|
|
: _("[<%s>]...");
|
|
|
|
}
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
2012-03-02 18:01:15 +00:00
|
|
|
case VSH_OT_ALIAS:
|
|
|
|
/* aliases are intentionally undocumented */
|
|
|
|
continue;
|
2010-10-15 13:38:49 +00:00
|
|
|
default:
|
2008-12-08 13:14:48 +00:00
|
|
|
assert(0);
|
2010-10-15 13:38:49 +00:00
|
|
|
}
|
2008-12-08 13:14:48 +00:00
|
|
|
fputc(' ', stdout);
|
2010-03-09 17:05:01 +00:00
|
|
|
fprintf(stdout, fmt, opt->name);
|
2008-12-08 13:14:48 +00:00
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2008-12-08 13:14:48 +00:00
|
|
|
fputc('\n', stdout);
|
|
|
|
|
|
|
|
if (desc[0]) {
|
2009-01-05 13:27:43 +00:00
|
|
|
/* Print the description only if it's not empty. */
|
2006-09-21 15:24:37 +00:00
|
|
|
fputs(_("\n DESCRIPTION\n"), stdout);
|
2011-06-20 20:25:08 +00:00
|
|
|
fprintf(stdout, " %s\n", _(desc));
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2008-12-08 13:14:48 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (def->opts) {
|
2008-12-08 13:14:48 +00:00
|
|
|
const vshCmdOptDef *opt;
|
2006-09-21 15:24:37 +00:00
|
|
|
fputs(_("\n OPTIONS\n"), stdout);
|
2006-03-15 12:13:25 +00:00
|
|
|
for (opt = def->opts; opt->name; opt++) {
|
2010-10-15 13:38:49 +00:00
|
|
|
switch (opt->type) {
|
|
|
|
case VSH_OT_BOOL:
|
2005-12-08 10:23:34 +00:00
|
|
|
snprintf(buf, sizeof(buf), "--%s", opt->name);
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_INT:
|
2010-10-19 16:27:02 +00:00
|
|
|
snprintf(buf, sizeof(buf),
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
(opt->flags & VSH_OFLAG_REQ) ? _("[--%s] <number>")
|
2010-10-19 16:27:02 +00:00
|
|
|
: _("--%s <number>"), opt->name);
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_STRING:
|
2010-10-19 16:27:02 +00:00
|
|
|
/* OT_STRING should never be VSH_OFLAG_REQ */
|
2006-09-21 15:24:37 +00:00
|
|
|
snprintf(buf, sizeof(buf), _("--%s <string>"), opt->name);
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_DATA:
|
2010-06-29 22:14:57 +00:00
|
|
|
snprintf(buf, sizeof(buf), _("[--%s] <string>"),
|
|
|
|
opt->name);
|
2010-10-15 13:38:49 +00:00
|
|
|
break;
|
|
|
|
case VSH_OT_ARGV:
|
2011-09-14 21:20:08 +00:00
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
shortopt ? _("[--%s] <string>") : _("<%s>"),
|
|
|
|
opt->name);
|
2011-06-07 09:11:08 +00:00
|
|
|
break;
|
2012-03-02 18:01:15 +00:00
|
|
|
case VSH_OT_ALIAS:
|
|
|
|
continue;
|
2010-10-15 13:38:49 +00:00
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2010-03-09 17:05:01 +00:00
|
|
|
fprintf(stdout, " %-15s %s\n", buf, _(opt->help));
|
2006-03-15 12:13:25 +00:00
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
fputc('\n', stdout);
|
|
|
|
}
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------
|
|
|
|
* Utils for work with runtime commands data
|
|
|
|
* ---------------
|
|
|
|
*/
|
2006-03-15 12:13:25 +00:00
|
|
|
static void
|
|
|
|
vshCommandOptFree(vshCmdOpt * arg)
|
|
|
|
{
|
2005-12-08 10:23:34 +00:00
|
|
|
vshCmdOpt *a = arg;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
while (a) {
|
2005-12-08 10:23:34 +00:00
|
|
|
vshCmdOpt *tmp = a;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
a = a->next;
|
|
|
|
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(tmp->data);
|
|
|
|
VIR_FREE(tmp);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-08-01 13:51:18 +00:00
|
|
|
vshCommandFree(vshCmd *cmd)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2005-12-08 10:23:34 +00:00
|
|
|
vshCmd *c = cmd;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
while (c) {
|
2005-12-08 10:23:34 +00:00
|
|
|
vshCmd *tmp = c;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
c = c->next;
|
|
|
|
|
|
|
|
if (tmp->opts)
|
|
|
|
vshCommandOptFree(tmp->opts);
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(tmp);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOpt:
|
|
|
|
* @cmd: parsed command line to search
|
|
|
|
* @name: option name to search for
|
|
|
|
* @opt: result of the search
|
|
|
|
*
|
|
|
|
* Look up an option passed to CMD by NAME. Returns 1 with *OPT set
|
|
|
|
* to the option if found, 0 with *OPT set to NULL if the name is
|
|
|
|
* valid and the option is not required, -1 with *OPT set to NULL if
|
|
|
|
* the option is required but not present, and -2 if NAME is not valid
|
|
|
|
* (-2 indicates a programming error). No error messages are issued.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2011-07-15 17:23:17 +00:00
|
|
|
static int
|
|
|
|
vshCommandOpt(const vshCmd *cmd, const char *name, vshCmdOpt **opt)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *candidate = cmd->opts;
|
|
|
|
const vshCmdOptDef *valid = cmd->def->opts;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/* See if option is present on command line. */
|
|
|
|
while (candidate) {
|
|
|
|
if (STREQ(candidate->def->name, name)) {
|
|
|
|
*opt = candidate;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
candidate = candidate->next;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
|
|
|
/* Option not present, see if command requires it. */
|
|
|
|
*opt = NULL;
|
|
|
|
while (valid) {
|
|
|
|
if (!valid->name)
|
|
|
|
break;
|
|
|
|
if (STREQ(name, valid->name))
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
return (valid->flags & VSH_OFLAG_REQ) == 0 ? 0 : -1;
|
2011-07-15 17:23:17 +00:00
|
|
|
valid++;
|
|
|
|
}
|
|
|
|
/* If we got here, the name is unknown. */
|
|
|
|
return -2;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptInt:
|
2011-03-08 16:29:31 +00:00
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
|
|
|
* Convert option to int
|
|
|
|
* Return value:
|
|
|
|
* >0 if option found and valid (@value updated)
|
2011-07-15 17:23:17 +00:00
|
|
|
* 0 if option not found and not required (@value untouched)
|
2011-03-08 16:29:31 +00:00
|
|
|
* <0 in all other cases (@value untouched)
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
|
|
|
static int
|
2011-03-08 16:29:31 +00:00
|
|
|
vshCommandOptInt(const vshCmd *cmd, const char *name, int *value)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (!arg->data) {
|
|
|
|
/* only possible on bool, but if name is bool, this is a
|
|
|
|
* programming bug */
|
|
|
|
return -2;
|
2007-08-16 13:21:36 +00:00
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
2012-04-18 23:26:17 +00:00
|
|
|
if (virStrToLong_i(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2011-05-12 16:29:12 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptUInt:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
2011-05-12 16:29:12 +00:00
|
|
|
* Convert option to unsigned int
|
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
vshCommandOptUInt(const vshCmd *cmd, const char *name, unsigned int *value)
|
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
2011-05-12 16:29:12 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (!arg->data) {
|
|
|
|
/* only possible on bool, but if name is bool, this is a
|
|
|
|
* programming bug */
|
|
|
|
return -2;
|
2011-05-12 16:29:12 +00:00
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
2012-04-18 23:26:17 +00:00
|
|
|
if (virStrToLong_ui(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
2011-05-12 16:29:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-08 16:29:31 +00:00
|
|
|
/*
|
2011-07-15 17:23:17 +00:00
|
|
|
* vshCommandOptUL:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
2011-03-08 16:29:31 +00:00
|
|
|
* Convert option to unsigned long
|
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
vshCommandOptUL(const vshCmd *cmd, const char *name, unsigned long *value)
|
2010-06-17 19:36:36 +00:00
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
2010-06-17 19:36:36 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (!arg->data) {
|
|
|
|
/* only possible on bool, but if name is bool, this is a
|
|
|
|
* programming bug */
|
|
|
|
return -2;
|
2010-06-17 19:36:36 +00:00
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
2012-04-18 23:26:17 +00:00
|
|
|
if (virStrToLong_ul(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
2010-06-17 19:36:36 +00:00
|
|
|
}
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptString:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
2005-12-08 10:23:34 +00:00
|
|
|
* Returns option as STRING
|
2011-07-15 17:23:17 +00:00
|
|
|
* Return value:
|
|
|
|
* >0 if option found and valid (@value updated)
|
|
|
|
* 0 if option not found and not required (@value untouched)
|
|
|
|
* <0 in all other cases (@value untouched)
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2011-03-08 16:29:31 +00:00
|
|
|
static int
|
|
|
|
vshCommandOptString(const vshCmd *cmd, const char *name, const char **value)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = vshCommandOpt(cmd, name, &arg);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (!arg->data) {
|
|
|
|
/* only possible on bool, but if name is bool, this is a
|
|
|
|
* programming bug */
|
|
|
|
return -2;
|
2011-03-08 16:29:31 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
virsh: prefer unsigned flags
virsh had some leftover 'int flags', and even an 'int flag'
declaration, compared to our preferred style of 'unsigned int flags'.
* tools/virsh.c (cmdUndefine, cmdSave, cmdSaveImageDumpxml)
(cmdSaveImageEdit, cmdManagedSave, cmdRestore, cmdDump)
(cmdVcpuPin, cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML)
(cmdDomXMLFromNative, cmdDomXMLToNative, doMigrate)
(cmdInterfaceEdit, cmdInterfaceDumpXML, cmdEdit): Match coding
style for flags.
(struct vshComdOptDef): Rename field member.
(vshCmddefOptParse, vshCmddefHelp): Adjust clients.
2011-09-01 03:11:23 +00:00
|
|
|
if (!*arg->data && !(arg->def->flags & VSH_OFLAG_EMPTY_OK)) {
|
2011-07-15 17:23:17 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*value = arg->data;
|
|
|
|
return 1;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptLongLong:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
2010-03-17 16:18:36 +00:00
|
|
|
* Returns option as long long
|
2011-03-08 16:29:31 +00:00
|
|
|
* See vshCommandOptInt()
|
2010-03-17 16:18:36 +00:00
|
|
|
*/
|
2011-03-08 16:29:31 +00:00
|
|
|
static int
|
|
|
|
vshCommandOptLongLong(const vshCmd *cmd, const char *name,
|
|
|
|
long long *value)
|
2010-03-17 16:18:36 +00:00
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
2010-03-17 16:18:36 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (!arg->data) {
|
|
|
|
/* only possible on bool, but if name is bool, this is a
|
|
|
|
* programming bug */
|
|
|
|
return -2;
|
2011-03-08 16:29:31 +00:00
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
2012-04-18 23:26:17 +00:00
|
|
|
if (virStrToLong_ll(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
2010-03-17 16:18:36 +00:00
|
|
|
}
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptULongLong:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
|
|
|
* Returns option as long long
|
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
2009-07-14 13:24:53 +00:00
|
|
|
static int
|
|
|
|
vshCommandOptULongLong(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned long long *value)
|
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
2009-07-14 13:24:53 +00:00
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (!arg->data) {
|
|
|
|
/* only possible on bool, but if name is bool, this is a
|
|
|
|
* programming bug */
|
|
|
|
return -2;
|
2009-07-14 13:24:53 +00:00
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
2012-04-18 23:26:17 +00:00
|
|
|
if (virStrToLong_ull(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
2009-07-14 13:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-08 01:10:30 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptScaledInt:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
* @scale default of 1 or 1024, if no suffix is present
|
|
|
|
* @max maximum value permitted
|
|
|
|
*
|
|
|
|
* Returns option as long long, scaled according to suffix
|
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
vshCommandOptScaledInt(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned long long *value, int scale,
|
|
|
|
unsigned long long max)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
int ret;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
ret = vshCommandOptString(cmd, name, &str);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (virStrToLong_ull(str, &end, 10, value) < 0 ||
|
|
|
|
virScaleInteger(value, end, scale, max) < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptBool:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
*
|
|
|
|
* Returns true/false if the option exists. Note that this does NOT
|
|
|
|
* validate whether the option is actually boolean, or even whether
|
|
|
|
* name is legal; so that this can be used to probe whether a data
|
|
|
|
* option is present without actually using that data.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2008-08-01 13:51:18 +00:00
|
|
|
vshCommandOptBool(const vshCmd *cmd, const char *name)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-07-15 17:23:17 +00:00
|
|
|
vshCmdOpt *dummy;
|
|
|
|
|
|
|
|
return vshCommandOpt(cmd, name, &dummy) == 1;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptArgv:
|
|
|
|
* @cmd command reference
|
|
|
|
* @opt starting point for the search
|
|
|
|
*
|
2011-06-14 17:26:20 +00:00
|
|
|
* Returns the next argv argument after OPT (or the first one if OPT
|
|
|
|
* is NULL), or NULL if no more are present.
|
2010-10-15 13:38:49 +00:00
|
|
|
*
|
2011-06-14 17:26:20 +00:00
|
|
|
* Requires that a VSH_OT_ARGV option be last in the
|
2010-10-15 13:38:49 +00:00
|
|
|
* list of supported options in CMD->def->opts.
|
|
|
|
*/
|
2011-06-14 17:26:20 +00:00
|
|
|
static const vshCmdOpt *
|
|
|
|
vshCommandOptArgv(const vshCmd *cmd, const vshCmdOpt *opt)
|
2010-10-15 13:38:49 +00:00
|
|
|
{
|
2011-06-14 17:26:20 +00:00
|
|
|
opt = opt ? opt->next : cmd->opts;
|
2010-10-15 13:38:49 +00:00
|
|
|
|
|
|
|
while (opt) {
|
2011-07-15 17:23:17 +00:00
|
|
|
if (opt->def->type == VSH_OT_ARGV) {
|
2011-06-14 17:26:20 +00:00
|
|
|
return opt;
|
2010-10-15 13:38:49 +00:00
|
|
|
}
|
|
|
|
opt = opt->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
/* Determine whether CMD->opts includes an option with name OPTNAME.
|
|
|
|
If not, give a diagnostic and return false.
|
|
|
|
If so, return true. */
|
|
|
|
static bool
|
2012-07-11 06:17:28 +00:00
|
|
|
cmd_has_option(vshControl *ctl, const vshCmd *cmd, const char *optname)
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
{
|
|
|
|
/* Iterate through cmd->opts, to ensure that there is an entry
|
|
|
|
with name OPTNAME and type VSH_OT_DATA. */
|
|
|
|
bool found = false;
|
|
|
|
const vshCmdOpt *opt;
|
|
|
|
for (opt = cmd->opts; opt; opt = opt->next) {
|
2012-07-11 06:17:28 +00:00
|
|
|
if (STREQ(opt->def->name, optname) && opt->def->type == VSH_OT_DATA) {
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("internal error: virsh %s: no %s VSH_OT_DATA option"),
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
cmd->def->name, optname);
|
|
|
|
return found;
|
|
|
|
}
|
2006-01-25 09:46:22 +00:00
|
|
|
|
2005-12-15 17:00:43 +00:00
|
|
|
static virDomainPtr
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
|
2011-03-08 16:29:30 +00:00
|
|
|
const char **name, int flag)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2005-12-15 17:00:43 +00:00
|
|
|
virDomainPtr dom = NULL;
|
2011-03-08 16:29:31 +00:00
|
|
|
const char *n = NULL;
|
2005-12-15 17:00:43 +00:00
|
|
|
int id;
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
const char *optname = "domain";
|
2012-07-11 06:17:28 +00:00
|
|
|
if (!cmd_has_option(ctl, cmd, optname))
|
remove redundant optname arguments
This is the second part of the change mentioned here:
http://thread.gmane.org/gmane.comp.emulators.libvirt/10331
It removes the essentially redundant "optname" parameter
from each of the vshCommandOptNetworkBy and vshCommandOptDomainBy
functions as well as the correspond macros (without "By" suffix).
Now, instead of always passing the optname, "domain", to
vshCommandOptDomainBy, that function requires that its command
argument refer to an opts array containing a "domain" option.
This normalization makes one more help-related change:
it renames the net-start "name" argument to the more
sensible and consistent "network".
* src/virsh.c (VSH_BYNAME, vshCommandOptDomain)
(cmd_has_option): New function, used in vshCommandOptDomainBy
and vshCommandOptNetworkBy.
(vshCommandOptDomainBy, vshCommandOptNetworkBy): Remove the optname
parameter, it's always "domain" ("network"). Update all callers.
Call cmd_has_option.
(vshCommandOptNetwork, cmdAutostart, cmdConsole, cmdDomstate)
(cmdDomblkstat, cmdDomIfstat, cmdSuspend, cmdUndefine, cmdStart)
(cmdSave, cmdSchedinfo, cmdDump, cmdResume, cmdShutdown)
(cmdReboot, cmdDestroy, cmdDominfo, cmdVcpuinfo, cmdVcpupin)
(cmdSetvcpus, cmdSetmem, cmdSetmaxmem, cmdDumpXML, cmdDomname)
(cmdDomid, cmdDomuuid, cmdMigrate, cmdNetworkAutostart)
(cmdNetworkDestroy, cmdNetworkDumpXML, cmdNetworkName)
(opts_network_start, cmdNetworkStart, cmdNetworkUndefine)
(cmdNetworkUuid, cmdVNCDisplay, cmdTTYConsole, cmdAttachDevice)
(cmdDetachDevice, cmdAttachInterface, cmdDetachInterface)
(cmdAttachDisk, cmdDetachDisk, cmdEdit)
* src/Makefile.am (virsh-pool-edit.c): This code is generated
from cmdEdit, and cmdEdit uses the vshCommandOptDomain macro which
now, with the changes above, has only 3 (was 4) arguments, yet the
macro use is mapped to vshCommandOptPool, which still requires 4
arguments. So this change adjusts the sed code to reinsert the
just-removed argument -- we're not changing pool-related code right
now, because it's not as straight-forward.
2008-12-15 10:26:54 +00:00
|
|
|
return NULL;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-03-08 16:29:31 +00:00
|
|
|
if (vshCommandOptString(cmd, optname, &n) <= 0)
|
2006-03-15 12:13:25 +00:00
|
|
|
return NULL;
|
|
|
|
|
2011-06-30 08:22:20 +00:00
|
|
|
vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n",
|
2006-03-15 12:13:25 +00:00
|
|
|
cmd->def->name, optname, n);
|
|
|
|
|
2005-12-15 17:00:43 +00:00
|
|
|
if (name)
|
|
|
|
*name = n;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-15 17:00:43 +00:00
|
|
|
/* try it by ID */
|
2007-02-14 15:44:58 +00:00
|
|
|
if (flag & VSH_BYID) {
|
2008-02-08 09:15:16 +00:00
|
|
|
if (virStrToLong_i(n, NULL, 10, &id) == 0 && id >= 0) {
|
2011-06-30 08:22:20 +00:00
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
|
|
"%s: <%s> seems like domain ID\n",
|
2006-05-29 15:39:31 +00:00
|
|
|
cmd->def->name, optname);
|
|
|
|
dom = virDomainLookupByID(ctl->conn, id);
|
|
|
|
}
|
2006-01-25 09:46:22 +00:00
|
|
|
}
|
2006-05-22 14:38:33 +00:00
|
|
|
/* try it by UUID */
|
2007-02-14 15:44:58 +00:00
|
|
|
if (dom==NULL && (flag & VSH_BYUUID) && strlen(n)==VIR_UUID_STRING_BUFLEN-1) {
|
2011-06-30 08:22:20 +00:00
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as domain UUID\n",
|
2007-02-07 13:50:18 +00:00
|
|
|
cmd->def->name, optname);
|
2006-05-29 15:39:31 +00:00
|
|
|
dom = virDomainLookupByUUIDString(ctl->conn, n);
|
2006-05-22 14:38:33 +00:00
|
|
|
}
|
2005-12-15 17:00:43 +00:00
|
|
|
/* try it by NAME */
|
2007-02-14 15:44:58 +00:00
|
|
|
if (dom==NULL && (flag & VSH_BYNAME)) {
|
2011-06-30 08:22:20 +00:00
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as domain NAME\n",
|
2006-03-15 12:13:25 +00:00
|
|
|
cmd->def->name, optname);
|
2005-12-15 17:00:43 +00:00
|
|
|
dom = virDomainLookupByName(ctl->conn, n);
|
2006-01-25 09:46:22 +00:00
|
|
|
}
|
2006-05-22 14:38:33 +00:00
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
if (!dom)
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("failed to get domain '%s'"), n);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-15 17:00:43 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
|
|
|
* Executes command(s) and returns return code from last command
|
|
|
|
*/
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2008-08-01 13:51:18 +00:00
|
|
|
vshCommandRun(vshControl *ctl, const vshCmd *cmd)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-04-18 22:37:42 +00:00
|
|
|
bool ret = true;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
|
|
|
while (cmd) {
|
2005-12-08 10:23:34 +00:00
|
|
|
struct timeval before, after;
|
2010-04-14 07:04:28 +00:00
|
|
|
bool enable_timing = ctl->timing;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
if ((ctl->conn == NULL || disconnected) &&
|
|
|
|
!(cmd->def->flags & VSH_CMD_FLAG_NOCONNECT))
|
2010-03-05 09:59:52 +00:00
|
|
|
vshReconnect(ctl);
|
|
|
|
|
2010-04-14 07:04:28 +00:00
|
|
|
if (enable_timing)
|
2005-12-08 10:23:34 +00:00
|
|
|
GETTIMEOFDAY(&before);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
ret = cmd->def->handler(ctl, cmd);
|
|
|
|
|
2010-04-14 07:04:28 +00:00
|
|
|
if (enable_timing)
|
2005-12-08 10:23:34 +00:00
|
|
|
GETTIMEOFDAY(&after);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2012-01-02 16:07:31 +00:00
|
|
|
/* try to automatically catch disconnections */
|
|
|
|
if (!ret &&
|
|
|
|
((last_error != NULL) &&
|
|
|
|
(((last_error->code == VIR_ERR_SYSTEM_ERROR) &&
|
|
|
|
(last_error->domain == VIR_FROM_REMOTE)) ||
|
|
|
|
(last_error->code == VIR_ERR_RPC) ||
|
|
|
|
(last_error->code == VIR_ERR_NO_CONNECT) ||
|
|
|
|
(last_error->code == VIR_ERR_INVALID_CONN))))
|
|
|
|
disconnected++;
|
|
|
|
|
2011-05-05 20:27:51 +00:00
|
|
|
if (!ret)
|
2009-02-09 14:24:06 +00:00
|
|
|
virshReportError(ctl);
|
|
|
|
|
2012-01-02 16:07:31 +00:00
|
|
|
if (!ret && disconnected != 0)
|
2010-03-05 09:59:52 +00:00
|
|
|
vshReconnect(ctl);
|
|
|
|
|
2008-05-14 19:51:24 +00:00
|
|
|
if (STREQ(cmd->def->name, "quit")) /* hack ... */
|
2005-12-08 10:23:34 +00:00
|
|
|
return ret;
|
|
|
|
|
2010-04-14 07:04:28 +00:00
|
|
|
if (enable_timing)
|
2006-09-21 15:24:37 +00:00
|
|
|
vshPrint(ctl, _("\n(Time: %.3f ms)\n\n"),
|
2006-03-15 12:13:25 +00:00
|
|
|
DIFF_MSEC(&after, &before));
|
|
|
|
else
|
2006-05-22 14:38:33 +00:00
|
|
|
vshPrintExtra(ctl, "\n");
|
2005-12-08 10:23:34 +00:00
|
|
|
cmd = cmd->next;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------
|
2010-10-12 22:01:02 +00:00
|
|
|
* Command parsing
|
2005-12-08 10:23:34 +00:00
|
|
|
* ---------------
|
|
|
|
*/
|
|
|
|
|
2010-10-12 07:13:50 +00:00
|
|
|
typedef enum {
|
|
|
|
VSH_TK_ERROR, /* Failed to parse a token */
|
|
|
|
VSH_TK_ARG, /* Arbitrary argument, might be option or empty */
|
|
|
|
VSH_TK_SUBCMD_END, /* Separation between commands */
|
|
|
|
VSH_TK_END /* No more commands */
|
|
|
|
} vshCommandToken;
|
|
|
|
|
|
|
|
typedef struct __vshCommandParser {
|
2012-07-11 06:17:28 +00:00
|
|
|
vshCommandToken(*getNextArg)(vshControl *, struct __vshCommandParser *,
|
2010-10-12 07:13:50 +00:00
|
|
|
char **);
|
2010-10-12 07:14:01 +00:00
|
|
|
/* vshCommandStringGetArg() */
|
2010-10-12 07:13:50 +00:00
|
|
|
char *pos;
|
2010-10-12 07:14:01 +00:00
|
|
|
/* vshCommandArgvGetArg() */
|
|
|
|
char **arg_pos;
|
|
|
|
char **arg_end;
|
2010-10-12 07:13:50 +00:00
|
|
|
} vshCommandParser;
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2010-10-12 07:13:50 +00:00
|
|
|
vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2005-12-08 10:23:34 +00:00
|
|
|
char *tkdata = NULL;
|
|
|
|
vshCmd *clast = NULL;
|
|
|
|
vshCmdOpt *first = NULL;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (ctl->cmd) {
|
|
|
|
vshCommandFree(ctl->cmd);
|
|
|
|
ctl->cmd = NULL;
|
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2010-10-12 07:13:50 +00:00
|
|
|
while (1) {
|
2005-12-08 10:23:34 +00:00
|
|
|
vshCmdOpt *last = NULL;
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdDef *cmd = NULL;
|
2010-10-12 07:13:50 +00:00
|
|
|
vshCommandToken tk;
|
2010-10-12 07:14:22 +00:00
|
|
|
bool data_only = false;
|
2011-04-12 20:42:59 +00:00
|
|
|
uint32_t opts_need_arg = 0;
|
|
|
|
uint32_t opts_required = 0;
|
|
|
|
uint32_t opts_seen = 0;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
first = NULL;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2010-10-12 07:13:50 +00:00
|
|
|
while (1) {
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdOptDef *opt = NULL;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
tkdata = NULL;
|
2010-10-12 07:13:50 +00:00
|
|
|
tk = parser->getNextArg(ctl, parser, &tkdata);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
|
|
|
if (tk == VSH_TK_ERROR)
|
2005-12-08 10:23:34 +00:00
|
|
|
goto syntaxError;
|
2010-12-22 07:12:34 +00:00
|
|
|
if (tk != VSH_TK_ARG) {
|
|
|
|
VIR_FREE(tkdata);
|
2010-10-12 07:13:50 +00:00
|
|
|
break;
|
2010-12-22 07:12:34 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
|
|
|
if (cmd == NULL) {
|
2005-12-08 10:23:34 +00:00
|
|
|
/* first token must be command name */
|
|
|
|
if (!(cmd = vshCmddefSearch(tkdata))) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("unknown command: '%s'"), tkdata);
|
2006-03-15 12:13:25 +00:00
|
|
|
goto syntaxError; /* ... or ignore this command only? */
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2011-04-12 20:42:59 +00:00
|
|
|
if (vshCmddefOptParse(cmd, &opts_need_arg,
|
|
|
|
&opts_required) < 0) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("internal error: bad options in command: '%s'"),
|
|
|
|
tkdata);
|
|
|
|
goto syntaxError;
|
|
|
|
}
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(tkdata);
|
2010-10-12 07:14:22 +00:00
|
|
|
} else if (data_only) {
|
|
|
|
goto get_data;
|
|
|
|
} else if (tkdata[0] == '-' && tkdata[1] == '-' &&
|
|
|
|
c_isalnum(tkdata[2])) {
|
2010-10-12 07:13:39 +00:00
|
|
|
char *optstr = strchr(tkdata + 2, '=');
|
2011-09-21 14:54:47 +00:00
|
|
|
int opt_index;
|
|
|
|
|
2010-10-12 07:13:39 +00:00
|
|
|
if (optstr) {
|
|
|
|
*optstr = '\0'; /* convert the '=' to '\0' */
|
|
|
|
optstr = vshStrdup(ctl, optstr + 1);
|
|
|
|
}
|
2011-04-12 20:42:59 +00:00
|
|
|
if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
|
2011-09-21 14:54:47 +00:00
|
|
|
&opts_seen, &opt_index))) {
|
2010-10-12 07:13:39 +00:00
|
|
|
VIR_FREE(optstr);
|
2005-12-08 10:23:34 +00:00
|
|
|
goto syntaxError;
|
|
|
|
}
|
2010-10-12 07:13:39 +00:00
|
|
|
VIR_FREE(tkdata);
|
2005-12-08 10:23:34 +00:00
|
|
|
|
|
|
|
if (opt->type != VSH_OT_BOOL) {
|
|
|
|
/* option data */
|
2010-10-12 07:13:39 +00:00
|
|
|
if (optstr)
|
|
|
|
tkdata = optstr;
|
|
|
|
else
|
2010-10-12 07:13:50 +00:00
|
|
|
tk = parser->getNextArg(ctl, parser, &tkdata);
|
2006-03-15 12:13:25 +00:00
|
|
|
if (tk == VSH_TK_ERROR)
|
2005-12-08 10:23:34 +00:00
|
|
|
goto syntaxError;
|
2010-10-12 07:13:50 +00:00
|
|
|
if (tk != VSH_TK_ARG) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl,
|
2006-09-21 15:24:37 +00:00
|
|
|
_("expected syntax: --%s <%s>"),
|
2006-03-15 12:13:25 +00:00
|
|
|
opt->name,
|
|
|
|
opt->type ==
|
2006-09-21 15:24:37 +00:00
|
|
|
VSH_OT_INT ? _("number") : _("string"));
|
2005-12-08 10:23:34 +00:00
|
|
|
goto syntaxError;
|
|
|
|
}
|
2011-09-21 14:54:47 +00:00
|
|
|
if (opt->type != VSH_OT_ARGV)
|
|
|
|
opts_need_arg &= ~(1 << opt_index);
|
2010-10-12 07:13:39 +00:00
|
|
|
} else {
|
|
|
|
tkdata = NULL;
|
|
|
|
if (optstr) {
|
|
|
|
vshError(ctl, _("invalid '=' after option --%s"),
|
|
|
|
opt->name);
|
|
|
|
VIR_FREE(optstr);
|
|
|
|
goto syntaxError;
|
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2010-10-12 07:14:22 +00:00
|
|
|
} else if (tkdata[0] == '-' && tkdata[1] == '-' &&
|
|
|
|
tkdata[2] == '\0') {
|
|
|
|
data_only = true;
|
|
|
|
continue;
|
2010-10-12 07:13:50 +00:00
|
|
|
} else {
|
2010-10-12 07:14:22 +00:00
|
|
|
get_data:
|
2011-04-12 20:42:59 +00:00
|
|
|
if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
|
|
|
|
&opts_seen))) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, _("unexpected data '%s'"), tkdata);
|
2005-12-08 10:23:34 +00:00
|
|
|
goto syntaxError;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (opt) {
|
|
|
|
/* save option */
|
2006-04-06 10:33:06 +00:00
|
|
|
vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
arg->def = opt;
|
|
|
|
arg->data = tkdata;
|
|
|
|
arg->next = NULL;
|
|
|
|
tkdata = NULL;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (!first)
|
|
|
|
first = arg;
|
|
|
|
if (last)
|
|
|
|
last->next = arg;
|
|
|
|
last = arg;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-06-30 08:22:20 +00:00
|
|
|
vshDebug(ctl, VSH_ERR_INFO, "%s: %s(%s): %s\n",
|
2006-03-15 12:13:25 +00:00
|
|
|
cmd->name,
|
|
|
|
opt->name,
|
2010-10-12 07:13:39 +00:00
|
|
|
opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
|
|
|
|
opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2008-04-04 07:58:29 +00:00
|
|
|
/* command parsed -- allocate new struct for the command */
|
2005-12-08 10:23:34 +00:00
|
|
|
if (cmd) {
|
2006-04-06 10:33:06 +00:00
|
|
|
vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
|
2006-03-30 12:14:40 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
c->opts = first;
|
|
|
|
c->def = cmd;
|
|
|
|
c->next = NULL;
|
|
|
|
|
2011-04-12 20:42:59 +00:00
|
|
|
if (vshCommandCheckOpts(ctl, c, opts_required, opts_seen) < 0) {
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(c);
|
2006-01-25 09:46:22 +00:00
|
|
|
goto syntaxError;
|
2007-05-29 13:55:19 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (!ctl->cmd)
|
|
|
|
ctl->cmd = c;
|
|
|
|
if (clast)
|
|
|
|
clast->next = c;
|
|
|
|
clast = c;
|
|
|
|
}
|
2010-10-12 07:13:50 +00:00
|
|
|
|
|
|
|
if (tk == VSH_TK_END)
|
|
|
|
break;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2007-02-07 13:50:18 +00:00
|
|
|
syntaxError:
|
2010-03-12 11:00:46 +00:00
|
|
|
if (ctl->cmd) {
|
2005-12-08 10:23:34 +00:00
|
|
|
vshCommandFree(ctl->cmd);
|
2010-03-12 11:00:46 +00:00
|
|
|
ctl->cmd = NULL;
|
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
if (first)
|
|
|
|
vshCommandOptFree(first);
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(tkdata);
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 22:01:02 +00:00
|
|
|
/* --------------------
|
|
|
|
* Command argv parsing
|
|
|
|
* --------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
|
|
vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
|
|
|
|
{
|
|
|
|
if (parser->arg_pos == parser->arg_end) {
|
|
|
|
*res = NULL;
|
|
|
|
return VSH_TK_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
*res = vshStrdup(ctl, *parser->arg_pos);
|
|
|
|
parser->arg_pos++;
|
|
|
|
return VSH_TK_ARG;
|
|
|
|
}
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
|
|
|
vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
|
2010-10-12 22:01:02 +00:00
|
|
|
{
|
|
|
|
vshCommandParser parser;
|
|
|
|
|
|
|
|
if (nargs <= 0)
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2010-10-12 22:01:02 +00:00
|
|
|
|
|
|
|
parser.arg_pos = argv;
|
|
|
|
parser.arg_end = argv + nargs;
|
|
|
|
parser.getNextArg = vshCommandArgvGetArg;
|
|
|
|
return vshCommandParse(ctl, &parser);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------
|
|
|
|
* Command string parsing
|
|
|
|
* ----------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
|
|
vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
|
|
|
|
{
|
|
|
|
bool single_quote = false;
|
|
|
|
bool double_quote = false;
|
|
|
|
int sz = 0;
|
|
|
|
char *p = parser->pos;
|
|
|
|
char *q = vshStrdup(ctl, p);
|
|
|
|
|
|
|
|
*res = q;
|
|
|
|
|
|
|
|
while (*p && (*p == ' ' || *p == '\t'))
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p == '\0')
|
|
|
|
return VSH_TK_END;
|
|
|
|
if (*p == ';') {
|
|
|
|
parser->pos = ++p; /* = \0 or begin of next command */
|
|
|
|
return VSH_TK_SUBCMD_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
/* end of token is blank space or ';' */
|
|
|
|
if (!double_quote && !single_quote &&
|
|
|
|
(*p == ' ' || *p == '\t' || *p == ';'))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!double_quote && *p == '\'') { /* single quote */
|
|
|
|
single_quote = !single_quote;
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
} else if (!single_quote && *p == '\\') { /* escape */
|
|
|
|
/*
|
|
|
|
* The same as the bash, a \ in "" is an escaper,
|
|
|
|
* but a \ in '' is not an escaper.
|
|
|
|
*/
|
|
|
|
p++;
|
|
|
|
if (*p == '\0') {
|
|
|
|
vshError(ctl, "%s", _("dangling \\"));
|
|
|
|
return VSH_TK_ERROR;
|
|
|
|
}
|
|
|
|
} else if (!single_quote && *p == '"') { /* double quote */
|
|
|
|
double_quote = !double_quote;
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*q++ = *p++;
|
|
|
|
sz++;
|
|
|
|
}
|
|
|
|
if (double_quote) {
|
|
|
|
vshError(ctl, "%s", _("missing \""));
|
|
|
|
return VSH_TK_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
*q = '\0';
|
|
|
|
parser->pos = p;
|
|
|
|
return VSH_TK_ARG;
|
|
|
|
}
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
|
|
|
vshCommandStringParse(vshControl *ctl, char *cmdstr)
|
2010-10-12 22:01:02 +00:00
|
|
|
{
|
|
|
|
vshCommandParser parser;
|
|
|
|
|
|
|
|
if (cmdstr == NULL || *cmdstr == '\0')
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2010-10-12 22:01:02 +00:00
|
|
|
|
|
|
|
parser.pos = cmdstr;
|
|
|
|
parser.getNextArg = vshCommandStringGetArg;
|
|
|
|
return vshCommandParse(ctl, &parser);
|
|
|
|
}
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/* ---------------
|
2007-02-07 13:50:18 +00:00
|
|
|
* Misc utils
|
2005-12-08 10:23:34 +00:00
|
|
|
* ---------------
|
|
|
|
*/
|
2011-04-29 08:20:49 +00:00
|
|
|
static int
|
|
|
|
vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason)
|
|
|
|
{
|
|
|
|
virDomainInfo info;
|
|
|
|
|
|
|
|
if (reason)
|
|
|
|
*reason = -1;
|
|
|
|
|
|
|
|
if (!ctl->useGetInfo) {
|
|
|
|
int state;
|
|
|
|
if (virDomainGetState(dom, &state, reason, 0) < 0) {
|
|
|
|
virErrorPtr err = virGetLastError();
|
|
|
|
if (err && err->code == VIR_ERR_NO_SUPPORT)
|
|
|
|
ctl->useGetInfo = true;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fall back to virDomainGetInfo if virDomainGetState is not supported */
|
|
|
|
if (virDomainGetInfo(dom, &info) < 0)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return info.state;
|
|
|
|
}
|
|
|
|
|
2011-12-19 23:06:08 +00:00
|
|
|
/* Return a non-NULL string representation of a typed parameter; exit
|
|
|
|
* if we are out of memory. */
|
2011-09-19 12:23:12 +00:00
|
|
|
static char *
|
|
|
|
vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
char *str = NULL;
|
|
|
|
|
|
|
|
switch(item->type) {
|
|
|
|
case VIR_TYPED_PARAM_INT:
|
|
|
|
ret = virAsprintf(&str, "%d", item->value.i);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_TYPED_PARAM_UINT:
|
|
|
|
ret = virAsprintf(&str, "%u", item->value.ui);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_TYPED_PARAM_LLONG:
|
|
|
|
ret = virAsprintf(&str, "%lld", item->value.l);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_TYPED_PARAM_ULLONG:
|
|
|
|
ret = virAsprintf(&str, "%llu", item->value.ul);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_TYPED_PARAM_DOUBLE:
|
|
|
|
ret = virAsprintf(&str, "%f", item->value.d);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_TYPED_PARAM_BOOLEAN:
|
|
|
|
ret = virAsprintf(&str, "%s", item->value.b ? _("yes") : _("no"));
|
|
|
|
break;
|
|
|
|
|
2011-12-19 23:06:08 +00:00
|
|
|
case VIR_TYPED_PARAM_STRING:
|
|
|
|
str = vshStrdup(ctl, item->value.s);
|
|
|
|
break;
|
|
|
|
|
2011-09-19 12:23:12 +00:00
|
|
|
default:
|
2011-12-19 23:06:08 +00:00
|
|
|
vshError(ctl, _("unimplemented parameter type %d"), item->type);
|
2011-09-19 12:23:12 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 23:06:08 +00:00
|
|
|
if (ret < 0) {
|
2011-09-19 12:23:12 +00:00
|
|
|
vshError(ctl, "%s", _("Out of memory"));
|
2011-12-19 23:06:08 +00:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2011-09-19 12:23:12 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virTypedParameterPtr
|
|
|
|
vshFindTypedParamByName(const char *name, virTypedParameterPtr list, int count)
|
|
|
|
{
|
|
|
|
int i = count;
|
|
|
|
virTypedParameterPtr found = list;
|
|
|
|
|
|
|
|
if (!list || !name)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (i-- > 0) {
|
|
|
|
if (STREQ(name, found->field))
|
|
|
|
return found;
|
|
|
|
|
|
|
|
found++; /* go to next struct in array */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* not found */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2010-06-17 14:47:06 +00:00
|
|
|
vshConnectionUsability(vshControl *ctl, virConnectPtr conn)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2007-02-07 13:50:18 +00:00
|
|
|
/* TODO: use something like virConnectionState() to
|
|
|
|
* check usability of the connection
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
|
|
|
if (!conn) {
|
2010-06-17 14:47:06 +00:00
|
|
|
vshError(ctl, "%s", _("no valid connection"));
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2006-05-22 14:38:33 +00:00
|
|
|
static void
|
2008-08-01 13:51:18 +00:00
|
|
|
vshDebug(vshControl *ctl, int level, const char *format, ...)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2006-05-22 14:38:33 +00:00
|
|
|
va_list ap;
|
2011-04-28 21:09:08 +00:00
|
|
|
char *str;
|
2006-05-22 14:38:33 +00:00
|
|
|
|
2011-06-30 08:22:32 +00:00
|
|
|
/* Aligning log levels to that of libvirt.
|
|
|
|
* Traces with levels >= user-specified-level
|
|
|
|
* gets logged into file
|
|
|
|
*/
|
|
|
|
if (level < ctl->debug)
|
|
|
|
return;
|
|
|
|
|
2007-06-06 12:24:31 +00:00
|
|
|
va_start(ap, format);
|
2011-06-30 08:22:32 +00:00
|
|
|
vshOutputLogFile(ctl, level, format, ap);
|
2007-06-06 12:24:31 +00:00
|
|
|
va_end(ap);
|
|
|
|
|
2006-05-22 14:38:33 +00:00
|
|
|
va_start(ap, format);
|
2011-04-28 21:09:08 +00:00
|
|
|
if (virVasprintf(&str, format, ap) < 0) {
|
|
|
|
/* Skip debug messages on low memory */
|
|
|
|
va_end(ap);
|
|
|
|
return;
|
|
|
|
}
|
2006-05-22 14:38:33 +00:00
|
|
|
va_end(ap);
|
2011-04-28 21:09:08 +00:00
|
|
|
fputs(str, stdout);
|
|
|
|
VIR_FREE(str);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-08-01 13:51:18 +00:00
|
|
|
vshPrintExtra(vshControl *ctl, const char *format, ...)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2005-12-08 10:23:34 +00:00
|
|
|
va_list ap;
|
2011-02-12 00:17:12 +00:00
|
|
|
char *str;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-05-05 20:27:51 +00:00
|
|
|
if (ctl && ctl->quiet)
|
2005-12-08 10:23:34 +00:00
|
|
|
return;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
va_start(ap, format);
|
2011-02-12 00:17:12 +00:00
|
|
|
if (virVasprintf(&str, format, ap) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Out of memory"));
|
|
|
|
va_end(ap);
|
|
|
|
return;
|
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
va_end(ap);
|
2011-04-28 21:09:08 +00:00
|
|
|
fputs(str, stdout);
|
2011-02-12 00:17:12 +00:00
|
|
|
VIR_FREE(str);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2006-05-22 14:38:33 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
static void
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(vshControl *ctl, const char *format, ...)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2005-12-08 10:23:34 +00:00
|
|
|
va_list ap;
|
2011-02-12 00:17:12 +00:00
|
|
|
char *str;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2010-03-05 09:59:52 +00:00
|
|
|
if (ctl != NULL) {
|
|
|
|
va_start(ap, format);
|
|
|
|
vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
2007-06-06 12:24:31 +00:00
|
|
|
|
2011-08-19 15:20:35 +00:00
|
|
|
/* Most output is to stdout, but if someone ran virsh 2>&1, then
|
|
|
|
* printing to stderr will not interleave correctly with stdout
|
|
|
|
* unless we flush between every transition between streams. */
|
|
|
|
fflush(stdout);
|
2009-09-29 11:42:42 +00:00
|
|
|
fputs(_("error: "), stderr);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
va_start(ap, format);
|
2011-02-12 00:17:12 +00:00
|
|
|
/* We can't recursively call vshError on an OOM situation, so ignore
|
|
|
|
failure here. */
|
|
|
|
ignore_value(virVasprintf(&str, format, ap));
|
2005-12-08 10:23:34 +00:00
|
|
|
va_end(ap);
|
|
|
|
|
2011-02-12 00:17:12 +00:00
|
|
|
fprintf(stderr, "%s\n", NULLSTR(str));
|
2011-08-19 15:20:35 +00:00
|
|
|
fflush(stderr);
|
2011-02-12 00:17:12 +00:00
|
|
|
VIR_FREE(str);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2011-04-29 08:20:49 +00:00
|
|
|
|
2011-10-11 13:05:52 +00:00
|
|
|
static void
|
|
|
|
vshEventLoop(void *opaque)
|
|
|
|
{
|
|
|
|
vshControl *ctl = opaque;
|
|
|
|
|
2011-11-30 19:42:20 +00:00
|
|
|
while (1) {
|
|
|
|
bool quit;
|
|
|
|
virMutexLock(&ctl->lock);
|
|
|
|
quit = ctl->quit;
|
|
|
|
virMutexUnlock(&ctl->lock);
|
|
|
|
|
|
|
|
if (quit)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (virEventRunDefaultImpl() < 0)
|
2011-10-11 13:05:52 +00:00
|
|
|
virshReportError(ctl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
2007-06-20 17:22:09 +00:00
|
|
|
* Initialize connection.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2008-08-01 13:51:18 +00:00
|
|
|
vshInit(vshControl *ctl)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2011-05-09 07:08:06 +00:00
|
|
|
char *debugEnv;
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (ctl->conn)
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2011-07-14 11:58:02 +00:00
|
|
|
if (ctl->debug == VSH_DEBUG_DEFAULT) {
|
2011-05-09 07:08:06 +00:00
|
|
|
/* log level not set from commandline, check env variable */
|
|
|
|
debugEnv = getenv("VIRSH_DEBUG");
|
|
|
|
if (debugEnv) {
|
2011-07-14 11:58:02 +00:00
|
|
|
int debug;
|
|
|
|
if (virStrToLong_i(debugEnv, NULL, 10, &debug) < 0 ||
|
|
|
|
debug < VSH_ERR_DEBUG || debug > VSH_ERR_ERROR) {
|
2011-05-09 07:08:06 +00:00
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("VIRSH_DEBUG not set with a valid numeric value"));
|
2011-07-14 11:58:02 +00:00
|
|
|
} else {
|
|
|
|
ctl->debug = debug;
|
2011-05-09 07:08:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctl->logfile == NULL) {
|
|
|
|
/* log file not set from cmdline */
|
|
|
|
debugEnv = getenv("VIRSH_LOG_FILE");
|
|
|
|
if (debugEnv && *debugEnv) {
|
|
|
|
ctl->logfile = vshStrdup(ctl, debugEnv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-06 12:24:31 +00:00
|
|
|
vshOpenLogFile(ctl);
|
|
|
|
|
2006-02-27 21:34:28 +00:00
|
|
|
/* set up the library error handler */
|
|
|
|
virSetErrorFunc(NULL, virshErrorHandler);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-03-02 16:59:54 +00:00
|
|
|
if (virEventRegisterDefaultImpl() < 0)
|
2011-04-18 22:37:42 +00:00
|
|
|
return false;
|
2010-07-27 09:40:30 +00:00
|
|
|
|
2011-10-11 13:05:52 +00:00
|
|
|
if (virThreadCreate(&ctl->eventLoop, true, vshEventLoop, ctl) < 0)
|
|
|
|
return false;
|
|
|
|
ctl->eventLoopStarted = true;
|
|
|
|
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
if (ctl->name) {
|
|
|
|
ctl->conn = virConnectOpenAuth(ctl->name,
|
|
|
|
virConnectAuthPtrDefault,
|
|
|
|
ctl->readonly ? VIR_CONNECT_RO : 0);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
virsh: optimize creation of default connection
Ramon de Carvalho Valle reported a problem with:
virsh connect qemu:///system
as a non-root user. The real root problem appears to be a regression
in libvirtd being auto-started on the default qemu:///session URI;
however, the symptom points to an independent flaw in virsh - we
shouldn't be wasting efforts on making a connection if we aren't going
to be using that connection. Fixing virsh avoids Ramon's issue, while
I work in the meantime to fix the real libvirtd regression.
This patch looks big, but that's because 'gcc -Wmissing-field-initializers'
gets triggered by './autobuild.sh --enable-compile-warnings=error', so I
had to add 0 initialization to everyone (rather than my preference of
just adding the non-zero flags to virshCmds and to cmdConnect).
Meanwhile, if you use 'virsh -c URI', the connection must succeed; this
patch _only_ optimizes the default connection to be deferred to a later
point where we know if a particular command to be run needs a connection.
* tools/virsh.c (VSH_CMD_FLAG_NOCONNECT): New flag.
(vshCmdDef): Add new flags field.
(vshCommandRun): Honor new flag.
(domManagementCmds, domMonitoringCmds, storagePoolCmds)
(storageVolCmds, networkCmds, nodedevCmds, ifaceCmds)
(nwfilterCmds, secretCmds, virshCmds, snapshotCmds)
(hostAndHypervisorCmds): Populate new field.
(vshReconnect): Don't warn on initial connection.
2011-03-14 20:30:24 +00:00
|
|
|
/* Connecting to a named connection must succeed, but we delay
|
|
|
|
* connecting to the default connection until we need it
|
|
|
|
* (since the first command might be 'connect' which allows a
|
|
|
|
* non-default connection, or might be 'help' which needs no
|
|
|
|
* connection).
|
|
|
|
*/
|
|
|
|
if (!ctl->conn) {
|
|
|
|
virshReportError(ctl);
|
|
|
|
vshError(ctl, "%s", _("failed to connect to the hypervisor"));
|
|
|
|
return false;
|
|
|
|
}
|
2007-12-05 16:24:22 +00:00
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2007-12-07 14:56:37 +00:00
|
|
|
#define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT | O_SYNC)
|
|
|
|
|
2007-06-06 12:24:31 +00:00
|
|
|
/**
|
|
|
|
* vshOpenLogFile:
|
|
|
|
*
|
|
|
|
* Open log file.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
vshOpenLogFile(vshControl *ctl)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (ctl->logfile == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* check log file */
|
|
|
|
if (stat(ctl->logfile, &st) == -1) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOENT:
|
|
|
|
break;
|
|
|
|
default:
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, "%s",
|
2008-01-16 17:13:23 +00:00
|
|
|
_("failed to get the log file information"));
|
2009-09-29 11:42:42 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2007-06-06 12:24:31 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!S_ISREG(st.st_mode)) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, "%s", _("the log path is not a file"));
|
|
|
|
exit(EXIT_FAILURE);
|
2007-06-06 12:24:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* log file open */
|
2007-12-07 14:56:37 +00:00
|
|
|
if ((ctl->log_fd = open(ctl->logfile, LOGFILE_FLAGS, FILE_MODE)) < 0) {
|
2009-09-29 11:42:42 +00:00
|
|
|
vshError(ctl, "%s",
|
2008-01-16 17:13:23 +00:00
|
|
|
_("failed to open the log file. check the log file path"));
|
2009-09-29 11:42:42 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2007-06-06 12:24:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vshOutputLogFile:
|
|
|
|
*
|
|
|
|
* Outputting an error to log file.
|
|
|
|
*/
|
|
|
|
static void
|
2011-04-30 10:56:14 +00:00
|
|
|
vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format,
|
|
|
|
va_list ap)
|
2007-06-06 12:24:31 +00:00
|
|
|
{
|
2011-04-30 17:05:43 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
char *str;
|
|
|
|
size_t len;
|
2007-06-06 12:24:31 +00:00
|
|
|
const char *lvl = "";
|
|
|
|
struct timeval stTimeval;
|
|
|
|
struct tm *stTm;
|
|
|
|
|
|
|
|
if (ctl->log_fd == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create log format
|
|
|
|
*
|
|
|
|
* [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message
|
|
|
|
*/
|
|
|
|
gettimeofday(&stTimeval, NULL);
|
|
|
|
stTm = localtime(&stTimeval.tv_sec);
|
2011-05-09 07:08:06 +00:00
|
|
|
virBufferAsprintf(&buf, "[%d.%02d.%02d %02d:%02d:%02d %s %d] ",
|
2011-04-30 17:05:43 +00:00
|
|
|
(1900 + stTm->tm_year),
|
|
|
|
(1 + stTm->tm_mon),
|
|
|
|
stTm->tm_mday,
|
|
|
|
stTm->tm_hour,
|
|
|
|
stTm->tm_min,
|
|
|
|
stTm->tm_sec,
|
2011-05-09 07:08:06 +00:00
|
|
|
SIGN_NAME,
|
|
|
|
(int) getpid());
|
2007-06-06 12:24:31 +00:00
|
|
|
switch (log_level) {
|
|
|
|
case VSH_ERR_DEBUG:
|
|
|
|
lvl = LVL_DEBUG;
|
|
|
|
break;
|
|
|
|
case VSH_ERR_INFO:
|
|
|
|
lvl = LVL_INFO;
|
|
|
|
break;
|
|
|
|
case VSH_ERR_NOTICE:
|
|
|
|
lvl = LVL_INFO;
|
|
|
|
break;
|
|
|
|
case VSH_ERR_WARNING:
|
|
|
|
lvl = LVL_WARNING;
|
|
|
|
break;
|
|
|
|
case VSH_ERR_ERROR:
|
|
|
|
lvl = LVL_ERROR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
lvl = LVL_DEBUG;
|
|
|
|
break;
|
|
|
|
}
|
2011-04-30 17:05:43 +00:00
|
|
|
virBufferAsprintf(&buf, "%s ", lvl);
|
|
|
|
virBufferVasprintf(&buf, msg_format, ap);
|
|
|
|
virBufferAddChar(&buf, '\n');
|
2007-06-06 12:24:31 +00:00
|
|
|
|
2011-04-30 17:05:43 +00:00
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto error;
|
2007-06-06 12:24:31 +00:00
|
|
|
|
2011-04-30 17:05:43 +00:00
|
|
|
str = virBufferContentAndReset(&buf);
|
|
|
|
len = strlen(str);
|
|
|
|
if (len > 1 && str[len - 2] == '\n') {
|
|
|
|
str[len - 1] = '\0';
|
|
|
|
len--;
|
2007-06-06 12:24:31 +00:00
|
|
|
}
|
2011-04-03 09:21:23 +00:00
|
|
|
|
2011-04-30 17:05:43 +00:00
|
|
|
/* write log */
|
|
|
|
if (safewrite(ctl->log_fd, str, len) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
vshCloseLogFile(ctl);
|
|
|
|
vshError(ctl, "%s", _("failed to write the log file"));
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
VIR_FREE(str);
|
2007-06-06 12:24:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vshCloseLogFile:
|
|
|
|
*
|
|
|
|
* Close log file.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
vshCloseLogFile(vshControl *ctl)
|
|
|
|
{
|
|
|
|
/* log file close */
|
2010-11-09 20:48:48 +00:00
|
|
|
if (VIR_CLOSE(ctl->log_fd) < 0) {
|
|
|
|
vshError(ctl, _("%s: failed to write log file: %s"),
|
|
|
|
ctl->logfile ? ctl->logfile : "?", strerror (errno));
|
2007-06-06 12:24:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ctl->logfile) {
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(ctl->logfile);
|
2007-06-06 12:24:31 +00:00
|
|
|
ctl->logfile = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-06 10:24:52 +00:00
|
|
|
#ifdef USE_READLINE
|
2007-12-04 18:27:52 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/* -----------------
|
|
|
|
* Readline stuff
|
|
|
|
* -----------------
|
|
|
|
*/
|
|
|
|
|
2007-02-07 13:50:18 +00:00
|
|
|
/*
|
2005-12-08 10:23:34 +00:00
|
|
|
* Generator function for command completion. STATE lets us
|
|
|
|
* know whether to start from scratch; without any state
|
2007-02-07 13:50:18 +00:00
|
|
|
* (i.e. STATE == 0), then we start at the top of the list.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
|
|
|
static char *
|
2006-03-15 12:13:25 +00:00
|
|
|
vshReadlineCommandGenerator(const char *text, int state)
|
|
|
|
{
|
2010-11-30 06:37:04 +00:00
|
|
|
static int grp_list_index, cmd_list_index, len;
|
2005-12-08 14:22:52 +00:00
|
|
|
const char *name;
|
2010-11-30 06:37:04 +00:00
|
|
|
const vshCmdGrp *grp;
|
|
|
|
const vshCmdDef *cmds;
|
2005-12-08 10:23:34 +00:00
|
|
|
|
|
|
|
if (!state) {
|
2010-11-30 06:37:04 +00:00
|
|
|
grp_list_index = 0;
|
|
|
|
cmd_list_index = 0;
|
2006-03-15 12:13:25 +00:00
|
|
|
len = strlen(text);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
grp = cmdGroups;
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/* Return the next name which partially matches from the
|
2007-02-07 13:50:18 +00:00
|
|
|
* command list.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2010-11-30 06:37:04 +00:00
|
|
|
while (grp[grp_list_index].name) {
|
|
|
|
cmds = grp[grp_list_index].commands;
|
|
|
|
|
|
|
|
if (cmds[cmd_list_index].name) {
|
|
|
|
while ((name = cmds[cmd_list_index].name)) {
|
|
|
|
cmd_list_index++;
|
|
|
|
|
|
|
|
if (STREQLEN(name, text, len))
|
|
|
|
return vshStrdup(NULL, name);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cmd_list_index = 0;
|
|
|
|
grp_list_index++;
|
|
|
|
}
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If no names matched, then return NULL. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2006-03-15 12:13:25 +00:00
|
|
|
vshReadlineOptionsGenerator(const char *text, int state)
|
|
|
|
{
|
2005-12-08 10:23:34 +00:00
|
|
|
static int list_index, len;
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdDef *cmd = NULL;
|
2005-12-08 14:22:52 +00:00
|
|
|
const char *name;
|
2005-12-08 10:23:34 +00:00
|
|
|
|
|
|
|
if (!state) {
|
|
|
|
/* determine command name */
|
|
|
|
char *p;
|
|
|
|
char *cmdname;
|
|
|
|
|
|
|
|
if (!(p = strchr(rl_line_buffer, ' ')))
|
|
|
|
return NULL;
|
|
|
|
|
2006-04-06 10:33:06 +00:00
|
|
|
cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
|
2006-03-15 12:13:25 +00:00
|
|
|
memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
|
2005-12-08 10:23:34 +00:00
|
|
|
|
|
|
|
cmd = vshCmddefSearch(cmdname);
|
|
|
|
list_index = 0;
|
2006-03-15 12:13:25 +00:00
|
|
|
len = strlen(text);
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(cmdname);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!cmd)
|
|
|
|
return NULL;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2007-02-27 15:35:50 +00:00
|
|
|
if (!cmd->opts)
|
|
|
|
return NULL;
|
|
|
|
|
2005-12-08 14:22:52 +00:00
|
|
|
while ((name = cmd->opts[list_index].name)) {
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdOptDef *opt = &cmd->opts[list_index];
|
2005-12-08 10:23:34 +00:00
|
|
|
char *res;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
list_index++;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2011-06-07 09:11:08 +00:00
|
|
|
if (opt->type == VSH_OT_DATA || opt->type == VSH_OT_ARGV)
|
2005-12-08 10:23:34 +00:00
|
|
|
/* ignore non --option */
|
|
|
|
continue;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (len > 2) {
|
2008-05-14 19:51:24 +00:00
|
|
|
if (STRNEQLEN(name, text + 2, len - 2))
|
2005-12-08 10:23:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-04-06 10:33:06 +00:00
|
|
|
res = vshMalloc(NULL, strlen(name) + 3);
|
2007-03-23 16:15:07 +00:00
|
|
|
snprintf(res, strlen(name) + 3, "--%s", name);
|
2005-12-08 10:23:34 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If no names matched, then return NULL. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char **
|
2006-03-15 12:13:25 +00:00
|
|
|
vshReadlineCompletion(const char *text, int start,
|
|
|
|
int end ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2005-12-08 10:23:34 +00:00
|
|
|
char **matches = (char **) NULL;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
if (start == 0)
|
2005-12-08 10:23:34 +00:00
|
|
|
/* command name generator */
|
2006-03-15 12:13:25 +00:00
|
|
|
matches = rl_completion_matches(text, vshReadlineCommandGenerator);
|
2005-12-08 10:23:34 +00:00
|
|
|
else
|
|
|
|
/* commands options */
|
2006-03-15 12:13:25 +00:00
|
|
|
matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
|
2005-12-08 10:23:34 +00:00
|
|
|
return matches;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-03 14:45:10 +00:00
|
|
|
static int
|
|
|
|
vshReadlineInit(vshControl *ctl)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2010-01-03 14:45:10 +00:00
|
|
|
char *userdir = NULL;
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/* Allow conditional parsing of the ~/.inputrc file. */
|
|
|
|
rl_readline_name = "virsh";
|
|
|
|
|
|
|
|
/* Tell the completer that we want a crack first. */
|
|
|
|
rl_attempted_completion_function = vshReadlineCompletion;
|
2009-02-09 10:24:27 +00:00
|
|
|
|
|
|
|
/* Limit the total size of the history buffer */
|
|
|
|
stifle_history(500);
|
2010-01-03 14:45:10 +00:00
|
|
|
|
2012-05-03 16:36:27 +00:00
|
|
|
/* Prepare to read/write history from/to the $XDG_CACHE_HOME/virsh/history file */
|
2012-05-24 12:29:42 +00:00
|
|
|
userdir = virGetUserCacheDirectory();
|
2010-01-03 14:45:10 +00:00
|
|
|
|
2011-05-15 05:31:42 +00:00
|
|
|
if (userdir == NULL) {
|
|
|
|
vshError(ctl, "%s", _("Could not determine home directory"));
|
2010-01-03 14:45:10 +00:00
|
|
|
return -1;
|
2011-05-15 05:31:42 +00:00
|
|
|
}
|
2010-01-03 14:45:10 +00:00
|
|
|
|
2012-05-03 16:36:27 +00:00
|
|
|
if (virAsprintf(&ctl->historydir, "%s/virsh", userdir) < 0) {
|
2010-01-03 14:45:10 +00:00
|
|
|
vshError(ctl, "%s", _("Out of memory"));
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(userdir);
|
2010-01-03 14:45:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&ctl->historyfile, "%s/history", ctl->historydir) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Out of memory"));
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(userdir);
|
2010-01-03 14:45:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(userdir);
|
2010-01-03 14:45:10 +00:00
|
|
|
|
|
|
|
read_history(ctl->historyfile);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-07-11 06:17:28 +00:00
|
|
|
vshReadlineDeinit(vshControl *ctl)
|
2010-01-03 14:45:10 +00:00
|
|
|
{
|
|
|
|
if (ctl->historyfile != NULL) {
|
2012-07-10 11:24:04 +00:00
|
|
|
if (virFileMakePathWithMode(ctl->historydir, 0755) < 0 &&
|
|
|
|
errno != EEXIST) {
|
2010-01-03 14:45:10 +00:00
|
|
|
char ebuf[1024];
|
|
|
|
vshError(ctl, _("Failed to create '%s': %s"),
|
2012-03-29 09:52:04 +00:00
|
|
|
ctl->historydir, virStrerror(errno, ebuf, sizeof(ebuf)));
|
2012-04-14 22:35:22 +00:00
|
|
|
} else {
|
2010-01-03 14:45:10 +00:00
|
|
|
write_history(ctl->historyfile);
|
2012-04-14 22:35:22 +00:00
|
|
|
}
|
2010-01-03 14:45:10 +00:00
|
|
|
}
|
|
|
|
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(ctl->historydir);
|
|
|
|
VIR_FREE(ctl->historyfile);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2007-12-04 18:27:52 +00:00
|
|
|
static char *
|
2012-07-11 06:17:28 +00:00
|
|
|
vshReadline(vshControl *ctl ATTRIBUTE_UNUSED, const char *prompt)
|
2007-12-04 18:27:52 +00:00
|
|
|
{
|
2012-07-11 06:17:28 +00:00
|
|
|
return readline(prompt);
|
2007-12-04 18:27:52 +00:00
|
|
|
}
|
|
|
|
|
2007-12-06 10:24:52 +00:00
|
|
|
#else /* !USE_READLINE */
|
2007-12-04 18:27:52 +00:00
|
|
|
|
2010-01-03 14:45:10 +00:00
|
|
|
static int
|
2012-07-11 06:17:28 +00:00
|
|
|
vshReadlineInit(vshControl *ctl ATTRIBUTE_UNUSED)
|
2010-01-03 14:45:10 +00:00
|
|
|
{
|
|
|
|
/* empty */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-04 18:27:52 +00:00
|
|
|
static void
|
2012-07-11 06:17:28 +00:00
|
|
|
vshReadlineDeinit(vshControl *ctl ATTRIBUTE_UNUSED)
|
2007-12-04 18:27:52 +00:00
|
|
|
{
|
|
|
|
/* empty */
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2012-07-11 06:17:28 +00:00
|
|
|
vshReadline(vshControl *ctl, const char *prompt)
|
2007-12-04 18:27:52 +00:00
|
|
|
{
|
|
|
|
char line[1024];
|
|
|
|
char *r;
|
|
|
|
int len;
|
|
|
|
|
2012-07-11 06:17:28 +00:00
|
|
|
fputs(prompt, stdout);
|
|
|
|
r = fgets(line, sizeof(line), stdin);
|
2007-12-04 18:27:52 +00:00
|
|
|
if (r == NULL) return NULL; /* EOF */
|
|
|
|
|
|
|
|
/* Chomp trailing \n */
|
2012-07-11 06:17:28 +00:00
|
|
|
len = strlen(r);
|
2007-12-04 18:27:52 +00:00
|
|
|
if (len > 0 && r[len-1] == '\n')
|
|
|
|
r[len-1] = '\0';
|
|
|
|
|
2012-07-11 06:17:28 +00:00
|
|
|
return vshStrdup(ctl, r);
|
2007-12-04 18:27:52 +00:00
|
|
|
}
|
|
|
|
|
2007-12-06 10:24:52 +00:00
|
|
|
#endif /* !USE_READLINE */
|
2007-12-04 18:27:52 +00:00
|
|
|
|
2011-11-30 19:42:20 +00:00
|
|
|
static void
|
|
|
|
vshDeinitTimer(int timer ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
/* nothing to be done here */
|
|
|
|
}
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
2008-02-04 14:58:47 +00:00
|
|
|
* Deinitialize virsh
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2011-04-18 22:37:42 +00:00
|
|
|
static bool
|
2008-08-01 13:51:18 +00:00
|
|
|
vshDeinit(vshControl *ctl)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2010-01-03 14:45:10 +00:00
|
|
|
vshReadlineDeinit(ctl);
|
2007-06-06 12:24:31 +00:00
|
|
|
vshCloseLogFile(ctl);
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(ctl->name);
|
2005-12-08 10:23:34 +00:00
|
|
|
if (ctl->conn) {
|
2010-11-11 15:15:46 +00:00
|
|
|
int ret;
|
|
|
|
if ((ret = virConnectClose(ctl->conn)) != 0) {
|
|
|
|
vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret);
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-01 15:45:25 +00:00
|
|
|
virResetLastError();
|
|
|
|
|
2011-10-11 13:05:52 +00:00
|
|
|
if (ctl->eventLoopStarted) {
|
2011-11-30 19:42:20 +00:00
|
|
|
int timer;
|
|
|
|
|
|
|
|
virMutexLock(&ctl->lock);
|
|
|
|
ctl->quit = true;
|
2011-10-11 13:05:52 +00:00
|
|
|
/* HACK: Add a dummy timeout to break event loop */
|
2011-11-30 19:42:20 +00:00
|
|
|
timer = virEventAddTimeout(0, vshDeinitTimer, NULL, NULL);
|
|
|
|
virMutexUnlock(&ctl->lock);
|
|
|
|
|
|
|
|
virThreadJoin(&ctl->eventLoop);
|
|
|
|
|
2011-10-11 13:05:52 +00:00
|
|
|
if (timer != -1)
|
|
|
|
virEventRemoveTimeout(timer);
|
|
|
|
|
|
|
|
ctl->eventLoopStarted = false;
|
|
|
|
}
|
|
|
|
|
2011-11-30 19:42:20 +00:00
|
|
|
virMutexDestroy(&ctl->lock);
|
|
|
|
|
2011-04-18 22:37:42 +00:00
|
|
|
return true;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
|
|
|
* Print usage
|
|
|
|
*/
|
|
|
|
static void
|
2008-12-08 13:14:48 +00:00
|
|
|
vshUsage(void)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2010-11-30 06:37:04 +00:00
|
|
|
const vshCmdGrp *grp;
|
2008-08-01 12:19:56 +00:00
|
|
|
const vshCmdDef *cmd;
|
2010-11-30 06:37:04 +00:00
|
|
|
|
2010-10-12 07:14:01 +00:00
|
|
|
fprintf(stdout, _("\n%s [options]... [<command_string>]"
|
|
|
|
"\n%s [options]... <command> [args...]\n\n"
|
2008-12-08 13:14:48 +00:00
|
|
|
" options:\n"
|
2011-11-22 16:08:05 +00:00
|
|
|
" -c | --connect=URI hypervisor connection URI\n"
|
2008-12-08 13:14:48 +00:00
|
|
|
" -r | --readonly connect readonly\n"
|
2011-11-22 16:08:05 +00:00
|
|
|
" -d | --debug=NUM debug level [0-4]\n"
|
2008-12-08 13:14:48 +00:00
|
|
|
" -h | --help this help\n"
|
|
|
|
" -q | --quiet quiet mode\n"
|
|
|
|
" -t | --timing print timing information\n"
|
2011-11-22 16:08:05 +00:00
|
|
|
" -l | --log=FILE output logging to file\n"
|
|
|
|
" -v short version\n"
|
|
|
|
" -V long version\n"
|
|
|
|
" --version[=TYPE] version, TYPE is short or long (default short)\n"
|
|
|
|
" -e | --escape <char> set escape sequence for console\n\n"
|
2010-11-30 06:37:04 +00:00
|
|
|
" commands (non interactive mode):\n\n"), progname, progname);
|
2008-12-08 13:14:48 +00:00
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
for (grp = cmdGroups; grp->name; grp++) {
|
2012-03-16 19:23:00 +00:00
|
|
|
fprintf(stdout, _(" %s (help keyword '%s')\n"),
|
|
|
|
grp->name, grp->keyword);
|
|
|
|
for (cmd = grp->commands; cmd->name; cmd++) {
|
|
|
|
if (cmd->flags & VSH_CMD_FLAG_ALIAS)
|
|
|
|
continue;
|
2010-11-30 06:37:04 +00:00
|
|
|
fprintf(stdout,
|
2012-03-16 19:23:00 +00:00
|
|
|
" %-30s %s\n", cmd->name,
|
|
|
|
_(vshCmddefGetInfo(cmd, "help")));
|
|
|
|
}
|
2010-11-30 06:37:04 +00:00
|
|
|
fprintf(stdout, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stdout, "%s",
|
|
|
|
_("\n (specify help <group> for details about the commands in the group)\n"));
|
2008-12-08 13:14:48 +00:00
|
|
|
fprintf(stdout, "%s",
|
|
|
|
_("\n (specify help <command> for details about the command)\n\n"));
|
|
|
|
return;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
2010-11-08 14:03:32 +00:00
|
|
|
/*
|
|
|
|
* Show version and options compiled in
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
/* FIXME - list a copyright blurb, as in GNU programs? */
|
|
|
|
vshPrint(ctl, _("Virsh command line tool of libvirt %s\n"), VERSION);
|
|
|
|
vshPrint(ctl, _("See web site at %s\n\n"), "http://libvirt.org/");
|
|
|
|
|
2010-11-09 22:37:05 +00:00
|
|
|
vshPrint(ctl, "%s", _("Compiled with support for:\n"));
|
|
|
|
vshPrint(ctl, "%s", _(" Hypervisors:"));
|
2010-11-08 14:03:32 +00:00
|
|
|
#ifdef WITH_QEMU
|
|
|
|
vshPrint(ctl, " QEmu/KVM");
|
|
|
|
#endif
|
2012-06-26 18:31:31 +00:00
|
|
|
#ifdef WITH_LXC
|
|
|
|
vshPrint(ctl, " LXC");
|
|
|
|
#endif
|
2010-11-08 14:03:32 +00:00
|
|
|
#ifdef WITH_UML
|
|
|
|
vshPrint(ctl, " UML");
|
|
|
|
#endif
|
2012-06-26 18:31:31 +00:00
|
|
|
#ifdef WITH_XEN
|
|
|
|
vshPrint(ctl, " Xen");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_LIBXL
|
|
|
|
vshPrint(ctl, " LibXL");
|
|
|
|
#endif
|
2010-11-08 14:03:32 +00:00
|
|
|
#ifdef WITH_OPENVZ
|
|
|
|
vshPrint(ctl, " OpenVZ");
|
|
|
|
#endif
|
2012-06-26 18:31:31 +00:00
|
|
|
#ifdef WITH_VMWARE
|
|
|
|
vshPrint(ctl, " VMWare");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
2012-06-26 18:31:31 +00:00
|
|
|
#ifdef WITH_PHYP
|
|
|
|
vshPrint(ctl, " PHYP");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
2012-06-26 18:31:31 +00:00
|
|
|
#ifdef WITH_VBOX
|
|
|
|
vshPrint(ctl, " VirtualBox");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
|
|
|
#ifdef WITH_ESX
|
|
|
|
vshPrint(ctl, " ESX");
|
|
|
|
#endif
|
2012-06-26 18:31:31 +00:00
|
|
|
#ifdef WITH_HYPERV
|
|
|
|
vshPrint(ctl, " Hyper-V");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
2012-06-26 18:31:31 +00:00
|
|
|
#ifdef WITH_XENAPI
|
|
|
|
vshPrint(ctl, " XenAPI");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
|
|
|
#ifdef WITH_TEST
|
|
|
|
vshPrint(ctl, " Test");
|
|
|
|
#endif
|
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
|
2010-11-09 22:37:05 +00:00
|
|
|
vshPrint(ctl, "%s", _(" Networking:"));
|
2010-11-08 14:03:32 +00:00
|
|
|
#ifdef WITH_REMOTE
|
|
|
|
vshPrint(ctl, " Remote");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_LIBVIRTD
|
|
|
|
vshPrint(ctl, " Daemon");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_NETWORK
|
|
|
|
vshPrint(ctl, " Network");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_BRIDGE
|
|
|
|
vshPrint(ctl, " Bridging");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_NETCF
|
2012-06-26 18:31:31 +00:00
|
|
|
vshPrint(ctl, " Interface");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
|
|
|
#ifdef WITH_NWFILTER
|
|
|
|
vshPrint(ctl, " Nwfilter");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_VIRTUALPORT
|
|
|
|
vshPrint(ctl, " VirtualPort");
|
|
|
|
#endif
|
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
|
2010-11-09 22:37:05 +00:00
|
|
|
vshPrint(ctl, "%s", _(" Storage:"));
|
2010-11-08 14:03:32 +00:00
|
|
|
#ifdef WITH_STORAGE_DIR
|
|
|
|
vshPrint(ctl, " Dir");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_DISK
|
|
|
|
vshPrint(ctl, " Disk");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_FS
|
|
|
|
vshPrint(ctl, " Filesystem");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_SCSI
|
|
|
|
vshPrint(ctl, " SCSI");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_MPATH
|
|
|
|
vshPrint(ctl, " Multipath");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_ISCSI
|
|
|
|
vshPrint(ctl, " iSCSI");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_LVM
|
|
|
|
vshPrint(ctl, " LVM");
|
2012-05-14 09:06:42 +00:00
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_RBD
|
|
|
|
vshPrint(ctl, " RBD");
|
2012-07-18 19:06:58 +00:00
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_SHEEPDOG
|
|
|
|
vshPrint(ctl, " Sheepdog");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
vshPrint(ctl, "%s", _(" Miscellaneous:"));
|
|
|
|
#ifdef WITH_NODE_DEVICES
|
|
|
|
vshPrint(ctl, " Nodedev");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_SECDRIVER_APPARMOR
|
|
|
|
vshPrint(ctl, " AppArmor");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_SECDRIVER_SELINUX
|
|
|
|
vshPrint(ctl, " SELinux");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_SECRETS
|
|
|
|
vshPrint(ctl, " Secrets");
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_DEBUG
|
|
|
|
vshPrint(ctl, " Debug");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_DTRACE_PROBES
|
|
|
|
vshPrint(ctl, " DTrace");
|
|
|
|
#endif
|
|
|
|
#ifdef USE_READLINE
|
|
|
|
vshPrint(ctl, " Readline");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_DRIVER_MODULES
|
|
|
|
vshPrint(ctl, " Modular");
|
|
|
|
#endif
|
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
vshAllowedEscapeChar(char c)
|
|
|
|
{
|
|
|
|
/* Allowed escape characters:
|
|
|
|
* a-z A-Z @ [ \ ] ^ _
|
|
|
|
*/
|
|
|
|
return ('a' <= c && c <= 'z') ||
|
|
|
|
('@' <= c && c <= '_');
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* argv[]: virsh [options] [command]
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
vshParseArgv(vshControl *ctl, int argc, char **argv)
|
|
|
|
{
|
2012-07-26 14:05:51 +00:00
|
|
|
int arg, len, debug;
|
2012-07-23 03:57:53 +00:00
|
|
|
struct option opt[] = {
|
|
|
|
{"debug", required_argument, NULL, 'd'},
|
|
|
|
{"help", no_argument, NULL, 'h'},
|
|
|
|
{"quiet", no_argument, NULL, 'q'},
|
|
|
|
{"timing", no_argument, NULL, 't'},
|
|
|
|
{"version", optional_argument, NULL, 'v'},
|
|
|
|
{"connect", required_argument, NULL, 'c'},
|
|
|
|
{"readonly", no_argument, NULL, 'r'},
|
|
|
|
{"log", required_argument, NULL, 'l'},
|
|
|
|
{"escape", required_argument, NULL, 'e'},
|
|
|
|
{NULL, 0, NULL, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Standard (non-command) options. The leading + ensures that no
|
|
|
|
* argument reordering takes place, so that command options are
|
|
|
|
* not confused with top-level virsh options. */
|
|
|
|
while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:", opt, NULL)) != -1) {
|
|
|
|
switch (arg) {
|
|
|
|
case 'd':
|
2012-07-26 14:05:51 +00:00
|
|
|
if (virStrToLong_i(optarg, NULL, 10, &debug) < 0) {
|
2012-07-23 03:57:53 +00:00
|
|
|
vshError(ctl, "%s", _("option -d takes a numeric argument"));
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-07-26 14:05:51 +00:00
|
|
|
if (debug < VSH_ERR_DEBUG || debug > VSH_ERR_ERROR)
|
|
|
|
vshError(ctl, _("ignoring debug level %d out of range [%d-%d]"),
|
|
|
|
debug, VSH_ERR_DEBUG, VSH_ERR_ERROR);
|
|
|
|
else
|
|
|
|
ctl->debug = debug;
|
2012-07-23 03:57:53 +00:00
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
vshUsage();
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
ctl->quiet = true;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
ctl->timing = true;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
ctl->name = vshStrdup(ctl, optarg);
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
if (STRNEQ_NULLABLE(optarg, "long")) {
|
|
|
|
puts(VERSION);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
case 'V':
|
|
|
|
vshShowVersion(ctl);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
case 'r':
|
|
|
|
ctl->readonly = true;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
ctl->logfile = vshStrdup(ctl, optarg);
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
len = strlen(optarg);
|
|
|
|
|
|
|
|
if ((len == 2 && *optarg == '^' &&
|
|
|
|
vshAllowedEscapeChar(optarg[1])) ||
|
|
|
|
(len == 1 && *optarg != '^')) {
|
|
|
|
ctl->escapeChar = optarg;
|
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Invalid string '%s' for escape sequence"),
|
|
|
|
optarg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc > optind) {
|
|
|
|
/* parse command */
|
|
|
|
ctl->imode = false;
|
|
|
|
if (argc - optind == 1) {
|
|
|
|
vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
|
|
|
|
return vshCommandStringParse(ctl, argv[optind]);
|
|
|
|
} else {
|
|
|
|
return vshCommandArgvParse(ctl, argc - optind, argv + optind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
#include "virsh-domain.c"
|
2012-07-24 08:24:50 +00:00
|
|
|
#include "virsh-domain-monitor.c"
|
2012-07-24 08:49:27 +00:00
|
|
|
#include "virsh-pool.c"
|
2012-07-24 08:44:49 +00:00
|
|
|
#include "virsh-volume.c"
|
2012-07-23 06:02:14 +00:00
|
|
|
#include "virsh-network.c"
|
2012-07-23 07:08:39 +00:00
|
|
|
#include "virsh-nodedev.c"
|
2012-07-24 08:56:49 +00:00
|
|
|
#include "virsh-interface.c"
|
2012-07-23 06:15:55 +00:00
|
|
|
#include "virsh-nwfilter.c"
|
2012-07-23 06:18:51 +00:00
|
|
|
#include "virsh-secret.c"
|
2012-07-23 07:19:04 +00:00
|
|
|
#include "virsh-snapshot.c"
|
|
|
|
#include "virsh-host.c"
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
static const vshCmdDef virshCmds[] = {
|
|
|
|
{"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT},
|
|
|
|
{"echo", cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT},
|
|
|
|
{"exit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT},
|
|
|
|
{"help", cmdHelp, opts_help, info_help, VSH_CMD_FLAG_NOCONNECT},
|
|
|
|
{"pwd", cmdPwd, NULL, info_pwd, VSH_CMD_FLAG_NOCONNECT},
|
|
|
|
{"quit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT},
|
|
|
|
{NULL, NULL, NULL, NULL, 0}
|
|
|
|
};
|
2011-11-22 16:08:05 +00:00
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
static const vshCmdGrp cmdGroups[] = {
|
|
|
|
{VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds},
|
|
|
|
{VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds},
|
|
|
|
{VSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds},
|
|
|
|
{VSH_CMD_GRP_IFACE, "interface", ifaceCmds},
|
|
|
|
{VSH_CMD_GRP_NWFILTER, "filter", nwfilterCmds},
|
|
|
|
{VSH_CMD_GRP_NETWORK, "network", networkCmds},
|
|
|
|
{VSH_CMD_GRP_NODEDEV, "nodedev", nodedevCmds},
|
|
|
|
{VSH_CMD_GRP_SECRET, "secret", secretCmds},
|
|
|
|
{VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds},
|
|
|
|
{VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds},
|
|
|
|
{VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds},
|
|
|
|
{VSH_CMD_GRP_VIRSH, "virsh", virshCmds},
|
|
|
|
{NULL, NULL, NULL}
|
|
|
|
};
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
vshControl _ctl, *ctl = &_ctl;
|
2006-08-25 22:40:33 +00:00
|
|
|
char *defaultConn;
|
2011-04-18 22:37:42 +00:00
|
|
|
bool ret = true;
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2011-05-09 11:57:09 +00:00
|
|
|
memset(ctl, 0, sizeof(vshControl));
|
|
|
|
ctl->imode = true; /* default is interactive mode */
|
|
|
|
ctl->log_fd = -1; /* Initialize log file descriptor */
|
2011-07-14 11:58:02 +00:00
|
|
|
ctl->debug = VSH_DEBUG_DEFAULT;
|
2011-11-22 16:08:05 +00:00
|
|
|
ctl->escapeChar = CTRL_CLOSE_BRACKET;
|
|
|
|
|
2011-05-09 11:57:09 +00:00
|
|
|
|
2006-09-21 15:24:37 +00:00
|
|
|
if (!setlocale(LC_ALL, "")) {
|
|
|
|
perror("setlocale");
|
2009-01-29 11:49:33 +00:00
|
|
|
/* failure to setup locale is not fatal */
|
2006-09-21 15:24:37 +00:00
|
|
|
}
|
2010-11-16 14:54:17 +00:00
|
|
|
if (!bindtextdomain(PACKAGE, LOCALEDIR)) {
|
2006-09-21 15:24:37 +00:00
|
|
|
perror("bindtextdomain");
|
2010-11-16 19:01:37 +00:00
|
|
|
return EXIT_FAILURE;
|
2006-09-21 15:24:37 +00:00
|
|
|
}
|
2010-11-16 14:54:17 +00:00
|
|
|
if (!textdomain(PACKAGE)) {
|
2006-09-21 15:24:37 +00:00
|
|
|
perror("textdomain");
|
2010-11-16 19:01:37 +00:00
|
|
|
return EXIT_FAILURE;
|
2006-09-21 15:24:37 +00:00
|
|
|
}
|
|
|
|
|
2011-11-30 19:42:20 +00:00
|
|
|
if (virMutexInit(&ctl->lock) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to initialize mutex"));
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2011-05-09 11:57:09 +00:00
|
|
|
if (virInitialize() < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to initialize libvirt"));
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
if (!(progname = strrchr(argv[0], '/')))
|
2005-12-08 10:23:34 +00:00
|
|
|
progname = argv[0];
|
|
|
|
else
|
|
|
|
progname++;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2006-08-25 22:40:33 +00:00
|
|
|
if ((defaultConn = getenv("VIRSH_DEFAULT_CONNECT_URI"))) {
|
2010-10-12 17:24:00 +00:00
|
|
|
ctl->name = vshStrdup(ctl, defaultConn);
|
2006-08-25 22:40:33 +00:00
|
|
|
}
|
|
|
|
|
2007-12-01 15:45:25 +00:00
|
|
|
if (!vshParseArgv(ctl, argc, argv)) {
|
|
|
|
vshDeinit(ctl);
|
2005-12-08 10:23:34 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2007-12-01 15:45:25 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2007-12-01 15:45:25 +00:00
|
|
|
if (!vshInit(ctl)) {
|
|
|
|
vshDeinit(ctl);
|
2005-12-08 10:23:34 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2007-12-01 15:45:25 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
if (!ctl->imode) {
|
2006-03-15 12:13:25 +00:00
|
|
|
ret = vshCommandRun(ctl, ctl->cmd);
|
2005-12-01 16:35:42 +00:00
|
|
|
} else {
|
2005-12-08 10:23:34 +00:00
|
|
|
/* interactive mode */
|
|
|
|
if (!ctl->quiet) {
|
2006-05-22 14:38:33 +00:00
|
|
|
vshPrint(ctl,
|
2006-09-21 15:24:37 +00:00
|
|
|
_("Welcome to %s, the virtualization interactive terminal.\n\n"),
|
2006-03-15 12:13:25 +00:00
|
|
|
progname);
|
2008-01-16 17:13:23 +00:00
|
|
|
vshPrint(ctl, "%s",
|
2006-09-21 15:24:37 +00:00
|
|
|
_("Type: 'help' for help with commands\n"
|
2007-02-07 13:50:18 +00:00
|
|
|
" 'quit' to quit\n\n"));
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2010-01-03 14:45:10 +00:00
|
|
|
|
|
|
|
if (vshReadlineInit(ctl) < 0) {
|
|
|
|
vshDeinit(ctl);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
do {
|
2007-12-06 16:36:21 +00:00
|
|
|
const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW;
|
2006-03-15 12:13:25 +00:00
|
|
|
ctl->cmdstr =
|
2007-12-06 16:36:21 +00:00
|
|
|
vshReadline(ctl, prompt);
|
2006-03-15 12:13:25 +00:00
|
|
|
if (ctl->cmdstr == NULL)
|
|
|
|
break; /* EOF */
|
2005-12-08 10:23:34 +00:00
|
|
|
if (*ctl->cmdstr) {
|
2007-12-06 10:24:52 +00:00
|
|
|
#if USE_READLINE
|
2005-12-08 10:23:34 +00:00
|
|
|
add_history(ctl->cmdstr);
|
2007-12-04 18:27:52 +00:00
|
|
|
#endif
|
2010-10-12 07:13:50 +00:00
|
|
|
if (vshCommandStringParse(ctl, ctl->cmdstr))
|
2005-12-08 10:23:34 +00:00
|
|
|
vshCommandRun(ctl, ctl->cmd);
|
|
|
|
}
|
2010-01-03 16:13:27 +00:00
|
|
|
VIR_FREE(ctl->cmdstr);
|
2006-03-15 12:13:25 +00:00
|
|
|
} while (ctl->imode);
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
if (ctl->cmdstr == NULL)
|
|
|
|
fputc('\n', stdout); /* line break after alone prompt */
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
vshDeinit(ctl);
|
|
|
|
exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
|
2005-11-10 16:12:31 +00:00
|
|
|
}
|