• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/sys_info.h"
6 
7 #include "base/basictypes.h"
8 #include "base/file_path.h"
9 #include "base/file_util.h"
10 #include "base/lazy_instance.h"
11 #include "base/string_number_conversions.h"
12 #include "base/string_tokenizer.h"
13 #include "base/threading/thread_restrictions.h"
14 
15 #include <execinfo.h>
16 
17 namespace base {
18 
19 static const char* kLinuxStandardBaseVersionKeys[] = {
20   "CHROMEOS_RELEASE_VERSION",
21   "GOOGLE_RELEASE",
22   "DISTRIB_RELEASE",
23   NULL
24 };
25 
26 const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release";
27 
28 struct ChromeOSVersionNumbers {
ChromeOSVersionNumbersbase::ChromeOSVersionNumbers29   ChromeOSVersionNumbers()
30       : major_version(0),
31         minor_version(0),
32         bugfix_version(0),
33         parsed(false) {
34   }
35 
36   int32 major_version;
37   int32 minor_version;
38   int32 bugfix_version;
39   bool parsed;
40 };
41 
42 static base::LazyInstance<ChromeOSVersionNumbers>
43     g_chrome_os_version_numbers(base::LINKER_INITIALIZED);
44 
45 // static
OperatingSystemVersionNumbers(int32 * major_version,int32 * minor_version,int32 * bugfix_version)46 void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
47                                             int32* minor_version,
48                                             int32* bugfix_version) {
49   if (!g_chrome_os_version_numbers.Get().parsed) {
50     // The other implementations of SysInfo don't block on the disk.
51     // See http://code.google.com/p/chromium/issues/detail?id=60394
52     // Perhaps the caller ought to cache this?
53     // Temporary allowing while we work the bug out.
54     base::ThreadRestrictions::ScopedAllowIO allow_io;
55 
56     FilePath path(kLinuxStandardBaseReleaseFile);
57     std::string contents;
58     if (file_util::ReadFileToString(path, &contents)) {
59       g_chrome_os_version_numbers.Get().parsed = true;
60       ParseLsbRelease(contents,
61           &(g_chrome_os_version_numbers.Get().major_version),
62           &(g_chrome_os_version_numbers.Get().minor_version),
63           &(g_chrome_os_version_numbers.Get().bugfix_version));
64     }
65   }
66   *major_version = g_chrome_os_version_numbers.Get().major_version;
67   *minor_version = g_chrome_os_version_numbers.Get().minor_version;
68   *bugfix_version = g_chrome_os_version_numbers.Get().bugfix_version;
69 }
70 
71 // static
GetLinuxStandardBaseVersionKey()72 std::string SysInfo::GetLinuxStandardBaseVersionKey() {
73   return std::string(kLinuxStandardBaseVersionKeys[0]);
74 }
75 
76 // static
ParseLsbRelease(const std::string & lsb_release,int32 * major_version,int32 * minor_version,int32 * bugfix_version)77 void SysInfo::ParseLsbRelease(const std::string& lsb_release,
78                               int32* major_version,
79                               int32* minor_version,
80                               int32* bugfix_version) {
81   size_t version_key_index = std::string::npos;
82   for (int i = 0; kLinuxStandardBaseVersionKeys[i] != NULL; ++i) {
83     version_key_index = lsb_release.find(kLinuxStandardBaseVersionKeys[i]);
84     if (std::string::npos != version_key_index) {
85       break;
86     }
87   }
88   if (std::string::npos == version_key_index) {
89     return;
90   }
91 
92   size_t start_index = lsb_release.find_first_of('=', version_key_index);
93   start_index++;  // Move past '='.
94   size_t length = lsb_release.find_first_of('\n', start_index) - start_index;
95   std::string version = lsb_release.substr(start_index, length);
96   StringTokenizer tokenizer(version, ".");
97   // TODO(rkc): Ignore the 0. here; fix this once we move Chrome OS version
98   // numbers from the 0.xx.yyy.zz format to the xx.yyy.zz format.
99   // Refer to http://code.google.com/p/chromium-os/issues/detail?id=15789
100   for (int i = 0; i < 4 && tokenizer.GetNext(); i++) {
101     if (1 == i) {
102       StringToInt(tokenizer.token_begin(),
103                   tokenizer.token_end(),
104                   major_version);
105       *minor_version = *bugfix_version = 0;
106     } else if (2 == i) {
107       StringToInt(tokenizer.token_begin(),
108                   tokenizer.token_end(),
109                   minor_version);
110     } else {  // 3 == i
111       StringToInt(tokenizer.token_begin(),
112                   tokenizer.token_end(),
113                   bugfix_version);
114     }
115   }
116 }
117 
118 }  // namespace base
119