]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Adding structured data to Tools. (feature DISABLED)
authorOliver Kurth <okurth@vmware.com>
Wed, 29 Aug 2018 20:29:45 +0000 (13:29 -0700)
committerOliver Kurth <okurth@vmware.com>
Wed, 29 Aug 2018 20:29:45 +0000 (13:29 -0700)
This change touches both vmware-tools and the VMX.

Tools:
Added new rpc for sending a structured data. The structured data is
composed of 2 parts. A struct header and a well formatted property list
string called structured string.

The structured string is built by appending key='value' pairs
separated by ' '. This string will include any extra information
regarding the guest that is applicable to the VMX and higher up.

The structured string will not include any '"' characters and all '\\'
and '\'' characters are escaped. The fields included in the structured
string will vary depending on the guest OS, and if Linux, also what lsb
standard it conforms to.

The structure header contains the OS name and OS long name and will
always be included. If the structured data can be sent successfully the
short and long os names are not sent individually. If the VMX is an
older version and does not support the structured data RPC, then the
send in Tools will fail and can react accordingly.

open-vm-tools/lib/include/guestInfo.h
open-vm-tools/lib/include/hostinfo.h
open-vm-tools/lib/misc/hostinfo.c
open-vm-tools/lib/misc/hostinfoInt.h
open-vm-tools/lib/misc/hostinfoPosix.c
open-vm-tools/services/plugins/guestInfo/guestInfoServer.c

index dabcae6c14ec8266e70cfd86e0ec849ef9c26158..b1ae3a7733c86b5c392f35ed3f75a1e0494ef9f8 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2003-2017 VMware, Inc. All rights reserved.
+ * Copyright (C) 2003-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -71,6 +71,7 @@ typedef enum {
    INFO_MEMORY,
    INFO_IPADDRESS_V2,
    INFO_IPADDRESS_V3,
+   INFO_OS_STRUCTURED,
    INFO_MAX
 } GuestInfoType;
 
index d245d6a2c4096b6e6ee42e6b60f4ae708cedfc37..3456b8f1163292478243db627a42b0490c5d8b35 100644 (file)
@@ -39,6 +39,9 @@
 extern "C" {
 #endif
 
+#define MAX_OS_NAME_LEN 128
+#define MAX_OS_FULLNAME_LEN 512
+
 typedef enum {
    HOSTINFO_PROCESS_QUERY_DEAD,    // Procss is dead (does not exist)
    HOSTINFO_PROCESS_QUERY_ALIVE,   // Process is alive (does exist)
@@ -47,10 +50,25 @@ typedef enum {
 
 HostinfoProcessQuery Hostinfo_QueryProcessExistence(int pid);
 
-char *Hostinfo_NameGet(void);           // Don't free result
-char *Hostinfo_HostName(void);          // free result
-char *Hostinfo_GetOSName(void);         // free result
-char *Hostinfo_GetOSGuestString(void);  // free result
+/* This macro defines the current version of the structured header. */
+#define HOSTINFO_STRUCT_HEADER_VERSION 1
+
+/*
+ * This struct is used to build a structured OS data. The structured data will
+ * be composed of two parts. The first part is the header and the second part
+ * will be a structured string that is appended to this header in memory.
+ */
+typedef struct HostinfoStructuredHeader {
+   uint32  version;
+   char    shortName[MAX_OS_NAME_LEN + 1];
+   char    fullName[MAX_OS_FULLNAME_LEN + 1];
+} HostinfoStructuredHeader;
+
+char *Hostinfo_NameGet(void);                // Don't free result
+char *Hostinfo_HostName(void);               // free result
+char *Hostinfo_GetOSName(void);              // free result
+char *Hostinfo_GetOSGuestString(void);       // free result
+char *Hostinfo_GetOSStructuredString(void);  // free result
 
 void Hostinfo_MachineID(uint32 *hostNameHash,
                         uint64 *hostHardwareID);
index 635f9ac7e1b4dafd74c6cfb7135e0dd1fedab999..5c81805a44ca936e740848afc08b3a037b6587c1 100644 (file)
@@ -50,6 +50,7 @@
 volatile Bool HostinfoOSNameCacheValid = FALSE;
 char HostinfoCachedOSName[MAX_OS_NAME_LEN];
 char HostinfoCachedOSFullName[MAX_OS_FULLNAME_LEN];
+char HostinfoCachedStructuredString[MAX_STRUCTURED_STRING_LEN];
 
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -268,7 +269,6 @@ Hostinfo_GetOSName(void)
 }
 
 
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -302,3 +302,37 @@ Hostinfo_GetOSGuestString(void)
    return name;
 }
 
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Hostinfo_GetOSStructuredString --
+ *
+ *      Query the operating system and build a string of property list
+ *      containing detailed information about the guest OS. The returned string
+ *      is written into the VM's .vmx file
+ *
+ * Return value:
+ *      NULL  Unable to obtain the structured string.
+ *     !NULL  The structured string. The caller is responsible for freeing it.
+ *
+ * Side effects:
+ *      Memory is allocated.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+char *
+Hostinfo_GetOSStructuredString(void)
+{
+   char *structuredString;
+   Bool data = HostinfoOSNameCacheValid ? TRUE : HostinfoOSData();
+
+   if (data) {
+      structuredString = Util_SafeStrdup(HostinfoCachedStructuredString);
+   } else {
+      structuredString = NULL;
+   }
+
+   return structuredString;
+}
index 40dab2c95465f0abe28a68243ea40dbeec92c7ce..a7d434b4268e784f4228f3c9238ae3827cbdad65 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2009-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2009-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
 
 #define MAX_OS_NAME_LEN 128
 #define MAX_OS_FULLNAME_LEN 512
+#define MAX_STRUCTURED_FIELD_LEN 1024
+
+#define STRUCTURED_STRING_DELIMITER " "
 
 
 /*
  * Global variables
  */
 
+typedef struct {
+   char  *name;
+   char  value[MAX_STRUCTURED_FIELD_LEN];
+} StructuredField;
+
+/* Must be sorted. Keep in same ordering as structuredFields */
+typedef enum {
+   BITNESS,
+   BUILD_NUMBER,
+   DISTRO_NAME,
+   DISTRO_VERSION,
+   FAMILY_NAME,
+   KERNEL_VERSION,
+   PRETTY_NAME
+} StructuredFieldType;
+
+/* Must be sorted. Keep in same ordering as StructuredFieldType. Defined in
+ * hostinfoPosix.c */
+extern StructuredField structuredFields[];
+
+#define MAX_STRUCTURED_STRING_LEN MAX_STRUCTURED_FIELD_LEN * 10
+
+
 extern volatile Bool HostinfoOSNameCacheValid;
 extern char HostinfoCachedOSName[MAX_OS_NAME_LEN];
 extern char HostinfoCachedOSFullName[MAX_OS_FULLNAME_LEN];
+extern char HostinfoCachedStructuredString[MAX_STRUCTURED_STRING_LEN];
 
 
 /*
index b6ebaa7e78e592648230c150ba4703989421a648..f34c2e0990f2b0391b3b24936a885013316c8735 100644 (file)
@@ -169,7 +169,10 @@ static const DistroNameScan lsbFields[] = {
 
 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 {
@@ -223,6 +226,18 @@ static const DistroInfo distroArray[] = {
 };
 #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().
@@ -517,6 +532,76 @@ HostinfoPostData(const char *osName,  // IN:
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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
 /*
  *-----------------------------------------------------------------------------
@@ -573,6 +658,13 @@ HostinfoMacOS(struct utsname *buf)  // IN:
       }
    }
 
+   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,
@@ -1124,20 +1216,74 @@ static Bool
 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;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -1161,6 +1307,9 @@ HostinfoLsb(char *distro,       // OUT:
 {
    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.
@@ -1178,7 +1327,6 @@ HostinfoLsb(char *distro,       // OUT:
       for (i = 0; distroArray[i].filename != NULL; i++) {
          if (HostinfoReadDistroFile(FALSE, distroArray[i].filename,
                                     &lsbFields[0], distroSize, distro)) {
-            success = TRUE;
             break;
          }
       }
@@ -1187,26 +1335,58 @@ HostinfoLsb(char *distro,       // OUT:
        * 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;
 }
 
@@ -1512,6 +1692,7 @@ HostinfoOSData(void)
 {
    Bool success;
    struct utsname buf;
+   const char *bitness;
 
    /*
     * Use uname to get complete OS information.
@@ -1523,6 +1704,22 @@ HostinfoOSData(void)
       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
@@ -1539,6 +1736,9 @@ HostinfoOSData(void)
    }
 #endif
 
+   /* Build structured string */
+   HostinfoOSStructuredString();
+
    return success;
 }
 
index 4b0642e2a240b66d46dd2a2425db1a6354b7dc9a..c51af4ce2fd4a678f2ae49b020cb603ea9d711ff 100644 (file)
@@ -114,10 +114,11 @@ typedef enum NicInfoMethod {
 
 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;
 
 
@@ -456,7 +457,54 @@ GuestInfoResetNicExcludeList(ToolsAppCtx *ctx)
 
 /*
  ******************************************************************************
- * 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.
  *
@@ -472,7 +520,6 @@ GuestInfoGather(gpointer data)
 {
    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;
@@ -521,26 +568,91 @@ GuestInfoGather(gpointer data)
 
    /* 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) {
@@ -1127,6 +1239,23 @@ GuestInfoUpdateVmdb(ToolsAppCtx *ctx,       // IN: Application context
       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)) {
@@ -1441,6 +1570,9 @@ GuestInfoClearCache(void)
       gInfoCache.value[i] = NULL;
    }
 
+   GuestInfoFreeStructuredInfo(gInfoCache.structuredOSInfo);
+   gInfoCache.structuredOSInfo = NULL;
+
    GuestInfo_FreeDiskInfo(gInfoCache.diskInfo);
    gInfoCache.diskInfo = NULL;