On Tue, Mar 31, 2009 at 12:09:21PM +0200, Daniel Veillard wrote:
> +#define MAX_INDENT 100
> +
> +static void
> +cmdNodeListDevicesPrint(vshControl *ctl,
> + char **devices,
> + char **parents,
> + int num_devices,
> + int devid,
> + int lastdev,
> + unsigned int depth,
> + char *indent)
> +{
> + int i;
> + int nextlastdev = -1;
Before even modifying indent[depth] here I would check that
depth + 2 < MAX_INDENT and abort on an error here,
Actually we have a 4 level indent here. This is all getting
rather confusing, so I've separated the depth we've descended
from the indentation used, and defined the buffer to be a
multiple of max depth.
Also fixed a minor leak in the virNodeDeviceGetParent() impl
of the remote driver. In the wonderful world of XDR, we have
to free the char**, but not the char *.
Daniel
diff -r 9a7241cce8db src/remote_internal.c
--- a/src/remote_internal.c Tue Mar 31 11:43:13 2009 +0100
+++ b/src/remote_internal.c Tue Mar 31 14:55:22 2009 +0100
@@ -4821,6 +4821,7 @@ static char *remoteNodeDeviceGetParent(v
/* Caller frees. */
rv = ret.parent ? *ret.parent : NULL;
+ VIR_FREE(ret.parent);
done:
remoteDriverUnlock(priv);
diff -r 9a7241cce8db src/virsh.c
--- a/src/virsh.c Tue Mar 31 11:43:13 2009 +0100
+++ b/src/virsh.c Tue Mar 31 14:55:22 2009 +0100
@@ -4391,16 +4391,96 @@ static const vshCmdInfo info_node_list_d
};
static const vshCmdOptDef opts_node_list_devices[] = {
+ {"tree", VSH_OT_BOOL, 0, gettext_noop("list devices in a
tree")},
{"cap", VSH_OT_STRING, VSH_OFLAG_NONE, gettext_noop("capability
name")},
{NULL, 0, 0, NULL}
};
+#define MAX_DEPTH 100
+#define INDENT_SIZE 4
+#define INDENT_BUFLEN ((MAX_DEPTH * INDENT_SIZE) + 1)
+
+static void
+cmdNodeListDevicesPrint(vshControl *ctl,
+ char **devices,
+ char **parents,
+ int num_devices,
+ int devid,
+ int lastdev,
+ unsigned int depth,
+ unsigned int indentIdx,
+ char *indentBuf)
+{
+ int i;
+ int nextlastdev = -1;
+
+ /* Prepare indent for this device, but not if at root */
+ if (depth && depth < MAX_DEPTH) {
+ indentBuf[indentIdx] = '+';
+ indentBuf[indentIdx+1] = '-';
+ }
+
+ /* Print this device */
+ vshPrint(ctl, indentBuf);
+ vshPrint(ctl, "%s\n", devices[devid]);
+
+
+ /* Update indent to show '|' or ' ' for child devices */
+ if (depth && depth < MAX_DEPTH) {
+ if (devid == lastdev)
+ indentBuf[indentIdx] = ' ';
+ else
+ indentBuf[indentIdx] = '|';
+ indentBuf[indentIdx+1] = ' ';
+ indentIdx+=2;
+ }
+
+ /* Determine the index of the last child device */
+ for (i = 0 ; i < num_devices ; i++) {
+ if (parents[i] &&
+ STREQ(parents[i], devices[devid])) {
+ nextlastdev = i;
+ }
+ }
+
+ /* If there is a child device, then print another blank line */
+ if (nextlastdev != -1) {
+ vshPrint(ctl, indentBuf);
+ vshPrint(ctl, " |\n");
+ }
+
+ /* Finally print all children */
+ if (depth < MAX_DEPTH)
+ indentBuf[indentIdx] = ' ';
+ for (i = 0 ; i < num_devices ; i++) {
+ if (depth < MAX_DEPTH) {
+ indentBuf[indentIdx] = ' ';
+ indentBuf[indentIdx+1] = ' ';
+ }
+ if (parents[i] &&
+ STREQ(parents[i], devices[devid]))
+ cmdNodeListDevicesPrint(ctl, devices, parents,
+ num_devices, i, nextlastdev,
+ depth + 1, indentIdx + 2, indentBuf);
+ if (depth < MAX_DEPTH)
+ indentBuf[indentIdx] = '\0';
+ }
+
+ /* 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, indentBuf);
+ vshPrint(ctl, "\n");
+ }
+}
+
static int
cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
char *cap;
char **devices;
int found, num_devices, i;
+ int tree = vshCommandOptBool(cmd, "tree");
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
@@ -4426,9 +4506,42 @@ cmdNodeListDevices (vshControl *ctl, con
return FALSE;
}
qsort(&devices[0], num_devices, sizeof(char*), namesorter);
- for (i = 0; i < num_devices; i++) {
- vshPrint(ctl, "%s\n", devices[i]);
- free(devices[i]);
+ if (tree) {
+ char indentBuf[INDENT_BUFLEN];
+ char **parents = vshMalloc(ctl, sizeof(char *) * num_devices);
+ for (i = 0; i < num_devices; i++) {
+ virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]);
+ if (dev && STRNEQ(devices[i], "computer")) {
+ const char *parent = virNodeDeviceGetParent(dev);
+ parents[i] = parent ? strdup(parent) : NULL;
+ } else {
+ parents[i] = NULL;
+ }
+ virNodeDeviceFree(dev);
+ }
+ for (i = 0 ; i < num_devices ; i++) {
+ memset(indentBuf, '\0', sizeof indentBuf);
+ if (parents[i] == NULL)
+ cmdNodeListDevicesPrint(ctl,
+ devices,
+ parents,
+ num_devices,
+ i,
+ i,
+ 0,
+ 0,
+ indentBuf);
+ }
+ for (i = 0 ; i < num_devices ; i++) {
+ free(devices[i]);
+ free(parents[i]);
+ }
+ free(parents);
+ } else {
+ for (i = 0; i < num_devices; i++) {
+ vshPrint(ctl, "%s\n", devices[i]);
+ free(devices[i]);
+ }
}
free(devices);
return TRUE;
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|