On 03/08/2011 09:29 AM, Michal Privoznik wrote:
This is needed to detect situations when optional argument was
specified with non-integer value: '--int-opt foo'. To keep functions
uniform vshCommandOptString function was also changed, because it
returns tri-state value as well. Given result pointer is updated only
in case of success. If parsing fails, result is not updated at all.
---
tools/virsh.c | 613 ++++++++++++++++++++++++++-------------------------------
1 files changed, 280 insertions(+), 333 deletions(-)
Git complained about some added whitespace; 'make syntax-check' would
have caught that in advance.
But we finally arrived at my vision of making these parse functions
useful! And the diffstat shows a net reduction in lines!
@@ -781,7 +779,7 @@ cmdConsole(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- name = vshCommandOptString(cmd, "devname", NULL);
+ vshCommandOptString(cmd, "devname", &name);
Hmm, so you didn't add the ATTRIBUTE_RETURN_CHECK, after all. I guess
that's okay for now.
@@ -2300,7 +2287,10 @@ cmdFreecell(vshControl *ctl, const vshCmd
*cmd)
if (!vshConnectionUsability(ctl, ctl->conn))
return FALSE;
- cell = vshCommandOptInt(cmd, "cellno", &cell_given);
+ if ( (cell_given = vshCommandOptInt(cmd, "cellno", &cell)) < 0) {
+ vshError(ctl, "%s", _("cell number has to be a number"));
+ goto cleanup;
+ }
Ouch - you didn't pre-initialize cell, but there is still a codepath
where you check if (cell == -1). Too bad gcc didn't flag it.
@@ -2862,7 +2850,7 @@ cmdSetvcpus(vshControl *ctl, const vshCmd
*cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- count = vshCommandOptInt(cmd, "count", &count);
+ vshCommandOptInt(cmd, "count", &count);
We really should be adding ATTRIBUTE_RETURN_CHECK, and flagging parse
errors. Otherwise, you end up using uninitialized data for count on a
parse error.
Basically, anywhere we used to give an error for !found, we now give an
error for result <= 0; and anywhere we didn't care about found, we now
give an error for result < 0.
@@ -2984,7 +2976,11 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd
*cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- kilobytes = vshCommandOptInt(cmd, "kilobytes", &kilobytes);
+ if (vshCommandOptInt(cmd, "kilobytes", &kilobytes) < 0) {
+ vshError(ctl, "%s", _("memory sizehas to be a number"));
s/sizehas/size has/
@@ -3055,23 +3051,19 @@ cmdMemtune(vshControl * ctl, const vshCmd *
cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- hard_limit =
- vshCommandOptLongLong(cmd, "hard-limit", NULL);
+ vshCommandOptLongLong(cmd, "hard-limit", (unsigned long long*)
&hard_limit);
Yuck - why are we casting here? Oh, because you set
vshCommandOptLongLong to take ull* instead of ll*.
/*
- * Returns option as INT
+ * @cmd command reference
+ * @name option name
+ * @value result
+ *
+ * Convert option to int
+ * Return value:
+ * >0 if option found and valid (@value updated)
+ * 0 in case option not found (@value untouched)
+ * <0 in all other cases (@value untouched)
*/
static int
-vshCommandOptInt(const vshCmd *cmd, const char *name, int *found)
+vshCommandOptInt(const vshCmd *cmd, const char *name, int *value)
{
vshCmdOpt *arg = vshCommandOpt(cmd, name);
- int res = 0, num_found = FALSE;
+ int ret = 0, num;
char *end_p = NULL;
if ((arg != NULL) && (arg->data != NULL)) {
- res = strtol(arg->data, &end_p, 10);
- if ((arg->data == end_p) || (*end_p!= 0))
- num_found = FALSE;
- else
- num_found = TRUE;
+ num = strtol(arg->data, &end_p, 10);
+ ret = -1;
+ if ((arg->data != end_p) && (*end_p == 0) && value) {
This check for non-NULL value is redundant, given that you already used
the compiler ATTRIBUTE_NONNULL to guarantee that (at least, for decently
smart compilers; it's a shame that gcc only warns for literal NULL and
that you have to use clang to catch other null parameters via data-flow
checks).
Here's what I'm squashing in before pushing:
diff --git i/tools/virsh.c w/tools/virsh.c
index d4d0949..14c6d6b 100644
--- i/tools/virsh.c
+++ w/tools/virsh.c
@@ -253,14 +253,16 @@ static int vshCmdGrpHelp(vshControl *ctl, const
char *name);
static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
static int vshCommandOptInt(const vshCmd *cmd, const char *name, int
*value)
- ATTRIBUTE_NONNULL(3);
+ ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static int vshCommandOptUL(const vshCmd *cmd, const char *name,
- unsigned long *value) ATTRIBUTE_NONNULL(3);
+ unsigned long *value)
+ ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static int vshCommandOptString(const vshCmd *cmd, const char *name,
- const char **value) ATTRIBUTE_NONNULL(3);
+ const char **value)
+ ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static int vshCommandOptLongLong(const vshCmd *cmd, const char *name,
- unsigned long long *value)
- ATTRIBUTE_NONNULL(3);
+ long long *value)
+ ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
static int vshCommandOptBool(const vshCmd *cmd, const char *name);
static char *vshCommandOptArgv(const vshCmd *cmd, int count);
@@ -780,7 +782,8 @@ cmdConsole(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- vshCommandOptString(cmd, "devname", &name);
+ if (vshCommandOptString(cmd, "devname", &name) < 0)
+ return FALSE;
ret = cmdRunConsole(ctl, dom, name);
@@ -2272,7 +2275,7 @@ cmdFreecell(vshControl *ctl, const vshCmd *cmd)
{
int func_ret = FALSE;
int ret;
- int cell, cell_given;
+ int cell = -1, cell_given;
unsigned long long memory;
xmlNodePtr *nodes = NULL;
unsigned long nodes_cnt;
@@ -2406,7 +2409,8 @@ cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd)
const char *type = NULL;
int vcpus;
- vshCommandOptString(cmd, "type", &type);
+ if (vshCommandOptString(cmd, "type", &type) < 0)
+ return FALSE;
if (!vshConnectionUsability(ctl, ctl->conn))
return FALSE;
@@ -2851,7 +2855,8 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- vshCommandOptInt(cmd, "count", &count);
+ if (vshCommandOptInt(cmd, "count", &count) < 0)
+ return FALSE;
if (!flags) {
if (virDomainSetVcpus(dom, count) != 0) {
@@ -2978,7 +2983,7 @@ cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
return FALSE;
if (vshCommandOptInt(cmd, "kilobytes", &kilobytes) < 0) {
- vshError(ctl, "%s", _("memory sizehas to be a number"));
+ vshError(ctl, "%s", _("memory size has to be a number"));
return FALSE;
}
@@ -3040,7 +3045,8 @@ static int
cmdMemtune(vshControl * ctl, const vshCmd * cmd)
{
virDomainPtr dom;
- long long hard_limit = 0, soft_limit = 0, swap_hard_limit = 0,
min_guarantee = 0;
+ long long hard_limit = 0, soft_limit = 0, swap_hard_limit = 0;
+ long long min_guarantee = 0;
int nparams = 0;
unsigned int i = 0;
virMemoryParameterPtr params = NULL, temp = NULL;
@@ -3052,19 +3058,24 @@ cmdMemtune(vshControl * ctl, const vshCmd * cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- vshCommandOptLongLong(cmd, "hard-limit", (unsigned long long*)
&hard_limit);
+ if (vshCommandOptLongLong(cmd, "hard-limit", &hard_limit) < 0 ||
+ vshCommandOptLongLong(cmd, "soft-limit", &soft_limit) < 0 ||
+ vshCommandOptLongLong(cmd, "swap-hard-limit", &swap_hard_limit)
< 0 ||
+ vshCommandOptLongLong(cmd, "min-guarantee", &min_guarantee) < 0)
{
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto cleanup;
+ }
+
if (hard_limit)
nparams++;
- vshCommandOptLongLong(cmd, "soft-limit", (unsigned long long*)
&soft_limit);
if (soft_limit)
nparams++;
- vshCommandOptLongLong(cmd, "swap-hard-limit", (unsigned long long*)
&swap_hard_limit);
if (swap_hard_limit)
nparams++;
- vshCommandOptLongLong(cmd, "min-guarantee", (unsigned long long*)
&min_guarantee);
if (min_guarantee)
nparams++;
@@ -3317,8 +3328,9 @@ cmdDomXMLFromNative(vshControl *ctl, const vshCmd
*cmd)
if (!vshConnectionUsability(ctl, ctl->conn))
return FALSE;
- vshCommandOptString(cmd, "format", &format);
- vshCommandOptString(cmd, "config", &configFile);
+ if (vshCommandOptString(cmd, "format", &format) < 0 ||
+ vshCommandOptString(cmd, "config", &configFile) < 0)
+ return FALSE;
if (virFileReadAll(configFile, 1024*1024, &configData) < 0)
return FALSE;
@@ -3362,8 +3374,9 @@ cmdDomXMLToNative(vshControl *ctl, const vshCmd *cmd)
if (!vshConnectionUsability(ctl, ctl->conn))
return FALSE;
- vshCommandOptString(cmd, "format", &format);
- vshCommandOptString(cmd, "xml", &xmlFile);
+ if (vshCommandOptString(cmd, "format", &format) < 0
+ || vshCommandOptString(cmd, "xml", &xmlFile) < 0)
+ return FALSE;
if (virFileReadAll(xmlFile, 1024*1024, &xmlData) < 0)
return FALSE;
@@ -3540,13 +3553,11 @@ doMigrate (void *opaque)
if (!(dom = vshCommandOptDomain (ctl, cmd, NULL)))
goto out;
- if (vshCommandOptString (cmd, "desturi", &desturi) <= 0)
+ if (vshCommandOptString(cmd, "desturi", &desturi) <= 0 ||
+ vshCommandOptString(cmd, "migrateuri", &migrateuri) < 0 ||
+ vshCommandOptString(cmd, "dname", &dname) < 0)
goto out;
- vshCommandOptString (cmd, "migrateuri", &migrateuri);
-
- vshCommandOptString (cmd, "dname", &dname);
-
if (vshCommandOptBool (cmd, "live"))
flags |= VIR_MIGRATE_LIVE;
if (vshCommandOptBool (cmd, "p2p"))
@@ -3794,8 +3805,8 @@ cmdMigrateSetMaxDowntime(vshControl *ctl, const
vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
- vshCommandOptLongLong(cmd, "downtime", (unsigned long long*)
&downtime);
- if (downtime < 1) {
+ if (vshCommandOptLongLong(cmd, "downtime", &downtime) < 0 ||
+ downtime < 1) {
vshError(ctl, "%s", _("migrate: Invalid downtime"));
goto done;
}
@@ -5343,12 +5354,13 @@ static int buildPoolXML(const vshCmd *cmd, const
char **retname, char **xml) {
if (vshCommandOptString(cmd, "type", &type) <= 0)
goto cleanup;
- vshCommandOptString(cmd, "source-host", &srcHost);
- vshCommandOptString(cmd, "source-path", &srcPath);
- vshCommandOptString(cmd, "source-dev", &srcDev);
- vshCommandOptString(cmd, "source-name", &srcName);
- vshCommandOptString(cmd, "source-format", &srcFormat);
- vshCommandOptString(cmd, "target", &target);
+ if (vshCommandOptString(cmd, "source-host", &srcHost) < 0 ||
+ vshCommandOptString(cmd, "source-path", &srcPath) < 0 ||
+ vshCommandOptString(cmd, "source-dev", &srcDev) < 0 ||
+ vshCommandOptString(cmd, "source-name", &srcName) < 0 ||
+ vshCommandOptString(cmd, "source-format", &srcFormat) < 0 ||
+ vshCommandOptString(cmd, "target", &target) < 0)
+ goto cleanup;
virBufferVSprintf(&buf, "<pool type='%s'>\n", type);
virBufferVSprintf(&buf, " <name>%s</name>\n", name);
@@ -6150,18 +6162,23 @@ cmdPoolDiscoverSourcesAs(vshControl * ctl, const
vshCmd * cmd ATTRIBUTE_UNUSED)
char *srcList;
const char *initiator = NULL;
- if (vshCommandOptString(cmd, "type", &type) <= 0)
+ if (vshCommandOptString(cmd, "type", &type) <= 0 ||
+ vshCommandOptString(cmd, "host", &host) < 0 ||
+ vshCommandOptString(cmd, "initiator", &initiator) < 0)
return FALSE;
- vshCommandOptString(cmd, "host", &host);
- vshCommandOptString(cmd, "initiator", &initiator);
if (!vshConnectionUsability(ctl, ctl->conn))
return FALSE;
if (host) {
const char *port = NULL;
- vshCommandOptString(cmd, "port", &port);
virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (vshCommandOptString(cmd, "port", &port) < 0) {
+ vshError(ctl, "%s", _("missing argument"));
+ virBufferFreeAndReset(&buf);
+ return FALSE;
+ }
virBufferAddLit(&buf, "<source>\n");
virBufferVSprintf(&buf, " <host name='%s'", host);
if (port)
@@ -6219,7 +6236,8 @@ cmdPoolDiscoverSources(vshControl * ctl, const
vshCmd * cmd ATTRIBUTE_UNUSED)
if (vshCommandOptString(cmd, "type", &type) <= 0)
return FALSE;
- vshCommandOptString(cmd, "srcSpec", &srcSpecFile);
+ if (vshCommandOptString(cmd, "srcSpec", &srcSpecFile) < 0)
+ return FALSE;
if (!vshConnectionUsability(ctl, ctl->conn))
return FALSE;
@@ -6485,9 +6503,13 @@ cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd)
(cmdVolSize(allocationStr, &allocation) < 0))
vshError(ctl, _("Malformed size %s"), allocationStr);
- vshCommandOptString(cmd, "format", &format);
- vshCommandOptString(cmd, "backing-vol", &snapshotStrVol);
- vshCommandOptString(cmd, "backing-vol-format", &snapshotStrFormat);
+ if (vshCommandOptString(cmd, "format", &format) < 0 ||
+ vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 ||
+ vshCommandOptString(cmd, "backing-vol-format",
+ &snapshotStrFormat) < 0) {
+ vshError(ctl, "%s", _("missing argument"));
+ }
+
virBufferAddLit(&buf, "<volume>\n");
virBufferVSprintf(&buf, " <name>%s</name>\n", name);
@@ -8686,11 +8708,12 @@ cmdAttachInterface(vshControl *ctl, const vshCmd
*cmd)
if (vshCommandOptString(cmd, "type", &type) <= 0)
goto cleanup;
- vshCommandOptString(cmd, "source", &source);
- vshCommandOptString(cmd, "target", &target);
- vshCommandOptString(cmd, "mac", &mac);
- vshCommandOptString(cmd, "script", &script);
- vshCommandOptString(cmd, "model", &model);
+ if (vshCommandOptString(cmd, "source", &source) < 0 ||
+ vshCommandOptString(cmd, "target", &target) < 0 ||
+ vshCommandOptString(cmd, "mac", &mac) < 0 ||
+ vshCommandOptString(cmd, "script", &script) < 0 ||
+ vshCommandOptString(cmd, "model", &model) < 0)
+ goto cleanup;
/* check interface type */
if (STREQ(type, "network")) {
@@ -8796,7 +8819,8 @@ cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
if (vshCommandOptString(cmd, "type", &type) <= 0)
goto cleanup;
- vshCommandOptString(cmd, "mac", &mac);
+ if (vshCommandOptString(cmd, "mac", &mac) < 0)
+ goto cleanup;
doc = virDomainGetXMLDesc(dom, 0);
if (!doc)
@@ -8941,11 +8965,13 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
if (vshCommandOptString(cmd, "target", &target) <= 0)
goto cleanup;
- vshCommandOptString(cmd, "driver", &driver);
- vshCommandOptString(cmd, "subdriver", &subdriver);
- vshCommandOptString(cmd, "type", &type);
- vshCommandOptString(cmd, "mode", &mode);
- vshCommandOptString(cmd, "sourcetype", &stype);
+ if (vshCommandOptString(cmd, "driver", &driver) < 0 ||
+ vshCommandOptString(cmd, "subdriver", &subdriver) < 0 ||
+ vshCommandOptString(cmd, "type", &type) < 0 ||
+ vshCommandOptString(cmd, "mode", &mode) < 0 ||
+ vshCommandOptString(cmd, "sourcetype", &stype) < 0) {
+ goto cleanup;
+ }
if (!stype) {
if (driver && (STREQ(driver, "file") || STREQ(driver,
"tap")))
@@ -10752,7 +10778,7 @@ vshCommandOptInt(const vshCmd *cmd, const char
*name, int *value)
if ((arg != NULL) && (arg->data != NULL)) {
num = strtol(arg->data, &end_p, 10);
ret = -1;
- if ((arg->data != end_p) && (*end_p == 0) && value) {
+ if ((arg->data != end_p) && (*end_p == 0)) {
*value = num;
ret = 1;
}
@@ -10775,7 +10801,7 @@ vshCommandOptUL(const vshCmd *cmd, const char
*name, unsigned long *value)
if ((arg != NULL) && (arg->data != NULL)) {
num = strtoul(arg->data, &end_p, 10);
ret = -1;
- if ((arg->data != end_p) && (*end_p == 0) && value) {
+ if ((arg->data != end_p) && (*end_p == 0)) {
*value = num;
ret = 1;
}
@@ -10801,7 +10827,7 @@ vshCommandOptString(const vshCmd *cmd, const
char *name, const char **value)
ret = 1;
}
} else if (arg->def && ((arg->def->flag) & VSH_OFLAG_REQ))
{
- vshError(NULL, _("Missing required option '%s'"),
name);
+ vshError(NULL, _("Missing required option '%s'"), name);
}
}
@@ -10814,7 +10840,7 @@ vshCommandOptString(const vshCmd *cmd, const
char *name, const char **value)
*/
static int
vshCommandOptLongLong(const vshCmd *cmd, const char *name,
- unsigned long long *value)
+ long long *value)
{
vshCmdOpt *arg = vshCommandOpt(cmd, name);
int ret = 0;
@@ -10824,7 +10850,7 @@ vshCommandOptLongLong(const vshCmd *cmd, const
char *name,
if ((arg != NULL) && (arg->data != NULL)) {
num = strtoll(arg->data, &end_p, 10);
ret = -1;
- if ((arg->data != end_p) && (*end_p == 0) && value) {
+ if ((arg->data != end_p) && (*end_p == 0)) {
*value = num;
ret = 1;
}
--
Eric Blake eblake(a)redhat.com +1-801-349-2682
Libvirt virtualization library
http://libvirt.org