summaryrefslogtreecommitdiffstats
path: root/chromium/base/linux_util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/linux_util.cc')
-rw-r--r--chromium/base/linux_util.cc99
1 files changed, 78 insertions, 21 deletions
diff --git a/chromium/base/linux_util.cc b/chromium/base/linux_util.cc
index caf471a39e1..2da24e1d89b 100644
--- a/chromium/base/linux_util.cc
+++ b/chromium/base/linux_util.cc
@@ -13,6 +13,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <iomanip>
#include <memory>
#include "base/command_line.h"
@@ -28,6 +29,8 @@
#include "base/synchronization/lock.h"
#include "build/build_config.h"
+namespace base {
+
namespace {
// Not needed for OS_CHROMEOS.
@@ -43,7 +46,7 @@ class LinuxDistroHelper {
public:
// Retrieves the Singleton.
static LinuxDistroHelper* GetInstance() {
- return base::Singleton<LinuxDistroHelper>::get();
+ return Singleton<LinuxDistroHelper>::get();
}
// The simple state machine goes from:
@@ -55,7 +58,7 @@ class LinuxDistroHelper {
// we automatically move to STATE_CHECK_STARTED so nobody else will
// do the check.
LinuxDistroState State() {
- base::AutoLock scoped_lock(lock_);
+ AutoLock scoped_lock(lock_);
if (STATE_DID_NOT_CHECK == state_) {
state_ = STATE_CHECK_STARTED;
return STATE_DID_NOT_CHECK;
@@ -65,21 +68,72 @@ class LinuxDistroHelper {
// Indicate the check finished, move to STATE_CHECK_FINISHED.
void CheckFinished() {
- base::AutoLock scoped_lock(lock_);
+ AutoLock scoped_lock(lock_);
DCHECK_EQ(STATE_CHECK_STARTED, state_);
state_ = STATE_CHECK_FINISHED;
}
private:
- base::Lock lock_;
+ Lock lock_;
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)
} // namespace
-namespace base {
-
// Account for the terminating null character.
static const int kDistroSize = 128 + 1;
@@ -94,6 +148,21 @@ char g_linux_distro[kDistroSize] =
"Unknown";
#endif
+// This function is only supposed to be used in tests. The declaration in the
+// header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
+// by tests but not non-test code. However, this .cc file is compiled as part
+// of "base" where "UNIT_TEST" is not defined. So we need to specify
+// "BASE_EXPORT" here again so that they are visible to tests.
+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() {
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
return g_linux_distro;
@@ -106,20 +175,8 @@ std::string GetLinuxDistro() {
return "Unknown"; // Don't wait for other thread to finish.
DCHECK_EQ(state, STATE_DID_NOT_CHECK);
// 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
- // lsb_release again.
- 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)));
- }
- }
+ // little reason to believe it will work if we attempt to run it again.
+ GetDistroNameFromOSRelease();
distro_state_singleton->CheckFinished();
return g_linux_distro;
#else
@@ -137,7 +194,7 @@ void SetLinuxDistro(const std::string& distro) {
bool GetThreadsForProcess(pid_t pid, std::vector<pid_t>* tids) {
// 25 > strlen("/proc//task") + strlen(std::to_string(INT_MAX)) + 1 = 22
char buf[25];
- base::strings::SafeSPrintf(buf, "/proc/%d/task", pid);
+ strings::SafeSPrintf(buf, "/proc/%d/task", pid);
DirReaderPosix dir_reader(buf);
if (!dir_reader.IsValid()) {