Commit 5b9b01f7 authored by Tomas Popela's avatar Tomas Popela Committed by Commit Bot

Get the distribution name from os-release instead of lsb_release

Use the PRETTY_NAME variable from /etc/os-release (or
/usr/lib/os-release) to get the "pretty operating system name in a format
suitable for presentation to the user" as the standard says.

This could allow us to drop a requirement on lsb_release binary on
Linux. The os-release is presented on most new distribution like Fedora,
RHEL 7, CentOS 7, Ubuntu 12.04+, Debian Wheezy+.

More information could be found on
https://www.freedesktop.org/software/systemd/man/os-release.html.

Bug: 420439
Change-Id: If4fc3cd3d22507e47b32d6184ac6ef4ae4b4ff3f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1156504
Commit-Queue: Tomáš Popela <tomas.popela@gmail.com>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Auto-Submit: Tomáš Popela <tomas.popela@gmail.com>
Cr-Commit-Position: refs/heads/master@{#695280}
parent 509d8bfa
...@@ -2991,7 +2991,10 @@ test("base_unittests") { ...@@ -2991,7 +2991,10 @@ test("base_unittests") {
} }
if (is_desktop_linux) { if (is_desktop_linux) {
sources += [ "nix/xdg_util_unittest.cc" ] sources += [
"linux_util_unittest.cc",
"nix/xdg_util_unittest.cc",
]
} }
if (!use_glib) { if (!use_glib) {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <iomanip>
#include <memory> #include <memory>
#include "base/command_line.h" #include "base/command_line.h"
...@@ -28,6 +29,8 @@ ...@@ -28,6 +29,8 @@
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "build/build_config.h" #include "build/build_config.h"
namespace base {
namespace { namespace {
// Not needed for OS_CHROMEOS. // Not needed for OS_CHROMEOS.
...@@ -43,7 +46,7 @@ class LinuxDistroHelper { ...@@ -43,7 +46,7 @@ class LinuxDistroHelper {
public: public:
// Retrieves the Singleton. // Retrieves the Singleton.
static LinuxDistroHelper* GetInstance() { static LinuxDistroHelper* GetInstance() {
return base::Singleton<LinuxDistroHelper>::get(); return Singleton<LinuxDistroHelper>::get();
} }
// The simple state machine goes from: // The simple state machine goes from:
...@@ -55,7 +58,7 @@ class LinuxDistroHelper { ...@@ -55,7 +58,7 @@ class LinuxDistroHelper {
// we automatically move to STATE_CHECK_STARTED so nobody else will // we automatically move to STATE_CHECK_STARTED so nobody else will
// do the check. // do the check.
LinuxDistroState State() { LinuxDistroState State() {
base::AutoLock scoped_lock(lock_); AutoLock scoped_lock(lock_);
if (STATE_DID_NOT_CHECK == state_) { if (STATE_DID_NOT_CHECK == state_) {
state_ = STATE_CHECK_STARTED; state_ = STATE_CHECK_STARTED;
return STATE_DID_NOT_CHECK; return STATE_DID_NOT_CHECK;
...@@ -65,21 +68,72 @@ class LinuxDistroHelper { ...@@ -65,21 +68,72 @@ class LinuxDistroHelper {
// Indicate the check finished, move to STATE_CHECK_FINISHED. // Indicate the check finished, move to STATE_CHECK_FINISHED.
void CheckFinished() { void CheckFinished() {
base::AutoLock scoped_lock(lock_); AutoLock scoped_lock(lock_);
DCHECK_EQ(STATE_CHECK_STARTED, state_); DCHECK_EQ(STATE_CHECK_STARTED, state_);
state_ = STATE_CHECK_FINISHED; state_ = STATE_CHECK_FINISHED;
} }
private: private:
base::Lock lock_; Lock lock_;
LinuxDistroState state_; LinuxDistroState state_;
}; };
#if !defined(OS_CHROMEOS)
std::string GetKeyValueFromOSReleaseFile(const std::string& input,
const char* key) {
StringPairs key_value_pairs;
SplitStringIntoKeyValuePairs(input, '=', '\n', &key_value_pairs);
for (const auto& pair : key_value_pairs) {
const std::string& key_str = pair.first;
const std::string& value_str = pair.second;
if (key_str == key) {
// It can contain quoted characters.
std::stringstream ss;
std::string pretty_name;
ss << value_str;
// Quoted with a single tick?
if (value_str[0] == '\'')
ss >> std::quoted(pretty_name, '\'');
else
ss >> std::quoted(pretty_name);
return pretty_name;
}
}
return "";
}
bool ReadDistroFromOSReleaseFile(const char* file) {
static const char kPrettyName[] = "PRETTY_NAME";
std::string os_release_content;
if (!ReadFileToString(FilePath(file), &os_release_content))
return false;
std::string pretty_name =
GetKeyValueFromOSReleaseFile(os_release_content, kPrettyName);
if (pretty_name.empty())
return false;
SetLinuxDistro(pretty_name);
return true;
}
// https://www.freedesktop.org/software/systemd/man/os-release.html
void GetDistroNameFromOSRelease() {
static const char* const kFilesToCheck[] = {"/etc/os-release",
"/usr/lib/os-release"};
for (const char* file : kFilesToCheck) {
if (ReadDistroFromOSReleaseFile(file))
return;
}
}
#endif // if !defined(OS_CHROMEOS)
#endif // if defined(OS_LINUX) #endif // if defined(OS_LINUX)
} // namespace } // namespace
namespace base {
// Account for the terminating null character. // Account for the terminating null character.
static const int kDistroSize = 128 + 1; static const int kDistroSize = 128 + 1;
...@@ -94,6 +148,16 @@ char g_linux_distro[kDistroSize] = ...@@ -94,6 +148,16 @@ char g_linux_distro[kDistroSize] =
"Unknown"; "Unknown";
#endif #endif
BASE_EXPORT std::string GetKeyValueFromOSReleaseFileForTesting(
const std::string& input,
const char* key) {
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
return GetKeyValueFromOSReleaseFile(input, key);
#else
return "";
#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
}
std::string GetLinuxDistro() { std::string GetLinuxDistro() {
#if defined(OS_CHROMEOS) || defined(OS_ANDROID) #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
return g_linux_distro; return g_linux_distro;
...@@ -106,20 +170,8 @@ std::string GetLinuxDistro() { ...@@ -106,20 +170,8 @@ std::string GetLinuxDistro() {
return "Unknown"; // Don't wait for other thread to finish. return "Unknown"; // Don't wait for other thread to finish.
DCHECK_EQ(state, STATE_DID_NOT_CHECK); DCHECK_EQ(state, STATE_DID_NOT_CHECK);
// We do this check only once per process. If it fails, there's // We do this check only once per process. If it fails, there's
// little reason to believe it will work if we attempt to run // little reason to believe it will work if we attempt to run it again.
// lsb_release again. GetDistroNameFromOSRelease();
std::vector<std::string> argv;
argv.push_back("lsb_release");
argv.push_back("-d");
std::string output;
GetAppOutput(CommandLine(argv), &output);
if (output.length() > 0) {
// lsb_release -d should return: Description:<tab>Distro Info
const char field[] = "Description:\t";
if (output.compare(0, strlen(field), field) == 0) {
SetLinuxDistro(output.substr(strlen(field)));
}
}
distro_state_singleton->CheckFinished(); distro_state_singleton->CheckFinished();
return g_linux_distro; return g_linux_distro;
#else #else
...@@ -137,7 +189,7 @@ void SetLinuxDistro(const std::string& distro) { ...@@ -137,7 +189,7 @@ void SetLinuxDistro(const std::string& distro) {
bool GetThreadsForProcess(pid_t pid, std::vector<pid_t>* tids) { bool GetThreadsForProcess(pid_t pid, std::vector<pid_t>* tids) {
// 25 > strlen("/proc//task") + strlen(std::to_string(INT_MAX)) + 1 = 22 // 25 > strlen("/proc//task") + strlen(std::to_string(INT_MAX)) + 1 = 22
char buf[25]; char buf[25];
base::strings::SafeSPrintf(buf, "/proc/%d/task", pid); strings::SafeSPrintf(buf, "/proc/%d/task", pid);
DirReaderPosix dir_reader(buf); DirReaderPosix dir_reader(buf);
if (!dir_reader.IsValid()) { if (!dir_reader.IsValid()) {
......
...@@ -22,6 +22,14 @@ BASE_EXPORT extern char g_linux_distro[]; ...@@ -22,6 +22,14 @@ BASE_EXPORT extern char g_linux_distro[];
// Get the Linux Distro if we can, or return "Unknown". // Get the Linux Distro if we can, or return "Unknown".
BASE_EXPORT std::string GetLinuxDistro(); BASE_EXPORT std::string GetLinuxDistro();
#if defined(UNIT_TEST)
// Get the value of given key from the given input (content of the
// /etc/os-release file. Exposed for testing.
BASE_EXPORT std::string GetKeyValueFromOSReleaseFileForTesting(
const std::string& input,
const char* key);
#endif // defined(UNIT_TEST)
// Set the Linux Distro string. // Set the Linux Distro string.
BASE_EXPORT void SetLinuxDistro(const std::string& distro); BASE_EXPORT void SetLinuxDistro(const std::string& distro);
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/linux_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kPrettyName[] = "PRETTY_NAME";
TEST(LinuxUtilTest, ParseEtcOsReleaseFile) {
const char kOsRelease[] = R"X(
NAME=Fedora
VERSION="30 (Workstation Edition\)\"
ID=fedora
VERSION_ID=30
VERSION_CODENAME=""
PLATFORM_ID="platform:f30
PRETTY_NAME="Fedora 30 (Workstation Edition)"
ANSI_COLOR="0;34"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:30"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f30/system-administrators-guide/"
SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=30
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=30
PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"
VARIANT="Workstation Edition"
VARIANT_ID=workstation)X";
const char kOsReleaseMissingPrettyName[] = R"(
NAME=Fedora
VERSION='30 (Workstation Edition)'
VARIANT_ID=workstation)";
std::string value =
base::GetKeyValueFromOSReleaseFileForTesting(kOsRelease, kPrettyName);
EXPECT_EQ(value, "Fedora 30 (Workstation Edition)");
// Missing key in the file
value = base::GetKeyValueFromOSReleaseFileForTesting(
kOsReleaseMissingPrettyName, kPrettyName);
EXPECT_EQ(value, "");
// Value quoted with single ticks
value = base::GetKeyValueFromOSReleaseFileForTesting(
kOsReleaseMissingPrettyName, "VERSION");
EXPECT_EQ(value, "30 (Workstation Edition)");
// Empty file
value = base::GetKeyValueFromOSReleaseFileForTesting("", kPrettyName);
EXPECT_EQ(value, "");
// Misspelled key
value =
base::GetKeyValueFromOSReleaseFileForTesting(kOsRelease, "PRETY_NAME");
EXPECT_EQ(value, "");
// Broken key=value format
value = base::GetKeyValueFromOSReleaseFileForTesting("A/B", kPrettyName);
EXPECT_EQ(value, "");
// Empty values
value =
base::GetKeyValueFromOSReleaseFileForTesting("PRETTY_NAME=", kPrettyName);
EXPECT_EQ(value, "");
value = base::GetKeyValueFromOSReleaseFileForTesting("PRETTY_NAME=\"\"",
kPrettyName);
EXPECT_EQ(value, "");
// Only one key=value in the whole file
value = base::GetKeyValueFromOSReleaseFileForTesting("PRETTY_NAME=\"Linux\"",
kPrettyName);
EXPECT_EQ(value, "Linux");
}
} // namespace
...@@ -302,18 +302,18 @@ void RecordLinuxDistro() { ...@@ -302,18 +302,18 @@ void RecordLinuxDistro() {
} }
} }
} else if (distro_tokens[0] == "Fedora") { } else if (distro_tokens[0] == "Fedora") {
// Format: Fedora release RR (<codename>) // Format: Fedora RR (<codename>)
distro_result = UMA_LINUX_DISTRO_FEDORA_OTHER; distro_result = UMA_LINUX_DISTRO_FEDORA_OTHER;
if (distro_tokens.size() >= 3) { if (distro_tokens.size() >= 2) {
if (distro_tokens[2] == "24") { if (distro_tokens[1] == "24") {
distro_result = UMA_LINUX_DISTRO_FEDORA_24; distro_result = UMA_LINUX_DISTRO_FEDORA_24;
} else if (distro_tokens[2] == "25") { } else if (distro_tokens[1] == "25") {
distro_result = UMA_LINUX_DISTRO_FEDORA_25; distro_result = UMA_LINUX_DISTRO_FEDORA_25;
} else if (distro_tokens[2] == "26") { } else if (distro_tokens[1] == "26") {
distro_result = UMA_LINUX_DISTRO_FEDORA_26; distro_result = UMA_LINUX_DISTRO_FEDORA_26;
} else if (distro_tokens[2] == "27") { } else if (distro_tokens[1] == "27") {
distro_result = UMA_LINUX_DISTRO_FEDORA_27; distro_result = UMA_LINUX_DISTRO_FEDORA_27;
} else if (distro_tokens[2] == "28") { } else if (distro_tokens[1] == "28") {
distro_result = UMA_LINUX_DISTRO_FEDORA_28; distro_result = UMA_LINUX_DISTRO_FEDORA_28;
} }
} }
...@@ -321,23 +321,23 @@ void RecordLinuxDistro() { ...@@ -321,23 +321,23 @@ void RecordLinuxDistro() {
// Format: Arch Linux // Format: Arch Linux
distro_result = UMA_LINUX_DISTRO_ARCH; distro_result = UMA_LINUX_DISTRO_ARCH;
} else if (distro_tokens[0] == "CentOS") { } else if (distro_tokens[0] == "CentOS") {
// Format: CentOS [Linux] release <version> (<codename>) // Format: CentOS [Linux] <version> (<codename>)
distro_result = UMA_LINUX_DISTRO_CENTOS; distro_result = UMA_LINUX_DISTRO_CENTOS;
} else if (distro_tokens[0] == "elementary") { } else if (distro_tokens[0] == "elementary") {
// Format: elementary OS <release name> // Format: elementary OS <release name>
distro_result = UMA_LINUX_DISTRO_ELEMENTARY; distro_result = UMA_LINUX_DISTRO_ELEMENTARY;
} else if (distro_tokens.size() >= 2 && distro_tokens[1] == "Mint") { } else if (distro_tokens.size() >= 2 && distro_tokens[1] == "Mint") {
// Format: Linux Mint RR <codename> // Format: Linux Mint RR
distro_result = UMA_LINUX_DISTRO_MINT; distro_result = UMA_LINUX_DISTRO_MINT;
} else if (distro_tokens.size() >= 4 && distro_tokens[0] == "Red" && } else if (distro_tokens.size() >= 4 && distro_tokens[0] == "Red" &&
distro_tokens[1] == "Hat" && distro_tokens[2] == "Enterprise" && distro_tokens[1] == "Hat" && distro_tokens[2] == "Enterprise" &&
distro_tokens[3] == "Linux") { distro_tokens[3] == "Linux") {
// Format: Red Hat Enterprise Linux <variant> [release] R.P (<codename>) // Format: Red Hat Enterprise Linux <variant> R.P (<codename>)
distro_result = UMA_LINUX_DISTRO_RHEL; distro_result = UMA_LINUX_DISTRO_RHEL;
} else if (distro_tokens.size() >= 3 && distro_tokens[0] == "SUSE" && } else if (distro_tokens.size() >= 3 && distro_tokens[0] == "SUSE" &&
distro_tokens[1] == "Linux" && distro_tokens[1] == "Linux" &&
distro_tokens[2] == "Enterprise") { distro_tokens[2] == "Enterprise") {
// Format: SUSE Linux Enterprise <variant> RR (<platform>) // Format: SUSE Linux Enterprise <variant> RR
distro_result = UMA_LINUX_DISTRO_SUSE_ENTERPRISE; distro_result = UMA_LINUX_DISTRO_SUSE_ENTERPRISE;
} }
} }
......
...@@ -17,9 +17,6 @@ libappindicator3-1 ...@@ -17,9 +17,6 @@ libappindicator3-1
# security and stability updates in NSS. # security and stability updates in NSS.
libnss3 (>= 3.26) libnss3 (>= 3.26)
# For lsb_release.
lsb-release
# For uploading crash reports with Breakpad. # For uploading crash reports with Breakpad.
wget wget
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
# #
# Additional dependencies not in the rpm find-requires output. # Additional dependencies not in the rpm find-requires output.
# For lsb_release.
/usr/bin/lsb_release
# Make sure users have SSL certificates. # Make sure users have SSL certificates.
ca-certificates ca-certificates
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment