omaha_request_params.cc revision 7fbbe8a9e57ec52f7bc597d0cb607036300ac54c
1// Copyright (c) 2011 The Chromium OS 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 "update_engine/omaha_request_params.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#include <sys/utsname.h>
10
11#include <map>
12#include <string>
13#include <vector>
14
15#include <base/file_util.h>
16#include <policy/device_policy.h>
17
18#include "update_engine/simple_key_value_store.h"
19#include "update_engine/utils.h"
20
21#define CALL_MEMBER_FN(object, member) ((object).*(member))
22
23using std::map;
24using std::string;
25using std::vector;
26
27namespace chromeos_update_engine {
28
29const char* const OmahaRequestParams::kAppId(
30    "{87efface-864d-49a5-9bb3-4b050a7c227a}");
31const char* const OmahaRequestParams::kOsPlatform("Chrome OS");
32const char* const OmahaRequestParams::kOsVersion("Indy");
33const char* const OmahaRequestParams::kUpdateUrl(
34    "https://tools.google.com/service/update2");
35
36const char OmahaRequestParams::kUpdateTrackKey[] = "CHROMEOS_RELEASE_TRACK";
37
38OmahaRequestDeviceParams::OmahaRequestDeviceParams() :
39    force_lock_down_(false),
40    forced_lock_down_(false) {}
41
42bool OmahaRequestDeviceParams::Init(const std::string& in_app_version,
43                                    const std::string& in_update_url,
44                                    const std::string& in_release_track) {
45  bool stateful_override = !ShouldLockDown();
46  os_platform = OmahaRequestParams::kOsPlatform;
47  os_version = OmahaRequestParams::kOsVersion;
48  app_version = in_app_version.empty() ?
49      GetLsbValue("CHROMEOS_RELEASE_VERSION", "", NULL, stateful_override) :
50      in_app_version;
51  os_sp = app_version + "_" + GetMachineType();
52  os_board = GetLsbValue("CHROMEOS_RELEASE_BOARD", "", NULL, stateful_override);
53  app_id = GetLsbValue("CHROMEOS_RELEASE_APPID",
54                       OmahaRequestParams::kAppId,
55                       NULL,
56                       stateful_override);
57  app_lang = "en-US";
58
59  // Determine the release track if it wasn't specified by the caller.
60  if (in_release_track.empty() || !IsValidTrack(in_release_track)) {
61    app_track = GetLsbValue(
62        kUpdateTrackKey,
63        "",
64        &chromeos_update_engine::OmahaRequestDeviceParams::IsValidTrack,
65        true);  // stateful_override
66  } else {
67    app_track = in_release_track;
68  }
69
70  hardware_class = utils::GetHardwareClass();
71  struct stat stbuf;
72
73  // Deltas are only okay if the /.nodelta file does not exist.  If we don't
74  // know (i.e. stat() returns some unexpected error), then err on the side of
75  // caution and say deltas are not okay.
76  delta_okay = (stat((root_ + "/.nodelta").c_str(), &stbuf) < 0) &&
77               (errno == ENOENT);
78
79  // For now, disable delta updates if the rootfs track is different than the
80  // track that we're sending to the update server because such updates are
81  // destined to fail -- the source rootfs hash will be different than the
82  // expected hash due to the different track in /etc/lsb-release.
83  //
84  // Longer term we should consider an alternative: (a) clients can send
85  // (current_version, current_channel, new_channel) information, or (b) the
86  // build process can make sure releases on separate tracks are identical (i.e,
87  // by not stamping the release with the channel), or (c) the release process
88  // can ensure that different channels get different version numbers.
89  const string rootfs_track = GetLsbValue(
90      kUpdateTrackKey,
91      "",
92      NULL,  // No need to validate the read-only rootfs track.
93      false);  // stateful_override
94  delta_okay = delta_okay && rootfs_track == app_track;
95
96  update_url = in_update_url.empty() ?
97      GetLsbValue("CHROMEOS_AUSERVER",
98                  OmahaRequestParams::kUpdateUrl,
99                  NULL,
100                  stateful_override) :
101      in_update_url;
102  return true;
103}
104
105bool OmahaRequestDeviceParams::SetTrack(const std::string& track) {
106  TEST_AND_RETURN_FALSE(IsValidTrack(track));
107  FilePath kFile(root_ + utils::kStatefulPartition + "/etc/lsb-release");
108  string file_data;
109  map<string, string> data;
110  if (file_util::ReadFileToString(kFile, &file_data)) {
111    data = simple_key_value_store::ParseString(file_data);
112  }
113  data[kUpdateTrackKey] = track;
114  file_data = simple_key_value_store::AssembleString(data);
115  TEST_AND_RETURN_FALSE(file_util::CreateDirectory(kFile.DirName()));
116  TEST_AND_RETURN_FALSE(
117      file_util::WriteFile(kFile, file_data.data(), file_data.size()) ==
118      static_cast<int>(file_data.size()));
119  app_track = track;
120  return true;
121}
122
123bool OmahaRequestDeviceParams::SetDeviceTrack(const std::string& track) {
124  OmahaRequestDeviceParams params;
125  TEST_AND_RETURN_FALSE(params.Init("", "", ""));
126  return params.SetTrack(track);
127}
128
129string OmahaRequestDeviceParams::GetDeviceTrack() {
130  OmahaRequestDeviceParams params;
131  // Note that params.app_track is an empty string if the value in
132  // lsb-release file is invalid. See Init() for details.
133  return params.Init("", "", "") ? params.app_track : "";
134}
135
136string OmahaRequestDeviceParams::GetLsbValue(const string& key,
137                                             const string& default_value,
138                                             ValueValidator validator,
139                                             bool stateful_override) const {
140  vector<string> files;
141  if (stateful_override) {
142    files.push_back(string(utils::kStatefulPartition) + "/etc/lsb-release");
143  }
144  files.push_back("/etc/lsb-release");
145  for (vector<string>::const_iterator it = files.begin();
146       it != files.end(); ++it) {
147    // TODO(adlr): make sure files checked are owned as root (and all their
148    // parents are recursively, too).
149    string file_data;
150    if (!utils::ReadFileToString(root_ + *it, &file_data))
151      continue;
152
153    map<string, string> data = simple_key_value_store::ParseString(file_data);
154    if (utils::MapContainsKey(data, key)) {
155      const string& value = data[key];
156      if (validator && !CALL_MEMBER_FN(*this, validator)(value)) {
157        continue;
158      }
159      return value;
160    }
161  }
162  // not found
163  return default_value;
164}
165
166string OmahaRequestDeviceParams::GetMachineType() const {
167  struct utsname buf;
168  string ret;
169  if (uname(&buf) == 0)
170    ret = buf.machine;
171  return ret;
172}
173
174bool OmahaRequestDeviceParams::ShouldLockDown() const {
175  if (force_lock_down_) {
176    return forced_lock_down_;
177  }
178  return utils::IsOfficialBuild() && utils::IsNormalBootMode();
179}
180
181bool OmahaRequestDeviceParams::IsValidTrack(const std::string& track) const {
182  static const char* kValidTracks[] = {
183    "canary-channel",
184    "stable-channel",
185    "beta-channel",
186    "dev-channel",
187  };
188  if (!ShouldLockDown()) {
189    return true;
190  }
191  for (size_t t = 0; t < arraysize(kValidTracks); ++t) {
192    if (track == kValidTracks[t]) {
193      return true;
194    }
195  }
196  return false;
197}
198
199void OmahaRequestDeviceParams::SetLockDown(bool lock) {
200  force_lock_down_ = true;
201  forced_lock_down_ = lock;
202}
203
204}  // namespace chromeos_update_engine
205