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
|
|
|
*
|
2015-02-19 13:16:39 +00:00
|
|
|
* Copyright (C) 2005, 2007-2015 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-27 09:39:53 +00:00
|
|
|
* <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>
|
2012-08-18 03:16:04 +00:00
|
|
|
#include "virsh.h"
|
2007-12-04 18:27:52 +00:00
|
|
|
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
#include <assert.h>
|
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-08 14:22:52 +00:00
|
|
|
#include <sys/time.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-06 12:24:31 +00:00
|
|
|
#include <sys/stat.h>
|
2007-08-21 10:08:12 +00:00
|
|
|
#include <inttypes.h>
|
2011-07-15 21:49:37 +00:00
|
|
|
#include <strings.h>
|
virsh: common code for waiting for an event
I plan to add 'virsh event' to virsh-domain.c and 'virsh
net-event' to virsh-network.c; but as they will share quite
a bit of common boilerplate, it's better to set that up now
in virsh.c.
* tools/virsh.h (_vshControl): Add fields.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup): New
prototypes.
* tools/virsh.c (vshEventFd, vshEventOldAction, vshEventInt)
(vshEventTimeout): New helper variables and functions.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup):
Implement new functions.
(vshInit, vshDeinit, main): Manage event timeout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-14 22:30:23 +00:00
|
|
|
#include <signal.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
|
|
|
|
2013-10-04 17:51:41 +00:00
|
|
|
#if WITH_READLINE
|
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"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2009-07-28 10:27:25 +00:00
|
|
|
#include "base64.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:13:21 +00:00
|
|
|
#include "virxml.h"
|
2013-04-17 10:19:19 +00:00
|
|
|
#include <libvirt/libvirt-qemu.h>
|
|
|
|
#include <libvirt/libvirt-lxc.h>
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2010-11-16 14:54:17 +00:00
|
|
|
#include "configmake.h"
|
2012-12-13 15:49:48 +00:00
|
|
|
#include "virthread.h"
|
2012-12-12 16:27:01 +00:00
|
|
|
#include "vircommand.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"
|
2012-12-04 11:56:32 +00:00
|
|
|
#include "virbitmap.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"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2013-08-26 09:53:43 +00:00
|
|
|
#include "virsh-console.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
#include "virsh-domain.h"
|
2012-08-20 13:46:38 +00:00
|
|
|
#include "virsh-domain-monitor.h"
|
2012-08-20 20:01:45 +00:00
|
|
|
#include "virsh-host.h"
|
2012-08-20 20:30:53 +00:00
|
|
|
#include "virsh-interface.h"
|
2012-08-20 21:43:25 +00:00
|
|
|
#include "virsh-network.h"
|
2012-08-20 22:23:10 +00:00
|
|
|
#include "virsh-nodedev.h"
|
2012-08-20 22:56:03 +00:00
|
|
|
#include "virsh-nwfilter.h"
|
2012-08-20 22:56:53 +00:00
|
|
|
#include "virsh-pool.h"
|
2012-08-20 23:14:37 +00:00
|
|
|
#include "virsh-secret.h"
|
2012-08-20 23:29:03 +00:00
|
|
|
#include "virsh-snapshot.h"
|
2012-08-20 23:41:24 +00:00
|
|
|
#include "virsh-volume.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
|
virsh: common code for waiting for an event
I plan to add 'virsh event' to virsh-domain.c and 'virsh
net-event' to virsh-network.c; but as they will share quite
a bit of common boilerplate, it's better to set that up now
in virsh.c.
* tools/virsh.h (_vshControl): Add fields.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup): New
prototypes.
* tools/virsh.c (vshEventFd, vshEventOldAction, vshEventInt)
(vshEventTimeout): New helper variables and functions.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup):
Implement new functions.
(vshInit, vshDeinit, main): Manage event timeout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-14 22:30:23 +00:00
|
|
|
/* Gnulib doesn't guarantee SA_SIGINFO support. */
|
|
|
|
#ifndef SA_SIGINFO
|
|
|
|
# define SA_SIGINFO 0
|
|
|
|
#endif
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
static char *progname;
|
|
|
|
|
2010-11-30 06:37:04 +00:00
|
|
|
static const vshCmdGrp cmdGroups[];
|
2005-12-08 10:23:34 +00:00
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
/* Bypass header poison */
|
|
|
|
#undef strdup
|
2006-04-06 10:33:06 +00:00
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
void *
|
2010-10-12 17:24:00 +00:00
|
|
|
_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);
|
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
void *
|
|
|
|
_vshCalloc(vshControl *ctl, size_t nmemb, size_t size, const char *filename,
|
|
|
|
int line)
|
2010-10-12 17:24:00 +00:00
|
|
|
{
|
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);
|
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
char *
|
2010-10-12 17:24:00 +00:00
|
|
|
_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line)
|
|
|
|
{
|
|
|
|
char *x;
|
|
|
|
|
2013-05-23 07:51:59 +00:00
|
|
|
if (VIR_STRDUP(x, s) >= 0)
|
2010-10-12 17:24:00 +00:00
|
|
|
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. */
|
|
|
|
#define strdup use_vshStrdup_instead_of_strdup
|
2007-02-14 15:44:58 +00:00
|
|
|
|
2012-08-20 20:29:27 +00:00
|
|
|
int
|
2012-06-19 13:13:47 +00:00
|
|
|
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-08-14 07:21:44 +00:00
|
|
|
return vshStrcasecmp(*sa, *sb);
|
2007-02-14 15:44:58 +00:00
|
|
|
}
|
|
|
|
|
2012-08-18 04:00:42 +00:00
|
|
|
double
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshPrettyCapacity(unsigned long long val, const char **unit)
|
2012-08-18 04:00:42 +00:00
|
|
|
{
|
2014-09-09 04:09:53 +00:00
|
|
|
double limit = 1024;
|
|
|
|
|
|
|
|
if (val < limit) {
|
2013-02-14 13:45:48 +00:00
|
|
|
*unit = "B";
|
2014-09-09 04:09:53 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
limit *= 1024;
|
|
|
|
if (val < limit) {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "KiB";
|
2014-09-09 04:09:53 +00:00
|
|
|
return val / (limit / 1024);
|
|
|
|
}
|
|
|
|
limit *= 1024;
|
|
|
|
if (val < limit) {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "MiB";
|
2014-09-09 04:09:53 +00:00
|
|
|
return val / (limit / 1024);
|
|
|
|
}
|
|
|
|
limit *= 1024;
|
|
|
|
if (val < limit) {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "GiB";
|
2014-09-09 04:09:53 +00:00
|
|
|
return val / (limit / 1024);
|
|
|
|
}
|
|
|
|
limit *= 1024;
|
|
|
|
if (val < limit) {
|
2012-04-30 20:27:56 +00:00
|
|
|
*unit = "TiB";
|
2014-09-09 04:09:53 +00:00
|
|
|
return val / (limit / 1024);
|
|
|
|
}
|
|
|
|
limit *= 1024;
|
|
|
|
if (val < limit) {
|
|
|
|
*unit = "PiB";
|
|
|
|
return val / (limit / 1024);
|
2010-02-03 16:45:05 +00:00
|
|
|
}
|
2014-09-09 04:09:53 +00:00
|
|
|
limit *= 1024;
|
|
|
|
*unit = "EiB";
|
|
|
|
return val / (limit / 1024);
|
2010-02-03 16:45:05 +00:00
|
|
|
}
|
|
|
|
|
2012-09-04 15:16:29 +00:00
|
|
|
/*
|
2013-08-15 16:20:05 +00:00
|
|
|
* Convert the strings separated by ',' into array. The returned
|
|
|
|
* array is a NULL terminated string list. The caller has to free
|
|
|
|
* the array using virStringFreeList or a similar method.
|
2012-09-04 15:16:29 +00:00
|
|
|
*
|
|
|
|
* Returns the length of the filled array on success, or -1
|
|
|
|
* on error.
|
|
|
|
*/
|
|
|
|
int
|
2012-09-14 16:21:07 +00:00
|
|
|
vshStringToArray(const char *str,
|
2012-09-04 15:16:29 +00:00
|
|
|
char ***array)
|
|
|
|
{
|
2012-09-14 16:21:07 +00:00
|
|
|
char *str_copied = vshStrdup(NULL, str);
|
2012-09-04 15:16:29 +00:00
|
|
|
char *str_tok = NULL;
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
char *tmp;
|
2012-09-04 15:16:29 +00:00
|
|
|
unsigned int nstr_tokens = 0;
|
|
|
|
char **arr = NULL;
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
size_t len = strlen(str_copied);
|
2012-09-04 15:16:29 +00:00
|
|
|
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
/* tokenize the string from user and save its parts into an array */
|
|
|
|
nstr_tokens = 1;
|
2012-09-04 15:16:29 +00:00
|
|
|
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
/* count the delimiters, recognizing ,, as an escape for a
|
|
|
|
* literal comma */
|
|
|
|
str_tok = str_copied;
|
|
|
|
while ((str_tok = strchr(str_tok, ','))) {
|
|
|
|
if (str_tok[1] == ',')
|
2012-09-04 15:16:29 +00:00
|
|
|
str_tok++;
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
else
|
|
|
|
nstr_tokens++;
|
|
|
|
str_tok++;
|
|
|
|
}
|
2012-09-04 15:16:29 +00:00
|
|
|
|
2013-08-15 16:20:05 +00:00
|
|
|
/* reserve the NULL element at the end */
|
|
|
|
if (VIR_ALLOC_N(arr, nstr_tokens + 1) < 0) {
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
VIR_FREE(str_copied);
|
|
|
|
return -1;
|
|
|
|
}
|
2012-09-04 15:16:29 +00:00
|
|
|
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
/* tokenize the input string, while treating ,, as a literal comma */
|
|
|
|
nstr_tokens = 0;
|
|
|
|
tmp = str_tok = str_copied;
|
|
|
|
while ((tmp = strchr(tmp, ','))) {
|
|
|
|
if (tmp[1] == ',') {
|
|
|
|
memmove(&tmp[1], &tmp[2], len - (tmp - str_copied) - 2 + 1);
|
|
|
|
len--;
|
|
|
|
tmp++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*tmp++ = '\0';
|
2013-08-15 16:20:05 +00:00
|
|
|
arr[nstr_tokens++] = vshStrdup(NULL, str_tok);
|
virsh: make ,, escape parsing common
So far, none of the existing callers of vshStringToArray expected
the user to ever pass a literal comma; meanwhile, snapshot parsing
had rolled its own array parser. Moving the comma escaping into
the common function won't affect any existing callers, and will make
this function reusable for adding memory handling to snapshot parsing.
As a bonus, the testsuite was already testing snapshot parsing, so
the fact that the test still passes means that we are now giving
testsuite exposure to vshStringToArray.
* tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
parsing...
* tools/virsh.c (vshStringToArray): ...into common function.
Also, vshStrdup can't fail.
2012-11-07 00:45:09 +00:00
|
|
|
str_tok = tmp;
|
2012-09-04 15:16:29 +00:00
|
|
|
}
|
2013-08-15 16:20:05 +00:00
|
|
|
arr[nstr_tokens++] = vshStrdup(NULL, str_tok);
|
2012-09-04 15:16:29 +00:00
|
|
|
|
|
|
|
*array = arr;
|
2013-08-15 16:20:05 +00:00
|
|
|
VIR_FREE(str_copied);
|
2012-09-04 15:16:29 +00:00
|
|
|
return nstr_tokens;
|
|
|
|
}
|
2010-02-03 16:45:05 +00:00
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
virErrorPtr last_error;
|
2009-02-09 14:24:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Quieten libvirt until we're done with the command.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
virshErrorHandler(void *unused ATTRIBUTE_UNUSED, virErrorPtr error)
|
|
|
|
{
|
|
|
|
virFreeError(last_error);
|
|
|
|
last_error = virSaveLastError();
|
2013-10-09 10:18:15 +00:00
|
|
|
if (virGetEnvAllowSUID("VIRSH_DEBUG") != NULL)
|
2009-02-09 14:24:06 +00:00
|
|
|
virDefaultErrorFunc(error);
|
|
|
|
}
|
|
|
|
|
2012-12-03 13:17:52 +00:00
|
|
|
/* Store a libvirt error that is from a helper API that doesn't raise errors
|
|
|
|
* so it doesn't get overwritten */
|
|
|
|
void
|
|
|
|
vshSaveLibvirtError(void)
|
|
|
|
{
|
|
|
|
virFreeError(last_error);
|
|
|
|
last_error = virSaveLastError();
|
|
|
|
}
|
|
|
|
|
2012-07-25 11:41:49 +00:00
|
|
|
/*
|
|
|
|
* Reset libvirt error on graceful fallback paths
|
|
|
|
*/
|
2012-08-18 04:00:42 +00:00
|
|
|
void
|
2012-07-25 11:41:49 +00:00
|
|
|
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.
|
|
|
|
*/
|
2012-08-18 04:00:42 +00:00
|
|
|
void
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(vshControl *ctl)
|
2009-02-09 14:24:06 +00:00
|
|
|
{
|
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
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
out:
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2009-02-09 14:24:06 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 09:59:52 +00:00
|
|
|
/*
|
|
|
|
* Detection of disconnections and automatic reconnection support
|
|
|
|
*/
|
2014-10-28 18:38:04 +00:00
|
|
|
static int disconnected; /* we may have been disconnected */
|
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
|
|
|
}
|
|
|
|
|
2014-03-06 16:20:11 +00:00
|
|
|
/* Main Function which should be used for connecting.
|
|
|
|
* This function properly handles keepalive settings. */
|
|
|
|
virConnectPtr
|
|
|
|
vshConnect(vshControl *ctl, const char *uri, bool readonly)
|
|
|
|
{
|
|
|
|
virConnectPtr c = NULL;
|
|
|
|
int interval = 5; /* Default */
|
|
|
|
int count = 6; /* Default */
|
|
|
|
bool keepalive_forced = false;
|
|
|
|
|
|
|
|
if (ctl->keepalive_interval >= 0) {
|
|
|
|
interval = ctl->keepalive_interval;
|
|
|
|
keepalive_forced = true;
|
|
|
|
}
|
|
|
|
if (ctl->keepalive_count >= 0) {
|
|
|
|
count = ctl->keepalive_count;
|
|
|
|
keepalive_forced = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = virConnectOpenAuth(uri, virConnectAuthPtrDefault,
|
|
|
|
readonly ? VIR_CONNECT_RO : 0);
|
|
|
|
if (!c)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (interval > 0 &&
|
|
|
|
virConnectSetKeepAlive(c, interval, count) != 0) {
|
|
|
|
if (keepalive_forced) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Cannot setup keepalive on connection "
|
|
|
|
"as requested, disconnecting"));
|
|
|
|
virConnectClose(c);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vshDebug(ctl, VSH_ERR_INFO, "%s",
|
|
|
|
_("Failed to setup keepalive on connection\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2013-03-26 09:54:55 +00:00
|
|
|
if (ctl->conn) {
|
|
|
|
int ret;
|
|
|
|
|
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
|
|
|
connected = true;
|
2013-03-26 09:54:55 +00:00
|
|
|
|
|
|
|
virConnectUnregisterCloseCallback(ctl->conn, vshCatchDisconnect);
|
|
|
|
ret = virConnectClose(ctl->conn);
|
|
|
|
if (ret < 0)
|
|
|
|
vshError(ctl, "%s", _("Failed to disconnect from the hypervisor"));
|
|
|
|
else if (ret > 0)
|
|
|
|
vshError(ctl, "%s", _("One or more references were leaked after "
|
|
|
|
"disconnect from the hypervisor"));
|
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
|
|
|
|
2014-03-06 16:20:11 +00:00
|
|
|
ctl->conn = vshConnect(ctl, ctl->name, ctl->readonly);
|
|
|
|
|
2012-08-02 17:15:16 +00:00
|
|
|
if (!ctl->conn) {
|
2012-12-13 13:08:00 +00:00
|
|
|
if (disconnected)
|
|
|
|
vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
|
|
|
|
else
|
|
|
|
vshError(ctl, "%s", _("failed to connect 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;
|
2014-08-28 23:39:25 +00:00
|
|
|
ctl->blockJobNoBytes = false;
|
2010-03-05 09:59:52 +00:00
|
|
|
}
|
2007-02-14 15:44:58 +00:00
|
|
|
|
2013-03-27 13:22:47 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "connect" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_connect[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("(re)connect to hypervisor")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Connect to local hypervisor. This is built-in "
|
|
|
|
"command after shell start up.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_connect[] = {
|
|
|
|
{.name = "name",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-03-27 13:22:47 +00:00
|
|
|
.flags = VSH_OFLAG_EMPTY_OK,
|
|
|
|
.help = N_("hypervisor connection URI")
|
|
|
|
},
|
|
|
|
{.name = "readonly",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("read-only connection")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdConnect(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
bool ro = vshCommandOptBool(cmd, "readonly");
|
|
|
|
const char *name = NULL;
|
|
|
|
|
|
|
|
if (ctl->conn) {
|
|
|
|
int ret;
|
2013-03-27 13:37:01 +00:00
|
|
|
|
|
|
|
virConnectUnregisterCloseCallback(ctl->conn, vshCatchDisconnect);
|
|
|
|
ret = virConnectClose(ctl->conn);
|
|
|
|
if (ret < 0)
|
|
|
|
vshError(ctl, "%s", _("Failed to disconnect from the hypervisor"));
|
|
|
|
else if (ret > 0)
|
|
|
|
vshError(ctl, "%s", _("One or more references were leaked after "
|
|
|
|
"disconnect from the hypervisor"));
|
2013-03-27 13:22:47 +00:00
|
|
|
ctl->conn = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(ctl->name);
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ctl->name = vshStrdup(ctl, name);
|
|
|
|
|
|
|
|
ctl->useGetInfo = false;
|
|
|
|
ctl->useSnapshotOld = false;
|
2014-08-28 23:39:25 +00:00
|
|
|
ctl->blockJobNoBytes = false;
|
2013-03-27 13:22:47 +00:00
|
|
|
ctl->readonly = ro;
|
|
|
|
|
2014-03-06 16:20:11 +00:00
|
|
|
ctl->conn = vshConnect(ctl, ctl->name, ctl->readonly);
|
2013-03-27 13:22:47 +00:00
|
|
|
|
2013-03-27 13:37:01 +00:00
|
|
|
if (!ctl->conn) {
|
2013-03-27 13:22:47 +00:00
|
|
|
vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
|
2013-03-27 13:37:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virConnectRegisterCloseCallback(ctl->conn, vshCatchDisconnect,
|
|
|
|
NULL, NULL) < 0)
|
|
|
|
vshError(ctl, "%s", _("Unable to register disconnect callback"));
|
2013-03-27 13:22:47 +00:00
|
|
|
|
2013-03-27 13:37:01 +00:00
|
|
|
return true;
|
2013-03-27 13:22:47 +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);
|
2014-11-13 14:20:51 +00:00
|
|
|
while ((key = va_arg(ap, char *)) != NULL)
|
2012-06-13 09:11:27 +00:00
|
|
|
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
|
|
|
|
* 'n' if he doesn't want to
|
2015-02-19 13:16:39 +00:00
|
|
|
* 'i' if he wants to try defining it again while ignoring validation
|
|
|
|
* 'f' if he forcibly wants to
|
2012-05-18 10:21:06 +00:00
|
|
|
* -1 on error
|
|
|
|
* 0 otherwise
|
|
|
|
*/
|
2012-08-18 04:00:42 +00:00
|
|
|
int
|
2015-02-19 13:16:39 +00:00
|
|
|
vshAskReedit(vshControl *ctl, const char *msg, bool relax_avail)
|
2012-05-18 10:21:06 +00:00
|
|
|
{
|
|
|
|
int c = -1;
|
|
|
|
|
|
|
|
if (!isatty(STDIN_FILENO))
|
|
|
|
return -1;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2012-05-18 10:21:06 +00:00
|
|
|
|
2013-08-29 16:15:07 +00:00
|
|
|
if (vshTTYMakeRaw(ctl, false) < 0)
|
2012-05-18 10:21:06 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (true) {
|
2015-02-19 13:16:39 +00:00
|
|
|
vshPrint(ctl, "\r%s %s %s: ", msg, _("Try again?"),
|
|
|
|
relax_avail ? "[y,n,i,f,?]" : "[y,n,f,?]");
|
2012-05-18 10:21:06 +00:00
|
|
|
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"),
|
2015-02-19 13:16:39 +00:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (relax_avail) {
|
|
|
|
vshPrintRaw(ctl,
|
|
|
|
_("i - turn off validation and try to redefine again"),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
vshPrintRaw(ctl,
|
2012-06-13 09:11:27 +00:00
|
|
|
_("f - force, try to redefine again"),
|
|
|
|
_("? - print this help"),
|
|
|
|
NULL);
|
2012-05-18 10:21:06 +00:00
|
|
|
continue;
|
2015-02-19 13:16:39 +00:00
|
|
|
} else if (c == 'y' || c == 'n' || c == 'f' ||
|
|
|
|
(relax_avail && c == 'i')) {
|
2012-05-18 10:21:06 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-29 16:15:07 +00:00
|
|
|
vshTTYRestore(ctl);
|
2012-05-18 10:21:06 +00:00
|
|
|
|
|
|
|
vshPrint(ctl, "\r\n");
|
|
|
|
return c;
|
2012-06-21 13:46:03 +00:00
|
|
|
}
|
|
|
|
#else /* WIN32 */
|
2012-08-20 12:29:14 +00:00
|
|
|
int
|
2015-02-19 13:16:39 +00:00
|
|
|
vshAskReedit(vshControl *ctl,
|
|
|
|
const char *msg ATTRIBUTE_UNUSED,
|
|
|
|
bool relax_avail ATTRIBUTE_UNUSED)
|
2012-06-21 13:46:03 +00:00
|
|
|
{
|
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-08-18 04:00:42 +00:00
|
|
|
int vshStreamSink(virStreamPtr st ATTRIBUTE_UNUSED,
|
|
|
|
const char *bytes, size_t nbytes, void *opaque)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
|
|
|
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[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("print help")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Prints global help, command specific help, or help for a\n"
|
|
|
|
" group of related commands")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2005-12-08 10:23:34 +00:00
|
|
|
};
|
|
|
|
|
2008-08-01 12:19:56 +00:00
|
|
|
static const vshCmdOptDef opts_help[] = {
|
2013-01-14 11:26:23 +00:00
|
|
|
{.name = "command",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:23 +00:00
|
|
|
.help = N_("Prints global help, command specific help, or help for a group of related commands")
|
|
|
|
},
|
|
|
|
{.name = 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. */
|
|
|
|
|
|
|
|
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
|
|
|
{
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-25 15:37:18 +00:00
|
|
|
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 */
|
2013-05-21 07:44:53 +00:00
|
|
|
for (i = 0; i < num_devices; i++) {
|
2012-07-25 15:37:18 +00:00
|
|
|
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, " ");
|
2013-01-15 18:12:57 +00:00
|
|
|
if (virBufferError(indent))
|
|
|
|
goto cleanup;
|
2013-05-21 07:44:53 +00:00
|
|
|
for (i = 0; i < num_devices; i++) {
|
2012-07-25 15:37:18 +00:00
|
|
|
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
|
|
|
}
|
2013-06-18 15:52:00 +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
|
|
|
|
2013-06-18 15:52:00 +00:00
|
|
|
if (!root)
|
|
|
|
virBufferTrim(indent, NULL, 2);
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = 0;
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2012-02-28 06:38:03 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-08-20 22:23:10 +00:00
|
|
|
int
|
2012-07-25 15:37:18 +00:00
|
|
|
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. */
|
2012-08-18 03:16:04 +00:00
|
|
|
char *
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshEditWriteToTempFile(vshControl *ctl, const char *doc)
|
2008-08-01 14:30:41 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
const char *tmpdir;
|
|
|
|
int fd;
|
2012-09-04 23:35:27 +00:00
|
|
|
char ebuf[1024];
|
2008-08-01 14:30:41 +00:00
|
|
|
|
2013-10-09 10:18:15 +00:00
|
|
|
tmpdir = virGetEnvBlockSUID("TMPDIR");
|
2008-08-01 14:30:41 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-10-31 14:13:47 +00:00
|
|
|
fd = mkostemps(ret, 4, O_CLOEXEC);
|
2008-08-01 14:30:41 +00:00
|
|
|
if (fd == -1) {
|
2012-10-31 14:13:47 +00:00
|
|
|
vshError(ctl, _("mkostemps: failed to create temporary file: %s"),
|
2012-09-04 23:35:27 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
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"),
|
2012-09-04 23:35:27 +00:00
|
|
|
ret, virStrerror(errno, ebuf, sizeof(ebuf)));
|
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"),
|
2012-09-04 23:35:27 +00:00
|
|
|
ret, virStrerror(errno, ebuf, sizeof(ebuf)));
|
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-/_.:@"
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshEditFile(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
|
|
|
|
2013-10-09 10:18:15 +00:00
|
|
|
editor = virGetEnvBlockSUID("VISUAL");
|
2011-01-28 21:22:39 +00:00
|
|
|
if (!editor)
|
2013-10-09 10:18:15 +00:00
|
|
|
editor = virGetEnvBlockSUID("EDITOR");
|
2011-01-28 21:22:39 +00:00
|
|
|
if (!editor)
|
2014-09-28 08:34:03 +00:00
|
|
|
editor = DEFAULT_EDITOR;
|
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) {
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2011-01-28 21:22:39 +00:00
|
|
|
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
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2011-01-28 21:22:39 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
2008-08-01 14:30:41 +00:00
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
char *
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshEditReadBackFile(vshControl *ctl, const char *filename)
|
2008-08-01 14:30:41 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
2012-09-04 23:35:27 +00:00
|
|
|
char ebuf[1024];
|
2008-08-01 14:30:41 +00:00
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(filename, VSH_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"),
|
2012-09-04 23:35:27 +00:00
|
|
|
filename, virStrerror(errno, ebuf, sizeof(ebuf)));
|
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[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("change the current directory")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Change the current directory.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2009-07-16 14:40:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_cd[] = {
|
2013-01-14 11:26:23 +00:00
|
|
|
{.name = "dir",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:23 +00:00
|
|
|
.help = N_("directory to switch to (default: home or else root)")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2009-07-16 14:40:08 +00:00
|
|
|
};
|
|
|
|
|
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;
|
2012-09-04 23:35:27 +00:00
|
|
|
char ebuf[1024];
|
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
|
|
|
}
|
|
|
|
|
2014-11-13 14:20:51 +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) {
|
2012-09-04 23:35:27 +00:00
|
|
|
vshError(ctl, _("cd: %s: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)), 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[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("print the current directory")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Print the current directory.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2009-07-16 14:40:08 +00:00
|
|
|
};
|
|
|
|
|
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;
|
2012-09-04 23:35:27 +00:00
|
|
|
char ebuf[1024];
|
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"),
|
2012-09-04 23:35:27 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
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[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("echo arguments")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Echo back arguments, possibly with quoting.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2010-10-15 13:39:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_echo[] = {
|
2013-01-14 11:26:23 +00:00
|
|
|
{.name = "shell",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("escape for shell use")
|
|
|
|
},
|
|
|
|
{.name = "xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("escape for XML use")
|
|
|
|
},
|
|
|
|
{.name = "str",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "string"
|
|
|
|
},
|
2013-10-24 07:06:29 +00:00
|
|
|
{.name = "hi",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "string=hello"
|
|
|
|
},
|
2013-01-14 11:26:23 +00:00
|
|
|
{.name = "string",
|
|
|
|
.type = VSH_OT_ARGV,
|
|
|
|
.help = N_("arguments to echo")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2010-10-15 13:39:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* 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);
|
2013-09-17 06:21:32 +00:00
|
|
|
if (virBufferError(&xmlbuf)) {
|
2011-10-13 20:49:15 +00:00
|
|
|
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[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("quit this interactive terminal")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = ""
|
|
|
|
},
|
|
|
|
{.name = 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
|
|
|
|
* ---------------
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
const char *
|
2012-07-23 03:57:53 +00:00
|
|
|
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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-23 03:57:53 +00:00
|
|
|
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) {
|
2014-11-11 10:01:05 +00:00
|
|
|
optional = true;
|
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) {
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t j;
|
2013-10-24 07:06:29 +00:00
|
|
|
char *name = (char *)opt->help; /* cast away const */
|
|
|
|
char *p;
|
|
|
|
|
2012-03-02 18:01:15 +00:00
|
|
|
if (opt->flags || !opt->help)
|
|
|
|
return -1; /* alias options are tracked by the original name */
|
2013-10-24 07:06:29 +00:00
|
|
|
if ((p = strchr(name, '=')) &&
|
|
|
|
VIR_STRNDUP(name, name, p - name) < 0)
|
|
|
|
return -1;
|
2012-03-02 18:01:15 +00:00
|
|
|
for (j = i + 1; cmd->opts[j].name; j++) {
|
2013-10-24 07:06:29 +00:00
|
|
|
if (STREQ(name, cmd->opts[j].name) &&
|
|
|
|
cmd->opts[j].type != VSH_OT_ALIAS)
|
2012-03-02 18:01:15 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-10-24 07:06:29 +00:00
|
|
|
if (name != opt->help) {
|
|
|
|
VIR_FREE(name);
|
|
|
|
/* If alias comes with value, replacement must not be bool */
|
|
|
|
if (cmd->opts[j].type == VSH_OT_BOOL)
|
|
|
|
return -1;
|
|
|
|
}
|
2012-03-02 18:01:15 +00:00
|
|
|
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;
|
2014-11-11 10:01:05 +00:00
|
|
|
else
|
|
|
|
optional = true;
|
2011-06-07 09:11:10 +00:00
|
|
|
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) {
|
2014-11-11 10:01:05 +00:00
|
|
|
if (optional && opt->type != VSH_OT_ARGV)
|
2011-04-12 20:42:59 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-01-14 11:26:23 +00:00
|
|
|
static vshCmdOptDef helpopt = {
|
|
|
|
.name = "help",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print help for this function")
|
|
|
|
};
|
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,
|
2013-10-24 07:06:29 +00:00
|
|
|
uint32_t *opts_seen, int *opt_index, char **optstr)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-10-24 07:06:29 +00:00
|
|
|
const vshCmdOptDef *ret = NULL;
|
|
|
|
char *alias = NULL;
|
2011-04-12 20:42:59 +00:00
|
|
|
|
2014-11-13 14:20:51 +00:00
|
|
|
if (STREQ(name, helpopt.name))
|
2012-08-11 18:45:45 +00:00
|
|
|
return &helpopt;
|
|
|
|
|
2011-04-12 20:42:59 +00:00
|
|
|
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) {
|
2013-10-24 07:06:29 +00:00
|
|
|
char *value;
|
|
|
|
|
|
|
|
/* Two types of replacements:
|
|
|
|
opt->help = "string": straight replacement of name
|
|
|
|
opt->help = "string=value": treat boolean flag as
|
|
|
|
alias of option and its default value */
|
|
|
|
sa_assert(!alias);
|
|
|
|
if (VIR_STRDUP(alias, opt->help) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
name = alias;
|
|
|
|
if ((value = strchr(name, '='))) {
|
|
|
|
*value = '\0';
|
|
|
|
if (*optstr) {
|
|
|
|
vshError(ctl, _("invalid '=' after option --%s"),
|
|
|
|
opt->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (VIR_STRDUP(*optstr, value + 1) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-03-02 18:01:15 +00:00
|
|
|
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);
|
2013-10-24 07:06:29 +00:00
|
|
|
goto cleanup;
|
2011-04-12 20:42:59 +00:00
|
|
|
}
|
2011-09-21 14:54:47 +00:00
|
|
|
*opts_seen |= 1 << i;
|
|
|
|
*opt_index = i;
|
2013-10-24 07:06:29 +00:00
|
|
|
ret = opt;
|
|
|
|
goto cleanup;
|
2011-04-12 20:42:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-05 22:13:18 +00:00
|
|
|
if (STRNEQ(cmd->name, "help")) {
|
|
|
|
vshError(ctl, _("command '%s' doesn't support option --%s"),
|
|
|
|
cmd->name, name);
|
|
|
|
}
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-10-24 07:06:29 +00:00
|
|
|
VIR_FREE(alias);
|
|
|
|
return ret;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-04-12 20:42:59 +00:00
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
const vshCmdGrp *
|
2010-11-30 06:37:04 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
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++) {
|
2013-04-26 10:20:29 +00:00
|
|
|
if (cmd->flags & VSH_CMD_FLAG_ALIAS)
|
|
|
|
continue;
|
2010-11-30 06:37:04 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
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
|
|
|
}
|
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
|
|
|
|
2013-05-22 03:15:45 +00:00
|
|
|
if (def->opts && def->opts->name) {
|
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 */
|
2014-11-11 11:03:11 +00:00
|
|
|
if (opt->flags & VSH_OFLAG_REQ) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("internal error: bad options in command: '%s'"),
|
|
|
|
def->name);
|
|
|
|
return false;
|
|
|
|
}
|
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:
|
2014-12-11 02:46:15 +00:00
|
|
|
/* OT_DATA should always be VSH_OFLAG_REQ */
|
|
|
|
if (!(opt->flags & VSH_OFLAG_REQ)) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("internal error: bad options in command: '%s'"),
|
|
|
|
def->name);
|
|
|
|
return false;
|
|
|
|
}
|
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
|
|
|
}
|
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
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
* @needData: true if option must be non-boolean
|
2011-07-15 17:23:17 +00:00
|
|
|
*
|
|
|
|
* 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
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
* the option is required but not present, and assert if NAME is not
|
|
|
|
* valid (which indicates a programming error). No error messages are
|
|
|
|
* issued if a value is returned.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
static int
|
|
|
|
vshCommandOpt(const vshCmd *cmd, const char *name, vshCmdOpt **opt,
|
|
|
|
bool needData)
|
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;
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* See if option is valid and/or required. */
|
|
|
|
*opt = NULL;
|
|
|
|
while (valid) {
|
|
|
|
assert(valid->name);
|
|
|
|
if (STREQ(name, valid->name))
|
|
|
|
break;
|
|
|
|
valid++;
|
|
|
|
}
|
|
|
|
assert(!needData || valid->type != VSH_OT_BOOL);
|
|
|
|
if (valid->flags & VSH_OFLAG_REQ)
|
|
|
|
ret = -1;
|
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;
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
ret = 1;
|
|
|
|
break;
|
2011-07-15 17:23:17 +00:00
|
|
|
}
|
|
|
|
candidate = candidate->next;
|
2005-12-08 10:23:34 +00:00
|
|
|
}
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
return ret;
|
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
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
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
|
|
|
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg, true);
|
2011-07-15 17:23:17 +00:00
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-05-29 11:12:26 +00:00
|
|
|
static int
|
|
|
|
vshCommandOptUIntInternal(const vshCmd *cmd,
|
|
|
|
const char *name,
|
|
|
|
unsigned int *value,
|
|
|
|
bool wrap)
|
|
|
|
{
|
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (wrap) {
|
|
|
|
if (virStrToLong_ui(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (virStrToLong_uip(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
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
|
|
|
|
*
|
2014-05-29 11:12:26 +00:00
|
|
|
* Convert option to unsigned int, reject negative numbers
|
2011-05-12 16:29:12 +00:00
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
2011-05-12 16:29:12 +00:00
|
|
|
vshCommandOptUInt(const vshCmd *cmd, const char *name, unsigned int *value)
|
|
|
|
{
|
2014-05-29 11:12:26 +00:00
|
|
|
return vshCommandOptUIntInternal(cmd, name, value, false);
|
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
2014-05-29 11:12:26 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptUIntWrap:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
|
|
|
* Convert option to unsigned int, wraps negative numbers to positive
|
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vshCommandOptUIntWrap(const vshCmd *cmd, const char *name, unsigned int *value)
|
|
|
|
{
|
|
|
|
return vshCommandOptUIntInternal(cmd, name, value, true);
|
2011-05-12 16:29:12 +00:00
|
|
|
}
|
|
|
|
|
2014-06-04 09:08:08 +00:00
|
|
|
static int
|
|
|
|
vshCommandOptULInternal(const vshCmd *cmd,
|
|
|
|
const char *name,
|
|
|
|
unsigned long *value,
|
|
|
|
bool wrap)
|
|
|
|
{
|
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (wrap) {
|
|
|
|
if (virStrToLong_ul(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (virStrToLong_ulp(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()
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
2011-03-08 16:29:31 +00:00
|
|
|
vshCommandOptUL(const vshCmd *cmd, const char *name, unsigned long *value)
|
2010-06-17 19:36:36 +00:00
|
|
|
{
|
2014-06-04 09:08:08 +00:00
|
|
|
return vshCommandOptULInternal(cmd, name, value, false);
|
|
|
|
}
|
2011-07-15 17:23:17 +00:00
|
|
|
|
2014-06-04 09:08:08 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptULWrap:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
|
|
|
* Convert option to unsigned long, wraps negative numbers to positive
|
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vshCommandOptULWrap(const vshCmd *cmd, const char *name, unsigned long *value)
|
|
|
|
{
|
|
|
|
return vshCommandOptULInternal(cmd, name, value, true);
|
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
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
2011-03-08 16:29:31 +00:00
|
|
|
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;
|
|
|
|
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg, true);
|
2011-07-15 17:23:17 +00:00
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2014-11-13 14:20:51 +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
|
|
|
}
|
|
|
|
|
2013-01-14 13:38:38 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptStringReq:
|
|
|
|
* @ctl virsh control structure
|
|
|
|
* @cmd command structure
|
|
|
|
* @name option name
|
|
|
|
* @value result (updated to NULL or the option argument)
|
|
|
|
*
|
|
|
|
* Gets a option argument as string.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or when the option is not present and not
|
|
|
|
* required, *value is set to the option argument. On error -1 is
|
|
|
|
* returned and error message printed.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vshCommandOptStringReq(vshControl *ctl,
|
|
|
|
const vshCmd *cmd,
|
|
|
|
const char *name,
|
|
|
|
const char **value)
|
|
|
|
{
|
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
|
|
|
const char *error = NULL;
|
|
|
|
|
|
|
|
/* clear out the value */
|
|
|
|
*value = NULL;
|
|
|
|
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg, true);
|
2013-01-14 13:38:38 +00:00
|
|
|
/* option is not required and not present */
|
|
|
|
if (ret == 0)
|
|
|
|
return 0;
|
|
|
|
/* this should not be propagated here, just to be sure */
|
|
|
|
if (ret == -1)
|
|
|
|
error = N_("Mandatory option not present");
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
else if (!*arg->data && !(arg->def->flags & VSH_OFLAG_EMPTY_OK))
|
2013-01-14 13:38:38 +00:00
|
|
|
error = N_("Option argument is empty");
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
vshError(ctl, _("Failed to get option '%s': %s"), name, _(error));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = arg->data;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
2011-03-08 16:29:31 +00:00
|
|
|
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
|
|
|
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
ret = vshCommandOpt(cmd, name, &arg, true);
|
2011-07-15 17:23:17 +00:00
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-06-04 09:08:08 +00:00
|
|
|
static int
|
|
|
|
vshCommandOptULongLongInternal(const vshCmd *cmd,
|
|
|
|
const char *name,
|
|
|
|
unsigned long long *value,
|
|
|
|
bool wrap)
|
|
|
|
{
|
|
|
|
vshCmdOpt *arg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (wrap) {
|
|
|
|
if (virStrToLong_ull(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (virStrToLong_ullp(arg->data, NULL, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-07-15 17:23:17 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptULongLong:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
2014-06-04 09:08:08 +00:00
|
|
|
* Returns option as long long, rejects negative numbers
|
2011-07-15 17:23:17 +00:00
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
2009-07-14 13:24:53 +00:00
|
|
|
vshCommandOptULongLong(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned long long *value)
|
|
|
|
{
|
2014-06-04 09:08:08 +00:00
|
|
|
return vshCommandOptULongLongInternal(cmd, name, value, false);
|
2009-07-14 13:24:53 +00:00
|
|
|
}
|
|
|
|
|
2014-06-04 09:08:08 +00:00
|
|
|
/**
|
|
|
|
* vshCommandOptULongLongWrap:
|
|
|
|
* @cmd command reference
|
|
|
|
* @name option name
|
|
|
|
* @value result
|
|
|
|
*
|
|
|
|
* Returns option as long long, wraps negative numbers to positive
|
|
|
|
* See vshCommandOptInt()
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vshCommandOptULongLongWrap(const vshCmd *cmd, const char *name,
|
|
|
|
unsigned long long *value)
|
|
|
|
{
|
|
|
|
return vshCommandOptULongLongInternal(cmd, name, value, true);
|
|
|
|
}
|
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()
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
2012-03-08 01:10:30 +00:00
|
|
|
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
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
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;
|
|
|
|
|
virsh: detect programming errors with option parsing
Noticed while reviewing another patch that had an accidental
mismatch due to refactoring. An audit of the code showed that
very few callers of vshCommandOpt were expecting a return of
-2, indicating programmer error, and of those that DID check,
they just propagated that status to yet another caller that
did not check. Fix this by making the code blatantly warn
the programmer, rather than silently ignoring it and possibly
doing the wrong thing downstream.
I know that we frown on assert()/abort() inside libvirtd
(libraries should NEVER kill the program that linked them),
but as virsh is an app rather than the library, and as this
is not the first use of assert() in virsh, I think this
approach is okay.
* tools/virsh.h (vshCommandOpt): Drop declaration.
* tools/virsh.c (vshCommandOpt): Make static, and add a
parameter. Abort on programmer errors rather than making callers
repeat that logic.
(vshCommandOptInt, vshCommandOptUInt, vshCommandOptUL)
(vshCommandOptString, vshCommandOptStringReq)
(vshCommandOptLongLong, vshCommandOptULongLong)
(vshCommandOptBool): Adjust callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-08-16 22:07:31 +00:00
|
|
|
return vshCommandOpt(cmd, name, &dummy, false) == 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.
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
const vshCmdOpt *
|
2011-06-14 17:26:20 +00:00
|
|
|
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) {
|
2014-11-13 14:20:51 +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;
|
|
|
|
}
|
|
|
|
|
2014-02-14 00:08:42 +00:00
|
|
|
/* Parse an optional --timeout parameter in seconds, but store the
|
|
|
|
* value of the timeout in milliseconds. Return -1 on error, 0 if
|
|
|
|
* no timeout was requested, and 1 if timeout was set. */
|
|
|
|
int
|
|
|
|
vshCommandOptTimeoutToMs(vshControl *ctl, const vshCmd *cmd, int *timeout)
|
|
|
|
{
|
|
|
|
int rv = vshCommandOptInt(cmd, "timeout", timeout);
|
|
|
|
|
|
|
|
if (rv < 0 || (rv > 0 && *timeout < 1)) {
|
|
|
|
vshError(ctl, "%s", _("invalid timeout"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (rv > 0) {
|
|
|
|
/* Ensure that we can multiply by 1000 without overflowing. */
|
|
|
|
if (*timeout > INT_MAX / 1000) {
|
|
|
|
vshError(ctl, "%s", _("timeout is too big"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*timeout *= 1000;
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-24 11:57:01 +00:00
|
|
|
static bool
|
|
|
|
vshConnectionUsability(vshControl *ctl, virConnectPtr conn)
|
|
|
|
{
|
|
|
|
if (!conn ||
|
|
|
|
virConnectIsAlive(conn) == 0) {
|
|
|
|
vshError(ctl, "%s", _("no valid connection"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The connection is considered dead only if
|
|
|
|
* virConnectIsAlive() successfuly says so.
|
|
|
|
*/
|
|
|
|
vshResetLibvirtError();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2012-11-29 10:46:00 +00:00
|
|
|
if (enable_timing)
|
|
|
|
GETTIMEOFDAY(&before);
|
|
|
|
|
2012-08-24 10:39:53 +00:00
|
|
|
if ((cmd->def->flags & VSH_CMD_FLAG_NOCONNECT) ||
|
|
|
|
vshConnectionUsability(ctl, ctl->conn)) {
|
|
|
|
ret = cmd->def->handler(ctl, cmd);
|
|
|
|
} else {
|
|
|
|
/* connection is not usable, return error */
|
|
|
|
ret = false;
|
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2012-11-29 10:46:00 +00:00
|
|
|
if (enable_timing)
|
|
|
|
GETTIMEOFDAY(&after);
|
|
|
|
|
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)
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2009-02-09 14:24:06 +00:00
|
|
|
|
2014-04-02 08:43:03 +00:00
|
|
|
if (STREQ(cmd->def->name, "quit") ||
|
|
|
|
STREQ(cmd->def->name, "exit")) /* hack ... */
|
2005-12-08 10:23:34 +00:00
|
|
|
return ret;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (enable_timing) {
|
2012-08-31 11:32:45 +00:00
|
|
|
double diff_ms = (((after.tv_sec - before.tv_sec) * 1000.0) +
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
((after.tv_usec - before.tv_usec) / 1000.0));
|
|
|
|
|
|
|
|
vshPrint(ctl, _("\n(Time: %.3f ms)\n\n"), diff_ms);
|
|
|
|
} else {
|
2006-05-22 14:38:33 +00:00
|
|
|
vshPrintExtra(ctl, "\n");
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
}
|
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;
|
|
|
|
|
2012-08-18 04:35:13 +00:00
|
|
|
typedef struct _vshCommandParser vshCommandParser;
|
|
|
|
struct _vshCommandParser {
|
|
|
|
vshCommandToken(*getNextArg)(vshControl *, vshCommandParser *,
|
|
|
|
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;
|
2012-08-18 04:35:13 +00:00
|
|
|
};
|
2010-10-12 07:13:50 +00:00
|
|
|
|
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, '=');
|
2012-08-11 19:00:46 +00:00
|
|
|
int opt_index = 0;
|
2011-09-21 14:54:47 +00:00
|
|
|
|
2010-10-12 07:13:39 +00:00
|
|
|
if (optstr) {
|
|
|
|
*optstr = '\0'; /* convert the '=' to '\0' */
|
|
|
|
optstr = vshStrdup(ctl, optstr + 1);
|
|
|
|
}
|
2012-08-05 22:13:18 +00:00
|
|
|
/* Special case 'help' to ignore all spurious options */
|
2011-04-12 20:42:59 +00:00
|
|
|
if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
|
2013-10-24 07:06:29 +00:00
|
|
|
&opts_seen, &opt_index,
|
|
|
|
&optstr))) {
|
2010-10-12 07:13:39 +00:00
|
|
|
VIR_FREE(optstr);
|
2012-08-05 22:13:18 +00:00
|
|
|
if (STREQ(cmd->name, "help"))
|
|
|
|
continue;
|
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"),
|
2013-10-24 07:06:29 +00:00
|
|
|
opt->name);
|
2010-10-12 07:13:39 +00:00
|
|
|
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 {
|
2014-03-25 06:53:59 +00:00
|
|
|
get_data:
|
2012-08-05 22:13:18 +00:00
|
|
|
/* Special case 'help' to ignore spurious data */
|
2011-04-12 20:42:59 +00:00
|
|
|
if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
|
2012-08-05 22:13:18 +00:00
|
|
|
&opts_seen)) &&
|
|
|
|
STRNEQ(cmd->name, "help")) {
|
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));
|
2012-08-11 18:45:45 +00:00
|
|
|
vshCmdOpt *tmpopt = first;
|
|
|
|
|
|
|
|
/* if we encountered --help, replace parsed command with
|
|
|
|
* 'help <cmdname>' */
|
|
|
|
for (tmpopt = first; tmpopt; tmpopt = tmpopt->next) {
|
|
|
|
if (STRNEQ(tmpopt->def->name, "help"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vshCommandOptFree(first);
|
|
|
|
first = vshMalloc(ctl, sizeof(vshCmdOpt));
|
|
|
|
first->def = &(opts_help[0]);
|
|
|
|
first->data = vshStrdup(ctl, cmd->name);
|
|
|
|
first->next = NULL;
|
|
|
|
|
|
|
|
cmd = vshCmddefSearch("help");
|
|
|
|
opts_required = 0;
|
|
|
|
opts_seen = 0;
|
|
|
|
break;
|
|
|
|
}
|
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
|
|
|
* ---------------
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
int
|
2011-04-29 08:20:49 +00:00
|
|
|
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. */
|
2012-08-18 03:16:04 +00:00
|
|
|
char *
|
2011-09-19 12:23:12 +00:00
|
|
|
vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
char *str = NULL;
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
switch (item->type) {
|
2011-09-19 12:23:12 +00:00
|
|
|
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:
|
2013-05-02 19:35:26 +00:00
|
|
|
str = vshStrdup(ctl, item->value.b ? _("yes") : _("no"));
|
2011-09-19 12:23:12 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
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
|
|
|
|
2013-08-29 08:36:00 +00:00
|
|
|
bool
|
2013-09-04 21:57:30 +00:00
|
|
|
vshTTYIsInterruptCharacter(vshControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char chr ATTRIBUTE_UNUSED)
|
2013-08-29 08:36:00 +00:00
|
|
|
{
|
2013-09-04 21:57:30 +00:00
|
|
|
#ifndef WIN32
|
2013-08-29 08:36:00 +00:00
|
|
|
if (ctl->istty &&
|
|
|
|
ctl->termattr.c_cc[VINTR] == chr)
|
|
|
|
return true;
|
2013-09-04 21:57:30 +00:00
|
|
|
#endif
|
2013-08-29 08:36:00 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-22 14:01:26 +00:00
|
|
|
bool
|
|
|
|
vshTTYAvailable(vshControl *ctl)
|
|
|
|
{
|
|
|
|
return ctl->istty;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-29 08:36:00 +00:00
|
|
|
int
|
2013-09-04 21:57:30 +00:00
|
|
|
vshTTYDisableInterrupt(vshControl *ctl ATTRIBUTE_UNUSED)
|
2013-08-29 08:36:00 +00:00
|
|
|
{
|
2013-09-04 21:57:30 +00:00
|
|
|
#ifndef WIN32
|
2013-08-29 08:36:00 +00:00
|
|
|
struct termios termset = ctl->termattr;
|
|
|
|
|
|
|
|
if (!ctl->istty)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* check if we need to set the terminal */
|
|
|
|
if (termset.c_cc[VINTR] == _POSIX_VDISABLE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
termset.c_cc[VINTR] = _POSIX_VDISABLE;
|
|
|
|
termset.c_lflag &= ~ICANON;
|
|
|
|
|
|
|
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &termset) < 0)
|
|
|
|
return -1;
|
2013-09-04 21:57:30 +00:00
|
|
|
#endif
|
2013-08-29 08:36:00 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2013-09-04 21:57:30 +00:00
|
|
|
vshTTYRestore(vshControl *ctl ATTRIBUTE_UNUSED)
|
2013-08-29 08:36:00 +00:00
|
|
|
{
|
2013-09-04 21:57:30 +00:00
|
|
|
#ifndef WIN32
|
2013-08-29 08:36:00 +00:00
|
|
|
if (!ctl->istty)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &ctl->termattr) < 0)
|
|
|
|
return -1;
|
2013-09-04 21:57:30 +00:00
|
|
|
#endif
|
2013-08-29 08:36:00 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-04 21:57:30 +00:00
|
|
|
#if !defined(WIN32) && !defined(HAVE_CFMAKERAW)
|
2013-08-29 16:15:07 +00:00
|
|
|
/* provide fallback in case cfmakeraw isn't available */
|
|
|
|
static void
|
|
|
|
cfmakeraw(struct termios *attr)
|
|
|
|
{
|
|
|
|
attr->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
|
|
|
| INLCR | IGNCR | ICRNL | IXON);
|
|
|
|
attr->c_oflag &= ~OPOST;
|
|
|
|
attr->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
|
|
|
attr->c_cflag &= ~(CSIZE | PARENB);
|
|
|
|
attr->c_cflag |= CS8;
|
|
|
|
}
|
2013-09-04 21:57:30 +00:00
|
|
|
#endif /* !WIN32 && !HAVE_CFMAKERAW */
|
2013-08-29 16:15:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
2013-09-04 21:57:30 +00:00
|
|
|
vshTTYMakeRaw(vshControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
bool report_errors ATTRIBUTE_UNUSED)
|
2013-08-29 16:15:07 +00:00
|
|
|
{
|
2013-09-04 21:57:30 +00:00
|
|
|
#ifndef WIN32
|
2013-08-29 16:15:07 +00:00
|
|
|
struct termios rawattr = ctl->termattr;
|
|
|
|
char ebuf[1024];
|
|
|
|
|
|
|
|
if (!ctl->istty) {
|
|
|
|
if (report_errors) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("unable to make terminal raw: console isn't a tty"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cfmakeraw(&rawattr);
|
|
|
|
|
|
|
|
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) {
|
|
|
|
if (report_errors)
|
|
|
|
vshError(ctl, _("unable to set tty attributes: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-09-04 21:57:30 +00:00
|
|
|
#endif
|
2013-08-29 16:15:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-18 03:16:04 +00:00
|
|
|
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)
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2011-10-11 13:05:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
virsh: common code for waiting for an event
I plan to add 'virsh event' to virsh-domain.c and 'virsh
net-event' to virsh-network.c; but as they will share quite
a bit of common boilerplate, it's better to set that up now
in virsh.c.
* tools/virsh.h (_vshControl): Add fields.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup): New
prototypes.
* tools/virsh.c (vshEventFd, vshEventOldAction, vshEventInt)
(vshEventTimeout): New helper variables and functions.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup):
Implement new functions.
(vshInit, vshDeinit, main): Manage event timeout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-14 22:30:23 +00:00
|
|
|
/*
|
|
|
|
* Helpers for waiting for a libvirt event.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* We want to use SIGINT to cancel a wait; but as signal handlers
|
|
|
|
* don't have an opaque argument, we have to use static storage. */
|
|
|
|
static int vshEventFd = -1;
|
|
|
|
static struct sigaction vshEventOldAction;
|
|
|
|
|
|
|
|
|
|
|
|
/* Signal handler installed in vshEventStart, removed in vshEventCleanup. */
|
|
|
|
static void
|
|
|
|
vshEventInt(int sig ATTRIBUTE_UNUSED,
|
|
|
|
siginfo_t *siginfo ATTRIBUTE_UNUSED,
|
|
|
|
void *context ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
char reason = VSH_EVENT_INTERRUPT;
|
|
|
|
if (vshEventFd >= 0)
|
|
|
|
ignore_value(safewrite(vshEventFd, &reason, 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Event loop handler used to limit length of waiting for any other event. */
|
|
|
|
static void
|
|
|
|
vshEventTimeout(int timer ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
vshControl *ctl = opaque;
|
|
|
|
char reason = VSH_EVENT_TIMEOUT;
|
|
|
|
|
|
|
|
if (ctl->eventPipe[1] >= 0)
|
|
|
|
ignore_value(safewrite(ctl->eventPipe[1], &reason, 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vshEventStart:
|
|
|
|
* @ctl virsh command struct
|
|
|
|
* @timeout_ms max wait time in milliseconds, or 0 for indefinite
|
|
|
|
*
|
|
|
|
* Set up a wait for a libvirt event. The wait can be canceled by
|
|
|
|
* SIGINT or by calling vshEventDone() in your event handler. If
|
|
|
|
* @timeout_ms is positive, the wait will also end if the timeout
|
|
|
|
* expires. Call vshEventWait() to block the main thread (the event
|
|
|
|
* handler runs in the event loop thread). When done (including if
|
|
|
|
* there was an error registering for an event), use vshEventCleanup()
|
|
|
|
* to quit waiting. Returns 0 on success, -1 on failure. */
|
|
|
|
int
|
|
|
|
vshEventStart(vshControl *ctl, int timeout_ms)
|
|
|
|
{
|
|
|
|
struct sigaction action;
|
|
|
|
|
|
|
|
assert(ctl->eventPipe[0] == -1 && ctl->eventPipe[1] == -1 &&
|
|
|
|
vshEventFd == -1 && ctl->eventTimerId >= 0);
|
|
|
|
if (pipe2(ctl->eventPipe, O_CLOEXEC) < 0) {
|
|
|
|
char ebuf[1024];
|
|
|
|
|
|
|
|
vshError(ctl, _("failed to create pipe: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
vshEventFd = ctl->eventPipe[1];
|
|
|
|
|
|
|
|
action.sa_sigaction = vshEventInt;
|
|
|
|
action.sa_flags = SA_SIGINFO;
|
|
|
|
sigemptyset(&action.sa_mask);
|
|
|
|
sigaction(SIGINT, &action, &vshEventOldAction);
|
|
|
|
|
|
|
|
if (timeout_ms)
|
|
|
|
virEventUpdateTimeout(ctl->eventTimerId, timeout_ms);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vshEventDone:
|
|
|
|
* @ctl virsh command struct
|
|
|
|
*
|
|
|
|
* Call this from an event callback to let the main thread quit
|
|
|
|
* blocking on further events.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
vshEventDone(vshControl *ctl)
|
|
|
|
{
|
|
|
|
char reason = VSH_EVENT_DONE;
|
|
|
|
|
|
|
|
if (ctl->eventPipe[1] >= 0)
|
|
|
|
ignore_value(safewrite(ctl->eventPipe[1], &reason, 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vshEventWait:
|
|
|
|
* @ctl virsh command struct
|
|
|
|
*
|
|
|
|
* Call this in the main thread after calling vshEventStart() then
|
|
|
|
* registering for one or more events. This call will block until
|
|
|
|
* SIGINT, the timeout registered at the start, or until one of your
|
|
|
|
* event handlers calls vshEventDone(). Returns an enum VSH_EVENT_*
|
|
|
|
* stating how the wait concluded, or -1 on error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vshEventWait(vshControl *ctl)
|
|
|
|
{
|
|
|
|
char buf;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
assert(ctl->eventPipe[0] >= 0);
|
|
|
|
while ((rv = read(ctl->eventPipe[0], &buf, 1)) < 0 && errno == EINTR);
|
|
|
|
if (rv != 1) {
|
|
|
|
char ebuf[1024];
|
|
|
|
|
|
|
|
if (!rv)
|
|
|
|
errno = EPIPE;
|
|
|
|
vshError(ctl, _("failed to determine loop exit status: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vshEventCleanup:
|
|
|
|
* @ctl virsh command struct
|
|
|
|
*
|
|
|
|
* Call at the end of any function that has used vshEventStart(), to
|
|
|
|
* tear down any remaining SIGINT or timeout handlers.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
vshEventCleanup(vshControl *ctl)
|
|
|
|
{
|
|
|
|
if (vshEventFd >= 0) {
|
|
|
|
sigaction(SIGINT, &vshEventOldAction, NULL);
|
|
|
|
vshEventFd = -1;
|
|
|
|
}
|
|
|
|
VIR_FORCE_CLOSE(ctl->eventPipe[0]);
|
|
|
|
VIR_FORCE_CLOSE(ctl->eventPipe[1]);
|
|
|
|
virEventUpdateTimeout(ctl->eventTimerId, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-08 10:23:34 +00:00
|
|
|
/*
|
2013-08-21 09:02:42 +00:00
|
|
|
* Initialize debug settings.
|
2005-12-08 10:23:34 +00:00
|
|
|
*/
|
2013-08-21 09:02:42 +00:00
|
|
|
static void
|
|
|
|
vshInitDebug(vshControl *ctl)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2013-10-09 10:18:15 +00:00
|
|
|
const char *debugEnv;
|
2011-05-09 07:08:06 +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 */
|
2013-10-09 10:18:15 +00:00
|
|
|
debugEnv = virGetEnvAllowSUID("VIRSH_DEBUG");
|
2011-05-09 07:08:06 +00:00
|
|
|
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 */
|
2013-10-09 10:18:15 +00:00
|
|
|
debugEnv = virGetEnvBlockSUID("VIRSH_LOG_FILE");
|
2011-05-09 07:08:06 +00:00
|
|
|
if (debugEnv && *debugEnv) {
|
|
|
|
ctl->logfile = vshStrdup(ctl, debugEnv);
|
2013-08-27 11:19:24 +00:00
|
|
|
vshOpenLogFile(ctl);
|
2011-05-09 07:08:06 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-21 09:02:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize connection.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
vshInit(vshControl *ctl)
|
|
|
|
{
|
2013-08-27 11:19:24 +00:00
|
|
|
/* Since we have the commandline arguments parsed, we need to
|
|
|
|
* re-initialize all the debugging to make it work properly */
|
|
|
|
vshInitDebug(ctl);
|
|
|
|
|
2013-08-21 09:02:42 +00:00
|
|
|
if (ctl->conn)
|
|
|
|
return false;
|
2007-06-06 12:24:31 +00:00
|
|
|
|
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: common code for waiting for an event
I plan to add 'virsh event' to virsh-domain.c and 'virsh
net-event' to virsh-network.c; but as they will share quite
a bit of common boilerplate, it's better to set that up now
in virsh.c.
* tools/virsh.h (_vshControl): Add fields.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup): New
prototypes.
* tools/virsh.c (vshEventFd, vshEventOldAction, vshEventInt)
(vshEventTimeout): New helper variables and functions.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup):
Implement new functions.
(vshInit, vshDeinit, main): Manage event timeout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-14 22:30:23 +00:00
|
|
|
if ((ctl->eventTimerId = virEventAddTimeout(-1, vshEventTimeout, ctl,
|
|
|
|
NULL)) < 0)
|
|
|
|
return false;
|
|
|
|
|
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) {
|
2012-12-13 13:08:01 +00:00
|
|
|
vshReconnect(ctl);
|
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) {
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
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
|
|
|
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.
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
void
|
2007-06-06 12:24:31 +00:00
|
|
|
vshOpenLogFile(vshControl *ctl)
|
|
|
|
{
|
|
|
|
if (ctl->logfile == NULL)
|
|
|
|
return;
|
|
|
|
|
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.
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
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;
|
2013-01-22 14:15:45 +00:00
|
|
|
char *str = NULL;
|
2011-04-30 17:05:43 +00:00
|
|
|
size_t len;
|
2007-06-06 12:24:31 +00:00
|
|
|
const char *lvl = "";
|
Pass a correct pointer type to localtime_r(3).
On 09/04/2012 08:20 AM, Eric Blake wrote:
> tv_sec is required by POSIX to be
> of type time_t; so this is a bug in the OpenBSD header
> [for declaring it as long]
Most likely this problem arose because of the patch I pushed
in gnulib commit e07d7c40f3ca5ec410cf5aa6fa03cfe51e712039.
Previously, gnulib required timeval's tv_sec to be
the same size as time_t. But now, it requires only that
tv_sec be big enough to hold a time_t.
This patch was needed for Emacs. Without the patch, gnulib
replaced struct timeval on OpenBSD, and this messed up
utimens.c, and Emacs wouldn't build.
Alternatively, gnulib could substitute its own struct timeval
for the system's, wrapping every struct timeval-using function
(gettimeofday, futimesat, futimes, lutimes, etc. That'd be
more work, though. And it would introduce some performance
issues with gettimeofday, which is supposed to be fast.
I've been trying to get away from using struct timeval,
and to use the higher-resolution struct timespec instead,
so messing with these obsolescent interfaces has been
lower priority for me. But if someone wants to take the
more-ambitious approach that'd be fine, I expect.
For this particular case, though, how about if we avoid
the problem entirely? libvirt doesn't need to use struct
timeval here at all. It makes libvirt smaller and probably
faster, and it ports to OpenBSD without messing with gnulib.
2012-09-04 17:03:41 +00:00
|
|
|
time_t stTime;
|
2012-09-04 23:35:27 +00:00
|
|
|
struct tm stTm;
|
2007-06-06 12:24:31 +00:00
|
|
|
|
|
|
|
if (ctl->log_fd == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create log format
|
|
|
|
*
|
|
|
|
* [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message
|
|
|
|
*/
|
2012-09-04 23:35:27 +00:00
|
|
|
time(&stTime);
|
|
|
|
localtime_r(&stTime, &stTm);
|
2011-05-09 07:08:06 +00:00
|
|
|
virBufferAsprintf(&buf, "[%d.%02d.%02d %02d:%02d:%02d %s %d] ",
|
2012-09-04 23:35:27 +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;
|
|
|
|
|
2013-08-27 11:07:27 +00:00
|
|
|
VIR_FREE(str);
|
2011-04-30 17:05:43 +00:00
|
|
|
return;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
error:
|
2011-04-30 17:05:43 +00:00
|
|
|
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.
|
|
|
|
*/
|
2012-08-18 03:16:04 +00:00
|
|
|
void
|
2007-06-06 12:24:31 +00:00
|
|
|
vshCloseLogFile(vshControl *ctl)
|
|
|
|
{
|
2012-09-04 23:35:27 +00:00
|
|
|
char ebuf[1024];
|
|
|
|
|
2007-06-06 12:24:31 +00:00
|
|
|
/* 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"),
|
2012-09-04 23:35:27 +00:00
|
|
|
ctl->logfile ? ctl->logfile : "?",
|
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-04 17:51:41 +00:00
|
|
|
#if WITH_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;
|
2014-10-28 18:38:04 +00:00
|
|
|
static const vshCmdDef *cmd;
|
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;
|
|
|
|
}
|
|
|
|
|
2013-10-28 13:38:46 +00:00
|
|
|
# define VIRSH_HISTSIZE_MAX 500000
|
2005-12-08 10:23:34 +00:00
|
|
|
|
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;
|
2013-10-28 13:38:46 +00:00
|
|
|
int max_history = 500;
|
|
|
|
const char *histsize_str;
|
2010-01-03 14:45:10 +00:00
|
|
|
|
2013-11-18 15:39:32 +00:00
|
|
|
/* Allow conditional parsing of the ~/.inputrc file.
|
|
|
|
* Work around ancient readline 4.1 (hello Mac OS X),
|
|
|
|
* which declared it as 'char *' instead of 'const char *'.
|
|
|
|
*/
|
|
|
|
rl_readline_name = (char *) "virsh";
|
2005-12-08 10:23:34 +00:00
|
|
|
|
|
|
|
/* 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 */
|
2013-10-28 13:38:46 +00:00
|
|
|
if ((histsize_str = virGetEnvBlockSUID("VIRSH_HISTSIZE"))) {
|
|
|
|
if (virStrToLong_i(histsize_str, NULL, 10, &max_history) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Bad $VIRSH_HISTSIZE value."));
|
|
|
|
VIR_FREE(userdir);
|
|
|
|
return -1;
|
|
|
|
} else if (max_history > VIRSH_HISTSIZE_MAX || max_history < 0) {
|
|
|
|
vshError(ctl, _("$VIRSH_HISTSIZE value should be between 0 and %d"),
|
|
|
|
VIRSH_HISTSIZE_MAX);
|
|
|
|
VIR_FREE(userdir);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stifle_history(max_history);
|
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
|
|
|
}
|
|
|
|
|
2013-10-04 17:51:41 +00:00
|
|
|
#else /* !WITH_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
|
|
|
}
|
|
|
|
|
2013-10-04 17:51:41 +00:00
|
|
|
#endif /* !WITH_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
|
|
|
*/
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +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;
|
2013-03-26 09:54:55 +00:00
|
|
|
virConnectUnregisterCloseCallback(ctl->conn, vshCatchDisconnect);
|
|
|
|
ret = virConnectClose(ctl->conn);
|
|
|
|
if (ret < 0)
|
|
|
|
vshError(ctl, "%s", _("Failed to disconnect from the hypervisor"));
|
|
|
|
else if (ret > 0)
|
|
|
|
vshError(ctl, "%s", _("One or more references were leaked after "
|
|
|
|
"disconnect from the hypervisor"));
|
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);
|
|
|
|
|
virsh: common code for waiting for an event
I plan to add 'virsh event' to virsh-domain.c and 'virsh
net-event' to virsh-network.c; but as they will share quite
a bit of common boilerplate, it's better to set that up now
in virsh.c.
* tools/virsh.h (_vshControl): Add fields.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup): New
prototypes.
* tools/virsh.c (vshEventFd, vshEventOldAction, vshEventInt)
(vshEventTimeout): New helper variables and functions.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup):
Implement new functions.
(vshInit, vshDeinit, main): Manage event timeout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-14 22:30:23 +00:00
|
|
|
if (ctl->eventTimerId != -1)
|
|
|
|
virEventRemoveTimeout(ctl->eventTimerId);
|
|
|
|
|
2011-10-11 13:05:52 +00:00
|
|
|
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
|
|
|
|
*/
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
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"
|
|
|
|
" -d | --debug=NUM debug level [0-4]\n"
|
2014-03-06 15:53:53 +00:00
|
|
|
" -e | --escape <char> set escape sequence for console\n"
|
2008-12-08 13:14:48 +00:00
|
|
|
" -h | --help this help\n"
|
2014-03-06 16:20:11 +00:00
|
|
|
" -k | --keepalive-interval=NUM\n"
|
|
|
|
" keepalive interval in seconds, 0 for disable\n"
|
|
|
|
" -K | --keepalive-count=NUM\n"
|
|
|
|
" number of possible missed keepalive messages\n"
|
2014-03-06 15:53:53 +00:00
|
|
|
" -l | --log=FILE output logging to file\n"
|
2008-12-08 13:14:48 +00:00
|
|
|
" -q | --quiet quiet mode\n"
|
2014-03-06 15:53:53 +00:00
|
|
|
" -r | --readonly connect readonly\n"
|
2008-12-08 13:14:48 +00:00
|
|
|
" -t | --timing print timing information\n"
|
2011-11-22 16:08:05 +00:00
|
|
|
" -v short version\n"
|
|
|
|
" -V long version\n"
|
|
|
|
" --version[=TYPE] version, TYPE is short or long (default short)\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
|
2012-09-09 22:07:28 +00:00
|
|
|
vshPrint(ctl, " QEMU/KVM");
|
2010-11-08 14:03:32 +00:00
|
|
|
#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
|
2014-06-10 18:25:10 +00:00
|
|
|
#ifdef WITH_BHYVE
|
|
|
|
vshPrint(ctl, " Bhyve");
|
|
|
|
#endif
|
2010-11-08 14:03:32 +00:00
|
|
|
#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_NETWORK
|
|
|
|
vshPrint(ctl, " Network");
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_BRIDGE
|
|
|
|
vshPrint(ctl, " Bridging");
|
|
|
|
#endif
|
2012-09-18 01:27:06 +00:00
|
|
|
#if defined(WITH_INTERFACE)
|
2012-06-26 18:31:31 +00:00
|
|
|
vshPrint(ctl, " Interface");
|
2012-09-18 01:27:06 +00:00
|
|
|
# if defined(WITH_NETCF)
|
|
|
|
vshPrint(ctl, " netcf");
|
2012-09-20 14:24:47 +00:00
|
|
|
# elif defined(WITH_UDEV)
|
2012-10-06 19:20:25 +00:00
|
|
|
vshPrint(ctl, " udev");
|
2012-09-18 01:27:06 +00:00
|
|
|
# endif
|
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");
|
2013-12-12 03:08:10 +00:00
|
|
|
#endif
|
|
|
|
#ifdef WITH_STORAGE_GLUSTER
|
|
|
|
vshPrint(ctl, " Gluster");
|
2010-11-08 14:03:32 +00:00
|
|
|
#endif
|
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
|
2012-07-23 03:57:53 +00:00
|
|
|
vshPrint(ctl, "%s", _(" Miscellaneous:"));
|
2012-09-09 22:07:27 +00:00
|
|
|
#ifdef WITH_LIBVIRTD
|
|
|
|
vshPrint(ctl, " Daemon");
|
|
|
|
#endif
|
2012-07-23 03:57:53 +00:00
|
|
|
#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
|
2013-10-04 17:51:41 +00:00
|
|
|
#if WITH_READLINE
|
2012-07-23 03:57:53 +00:00
|
|
|
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]
|
|
|
|
*
|
|
|
|
*/
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
static bool
|
2012-07-23 03:57:53 +00:00
|
|
|
vshParseArgv(vshControl *ctl, int argc, char **argv)
|
|
|
|
{
|
2014-03-06 16:20:11 +00:00
|
|
|
int arg, len, debug, keepalive;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-04-29 17:12:17 +00:00
|
|
|
int longindex = -1;
|
2012-07-23 03:57:53 +00:00
|
|
|
struct option opt[] = {
|
2014-03-06 15:53:53 +00:00
|
|
|
{"connect", required_argument, NULL, 'c'},
|
2012-07-23 03:57:53 +00:00
|
|
|
{"debug", required_argument, NULL, 'd'},
|
2014-03-06 15:53:53 +00:00
|
|
|
{"escape", required_argument, NULL, 'e'},
|
2012-07-23 03:57:53 +00:00
|
|
|
{"help", no_argument, NULL, 'h'},
|
2014-03-06 16:20:11 +00:00
|
|
|
{"keepalive-interval", required_argument, NULL, 'k'},
|
|
|
|
{"keepalive-count", required_argument, NULL, 'K'},
|
2014-03-06 15:53:53 +00:00
|
|
|
{"log", required_argument, NULL, 'l'},
|
2012-07-23 03:57:53 +00:00
|
|
|
{"quiet", no_argument, NULL, 'q'},
|
2014-03-06 15:53:53 +00:00
|
|
|
{"readonly", no_argument, NULL, 'r'},
|
2012-07-23 03:57:53 +00:00
|
|
|
{"timing", no_argument, NULL, 't'},
|
|
|
|
{"version", optional_argument, NULL, 'v'},
|
|
|
|
{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. */
|
2014-03-06 16:20:11 +00:00
|
|
|
while ((arg = getopt_long(argc, argv, "+:c:d:e:hk:K:l:qrtvV", opt, &longindex)) != -1) {
|
2012-07-23 03:57:53 +00:00
|
|
|
switch (arg) {
|
2014-03-06 15:53:53 +00:00
|
|
|
case 'c':
|
|
|
|
VIR_FREE(ctl->name);
|
|
|
|
ctl->name = vshStrdup(ctl, optarg);
|
|
|
|
break;
|
2012-07-23 03:57:53 +00:00
|
|
|
case 'd':
|
2012-07-26 14:05:51 +00:00
|
|
|
if (virStrToLong_i(optarg, NULL, 10, &debug) < 0) {
|
2013-04-29 17:12:17 +00:00
|
|
|
vshError(ctl, _("option %s takes a numeric argument"),
|
|
|
|
longindex == -1 ? "-d" : "--debug");
|
2012-07-23 03:57:53 +00:00
|
|
|
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;
|
2014-03-06 15:53:53 +00:00
|
|
|
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;
|
2012-07-23 03:57:53 +00:00
|
|
|
case 'h':
|
|
|
|
vshUsage();
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
break;
|
2014-03-06 16:20:11 +00:00
|
|
|
case 'k':
|
2014-08-27 14:20:29 +00:00
|
|
|
if (virStrToLong_i(optarg, NULL, 0, &keepalive) < 0) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("Invalid value for option %s"),
|
|
|
|
longindex == -1 ? "-k" : "--keepalive-interval");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keepalive < 0) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("option %s requires a positive integer argument"),
|
2014-03-06 16:20:11 +00:00
|
|
|
longindex == -1 ? "-k" : "--keepalive-interval");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
ctl->keepalive_interval = keepalive;
|
|
|
|
break;
|
|
|
|
case 'K':
|
2014-08-27 14:20:29 +00:00
|
|
|
if (virStrToLong_i(optarg, NULL, 0, &keepalive) < 0) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("Invalid value for option %s"),
|
|
|
|
longindex == -1 ? "-K" : "--keepalive-count");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keepalive < 0) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("option %s requires a positive integer argument"),
|
2014-03-06 16:20:11 +00:00
|
|
|
longindex == -1 ? "-K" : "--keepalive-count");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
ctl->keepalive_count = keepalive;
|
|
|
|
break;
|
2014-03-06 15:53:53 +00:00
|
|
|
case 'l':
|
|
|
|
vshCloseLogFile(ctl);
|
|
|
|
ctl->logfile = vshStrdup(ctl, optarg);
|
|
|
|
vshOpenLogFile(ctl);
|
|
|
|
break;
|
2012-07-23 03:57:53 +00:00
|
|
|
case 'q':
|
|
|
|
ctl->quiet = true;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
ctl->timing = true;
|
|
|
|
break;
|
2014-03-06 15:53:53 +00:00
|
|
|
case 'r':
|
|
|
|
ctl->readonly = true;
|
2012-07-23 03:57:53 +00:00
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
if (STRNEQ_NULLABLE(optarg, "long")) {
|
|
|
|
puts(VERSION);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
case 'V':
|
|
|
|
vshShowVersion(ctl);
|
|
|
|
exit(EXIT_SUCCESS);
|
2013-02-19 08:50:59 +00:00
|
|
|
case ':':
|
2013-04-29 17:12:17 +00:00
|
|
|
for (i = 0; opt[i].name != NULL; i++) {
|
2013-05-01 15:07:56 +00:00
|
|
|
if (opt[i].val == optopt)
|
|
|
|
break;
|
2013-04-29 17:12:17 +00:00
|
|
|
}
|
2013-05-01 15:07:56 +00:00
|
|
|
if (opt[i].name)
|
|
|
|
vshError(ctl, _("option '-%c'/'--%s' requires an argument"),
|
|
|
|
optopt, opt[i].name);
|
|
|
|
else
|
|
|
|
vshError(ctl, _("option '-%c' requires an argument"), optopt);
|
|
|
|
exit(EXIT_FAILURE);
|
2013-02-19 08:50:59 +00:00
|
|
|
case '?':
|
2013-04-29 17:12:17 +00:00
|
|
|
if (optopt)
|
|
|
|
vshError(ctl, _("unsupported option '-%c'. See --help."), optopt);
|
|
|
|
else
|
|
|
|
vshError(ctl, _("unsupported option '%s'. See --help."), argv[optind - 1]);
|
2013-02-19 08:50:59 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2012-07-23 03:57:53 +00:00
|
|
|
default:
|
2013-02-19 08:50:59 +00:00
|
|
|
vshError(ctl, _("unknown option"));
|
2012-07-23 03:57:53 +00:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2013-04-29 17:12:17 +00:00
|
|
|
longindex = -1;
|
2012-07-23 03:57:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const vshCmdDef virshCmds[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "cd",
|
|
|
|
.handler = cmdCd,
|
|
|
|
.opts = opts_cd,
|
|
|
|
.info = info_cd,
|
|
|
|
.flags = VSH_CMD_FLAG_NOCONNECT
|
2013-03-27 13:22:47 +00:00
|
|
|
},
|
|
|
|
{.name = "connect",
|
|
|
|
.handler = cmdConnect,
|
|
|
|
.opts = opts_connect,
|
|
|
|
.info = info_connect,
|
|
|
|
.flags = VSH_CMD_FLAG_NOCONNECT
|
2013-02-07 15:25:10 +00:00
|
|
|
},
|
|
|
|
{.name = "echo",
|
|
|
|
.handler = cmdEcho,
|
|
|
|
.opts = opts_echo,
|
|
|
|
.info = info_echo,
|
|
|
|
.flags = VSH_CMD_FLAG_NOCONNECT
|
|
|
|
},
|
|
|
|
{.name = "exit",
|
|
|
|
.handler = cmdQuit,
|
|
|
|
.opts = NULL,
|
|
|
|
.info = info_quit,
|
|
|
|
.flags = VSH_CMD_FLAG_NOCONNECT
|
|
|
|
},
|
|
|
|
{.name = "help",
|
|
|
|
.handler = cmdHelp,
|
|
|
|
.opts = opts_help,
|
|
|
|
.info = info_help,
|
|
|
|
.flags = VSH_CMD_FLAG_NOCONNECT
|
|
|
|
},
|
|
|
|
{.name = "pwd",
|
|
|
|
.handler = cmdPwd,
|
|
|
|
.opts = NULL,
|
|
|
|
.info = info_pwd,
|
|
|
|
.flags = VSH_CMD_FLAG_NOCONNECT
|
|
|
|
},
|
|
|
|
{.name = "quit",
|
|
|
|
.handler = cmdQuit,
|
|
|
|
.opts = NULL,
|
|
|
|
.info = info_quit,
|
|
|
|
.flags = VSH_CMD_FLAG_NOCONNECT
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 03:57:53 +00:00
|
|
|
};
|
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;
|
2013-10-09 10:18:15 +00:00
|
|
|
const 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;
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
ctl->escapeChar = "^]"; /* Same default as telnet */
|
2014-03-06 16:20:11 +00:00
|
|
|
|
|
|
|
/* In order to distinguish default from setting to 0 */
|
|
|
|
ctl->keepalive_interval = -1;
|
|
|
|
ctl->keepalive_count = -1;
|
|
|
|
|
virsh: common code for waiting for an event
I plan to add 'virsh event' to virsh-domain.c and 'virsh
net-event' to virsh-network.c; but as they will share quite
a bit of common boilerplate, it's better to set that up now
in virsh.c.
* tools/virsh.h (_vshControl): Add fields.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup): New
prototypes.
* tools/virsh.c (vshEventFd, vshEventOldAction, vshEventInt)
(vshEventTimeout): New helper variables and functions.
(vshEventStart, vshEventWait, vshEventDone, vshEventCleanup):
Implement new functions.
(vshInit, vshDeinit, main): Manage event timeout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-14 22:30:23 +00:00
|
|
|
ctl->eventPipe[0] = -1;
|
|
|
|
ctl->eventPipe[1] = -1;
|
|
|
|
ctl->eventTimerId = -1;
|
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
|
|
|
}
|
|
|
|
|
2013-08-29 08:36:00 +00:00
|
|
|
if (isatty(STDIN_FILENO)) {
|
|
|
|
ctl->istty = true;
|
|
|
|
|
2013-09-04 21:57:30 +00:00
|
|
|
#ifndef WIN32
|
2013-08-29 08:36:00 +00:00
|
|
|
if (tcgetattr(STDIN_FILENO, &ctl->termattr) < 0)
|
|
|
|
ctl->istty = false;
|
2013-09-04 21:57:30 +00:00
|
|
|
#endif
|
2013-08-29 08:36:00 +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;
|
|
|
|
}
|
|
|
|
|
2014-04-24 14:57:36 +00:00
|
|
|
virFileActivateDirOverride(argv[0]);
|
|
|
|
|
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
|
|
|
|
2014-11-13 14:20:51 +00:00
|
|
|
if ((defaultConn = virGetEnvBlockSUID("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
|
|
|
|
2013-08-21 09:02:42 +00:00
|
|
|
vshInitDebug(ctl);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2013-08-21 09:02:42 +00:00
|
|
|
if (!vshParseArgv(ctl, argc, argv) ||
|
|
|
|
!vshInit(ctl)) {
|
2007-12-01 15:45:25 +00:00
|
|
|
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) {
|
2013-10-04 17:51:41 +00:00
|
|
|
#if WITH_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
|
|
|
}
|