// Copyright (c) 2011 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/sys_info.h"
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/threading/thread_restrictions.h"
#include <execinfo.h>
namespace base {
static const char* kLinuxStandardBaseVersionKeys[] = {
"CHROMEOS_RELEASE_VERSION",
"GOOGLE_RELEASE",
"DISTRIB_RELEASE",
NULL
};
const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release";
struct ChromeOSVersionNumbers {
ChromeOSVersionNumbers()
: major_version(0),
minor_version(0),
bugfix_version(0),
parsed(false) {
}
int32 major_version;
int32 minor_version;
int32 bugfix_version;
bool parsed;
};
static base::LazyInstance<ChromeOSVersionNumbers>
g_chrome_os_version_numbers(base::LINKER_INITIALIZED);
// static
void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
int32* minor_version,
int32* bugfix_version) {
if (!g_chrome_os_version_numbers.Get().parsed) {
// The other implementations of SysInfo don't block on the disk.
// See http://code.google.com/p/chromium/issues/detail?id=60394
// Perhaps the caller ought to cache this?
// Temporary allowing while we work the bug out.
base::ThreadRestrictions::ScopedAllowIO allow_io;
FilePath path(kLinuxStandardBaseReleaseFile);
std::string contents;
if (file_util::ReadFileToString(path, &contents)) {
g_chrome_os_version_numbers.Get().parsed = true;
ParseLsbRelease(contents,
&(g_chrome_os_version_numbers.Get().major_version),
&(g_chrome_os_version_numbers.Get().minor_version),
&(g_chrome_os_version_numbers.Get().bugfix_version));
}
}
*major_version = g_chrome_os_version_numbers.Get().major_version;
*minor_version = g_chrome_os_version_numbers.Get().minor_version;
*bugfix_version = g_chrome_os_version_numbers.Get().bugfix_version;
}
// static
std::string SysInfo::GetLinuxStandardBaseVersionKey() {
return std::string(kLinuxStandardBaseVersionKeys[0]);
}
// static
void SysInfo::ParseLsbRelease(const std::string& lsb_release,
int32* major_version,
int32* minor_version,
int32* bugfix_version) {
size_t version_key_index = std::string::npos;
for (int i = 0; kLinuxStandardBaseVersionKeys[i] != NULL; ++i) {
version_key_index = lsb_release.find(kLinuxStandardBaseVersionKeys[i]);
if (std::string::npos != version_key_index) {
break;
}
}
if (std::string::npos == version_key_index) {
return;
}
size_t start_index = lsb_release.find_first_of('=', version_key_index);
start_index++; // Move past '='.
size_t length = lsb_release.find_first_of('\n', start_index) - start_index;
std::string version = lsb_release.substr(start_index, length);
StringTokenizer tokenizer(version, ".");
// TODO(rkc): Ignore the 0. here; fix this once we move Chrome OS version
// numbers from the 0.xx.yyy.zz format to the xx.yyy.zz format.
// Refer to http://code.google.com/p/chromium-os/issues/detail?id=15789
for (int i = 0; i < 4 && tokenizer.GetNext(); i++) {
if (1 == i) {
StringToInt(tokenizer.token_begin(),
tokenizer.token_end(),
major_version);
*minor_version = *bugfix_version = 0;
} else if (2 == i) {
StringToInt(tokenizer.token_begin(),
tokenizer.token_end(),
minor_version);
} else { // 3 == i
StringToInt(tokenizer.token_begin(),
tokenizer.token_end(),
bugfix_version);
}
}
}
} // namespace base