]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
GuestOS: Support the os-release standard
authorOliver Kurth <okurth@vmware.com>
Wed, 7 Feb 2018 00:32:37 +0000 (16:32 -0800)
committerOliver Kurth <okurth@vmware.com>
Wed, 7 Feb 2018 00:32:37 +0000 (16:32 -0800)
While bringing up Amazon Linux as a guest, it was discovered that
Amazon Linux was not LSB compilant. The LSB standard defines a way
to uniquely determine which distro one is running on. Since our code
was based on the LSB standard, we made some changes to explicitly
detect Amazon Linux and handle it as a special case.

Amazon let us know that there is a "new" standard - os-release - which
they are compliant with. One must explicitly install Amazon Linux in a
special way to obtain the LSB compliance.

Researching the "new" standard, it turned out to not be that different
than the LSB standard. Further research showed that some distros (e.g.
Ubuntu) are releasing with both standards.

This change refactors the existing code, removes the explicit Amazon
Linux checking, and accepts the os-release standard. Amazon Linux then
"just falls out".

open-vm-tools/lib/misc/hostinfoPosix.c

index e125382fc9116ac013d6d891a2c10751385dddfb..db78f6ec12b5139da9cc69276b6bcd95921f9203 100644 (file)
@@ -167,7 +167,7 @@ static const DistroNameScan lsbFields[] = {
    {NULL,                   NULL                     },
 };
 
-static const DistroNameScan amazonFields[] = {
+static const DistroNameScan osReleaseFields[] = {
    {"PRETTY_NAME=",        "PRETTY_NAME=%s"          },
    {NULL,                   NULL                     },
 };
@@ -752,6 +752,19 @@ HostinfoGetOSShortName(char *distro,         // IN: full distro name
       Str_Strcpy(distroShort, STR_OS_TURBO, distroShortSize);
    } else if (strstr(distroLower, "sun")) {
       Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
+   } else if (strstr(distroLower, "amazon")) {
+      int amazonMinor = 0;
+      int amazonMajor = 0;
+
+      if (sscanf(distroLower, "Amazon Linux %d.%d", &amazonMajor,
+                 &amazonMinor) != 2) {
+         /* Oldest known good release */
+         amazonMajor = 2;
+         amazonMinor = 0;
+      }
+
+      Str_Sprintf(distroShort, distroShortSize, "%s%d", STR_OS_AMAZON,
+                  amazonMajor);
    } else if (strstr(distroLower, "annvix")) {
       Str_Strcpy(distroShort, STR_OS_ANNVIX, distroShortSize);
    } else if (strstr(distroLower, "arch")) {
@@ -965,12 +978,7 @@ HostinfoReadDistroFile(char *filename,                // IN: version file
       }
    }
 
-   if (distro[0] == '\0') {
-      /* Copy original string. What we got wasn't LSB compliant. */
-      Str_Strcpy(distro, distroOrig, distroSize);
-   }
-
-   ret = TRUE;
+   ret =  (distro[0] != '\0');
 
 out:
    if (fd != -1) {
@@ -1073,70 +1081,64 @@ HostinfoGetCmdOutput(const char *cmd)  // IN:
 /*
  *-----------------------------------------------------------------------------
  *
- * HostinfoLinux --
+ * HostinfoOsRelease --
  *
- *      Determine the specifics concerning Linux.
+ *      Attempt to determine the distro string via the os-release standard.
  *
  * Return value:
  *      TRUE   Success
  *      FALSE  Failure
  *
  * Side effects:
- *      Cache values are set when returning TRUE
+ *      distro is set on success.
  *
  *-----------------------------------------------------------------------------
  */
 
 static Bool
-HostinfoLinux(struct utsname *buf)  // IN:
+HostinfoOsRelease(char *distro,       // OUT:
+                  size_t distroSize)  // IN:
 {
-   int len;
-   char *lsbOutput;
-   int majorVersion;
-   char distro[DISTRO_BUF_SIZE];
-   char distroShort[DISTRO_BUF_SIZE];
-   char osName[MAX_OS_NAME_LEN];
-   char osNameFull[MAX_OS_FULLNAME_LEN];
-   static int const distroSize = sizeof distro;
-
-   /*
-    * Write default distro string depending on the kernel version. If
-    * later we find more detailed information this will get overwritten.
-    */
+   Bool success;
 
-   majorVersion = Hostinfo_OSVersion(0);
-   if (majorVersion < 2) {
-      Str_Strcpy(distro, STR_OS_OTHER_FULL, distroSize);
-      Str_Strcpy(distroShort, STR_OS_OTHER, distroSize);
-   } else if (majorVersion == 2) {
-       if (Hostinfo_OSVersion(1) < 4) {
-         Str_Strcpy(distro, STR_OS_OTHER_FULL, distroSize);
-         Str_Strcpy(distroShort, STR_OS_OTHER, distroSize);
-      } else if (Hostinfo_OSVersion(1) < 6) {
-         Str_Strcpy(distro, STR_OS_OTHER_24_FULL, distroSize);
-         Str_Strcpy(distroShort, STR_OS_OTHER_24, distroSize);
-      } else {
-         Str_Strcpy(distro, STR_OS_OTHER_26_FULL, distroSize);
-         Str_Strcpy(distroShort, STR_OS_OTHER_26, distroSize);
-      }
-   } else if (majorVersion == 3) {
-      Str_Strcpy(distro, STR_OS_OTHER_3X_FULL, distroSize);
-      Str_Strcpy(distroShort, STR_OS_OTHER_3X, distroSize);
-   } else if (majorVersion == 4) {
-      Str_Strcpy(distro, STR_OS_OTHER_4X_FULL, distroSize);
-      Str_Strcpy(distroShort, STR_OS_OTHER_4X, distroSize);
-   } else {
-      /*
-       * Anything newer than this code explicitly handles returns the
-       * "highest" known short description and a dynamically created,
-       * appropriate long description.
-       */
+   success = HostinfoReadDistroFile("/etc/os-release",
+                                    &osReleaseFields[0],
+                                    distroSize, distro);
 
-      Str_Sprintf(distro, sizeof distro, "Other Linux %d.%d kernel",
-                  majorVersion, Hostinfo_OSVersion(1));
-      Str_Strcpy(distroShort, STR_OS_OTHER_4X, distroSize);
+   if (!success) {
+      success = HostinfoReadDistroFile("/usr/lib/os-release",
+                                       &osReleaseFields[0],
+                                       distroSize, distro);
    }
 
+   return success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HostinfoLsb --
+ *
+ *      Attempt to determine the disto string via the LSB standard.
+ *
+ * Return value:
+ *      TRUE   Success
+ *      FALSE  Failure
+ *
+ * Side effects:
+ *      distro is set on success.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HostinfoLsb(char *distro,       // OUT:
+            size_t distroSize)  // IN:
+{
+   char *lsbOutput;
+   Bool success = FALSE;
+
    /*
     * Try to get OS detailed information from the lsb_release command.
     */
@@ -1152,6 +1154,7 @@ HostinfoLinux(struct utsname *buf)  // IN:
       for (i = 0; distroArray[i].filename != NULL; i++) {
          if (HostinfoReadDistroFile(distroArray[i].filename, &lsbFields[0],
                                     distroSize, distro)) {
+            success = TRUE;
             break;
          }
       }
@@ -1163,8 +1166,6 @@ HostinfoLinux(struct utsname *buf)  // IN:
 
       if (distroArray[i].filename == NULL) {
          Warning("%s: Error: no distro file found\n", __FUNCTION__);
-
-         return FALSE;
       }
    } else {
       char *lsbStart = lsbOutput;
@@ -1179,9 +1180,127 @@ HostinfoLinux(struct utsname *buf)  // IN:
       }
       Str_Strcpy(distro, lsbStart, distroSize);
       free(lsbOutput);
+      success = TRUE;
+   }
+
+   return success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HostinfoDefaultLinux --
+ *
+ *      Build a generic description of the running Linux, along with a short
+ *      description (i.e. guestOS string).
+ *
+ * Return value:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HostinfoDefaultLinux(char *distro,            // OUT:
+                     size_t distroSize,       // OUT:
+                     char *distroShort,       // OUT:
+                     size_t distroShortSize)  // OUT:
+{
+   int majorVersion = Hostinfo_OSVersion(0);
+   int minorVersion = Hostinfo_OSVersion(1);
+
+   switch (majorVersion) {
+   case 1:
+      Str_Strcpy(distro, STR_OS_OTHER_FULL, distroSize);
+      Str_Strcpy(distroShort, STR_OS_OTHER, distroShortSize);
+      break;
+
+   case 2:
+      if (minorVersion < 4) {
+         Str_Strcpy(distro, STR_OS_OTHER_FULL, distroSize);
+         Str_Strcpy(distroShort, STR_OS_OTHER, distroShortSize);
+      } else if (minorVersion < 6) {
+         Str_Strcpy(distro, STR_OS_OTHER_24_FULL, distroSize);
+         Str_Strcpy(distroShort, STR_OS_OTHER_24, distroShortSize);
+      } else {
+         Str_Strcpy(distro, STR_OS_OTHER_26_FULL, distroSize);
+         Str_Strcpy(distroShort, STR_OS_OTHER_26, distroShortSize);
+      }
+
+      break;
+
+   case 3:
+      Str_Strcpy(distro, STR_OS_OTHER_3X_FULL, distroSize);
+      Str_Strcpy(distroShort, STR_OS_OTHER_3X, distroShortSize);
+      break;
+
+   case 4:
+      Str_Strcpy(distro, STR_OS_OTHER_4X_FULL, distroSize);
+      Str_Strcpy(distroShort, STR_OS_OTHER_4X, distroShortSize);
+      break;
+
+   default:
+      /*
+       * Anything newer than this code explicitly handles returns the
+       * "highest" known short description and a dynamically created,
+       * appropriate long description.
+       */
+
+      Str_Sprintf(distro, distroSize, "Other Linux %d.%d kernel",
+                  majorVersion, minorVersion);
+      Str_Strcpy(distroShort, STR_OS_OTHER_4X, distroShortSize);
    }
+}
 
-   HostinfoGetOSShortName(distro, distroShort, distroSize);
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HostinfoLinux --
+ *
+ *      Determine the specifics concerning Linux.
+ *
+ * Return value:
+ *      TRUE   Success
+ *      FALSE  Failure
+ *
+ * Side effects:
+ *      Cache values are set when returning TRUE
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HostinfoLinux(struct utsname *buf)  // IN:
+{
+   int len;
+   char distro[DISTRO_BUF_SIZE];
+   char distroShort[DISTRO_BUF_SIZE];
+   char osName[MAX_OS_NAME_LEN];
+   char osNameFull[MAX_OS_FULLNAME_LEN];
+
+   /* Try the LSB standard first, this maximizes compatibility */
+   if (HostinfoLsb(distro, sizeof distro)) {
+      HostinfoGetOSShortName(distro, distroShort, sizeof distro);
+      goto bail;
+   }
+
+   /* No LSB compliance, try the os-release standard */
+   if (HostinfoOsRelease(distro, sizeof distro)) {
+      HostinfoGetOSShortName(distro, distroShort, sizeof distro);
+      goto bail;
+   }
+
+   /* Not LSB or os-release compliant. Report something generic. */
+
+   HostinfoDefaultLinux(distro, sizeof distro,
+                        distroShort, sizeof distroShort);
+
+bail:
 
    len = Str_Snprintf(osNameFull, sizeof osNameFull, "%s %s %s", buf->sysname,
                       buf->release, distro);
@@ -1328,68 +1447,6 @@ HostinfoSun(struct utsname *buf)  // IN:
 
    return (len != -1);
 }
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HostinfoAmazon --
- *
- *      Determine the specifics concerning Amazon Linux.
- *
- * Return value:
- *      TRUE   Success
- *      FALSE  Failure
- *
- * Side effects:
- *      Cache values are set when returning TRUE
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HostinfoAmazon(struct utsname *buf)  // IN:
-{
-   int len;
-   char osName[MAX_OS_NAME_LEN];
-   char osNameFull[MAX_OS_FULLNAME_LEN] = { '\0' };
-
-   if (HostinfoReadDistroFile("/etc/os-release", &amazonFields[0],
-                              sizeof osNameFull, osNameFull)) {
-      len = strlen(osNameFull);
-   } else {
-      Log("%s: Using fallback\n", __FUNCTION__);
-
-      len = Str_Snprintf(osNameFull, sizeof osNameFull,
-                         "Amazon Linux x.y (kernel %d.%d)",
-                         Hostinfo_OSVersion(0),          // Kernel major
-                         Hostinfo_OSVersion(1));         // Kernel minor
-   }
-
-   if (len != -1) {
-      int amazonMinor = 0;
-      int amazonMajor = 0;
-
-      if (sscanf(osNameFull, "Amazon Linux %d.%d", &amazonMajor,
-                 &amazonMinor) != 2) {
-         /* Oldest known good release */
-         amazonMajor = 2;
-         amazonMinor = 0;
-      }
-
-      /* We are not offering a 32-bit version... or ever plan to. */
-      len = Str_Snprintf(osName, sizeof osName, "%s%d%s", STR_OS_AMAZON,
-                         amazonMajor, STR_OS_64BIT_SUFFIX);
-   }
-
-   if (len == -1) {
-      Warning("%s: Error: buffer too small\n", __FUNCTION__);
-   } else {
-      HostinfoPostData(osName, osNameFull);
-   }
-
-   return (len != -1);
-}
 #endif // !defined __APPLE__ && !defined USERWORLD
 
 
@@ -1432,13 +1489,7 @@ HostinfoOSData(void)
    success = HostinfoMacOS(&buf);
 #else
    if (strstr(buf.sysname, "Linux")) {
-      struct stat sb;
-
-      if (Posix_Stat("/etc/amazon", &sb) == 0) {
-         success = HostinfoAmazon(&buf);
-      } else {
-         success = HostinfoLinux(&buf);
-      }
+      success = HostinfoLinux(&buf);
    } else if (strstr(buf.sysname, "FreeBSD")) {
       success = HostinfoBSD(&buf);
    } else if (strstr(buf.sysname, "SunOS")) {