This patch adds 3 extra commands to virsh to allow storage pools and volumes to be defined & created without using XML. These have the names 'pool-define-as', 'pool-create-as', 'vol-create-as'. virsh will take the args to these commands and build suitable XML to pass into the libvirt APIs. This is a useful capability for people quickly shell scripting the virsh command, since they don't need to build up XML in the shell directly. In doing this we need to expose a couple of virBuffer* APIs to virsh. Turning these calls into macros exposed a couple of places where the existing code calls the virBufferVSprintf() function without actually having any va_args. These were turned int virBufferAdd calls instead. buf.c | 11 + buf.h | 12 + libvirt_sym.version | 4 qemu_conf.c | 6 virsh.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++ xend_internal.c | 22 +-- xm_internal.c | 2 xml.c | 8 - 8 files changed, 386 insertions(+), 26 deletions(-) diff -r 09ce185344bd src/buf.c --- a/src/buf.c Thu Feb 07 12:33:30 2008 -0500 +++ b/src/buf.c Thu Feb 07 12:33:33 2008 -0500 @@ -61,7 +61,7 @@ virBufferGrow(virBufferPtr buf, unsigned * Returns 0 successful, -1 in case of internal or API error. */ int -virBufferAdd(virBufferPtr buf, const char *str, int len) +__virBufferAdd(virBufferPtr buf, const char *str, int len) { unsigned int needSize; @@ -97,7 +97,7 @@ virBufferAdd(virBufferPtr buf, const cha * Returns 0 if successful, -1 in the case of error. */ int -virBufferAddChar (virBufferPtr buf, char c) +__virBufferAddChar (virBufferPtr buf, char c) { unsigned int needSize; @@ -190,7 +190,7 @@ virBufferContentAndFree (virBufferPtr bu * Returns 0 successful, -1 in case of internal or API error. */ int -virBufferVSprintf(virBufferPtr buf, const char *format, ...) +__virBufferVSprintf(virBufferPtr buf, const char *format, ...) { int size, count, grow_size; va_list locarg, argptr; @@ -198,6 +198,11 @@ virBufferVSprintf(virBufferPtr buf, cons if ((format == NULL) || (buf == NULL)) { return (-1); } + + if (buf->size == 0 && + virBufferGrow(buf, 100) < 0) + return -1; + size = buf->size - buf->use - 1; va_start(argptr, format); va_copy(locarg, argptr); diff -r 09ce185344bd src/buf.h --- a/src/buf.h Thu Feb 07 12:33:30 2008 -0500 +++ b/src/buf.h Thu Feb 07 12:33:33 2008 -0500 @@ -29,15 +29,19 @@ virBufferPtr virBufferNew(unsigned int s virBufferPtr virBufferNew(unsigned int size); void virBufferFree(virBufferPtr buf); char *virBufferContentAndFree(virBufferPtr buf); -int virBufferAdd(virBufferPtr buf, const char *str, int len); -int virBufferAddChar(virBufferPtr buf, char c); -int virBufferVSprintf(virBufferPtr buf, const char *format, ...) +int __virBufferAdd(virBufferPtr buf, const char *str, int len); +int __virBufferAddChar(virBufferPtr buf, char c); +int __virBufferVSprintf(virBufferPtr buf, const char *format, ...) ATTRIBUTE_FORMAT(printf, 2, 3); int virBufferStrcat(virBufferPtr buf, ...); int virBufferEscapeString(virBufferPtr buf, const char *format, const char *str); int virBufferURIEncodeString (virBufferPtr buf, const char *str); #define virBufferAddLit(buf_, literal_string_) \ - virBufferAdd (buf_, "" literal_string_ "", sizeof literal_string_ - 1) + __virBufferAdd (buf_, "" literal_string_ "", sizeof literal_string_ - 1) + +#define virBufferAdd(b,s,l) __virBufferAdd((b),(s),(l)) +#define virBufferAddChar(b,c) __virBufferAddChar((b),(c)) +#define virBufferVSprintf(b,f,...) __virBufferVSprintf((b),(f), __VA_ARGS__) #endif /* __VIR_BUFFER_H__ */ diff -r 09ce185344bd src/libvirt_sym.version --- a/src/libvirt_sym.version Thu Feb 07 12:33:30 2008 -0500 +++ b/src/libvirt_sym.version Thu Feb 07 12:33:33 2008 -0500 @@ -194,5 +194,9 @@ __virFileReadAll; + __virBufferVSprintf; + __virBufferAdd; + __virBufferAddChar; + local: *; }; diff -r 09ce185344bd src/qemu_conf.c --- a/src/qemu_conf.c Thu Feb 07 12:33:30 2008 -0500 +++ b/src/qemu_conf.c Thu Feb 07 12:33:33 2008 -0500 @@ -2818,7 +2818,7 @@ char *qemudGenerateXML(virConnectPtr con if (virBufferAddLit(buf, " <readonly/>\n") < 0) goto no_memory; - if (virBufferVSprintf(buf, " </disk>\n") < 0) + if (virBufferAddLit(buf, " </disk>\n") < 0) goto no_memory; disk = disk->next; @@ -2889,7 +2889,7 @@ char *qemudGenerateXML(virConnectPtr con } } - if (virBufferVSprintf(buf, " </interface>\n") < 0) + if (virBufferAddLit(buf, " </interface>\n") < 0) goto no_memory; net = net->next; @@ -2974,7 +2974,7 @@ char *qemudGenerateNetworkXML(virConnect if (!buf) goto no_memory; - if (virBufferVSprintf(buf, "<network>\n") < 0) + if (virBufferAddLit(buf, "<network>\n") < 0) goto no_memory; if (virBufferVSprintf(buf, " <name>%s</name>\n", def->name) < 0) diff -r 09ce185344bd src/virsh.c --- a/src/virsh.c Thu Feb 07 12:33:30 2008 -0500 +++ b/src/virsh.c Thu Feb 07 12:33:33 2008 -0500 @@ -50,6 +50,7 @@ #include "internal.h" #include "console.h" #include "util.h" +#include "buf.h" static char *progname; @@ -244,6 +245,9 @@ static int vshCommandOptInt(vshCmd * cmd static int vshCommandOptInt(vshCmd * cmd, const char *name, int *found); static char *vshCommandOptString(vshCmd * cmd, const char *name, int *found); +#if 0 +static int vshCommandOptStringList(vshCmd * cmd, const char *name, char ***data); +#endif static int vshCommandOptBool(vshCmd * cmd, const char *name); #define VSH_BYID (1 << 1) @@ -3157,6 +3161,100 @@ cmdPoolCreate(vshControl * ctl, vshCmd * return ret; } +/* + * "pool-create-as" command + */ +static vshCmdInfo info_pool_create_as[] = { + {"syntax", "pool-create-as <name> <type>"}, + {"help", gettext_noop("create a pool from a set of args")}, + {"desc", gettext_noop("Create a pool.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_create_as[] = { + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the pool")}, + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("type of the pool")}, + {"source-host", VSH_OT_DATA, 0, gettext_noop("source-host for underlying storage")}, + {"source-path", VSH_OT_DATA, 0, gettext_noop("source path for underlying storage")}, + {"source-dev", VSH_OT_DATA, 0, gettext_noop("source device for underlying storage")}, + {"target", VSH_OT_DATA, 0, gettext_noop("target for underlying storage")}, + {NULL, 0, 0, NULL} +}; + + +static int +cmdPoolCreateAs(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + int found; + char *name, *type, *srcHost, *srcPath, *srcDev, *target; + virBuffer buf; + + memset(&buf, 0, sizeof(buf)); + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + name = vshCommandOptString(cmd, "name", &found); + if (!found) + goto cleanup; + type = vshCommandOptString(cmd, "type", &found); + if (!found) + goto cleanup; + + srcHost = vshCommandOptString(cmd, "source-host", &found); + srcPath = vshCommandOptString(cmd, "source-path", &found); + srcDev = vshCommandOptString(cmd, "source-dev", &found); + target = vshCommandOptString(cmd, "target", &found); + + if (virBufferVSprintf(&buf, "<pool type='%s'>\n", type) < 0) + goto cleanup; + if (virBufferVSprintf(&buf, " <name>%s</name>\n", name) < 0) + goto cleanup; + if (srcHost || srcPath || srcDev) { + if (virBufferAddLit(&buf, " <source>\n") < 0) + goto cleanup; + if (srcHost && + virBufferVSprintf(&buf, " <host name='%s'>\n", srcHost) < 0) + goto cleanup; + if (srcPath && + virBufferVSprintf(&buf, " <dir path='%s'/>\n", srcPath) < 0) + goto cleanup; + if (srcDev && + virBufferVSprintf(&buf, " <device path='%s'/>\n", srcDev) < 0) + goto cleanup; + + if (virBufferAddLit(&buf, " </source>\n") < 0) + goto cleanup; + } + if (target) { + if (virBufferAddLit(&buf, " <target>\n") < 0) + goto cleanup; + if (virBufferVSprintf(&buf, " <path>%s</path>\n", target) < 0) + goto cleanup; + if (virBufferAddLit(&buf, " </target>\n") < 0) + goto cleanup; + } + if (virBufferAddLit(&buf, "</pool>\n") < 0) + goto cleanup; + + pool = virStoragePoolCreateXML(ctl->conn, buf.content); + free (buf.content); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s created\n"), name); + virStoragePoolFree(pool); + return TRUE; + } else { + vshError(ctl, FALSE, _("Failed to create pool %s"), name); + return FALSE; + } + + cleanup: + free(buf.content); + return FALSE; +} + /* * "pool-define" command @@ -3203,6 +3301,101 @@ cmdPoolDefine(vshControl * ctl, vshCmd * ret = FALSE; } return ret; +} + + +/* + * "pool-define-as" command + */ +static vshCmdInfo info_pool_define_as[] = { + {"syntax", "pool-define-as <name> <type>"}, + {"help", gettext_noop("define a pool from a set of args")}, + {"desc", gettext_noop("Define a pool.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_define_as[] = { + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the pool")}, + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("type of the pool")}, + {"source-host", VSH_OT_DATA, 0, gettext_noop("source-host for underlying storage")}, + {"source-path", VSH_OT_DATA, 0, gettext_noop("source path for underlying storage")}, + {"source-dev", VSH_OT_DATA, 0, gettext_noop("source device for underlying storage")}, + {"target", VSH_OT_DATA, 0, gettext_noop("target for underlying storage")}, + {NULL, 0, 0, NULL} +}; + + +static int +cmdPoolDefineAs(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + int found; + char *name, *type, *srcHost, *srcPath, *srcDev, *target; + virBuffer buf; + + memset(&buf, 0, sizeof(buf)); + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + name = vshCommandOptString(cmd, "name", &found); + if (!found) + goto cleanup; + type = vshCommandOptString(cmd, "type", &found); + if (!found) + goto cleanup; + + srcHost = vshCommandOptString(cmd, "source-host", &found); + srcPath = vshCommandOptString(cmd, "source-path", &found); + srcDev = vshCommandOptString(cmd, "source-dev", &found); + target = vshCommandOptString(cmd, "target", &found); + + if (virBufferVSprintf(&buf, "<pool type='%s'>\n", type) < 0) + goto cleanup; + if (virBufferVSprintf(&buf, " <name>%s</name>\n", name) < 0) + goto cleanup; + if (srcHost || srcPath || srcDev) { + if (virBufferAddLit(&buf, " <source>\n") < 0) + goto cleanup; + if (srcHost && + virBufferVSprintf(&buf, " <host>%s</host>\n", srcHost) < 0) + goto cleanup; + if (srcPath && + virBufferVSprintf(&buf, " <path>%s</path>\n", srcPath) < 0) + goto cleanup; + if (srcDev && + virBufferVSprintf(&buf, " <device>%s</device>\n", srcDev) < 0) + goto cleanup; + + if (virBufferAddLit(&buf, " </source>\n") < 0) + goto cleanup; + } + if (target) { + if (virBufferAddLit(&buf, " <target>\n") < 0) + goto cleanup; + if (virBufferVSprintf(&buf, " <path>%s</path>\n", target) < 0) + goto cleanup; + if (virBufferAddLit(&buf, " </target>\n") < 0) + goto cleanup; + } + if (virBufferAddLit(&buf, "</pool>\n") < 0) + goto cleanup; + + pool = virStoragePoolDefineXML(ctl->conn, buf.content); + free (buf.content); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s defined\n"), name); + virStoragePoolFree(pool); + return TRUE; + } else { + vshError(ctl, FALSE, _("Failed to define pool %s"), name); + return FALSE; + } + + cleanup: + free(buf.content); + return FALSE; } @@ -3746,6 +3939,131 @@ cmdPoolStart(vshControl * ctl, vshCmd * ret = FALSE; } return ret; +} + + +/* + * "vol-create-as" command + */ +static vshCmdInfo info_vol_create_as[] = { + {"syntax", "create-as <pool> <name> <capacity>"}, + {"help", gettext_noop("create a vol from a set of as")}, + {"desc", gettext_noop("Create a vol.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vol_create_as[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("pool name")}, + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the vol")}, + {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("size of the vol with optional k,M,G,T suffix")}, + {"allocation", VSH_OT_DATA, 0, gettext_noop("initial allocation size with optional k,M,G,T suffix")}, + {"format", VSH_OT_DATA, 0, gettext_noop("file format type raw,bochs,qcow,qcow2,vmdk")}, + {NULL, 0, 0, NULL} +}; + +static int cmdVolSize(const char *data, unsigned long long *val) +{ + char *end; + if (xstrtol_ull(data, &end, 10, val) < 0) + return -1; + + if (end && *end) { + /* Delibrate fallthrough cases here :-) */ + switch (*end) { + case 'T': + *val *= 1024; + case 'G': + *val *= 1024; + case 'M': + *val *= 1024; + case 'k': + *val *= 1024; + break; + default: + return -1; + } + end++; + if (*end) + return -1; + } + return 0; +} + +static int +cmdVolCreateAs(vshControl * ctl, vshCmd * cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + int found; + char *name, *capacityStr, *allocationStr, *format; + unsigned long long capacity, allocation = 0; + virBuffer buf; + + memset(&buf, 0, sizeof(buf)); + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return FALSE; + + name = vshCommandOptString(cmd, "name", &found); + if (!found) + goto cleanup; + + capacityStr = vshCommandOptString(cmd, "capacity", &found); + if (!found) + goto cleanup; + if (cmdVolSize(capacityStr, &capacity) < 0) + vshError(ctl, FALSE, _("Malformed size %s"), capacityStr); + + allocationStr = vshCommandOptString(cmd, "allocation", &found); + if (allocationStr && + cmdVolSize(allocationStr, &allocation) < 0) + vshError(ctl, FALSE, _("Malformed size %s"), allocationStr); + + format = vshCommandOptString(cmd, "format", &found); + + if (virBufferAddLit(&buf, "<volume>\n") < 0) + goto cleanup; + if (virBufferVSprintf(&buf, " <name>%s</name>\n", name) < 0) + goto cleanup; + if (virBufferVSprintf(&buf, " <capacity>%llu</capacity>\n", capacity) < 0) + goto cleanup; + if (allocationStr && + virBufferVSprintf(&buf, " <allocation>%llu</allocation>\n", allocation) < 0) + goto cleanup; + + if (format) { + if (virBufferAddLit(&buf, " <target>\n") < 0) + goto cleanup; + if (format) + if (virBufferVSprintf(&buf, " <format type='%s'/>\n",format) < 0) + goto cleanup; + if (virBufferAddLit(&buf, " </target>\n") < 0) + goto cleanup; + } + if (virBufferAddLit(&buf, "</volume>\n") < 0) + goto cleanup; + + vol = virStorageVolCreateXML(pool, buf.content, 0); + free (buf.content); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created\n"), name); + virStorageVolFree(vol); + return TRUE; + } else { + vshError(ctl, FALSE, _("Failed to create vol %s"), name); + return FALSE; + } + + cleanup: + free(buf.content); + virStoragePoolFree(pool); + return FALSE; } @@ -5160,7 +5478,9 @@ static vshCmdDef commands[] = { {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart}, {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build}, {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create}, + {"pool-create-as", cmdPoolCreateAs, opts_pool_create_as, info_pool_create_as}, {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define}, + {"pool-define-as", cmdPoolDefineAs, opts_pool_define_as, info_pool_define_as}, {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy}, {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete}, {"pool-discover", cmdPoolDiscover, opts_pool_discover, info_pool_discover}, @@ -5190,6 +5510,7 @@ static vshCmdDef commands[] = { {"uri", cmdURI, NULL, info_uri}, {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create}, + {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as}, {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete}, {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml}, {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info}, @@ -5429,6 +5750,32 @@ vshCommandOptString(vshCmd * cmd, const return arg && arg->data && *arg->data ? arg->data : NULL; } + +#if 0 +static int +vshCommandOptStringList(vshCmd * cmd, const char *name, char ***data) +{ + vshCmdOpt *arg = cmd->opts; + char **val = NULL; + int nval = 0; + + while (arg) { + if (arg->def && STREQ(arg->def->name, name)) { + char **tmp = realloc(val, sizeof(*tmp) * (nval+1)); + if (!tmp) { + free(val); + return -1; + } + val = tmp; + val[nval++] = arg->data; + } + arg = arg->next; + } + + *data = val; + return nval; +} +#endif /* * Returns TRUE/FALSE if the option exists diff -r 09ce185344bd src/xend_internal.c --- a/src/xend_internal.c Thu Feb 07 12:33:30 2008 -0500 +++ b/src/xend_internal.c Thu Feb 07 12:33:33 2008 -0500 @@ -1440,7 +1440,7 @@ xend_parse_sexp_desc(virConnectPtr conn, virBufferVSprintf(&buf, " <bootloader>%s</bootloader>\n", tmp); } else if (sexpr_has(root, "domain/bootloader")) { bootloader = 1; - virBufferVSprintf(&buf, " <bootloader/>\n"); + virBufferAddLit(&buf, " <bootloader/>\n"); } tmp = sexpr_node(root, "domain/bootloader_args"); if (tmp != NULL && bootloader) { @@ -1464,12 +1464,12 @@ xend_parse_sexp_desc(virConnectPtr conn, max_mem = cur_mem; virBufferVSprintf(&buf, " <memory>%d</memory>\n", max_mem); if ((cur_mem >= MIN_XEN_GUEST_SIZE) && (cur_mem != max_mem)) - virBufferVSprintf(&buf, " <currentMemory>%d</currentMemory>\n", - cur_mem); - - virBufferVSprintf(&buf, " <vcpu"); + virBufferVSprintf(&buf, " <currentMemory>%d</currentMemory>\n", + cur_mem); + + virBufferAddLit(&buf, " <vcpu"); if (cpus != NULL) { - virBufferVSprintf(&buf, " cpuset='%s'", cpus); + virBufferVSprintf(&buf, " cpuset='%s'", cpus); } virBufferVSprintf(&buf, ">%d</vcpu>\n", sexpr_int(root, "domain/vcpus")); @@ -1646,7 +1646,7 @@ xend_parse_sexp_desc(virConnectPtr conn, } } else { /* This case is the cdrom device only */ - virBufferVSprintf(&buf, " <disk device='cdrom'>\n"); + virBufferAddLit(&buf, " <disk device='cdrom'>\n"); } virBufferVSprintf(&buf, " <target dev='%s'/>\n", dst); @@ -1654,9 +1654,9 @@ xend_parse_sexp_desc(virConnectPtr conn, /* XXX should we force mode == r, if cdrom==1, or assume xend has already done this ? */ if ((mode != NULL) && (!strcmp(mode, "r"))) - virBufferVSprintf(&buf, " <readonly/>\n"); + virBufferAddLit(&buf, " <readonly/>\n"); else if ((mode != NULL) && (!strcmp(mode, "w!"))) - virBufferVSprintf(&buf, " <shareable/>\n"); + virBufferAddLit(&buf, " <shareable/>\n"); virBufferAddLit(&buf, " </disk>\n"); bad_parse: @@ -1667,12 +1667,12 @@ xend_parse_sexp_desc(virConnectPtr conn, tmp2 = sexpr_node(node, "device/vif/script"); tmp = sexpr_node(node, "device/vif/bridge"); if ((tmp2 && strstr(tmp2, "bridge")) || tmp) { - virBufferVSprintf(&buf, " <interface type='bridge'>\n"); + virBufferAddLit(&buf, " <interface type='bridge'>\n"); if (tmp != NULL) virBufferVSprintf(&buf, " <source bridge='%s'/>\n", tmp); } else { - virBufferVSprintf(&buf, " <interface type='ethernet'>\n"); + virBufferAddLit(&buf, " <interface type='ethernet'>\n"); } tmp = sexpr_node(node, "device/vif/vifname"); diff -r 09ce185344bd src/xm_internal.c --- a/src/xm_internal.c Thu Feb 07 12:33:30 2008 -0500 +++ b/src/xm_internal.c Thu Feb 07 12:33:33 2008 -0500 @@ -667,7 +667,7 @@ char *xenXMDomainFormatXML(virConnectPtr val = MIN_XEN_GUEST_SIZE * 2; virBufferVSprintf(buf, " <memory>%ld</memory>\n", val * 1024); - virBufferVSprintf(buf, " <vcpu"); + virBufferAddLit(buf, " <vcpu"); if (xenXMConfigGetString(conf, "cpus", &str) == 0) { char *ranges; diff -r 09ce185344bd src/xml.c --- a/src/xml.c Thu Feb 07 12:33:30 2008 -0500 +++ b/src/xml.c Thu Feb 07 12:33:33 2008 -0500 @@ -1298,11 +1298,11 @@ virDomainParseXMLDiskDesc(virConnectPtr } } if (ro == 1) - virBufferVSprintf(buf, "(mode 'r')"); + virBufferAddLit(buf, "(mode 'r')"); else if (shareable == 1) - virBufferVSprintf(buf, "(mode 'w!')"); + virBufferAddLit(buf, "(mode 'w!')"); else - virBufferVSprintf(buf, "(mode 'w')"); + virBufferAddLit(buf, "(mode 'w')"); virBufferAddLit(buf, ")"); virBufferAddLit(buf, ")"); @@ -1617,7 +1617,7 @@ virDomainParseXMLDesc(virConnectPtr conn free(str); } else if (virXPathNumber("count(/domain/bootloader)", ctxt, &f) == 0 && (f > 0)) { - virBufferVSprintf(&buf, "(bootloader)"); + virBufferAddLit(&buf, "(bootloader)"); /* * if using a bootloader, the kernel and initrd strings are not * significant and should be discarded -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list