static const DistroNameScan osReleaseFields[] = {
{"PRETTY_NAME=", "PRETTY_NAME=%s" },
- {NULL, NULL },
+ {"NAME=", "NAME=%s" },
+ {"VERSION_ID=", "VERSION_ID=%s" },
+ {"BUILD_ID=", "BUILD_ID=%s" },
+ {NULL, NULL },
};
typedef struct {
};
#endif
+/* Must be sorted. Keep in same ordering as StructuredFieldType*/
+StructuredField structuredFields[] = {
+ {"BITNESS", ""}, // "32" or "64"
+ {"BUILD_NUMBER", ""}, // Always present for MacOS. Present for some Linux distros.
+ {"DISTRO_NAME", ""}, // Defaults to uname -s
+ {"DISTRO_VERSION", ""}, // Always present for MacOS. Read from distro files for Linux.
+ {"FAMILY_NAME", ""}, // Defaults to uname -s
+ {"KERNEL_VERSION", ""}, // Defaults to uname -r
+ {"PRETTY_NAME", ""}, // Always present for MacOS. Read from distro files for Linux.
+ {NULL},
+};
+
#if defined __ANDROID__
/*
* Android doesn't support getloadavg() or iopl().
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HostinfoOSStructuredString --
+ *
+ * Builds, escapes, and stores the structured string into the cache.
+ *
+ * Return value:
+ * TRUE Success
+ * FALSE Failure
+ *
+ * Side effects:
+ * Cache values are set when returning TRUE
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HostinfoOSStructuredString(void)
+{
+ StructuredField *field;
+
+ /* Clear the string cache */
+ memset(HostinfoCachedStructuredString, 0,
+ sizeof HostinfoCachedStructuredString);
+
+ for (field = structuredFields; field->name != NULL; field++) {
+ if (field->value != NULL && *field->value != '\0') {
+ /* Account for escape char and null char */
+ char escapedString[MAX_STRUCTURED_FIELD_LEN * 2 + 1];
+ char fieldString[MAX_STRUCTURED_FIELD_LEN];
+ int i = 0;
+ int len;
+ const char *c;
+
+ /* escape single quotes and backslash from value */
+ for (c = field->value; *c != '\0'; c++) {
+ if (*c == '\'' || *c == '\\') {
+ escapedString[i] = '\\';
+ i++;
+ }
+ escapedString[i] = *c;
+ i++;
+ }
+ escapedString[i] = '\0';
+
+ len = Str_Snprintf(fieldString, sizeof fieldString, "%s='%s'",
+ field->name, escapedString);
+ if (len == -1) {
+ Warning("%s: Error: structured info field too large\n",
+ __FUNCTION__);
+ memset(HostinfoCachedStructuredString, 0,
+ sizeof HostinfoCachedStructuredString);
+ return;
+ }
+ Str_Strcat(HostinfoCachedStructuredString, fieldString,
+ sizeof HostinfoCachedStructuredString);
+
+ /* Add delimiter between properties */
+ if ((field + 1)->name != NULL) {
+ Str_Strcat(HostinfoCachedStructuredString,
+ STRUCTURED_STRING_DELIMITER,
+ sizeof HostinfoCachedStructuredString);
+ }
+ }
+ }
+ Log("structuredstring = \"%s\"\n", HostinfoCachedStructuredString);
+}
+
+
#if defined(__APPLE__) // MacOS
/*
*-----------------------------------------------------------------------------
}
}
+ Str_Strcpy(structuredFields[DISTRO_NAME].value, productName,
+ sizeof structuredFields[DISTRO_NAME].value);
+ Str_Strcpy(structuredFields[DISTRO_VERSION].value, productVersion,
+ sizeof structuredFields[DISTRO_VERSION].value);
+ Str_Strcpy(structuredFields[BUILD_NUMBER].value, productBuildVersion,
+ sizeof structuredFields[BUILD_NUMBER].value);
+
if (haveVersion) {
len = Str_Snprintf(osNameFull, sizeof osNameFull,
"%s %s (%s) %s %s", productName, productVersion,
HostinfoOsRelease(char *distro, // OUT:
size_t distroSize) // IN:
{
- Bool success = HostinfoReadDistroFile(TRUE, "/etc/os-release",
+ char distroName[DISTRO_BUF_SIZE] = "";
+ char distroBuild[DISTRO_BUF_SIZE] = "";
+ char distroRelease[DISTRO_BUF_SIZE] = "";
+ char *fileName = "/etc/os-release";
+
+ Bool success = HostinfoReadDistroFile(TRUE, fileName,
&osReleaseFields[0],
distroSize, distro);
-
if (!success) {
- success = HostinfoReadDistroFile(TRUE, "/usr/lib/os-release",
- &osReleaseFields[0],
- distroSize, distro);
- }
+ fileName = "/usr/lib/os-release";
+ }
+ success = HostinfoReadDistroFile(TRUE, fileName,
+ &osReleaseFields[0],
+ distroSize, distro);
+
+ /* These are used for the structured string. They can fail */
+ HostinfoReadDistroFile(TRUE, fileName, &osReleaseFields[1],
+ sizeof distroName, distroName);
+ HostinfoReadDistroFile(TRUE, fileName, &osReleaseFields[2],
+ sizeof distroRelease, distroRelease);
+ HostinfoReadDistroFile(TRUE, fileName, &osReleaseFields[3],
+ sizeof distroBuild, distroBuild);
+
+ Str_Strcpy(structuredFields[PRETTY_NAME].value, distro,
+ sizeof structuredFields[PRETTY_NAME].value);
+ Str_Strcpy(structuredFields[DISTRO_NAME].value, distroName,
+ sizeof structuredFields[DISTRO_NAME].value);
+ Str_Strcpy(structuredFields[BUILD_NUMBER].value, distroBuild,
+ sizeof structuredFields[BUILD_NUMBER].value);
+ Str_Strcpy(structuredFields[DISTRO_VERSION].value, distroRelease,
+ sizeof structuredFields[DISTRO_VERSION].value);
return success;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HostinfoLsbRemoveQuotes --
+ *
+ * If present, removes 1 set of double quotes around a LSB output.
+ *
+ * Return value:
+ * Pointer to a substring of the input
+ *
+ * Side effects:
+ * Replaces second double quote with a null character.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char *
+HostinfoLsbRemoveQuotes(char *lsbOutput) // IN/OUT:
+{
+ char *lsbStart = lsbOutput;
+
+ if (lsbStart[0] == '"') {
+ char *quoteEnd = strchr(++lsbStart, '"');
+ if (quoteEnd != NULL) {
+ *quoteEnd = '\0';
+ }
+ }
+
+ return lsbStart;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
{
char *lsbOutput;
Bool success = FALSE;
+ char distroName[DISTRO_BUF_SIZE] = "";
+ char distroRelease[DISTRO_BUF_SIZE] = "";
+ char distroDescription[DISTRO_BUF_SIZE] = "";
/*
* Try to get OS detailed information from the lsb_release command.
for (i = 0; distroArray[i].filename != NULL; i++) {
if (HostinfoReadDistroFile(FALSE, distroArray[i].filename,
&lsbFields[0], distroSize, distro)) {
- success = TRUE;
break;
}
}
* If we failed to read every distro file, exit now, before calling
* strlen on the distro buffer (which wasn't set).
*/
-
if (distroArray[i].filename == NULL) {
Log("%s: Error: no distro file found\n", __FUNCTION__);
- }
- } else {
- char *lsbStart = lsbOutput;
- char *quoteEnd = NULL;
-
- if (lsbStart[0] == '"') {
- lsbStart++;
- quoteEnd = strchr(lsbStart, '"');
- if (quoteEnd) {
- *quoteEnd = '\0';
+ } else {
+ if (!HostinfoReadDistroFile(FALSE, distroArray[i].filename,
+ &lsbFields[1], sizeof distroRelease,
+ distroRelease)) {
+ return FALSE;
+ }
+ if (!HostinfoReadDistroFile(FALSE, distroArray[i].filename,
+ &lsbFields[3], sizeof distroDescription,
+ distroDescription)) {
+ return FALSE;
}
+ /* When using distro files the distro is filled in by the distrib_id */
+ Str_Strcpy(distroName, distro, sizeof distroName);
+ success = TRUE;
}
+ } else {
+ /* LSB Description (pretty name) */
+ char *lsbStart = HostinfoLsbRemoveQuotes(lsbOutput);
+
Str_Strcpy(distro, lsbStart, distroSize);
free(lsbOutput);
+
+ /* LSB Release */
+ lsbOutput = HostinfoGetCmdOutput("/usr/bin/lsb_release -sr 2>/dev/null");
+ lsbStart = HostinfoLsbRemoveQuotes(lsbOutput);
+ Str_Strcpy(distroRelease, lsbStart, sizeof distroRelease);
+ free(lsbOutput);
+
+ /* LSB Distributor */
+ lsbOutput = HostinfoGetCmdOutput("/usr/bin/lsb_release -si 2>/dev/null");
+ lsbStart = HostinfoLsbRemoveQuotes(lsbOutput);
+ Str_Strcpy(distroName, lsbStart, sizeof distroName);
+ free(lsbOutput);
+
+ /* When using lsb_release, the distro is filled in by the discription
+ * (pretty name) */
+ Str_Strcpy(distroDescription, distro, sizeof distroDescription);
+
success = TRUE;
}
+ if (success) {
+ Str_Strcpy(structuredFields[DISTRO_NAME].value, distroName,
+ sizeof structuredFields[DISTRO_NAME].value);
+ Str_Strcpy(structuredFields[DISTRO_VERSION].value, distroRelease,
+ sizeof structuredFields[DISTRO_VERSION].value);
+ Str_Strcpy(structuredFields[PRETTY_NAME].value, distroDescription,
+ sizeof structuredFields[PRETTY_NAME].value);
+ }
+
return success;
}
{
Bool success;
struct utsname buf;
+ const char *bitness;
/*
* Use uname to get complete OS information.
return FALSE;
}
+ Str_Strcpy(structuredFields[FAMILY_NAME].value, buf.sysname,
+ sizeof structuredFields[FAMILY_NAME].value);
+ Str_Strcpy(structuredFields[KERNEL_VERSION].value, buf.release,
+ sizeof structuredFields[KERNEL_VERSION].value);
+ /* Default distro name is set to uname's sysname field */
+ Str_Strcpy(structuredFields[DISTRO_NAME].value, buf.sysname,
+ sizeof structuredFields[DISTRO_NAME].value);
+
+#if defined(USERWORLD) // ESXi
+ bitness = "64";
+#else
+ bitness = (Hostinfo_GetSystemBitness() == 64) ? "64" : "32";
+#endif
+ Str_Strcpy(structuredFields[BITNESS].value, bitness,
+ sizeof structuredFields[BITNESS].value);
+
#if defined(USERWORLD) // ESXi
success = HostinfoESX(&buf);
#elif defined(__APPLE__) // MacOS
}
#endif
+ /* Build structured string */
+ HostinfoOSStructuredString();
+
return success;
}
typedef struct _GuestInfoCache {
/* Stores values of all key-value pairs. */
- char *value[INFO_MAX];
- NicInfoV3 *nicInfo;
- GuestDiskInfo *diskInfo;
- NicInfoMethod method;
+ char *value[INFO_MAX];
+ HostinfoStructuredHeader *structuredOSInfo;
+ NicInfoV3 *nicInfo;
+ GuestDiskInfo *diskInfo;
+ NicInfoMethod method;
} GuestInfoCache;
/*
******************************************************************************
- * GuestInfoGather -- */ /**
+ * GuestInfoStructuredInfoIsEqual --
+ *
+ * Compares two HostinfoStructuredHeader and the structured string that
+ * follows each header.
+ *
+ * @returns True if equal
+ *
+ ******************************************************************************
+ */
+
+static Bool
+GuestInfoStructuredInfoIsEqual(const HostinfoStructuredHeader *info1, // IN:
+ const HostinfoStructuredHeader *info2) // IN:
+{
+ ASSERT(info1 != NULL);
+ ASSERT(info2 != NULL);
+
+ return (strncmp(info1->shortName, info2->shortName,
+ sizeof info1->shortName) == 0 &&
+ strncmp(info1->fullName, info2->fullName,
+ sizeof info1->fullName) == 0 &&
+ strcmp((char *)info1 + sizeof *info1,
+ (char *)info2 + sizeof *info2) == 0);
+}
+
+
+/*
+ ******************************************************************************
+ * GuestInfoFreeStructuredInfo --
+ *
+ * Free the HostinfoStructuredHeader and space allocated for the structured
+ * string.
+ *
+ * @returns None
+ *
+ ******************************************************************************
+ */
+
+static void
+GuestInfoFreeStructuredInfo(HostinfoStructuredHeader *info) // IN/OUT:
+{
+ free(info);
+}
+
+
+/*
+ ******************************************************************************
+ * GuestInfoGather --
*
* Collects all the desired guest information and updates the VMX.
*
{
char name[256]; // Size is derived from the SUS2 specification
// "Host names are limited to 255 bytes"
- char *osString = NULL;
#if !defined(USERWORLD)
gboolean disableQueryDiskInfo;
GuestDiskInfo *diskInfo = NULL;
/* Only use override if at least the short OS name is provided */
if (osNameOverride == NULL) {
+ Bool sendOsNames = FALSE;
+ static Bool sendStructuredOsInfo = FALSE;
+ char *osName = NULL;
+ char *osFullName = NULL;
+ char *structuredString = NULL;
+
/* Gather all the relevant guest information. */
- osString = Hostinfo_GetOSName();
- if (osString == NULL) {
- g_warning("Failed to get OS info.\n");
+ osFullName = Hostinfo_GetOSName();
+ osName = Hostinfo_GetOSGuestString();
+
+ if (sendStructuredOsInfo) {
+ structuredString = Hostinfo_GetOSStructuredString();
+ }
+ if (structuredString == NULL) {
+ sendOsNames = TRUE;
+ sendStructuredOsInfo = FALSE;
} else {
- if (!GuestInfoUpdateVmdb(ctx, INFO_OS_NAME_FULL, osString, 0)) {
- g_warning("Failed to update VMDB\n");
+ /* Build and attempt to send the structured data */
+ HostinfoStructuredHeader *structuredInfoHeader = NULL;
+ size_t infoHeaderSize;
+ size_t structuredStringLen;
+ size_t infoSize;
+
+ g_message("Sending structured OS info.\n");
+ structuredStringLen = strlen(structuredString);
+ infoHeaderSize = sizeof *structuredInfoHeader;
+ infoSize = infoHeaderSize + structuredStringLen + 1; // add 1 for '\0'
+ structuredInfoHeader = g_malloc(infoSize);
+ /* Clear struct and memory allocated for structured string */
+ memset(structuredInfoHeader, 0, infoSize);
+
+ /* Set the version of the structured header used */
+ structuredInfoHeader->version = HOSTINFO_STRUCT_HEADER_VERSION;
+
+ if (osName == NULL) {
+ g_warning("Failed to get OS name.\n");
+ } else {
+ Str_Strcpy(structuredInfoHeader->shortName, osName,
+ sizeof structuredInfoHeader->shortName);
+ }
+ if (osFullName == NULL) {
+ g_warning("Failed to get OS full name.\n");
+ } else {
+ Str_Strcpy(structuredInfoHeader->fullName, osFullName,
+ sizeof structuredInfoHeader->fullName);
+ }
+
+ Str_Strcpy((char *)structuredInfoHeader + infoHeaderSize,
+ structuredString, infoSize - infoHeaderSize);
+
+ if (GuestInfoUpdateVmdb(ctx, INFO_OS_STRUCTURED, structuredInfoHeader,
+ infoSize)) {
+ g_debug("Structured OS info sent successfully.\n");
+ GuestInfoFreeStructuredInfo(gInfoCache.structuredOSInfo);
+ gInfoCache.structuredOSInfo = structuredInfoHeader;
+ } else {
+ /* Only send the OS Name if the VMX failed to receive the
+ * structured os info. */
+ sendStructuredOsInfo = FALSE;
+ sendOsNames = TRUE;
+ g_warning("Failed to update VMX for structured OS info\n");
}
}
- free(osString);
- osString = Hostinfo_GetOSGuestString();
- if (osString == NULL) {
- g_warning("Failed to get OS info.\n");
- } else {
- if (!GuestInfoUpdateVmdb(ctx, INFO_OS_NAME, osString, 0)) {
- g_warning("Failed to update VMDB\n");
+ if (sendOsNames) {
+ g_warning("Sending the short and long name\n");
+ if (osFullName == NULL) {
+ g_warning("Failed to get OS info.\n");
+ } else {
+ if (!GuestInfoUpdateVmdb(ctx, INFO_OS_NAME_FULL, osFullName, 0)) {
+ g_warning("Failed to update VMDB\n");
+ }
+ }
+ if (osName == NULL) {
+ g_warning("Failed to get OS info.\n");
+ } else {
+ if (!GuestInfoUpdateVmdb(ctx, INFO_OS_NAME, osName, 0)) {
+ g_warning("Failed to update VMDB\n");
+ }
}
}
- free(osString);
+
+ free(structuredString);
+ free(osFullName);
+ free(osName);
} else {
/* Use osName and osNameFull provided in config file */
if (osNameFullOverride == NULL) {
gInfoCache.value[infoType] = Util_SafeStrdup((char *) info);
break;
+ case INFO_OS_STRUCTURED:
+ {
+ if (gInfoCache.structuredOSInfo != NULL &&
+ GuestInfoStructuredInfoIsEqual(gInfoCache.structuredOSInfo,
+ (HostinfoStructuredHeader *)info)) {
+ /* The value has not changed */
+ g_debug("Value unchanged for structuredOSInfo.\n");
+ break;
+ }
+
+ if (!GuestInfoSendData(ctx, info, infoSize, INFO_OS_STRUCTURED)) {
+ g_warning("Failed to update structured os information.\n");
+ return FALSE;
+ }
+ break;
+ }
+
case INFO_IPADDRESS:
{
if (!GuestInfoSendNicInfo(ctx, (NicInfoV3 *) info)) {
gInfoCache.value[i] = NULL;
}
+ GuestInfoFreeStructuredInfo(gInfoCache.structuredOSInfo);
+ gInfoCache.structuredOSInfo = NULL;
+
GuestInfo_FreeDiskInfo(gInfoCache.diskInfo);
gInfoCache.diskInfo = NULL;