From: Oliver Kurth Date: Wed, 7 Feb 2018 00:32:37 +0000 (-0800) Subject: GuestOS: Support the os-release standard X-Git-Tag: stable-10.3.0~160 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ce060ca498defdf08da4fac899dc623328d47a5d;p=thirdparty%2Fopen-vm-tools.git GuestOS: Support the os-release standard 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". --- diff --git a/open-vm-tools/lib/misc/hostinfoPosix.c b/open-vm-tools/lib/misc/hostinfoPosix.c index e125382fc..db78f6ec1 100644 --- a/open-vm-tools/lib/misc/hostinfoPosix.c +++ b/open-vm-tools/lib/misc/hostinfoPosix.c @@ -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")) {