diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 2e79610010..45ba94ab5e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -11093,6 +11093,65 @@ virDomainShmemDefParseXML(xmlNodePtr node, return ret; } +static int +virSysinfoBIOSParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virSysinfoBIOSDefPtr *bios) +{ + int ret = -1; + virSysinfoBIOSDefPtr def; + + if (!xmlStrEqual(node->name, BAD_CAST "bios")) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("XML does not contain expected 'bios' element")); + return ret; + } + + if (VIR_ALLOC(def) < 0) + goto cleanup; + + def->vendor = virXPathString("string(entry[@name='vendor'])", ctxt); + def->version = virXPathString("string(entry[@name='version'])", ctxt); + def->date = virXPathString("string(entry[@name='date'])", ctxt); + def->release = virXPathString("string(entry[@name='release'])", ctxt); + if (def->date != NULL) { + char *ptr; + int month, day, year; + + /* Validate just the format of the date + * Expect mm/dd/yyyy or mm/dd/yy, + * where yy must be 00->99 and would be assumed to be 19xx + * a yyyy date should be 1900 and beyond + */ + if (virStrToLong_i(def->date, &ptr, 10, &month) < 0 || + *ptr != '/' || + virStrToLong_i(ptr + 1, &ptr, 10, &day) < 0 || + *ptr != '/' || + virStrToLong_i(ptr + 1, &ptr, 10, &year) < 0 || + *ptr != '\0' || + (month < 1 || month > 12) || + (day < 1 || day > 31) || + (year < 0 || (year >= 100 && year < 1900))) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("Invalid BIOS 'date' format")); + goto cleanup; + } + } + + if (!def->vendor && !def->version && + !def->date && !def->release) { + virSysinfoBIOSDefFree(def); + def = NULL; + } + + *bios = def; + def = NULL; + ret = 0; + cleanup: + virSysinfoBIOSDefFree(def); + return ret; +} + static virSysinfoDefPtr virSysinfoParseXML(xmlNodePtr node, xmlXPathContextPtr ctxt, @@ -11100,6 +11159,7 @@ virSysinfoParseXML(xmlNodePtr node, bool uuid_generated) { virSysinfoDefPtr def; + xmlNodePtr oldnode, tmpnode; char *type; char *tmpUUID = NULL; @@ -11124,39 +11184,16 @@ virSysinfoParseXML(xmlNodePtr node, goto error; } - /* Extract BIOS related metadata */ - def->bios_vendor = - virXPathString("string(bios/entry[@name='vendor'])", ctxt); - def->bios_version = - virXPathString("string(bios/entry[@name='version'])", ctxt); - def->bios_date = - virXPathString("string(bios/entry[@name='date'])", ctxt); - if (def->bios_date != NULL) { - char *ptr; - int month, day, year; - - /* Validate just the format of the date - * Expect mm/dd/yyyy or mm/dd/yy, - * where yy must be 00->99 and would be assumed to be 19xx - * a yyyy date should be 1900 and beyond - */ - if (virStrToLong_i(def->bios_date, &ptr, 10, &month) < 0 || - *ptr != '/' || - virStrToLong_i(ptr + 1, &ptr, 10, &day) < 0 || - *ptr != '/' || - virStrToLong_i(ptr + 1, &ptr, 10, &year) < 0 || - *ptr != '\0' || - (month < 1 || month > 12) || - (day < 1 || day > 31) || - (year < 0 || (year >= 100 && year < 1900))) { - virReportError(VIR_ERR_XML_DETAIL, "%s", - _("Invalid BIOS 'date' format")); + if ((tmpnode = virXPathNode("./bios[1]", ctxt)) != NULL) { + oldnode = ctxt->node; + ctxt->node = tmpnode; + if (virSysinfoBIOSParseXML(tmpnode, ctxt, &def->bios) < 0) { + ctxt->node = oldnode; goto error; } + ctxt->node = oldnode; } - def->bios_release = - virXPathString("string(bios/entry[@name='release'])", ctxt); /* Extract system related metadata */ def->system_manufacturer = diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b7975d6e50..a88b874178 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2182,6 +2182,7 @@ virVasprintfInternal; # util/virsysinfo.h +virSysinfoBIOSDefFree; virSysinfoDefFree; virSysinfoFormat; virSysinfoRead; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 688b18059a..603ba9e14c 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6701,28 +6701,27 @@ static char *qemuBuildTPMDevStr(const virDomainDef *def, } -static char *qemuBuildSmbiosBiosStr(virSysinfoDefPtr def) +static char *qemuBuildSmbiosBiosStr(virSysinfoBIOSDefPtr def) { virBuffer buf = VIR_BUFFER_INITIALIZER; - if ((def->bios_vendor == NULL) && (def->bios_version == NULL) && - (def->bios_date == NULL) && (def->bios_release == NULL)) + if (!def) return NULL; virBufferAddLit(&buf, "type=0"); /* 0:Vendor */ - if (def->bios_vendor) - virBufferAsprintf(&buf, ",vendor=%s", def->bios_vendor); + if (def->vendor) + virBufferAsprintf(&buf, ",vendor=%s", def->vendor); /* 0:BIOS Version */ - if (def->bios_version) - virBufferAsprintf(&buf, ",version=%s", def->bios_version); + if (def->version) + virBufferAsprintf(&buf, ",version=%s", def->version); /* 0:BIOS Release Date */ - if (def->bios_date) - virBufferAsprintf(&buf, ",date=%s", def->bios_date); + if (def->date) + virBufferAsprintf(&buf, ",date=%s", def->date); /* 0:System BIOS Major Release and 0:System BIOS Minor Release */ - if (def->bios_release) - virBufferAsprintf(&buf, ",release=%s", def->bios_release); + if (def->release) + virBufferAsprintf(&buf, ",release=%s", def->release); if (virBufferCheckError(&buf) < 0) goto error; @@ -9047,7 +9046,7 @@ qemuBuildCommandLine(virConnectPtr conn, if (source != NULL) { char *smbioscmd; - smbioscmd = qemuBuildSmbiosBiosStr(source); + smbioscmd = qemuBuildSmbiosBiosStr(source->bios); if (smbioscmd != NULL) { virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL); VIR_FREE(smbioscmd); diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c index 7b0d80d62f..725894f0f1 100644 --- a/src/util/virsysinfo.c +++ b/src/util/virsysinfo.c @@ -64,6 +64,18 @@ void virSysinfoSetup(const char *dmidecode, const char *sysinfo, sysinfoCpuinfo = cpuinfo; } +void virSysinfoBIOSDefFree(virSysinfoBIOSDefPtr def) +{ + if (def == NULL) + return; + + VIR_FREE(def->vendor); + VIR_FREE(def->version); + VIR_FREE(def->date); + VIR_FREE(def->release); + VIR_FREE(def); +} + /** * virSysinfoDefFree: * @def: a sysinfo structure @@ -78,10 +90,7 @@ void virSysinfoDefFree(virSysinfoDefPtr def) if (def == NULL) return; - VIR_FREE(def->bios_vendor); - VIR_FREE(def->bios_version); - VIR_FREE(def->bios_date); - VIR_FREE(def->bios_release); + virSysinfoBIOSDefFree(def->bios); VIR_FREE(def->system_manufacturer); VIR_FREE(def->system_product); @@ -522,40 +531,56 @@ virSysinfoRead(void) #else /* !WIN32 && x86 */ static int -virSysinfoParseBIOS(const char *base, virSysinfoDefPtr ret) +virSysinfoParseBIOS(const char *base, virSysinfoBIOSDefPtr *bios) { + int ret = -1; const char *cur, *eol = NULL; + virSysinfoBIOSDefPtr def; if ((cur = strstr(base, "BIOS Information")) == NULL) return 0; + if (VIR_ALLOC(def) < 0) + return ret; + base = cur; if ((cur = strstr(base, "Vendor: ")) != NULL) { cur += 8; eol = strchr(cur, '\n'); - if (eol && VIR_STRNDUP(ret->bios_vendor, cur, eol - cur) < 0) - return -1; + if (eol && VIR_STRNDUP(def->vendor, cur, eol - cur) < 0) + goto cleanup; } if ((cur = strstr(base, "Version: ")) != NULL) { cur += 9; eol = strchr(cur, '\n'); - if (eol && VIR_STRNDUP(ret->bios_version, cur, eol - cur) < 0) - return -1; + if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0) + goto cleanup; } if ((cur = strstr(base, "Release Date: ")) != NULL) { cur += 14; eol = strchr(cur, '\n'); - if (eol && VIR_STRNDUP(ret->bios_date, cur, eol - cur) < 0) - return -1; + if (eol && VIR_STRNDUP(def->date, cur, eol - cur) < 0) + goto cleanup; } if ((cur = strstr(base, "BIOS Revision: ")) != NULL) { cur += 15; eol = strchr(cur, '\n'); - if (eol && VIR_STRNDUP(ret->bios_release, cur, eol - cur) < 0) - return -1; + if (eol && VIR_STRNDUP(def->release, cur, eol - cur) < 0) + goto cleanup; } - return 0; + if (!def->vendor && !def->version && + !def->date && !def->release) { + virSysinfoBIOSDefFree(def); + def = NULL; + } + + *bios = def; + def = NULL; + ret = 0; + cleanup: + virSysinfoBIOSDefFree(def); + return ret; } static int @@ -846,7 +871,7 @@ virSysinfoRead(void) ret->type = VIR_SYSINFO_SMBIOS; - if (virSysinfoParseBIOS(outbuf, ret) < 0) + if (virSysinfoParseBIOS(outbuf, &ret->bios) < 0) goto error; if (virSysinfoParseSystem(outbuf, ret) < 0) @@ -876,22 +901,21 @@ virSysinfoRead(void) #endif /* !WIN32 && x86 */ static void -virSysinfoBIOSFormat(virBufferPtr buf, virSysinfoDefPtr def) +virSysinfoBIOSFormat(virBufferPtr buf, virSysinfoBIOSDefPtr def) { - if (!def->bios_vendor && !def->bios_version && - !def->bios_date && !def->bios_release) + if (!def) return; virBufferAddLit(buf, "\n"); virBufferAdjustIndent(buf, 2); virBufferEscapeString(buf, "%s\n", - def->bios_vendor); + def->vendor); virBufferEscapeString(buf, "%s\n", - def->bios_version); + def->version); virBufferEscapeString(buf, "%s\n", - def->bios_date); + def->date); virBufferEscapeString(buf, "%s\n", - def->bios_release); + def->release); virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "\n"); } @@ -1055,7 +1079,7 @@ virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) virBufferAdjustIndent(&childrenBuf, indent + 2); - virSysinfoBIOSFormat(&childrenBuf, def); + virSysinfoBIOSFormat(&childrenBuf, def->bios); virSysinfoSystemFormat(&childrenBuf, def); virSysinfoProcessorFormat(&childrenBuf, def); virSysinfoMemoryFormat(&childrenBuf, def); @@ -1078,6 +1102,41 @@ virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) return ret; } +#define CHECK_FIELD(name, desc) \ + do { \ + if (STRNEQ_NULLABLE(src->name, dst->name)) { \ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \ + _("Target sysinfo %s %s does not match source %s"), \ + desc, NULLSTR(dst->name), NULLSTR(src->name)); \ + goto cleanup; \ + } \ + } while (0) + +static bool +virSysinfoBIOSIsEqual(virSysinfoBIOSDefPtr src, + virSysinfoBIOSDefPtr dst) +{ + bool identical = false; + + if (!src && !dst) + return true; + + if ((src && !dst) || (!src && dst)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Target sysinfo does not match source")); + goto cleanup; + } + + CHECK_FIELD(vendor, "BIOS vendor"); + CHECK_FIELD(version, "BIOS version"); + CHECK_FIELD(date, "BIOS date"); + CHECK_FIELD(release, "BIOS release"); + + identical = true; + cleanup: + return identical; +} + bool virSysinfoIsEqual(virSysinfoDefPtr src, virSysinfoDefPtr dst) { @@ -1100,19 +1159,8 @@ bool virSysinfoIsEqual(virSysinfoDefPtr src, goto cleanup; } -#define CHECK_FIELD(name, desc) \ - do { \ - if (STRNEQ_NULLABLE(src->name, dst->name)) { \ - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \ - _("Target sysinfo %s %s does not match source %s"), \ - desc, NULLSTR(src->name), NULLSTR(dst->name)); \ - } \ - } while (0) - - CHECK_FIELD(bios_vendor, "BIOS vendor"); - CHECK_FIELD(bios_version, "BIOS version"); - CHECK_FIELD(bios_date, "BIOS date"); - CHECK_FIELD(bios_release, "BIOS release"); + if (!virSysinfoBIOSIsEqual(src->bios, dst->bios)) + goto cleanup; CHECK_FIELD(system_manufacturer, "system vendor"); CHECK_FIELD(system_product, "system product"); diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h index 6236ca61a9..ec32f6cfcf 100644 --- a/src/util/virsysinfo.h +++ b/src/util/virsysinfo.h @@ -65,15 +65,21 @@ struct _virSysinfoMemoryDef { char *memory_part_number; }; +typedef struct _virSysinfoBIOSDef virSysinfoBIOSDef; +typedef virSysinfoBIOSDef *virSysinfoBIOSDefPtr; +struct _virSysinfoBIOSDef { + char *vendor; + char *version; + char *date; + char *release; +}; + typedef struct _virSysinfoDef virSysinfoDef; typedef virSysinfoDef *virSysinfoDefPtr; struct _virSysinfoDef { int type; - char *bios_vendor; - char *bios_version; - char *bios_date; - char *bios_release; + virSysinfoBIOSDefPtr bios; char *system_manufacturer; char *system_product; @@ -92,6 +98,7 @@ struct _virSysinfoDef { virSysinfoDefPtr virSysinfoRead(void); +void virSysinfoBIOSDefFree(virSysinfoBIOSDefPtr def); void virSysinfoDefFree(virSysinfoDefPtr def); int virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def)