• 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 "chrome/browser/chromeos/system_access.h"
6 
7 #include "base/file_path.h"
8 #include "base/file_util.h"
9 #include "base/logging.h"
10 #include "base/observer_list.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/singleton.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/chromeos/name_value_pairs_parser.h"
15 
16 namespace chromeos {  // NOLINT
17 
18 namespace { // NOLINT
19 
20 // The filepath to the timezone file that symlinks to the actual timezone file.
21 const char kTimezoneSymlink[] = "/var/lib/timezone/localtime";
22 const char kTimezoneSymlink2[] = "/var/lib/timezone/localtime2";
23 
24 // The directory that contains all the timezone files. So for timezone
25 // "US/Pacific", the actual timezone file is: "/usr/share/zoneinfo/US/Pacific"
26 const char kTimezoneFilesDir[] = "/usr/share/zoneinfo/";
27 
28 // The system command that returns the hardware class.
29 const char kHardwareClassKey[] = "hardware_class";
30 const char* kHardwareClassTool[] = { "/usr/bin/hardware_class" };
31 const char kUnknownHardwareClass[] = "unknown";
32 
33 // Command to get machine hardware info and key/value delimiters.
34 // /tmp/machine-info is generated by platform/init/chromeos_startup.
35 const char* kMachineHardwareInfoTool[] = { "cat", "/tmp/machine-info" };
36 const char kMachineHardwareInfoEq[] = "=";
37 const char kMachineHardwareInfoDelim[] = " \n";
38 
39 // Command to get machine OS info and key/value delimiters.
40 const char* kMachineOSInfoTool[] = { "cat", "/etc/lsb-release" };
41 const char kMachineOSInfoEq[] = "=";
42 const char kMachineOSInfoDelim[] = "\n";
43 
44 // Command to get  HWID and key.
45 const char kHwidKey[] = "hwid";
46 const char* kHwidTool[] = { "cat", "/sys/devices/platform/chromeos_acpi/HWID" };
47 
48 // Command to get VPD info and key/value delimiters.
49 const char* kVpdTool[] = { "cat", "/var/log/vpd_2.0.txt" };
50 const char kVpdEq[] = "=";
51 const char kVpdDelim[] = "\n";
52 
53 // Fallback time zone ID used in case of an unexpected error.
54 const char kFallbackTimeZoneId[] = "America/Los_Angeles";
55 
56 class SystemAccessImpl : public SystemAccess {
57  public:
58   // SystemAccess.implementation:
59   virtual const icu::TimeZone& GetTimezone();
60   virtual void SetTimezone(const icu::TimeZone& timezone);
61   virtual bool GetMachineStatistic(const std::string& name,
62                                    std::string* result);
63   virtual void AddObserver(Observer* observer);
64   virtual void RemoveObserver(Observer* observer);
65 
66   static SystemAccessImpl* GetInstance();
67 
68  private:
69   friend struct DefaultSingletonTraits<SystemAccessImpl>;
70 
71   SystemAccessImpl();
72 
73   // Updates the machine statistcs by examining the system.
74   void UpdateMachineStatistics();
75 
76   scoped_ptr<icu::TimeZone> timezone_;
77   ObserverList<Observer> observers_;
78   NameValuePairsParser::NameValueMap machine_info_;
79 
80   DISALLOW_COPY_AND_ASSIGN(SystemAccessImpl);
81 };
82 
GetTimezoneIDAsString()83 std::string GetTimezoneIDAsString() {
84   // Look at kTimezoneSymlink, see which timezone we are symlinked to.
85   char buf[256];
86   const ssize_t len = readlink(kTimezoneSymlink, buf,
87                                sizeof(buf)-1);
88   if (len == -1) {
89     LOG(ERROR) << "GetTimezoneID: Cannot read timezone symlink "
90                << kTimezoneSymlink;
91     return std::string();
92   }
93 
94   std::string timezone(buf, len);
95   // Remove kTimezoneFilesDir from the beginning.
96   if (timezone.find(kTimezoneFilesDir) != 0) {
97     LOG(ERROR) << "GetTimezoneID: Timezone symlink is wrong "
98                << timezone;
99     return std::string();
100   }
101 
102   return timezone.substr(strlen(kTimezoneFilesDir));
103 }
104 
SetTimezoneIDFromString(const std::string & id)105 void SetTimezoneIDFromString(const std::string& id) {
106   // Change the kTimezoneSymlink symlink to the path for this timezone.
107   // We want to do this in an atomic way. So we are going to create the symlink
108   // at kTimezoneSymlink2 and then move it to kTimezoneSymlink
109 
110   FilePath timezone_symlink(kTimezoneSymlink);
111   FilePath timezone_symlink2(kTimezoneSymlink2);
112   FilePath timezone_file(kTimezoneFilesDir + id);
113 
114   // Make sure timezone_file exists.
115   if (!file_util::PathExists(timezone_file)) {
116     LOG(ERROR) << "SetTimezoneID: Cannot find timezone file "
117                << timezone_file.value();
118     return;
119   }
120 
121   // Delete old symlink2 if it exists.
122   file_util::Delete(timezone_symlink2, false);
123 
124   // Create new symlink2.
125   if (symlink(timezone_file.value().c_str(),
126               timezone_symlink2.value().c_str()) == -1) {
127     LOG(ERROR) << "SetTimezoneID: Unable to create symlink "
128                << timezone_symlink2.value() << " to " << timezone_file.value();
129     return;
130   }
131 
132   // Move symlink2 to symlink.
133   if (!file_util::ReplaceFile(timezone_symlink2, timezone_symlink)) {
134     LOG(ERROR) << "SetTimezoneID: Unable to move symlink "
135                << timezone_symlink2.value() << " to "
136                << timezone_symlink.value();
137   }
138 }
139 
GetTimezone()140 const icu::TimeZone& SystemAccessImpl::GetTimezone() {
141   return *timezone_.get();
142 }
143 
SetTimezone(const icu::TimeZone & timezone)144 void SystemAccessImpl::SetTimezone(const icu::TimeZone& timezone) {
145   timezone_.reset(timezone.clone());
146   icu::UnicodeString unicode;
147   timezone.getID(unicode);
148   std::string id;
149   UTF16ToUTF8(unicode.getBuffer(), unicode.length(), &id);
150   VLOG(1) << "Setting timezone to " << id;
151   chromeos::SetTimezoneIDFromString(id);
152   icu::TimeZone::setDefault(timezone);
153   FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(timezone));
154 }
155 
GetMachineStatistic(const std::string & name,std::string * result)156 bool SystemAccessImpl::GetMachineStatistic(
157     const std::string& name, std::string* result) {
158   NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name);
159   if (iter != machine_info_.end()) {
160     *result = iter->second;
161     return true;
162   }
163   return false;
164 }
165 
AddObserver(Observer * observer)166 void SystemAccessImpl::AddObserver(Observer* observer) {
167   observers_.AddObserver(observer);
168 }
169 
RemoveObserver(Observer * observer)170 void SystemAccessImpl::RemoveObserver(Observer* observer) {
171   observers_.RemoveObserver(observer);
172 }
173 
SystemAccessImpl()174 SystemAccessImpl::SystemAccessImpl() {
175   // Get Statistics
176   UpdateMachineStatistics();
177   // Get Timezone
178   std::string id = GetTimezoneIDAsString();
179   if (id.empty()) {
180     id = kFallbackTimeZoneId;
181     LOG(ERROR) << "Got an empty string for timezone, default to " << id;
182   }
183   icu::TimeZone* timezone =
184       icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(id));
185   timezone_.reset(timezone);
186   icu::TimeZone::setDefault(*timezone);
187   VLOG(1) << "Timezone is " << id;
188 }
189 
UpdateMachineStatistics()190 void SystemAccessImpl::UpdateMachineStatistics() {
191   NameValuePairsParser parser(&machine_info_);
192   if (!parser.GetSingleValueFromTool(arraysize(kHardwareClassTool),
193                                      kHardwareClassTool,
194                                      kHardwareClassKey)) {
195     // Use kUnknownHardwareClass if the hardware class command fails.
196     parser.AddNameValuePair(kHardwareClassKey, kUnknownHardwareClass);
197   }
198   parser.ParseNameValuePairsFromTool(arraysize(kMachineHardwareInfoTool),
199                                      kMachineHardwareInfoTool,
200                                      kMachineHardwareInfoEq,
201                                      kMachineHardwareInfoDelim);
202   parser.ParseNameValuePairsFromTool(arraysize(kMachineOSInfoTool),
203                                      kMachineOSInfoTool,
204                                      kMachineOSInfoEq,
205                                      kMachineOSInfoDelim);
206   parser.GetSingleValueFromTool(arraysize(kHwidTool), kHwidTool, kHwidKey);
207   parser.ParseNameValuePairsFromTool(
208       arraysize(kVpdTool), kVpdTool, kVpdEq, kVpdDelim);
209 }
210 
GetInstance()211 SystemAccessImpl* SystemAccessImpl::GetInstance() {
212   return Singleton<SystemAccessImpl,
213                    DefaultSingletonTraits<SystemAccessImpl> >::get();
214 }
215 
216 }  // namespace
217 
GetInstance()218 SystemAccess* SystemAccess::GetInstance() {
219   return SystemAccessImpl::GetInstance();
220 }
221 
222 }  // namespace chromeos
223