blob: bdc1d41064f1afe7cacdbfb5ba62e10c7a1ded30 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2013 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Alex Deymo42432912013-07-12 20:21:15 -070016
17#include "update_engine/hardware.h"
18
Ben Chan06c76a42014-09-05 08:21:06 -070019#include <base/files/file_util.h>
Alex Deymo42432912013-07-12 20:21:15 -070020#include <base/logging.h>
Alex Deymoebbe7ef2014-10-30 13:02:49 -070021#include <base/strings/string_number_conversions.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070022#include <base/strings/string_util.h>
Alex Deymo42432912013-07-12 20:21:15 -070023#include <rootdev/rootdev.h>
J. Richard Barnettec7dd8532013-10-29 16:30:46 -070024#include <vboot/crossystem.h>
Alex Deymo42432912013-07-12 20:21:15 -070025
Don Garrett83692e42013-11-08 10:11:30 -080026extern "C" {
27#include "vboot/vboot_host.h"
28}
29
Chris Masonef8d037f2014-02-19 01:53:00 +000030#include "update_engine/hwid_override.h"
J. Richard Barnette522d36f2013-10-28 17:22:12 -070031#include "update_engine/subprocess.h"
32#include "update_engine/utils.h"
33
Alex Deymo42432912013-07-12 20:21:15 -070034using std::string;
J. Richard Barnette522d36f2013-10-28 17:22:12 -070035using std::vector;
Alex Deymo42432912013-07-12 20:21:15 -070036
Alex Deymobccbc382014-04-03 13:38:55 -070037namespace {
38
39static const char kOOBECompletedMarker[] = "/home/chronos/.oobe_completed";
40
Alex Deymoebbe7ef2014-10-30 13:02:49 -070041// The powerwash_count marker file contains the number of times the device was
42// powerwashed. This value is incremented by the clobber-state script when
43// a powerwash is performed.
44static const char kPowerwashCountMarker[] =
45 "/mnt/stateful_partition/unencrypted/preserve/powerwash_count";
46
Alex Deymobccbc382014-04-03 13:38:55 -070047} // namespace
48
Alex Deymo42432912013-07-12 20:21:15 -070049namespace chromeos_update_engine {
50
Chris Masonef8d037f2014-02-19 01:53:00 +000051Hardware::Hardware() {}
52
53Hardware::~Hardware() {}
54
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -080055string Hardware::BootKernelDevice() const {
Don Garrett83692e42013-11-08 10:11:30 -080056 return utils::KernelDeviceOfBootDevice(Hardware::BootDevice());
57}
58
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -080059string Hardware::BootDevice() const {
Alex Deymo42432912013-07-12 20:21:15 -070060 char boot_path[PATH_MAX];
61 // Resolve the boot device path fully, including dereferencing
62 // through dm-verity.
63 int ret = rootdev(boot_path, sizeof(boot_path), true, false);
64
65 if (ret < 0) {
66 LOG(ERROR) << "rootdev failed to find the root device";
67 return "";
68 }
69 LOG_IF(WARNING, ret > 0) << "rootdev found a device name with no device node";
70
71 // This local variable is used to construct the return string and is not
72 // passed around after use.
73 return boot_path;
74}
75
Alex Deymo5708ecd2014-04-29 19:44:50 -070076bool Hardware::IsBootDeviceRemovable() const {
77 return utils::IsRemovableDevice(utils::GetDiskName(BootDevice()));
78}
79
Alex Deymof329b932014-10-30 01:37:48 -070080bool Hardware::IsKernelBootable(const string& kernel_device,
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -080081 bool* bootable) const {
Don Garrett83692e42013-11-08 10:11:30 -080082 CgptAddParams params;
83 memset(&params, '\0', sizeof(params));
84
Alex Deymof329b932014-10-30 01:37:48 -070085 string disk_name;
Alex Vakulenko4f5b1442014-02-21 12:19:44 -080086 int partition_num = 0;
Don Garrett83692e42013-11-08 10:11:30 -080087
Alex Vakulenko4f5b1442014-02-21 12:19:44 -080088 if (!utils::SplitPartitionName(kernel_device, &disk_name, &partition_num))
89 return false;
90
91 params.drive_name = const_cast<char *>(disk_name.c_str());
92 params.partition = partition_num;
Don Garrett83692e42013-11-08 10:11:30 -080093
94 int retval = CgptGetPartitionDetails(&params);
95 if (retval != CGPT_OK)
96 return false;
97
98 *bootable = params.successful || (params.tries > 0);
99 return true;
100}
101
Alex Deymof329b932014-10-30 01:37:48 -0700102vector<string> Hardware::GetKernelDevices() const {
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800103 LOG(INFO) << "GetAllKernelDevices";
104
Alex Deymof329b932014-10-30 01:37:48 -0700105 string disk_name = utils::GetDiskName(Hardware::BootKernelDevice());
Alex Deymodf632d12014-04-29 20:04:36 -0700106 if (disk_name.empty()) {
Alex Vakulenko072359c2014-07-18 11:41:07 -0700107 LOG(ERROR) << "Failed to get the current kernel boot disk name";
Alex Deymof329b932014-10-30 01:37:48 -0700108 return vector<string>();
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800109 }
110
Alex Deymof329b932014-10-30 01:37:48 -0700111 vector<string> devices;
Alex Deymodf632d12014-04-29 20:04:36 -0700112 for (int partition_num : {2, 4}) { // for now, only #2, #4 for slot A & B
Alex Deymof329b932014-10-30 01:37:48 -0700113 string device = utils::MakePartitionName(disk_name, partition_num);
Alex Deymodf632d12014-04-29 20:04:36 -0700114 if (!device.empty()) {
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800115 devices.push_back(std::move(device));
116 } else {
117 LOG(ERROR) << "Cannot make a partition name for disk: "
118 << disk_name << ", partition: " << partition_num;
119 }
120 }
121
122 return devices;
123}
124
125
Alex Deymof329b932014-10-30 01:37:48 -0700126bool Hardware::MarkKernelUnbootable(const string& kernel_device) {
Don Garrett83692e42013-11-08 10:11:30 -0800127 LOG(INFO) << "MarkPartitionUnbootable: " << kernel_device;
128
Don Garrett6646b442013-11-13 15:29:11 -0800129 if (kernel_device == BootKernelDevice()) {
130 LOG(ERROR) << "Refusing to mark current kernel as unbootable.";
131 return false;
132 }
133
Alex Deymof329b932014-10-30 01:37:48 -0700134 string disk_name;
Alex Vakulenko4f5b1442014-02-21 12:19:44 -0800135 int partition_num = 0;
136
137 if (!utils::SplitPartitionName(kernel_device, &disk_name, &partition_num))
138 return false;
Don Garrett83692e42013-11-08 10:11:30 -0800139
140 CgptAddParams params;
141 memset(&params, 0, sizeof(params));
142
Alex Vakulenko4f5b1442014-02-21 12:19:44 -0800143 params.drive_name = const_cast<char *>(disk_name.c_str());
144 params.partition = partition_num;
Don Garrett83692e42013-11-08 10:11:30 -0800145
146 params.successful = false;
147 params.set_successful = true;
148
149 params.tries = 0;
150 params.set_tries = true;
151
152 int retval = CgptSetAttributes(&params);
153 if (retval != CGPT_OK) {
154 LOG(ERROR) << "Marking kernel unbootable failed.";
155 return false;
156 }
157
158 return true;
159}
160
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -0800161bool Hardware::IsOfficialBuild() const {
J. Richard Barnettec7dd8532013-10-29 16:30:46 -0700162 return VbGetSystemPropertyInt("debug_build") == 0;
J. Richard Barnette056b0ab2013-10-29 15:24:56 -0700163}
164
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -0800165bool Hardware::IsNormalBootMode() const {
J. Richard Barnettec7dd8532013-10-29 16:30:46 -0700166 bool dev_mode = VbGetSystemPropertyInt("devsw_boot") != 0;
J. Richard Barnette056b0ab2013-10-29 15:24:56 -0700167 LOG_IF(INFO, dev_mode) << "Booted in dev mode.";
168 return !dev_mode;
169}
170
Alex Deymobccbc382014-04-03 13:38:55 -0700171bool Hardware::IsOOBEComplete(base::Time* out_time_of_oobe) const {
172 struct stat statbuf;
173 if (stat(kOOBECompletedMarker, &statbuf) != 0) {
174 if (errno != ENOENT) {
175 PLOG(ERROR) << "Error getting information about "
176 << kOOBECompletedMarker;
177 }
178 return false;
179 }
180
181 if (out_time_of_oobe != nullptr)
182 *out_time_of_oobe = base::Time::FromTimeT(statbuf.st_mtime);
183 return true;
184}
185
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700186static string ReadValueFromCrosSystem(const string& key) {
J. Richard Barnettec7dd8532013-10-29 16:30:46 -0700187 char value_buffer[VB_MAX_STRING_PROPERTY];
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700188
J. Richard Barnettec7dd8532013-10-29 16:30:46 -0700189 const char *rv = VbGetSystemPropertyString(key.c_str(), value_buffer,
190 sizeof(value_buffer));
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700191 if (rv != nullptr) {
J. Richard Barnettec7dd8532013-10-29 16:30:46 -0700192 string return_value(value_buffer);
Ben Chan736fcb52014-05-21 18:28:22 -0700193 base::TrimWhitespaceASCII(return_value, base::TRIM_ALL, &return_value);
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700194 return return_value;
195 }
J. Richard Barnettec7dd8532013-10-29 16:30:46 -0700196
197 LOG(ERROR) << "Unable to read crossystem key " << key;
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700198 return "";
199}
200
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -0800201string Hardware::GetHardwareClass() const {
Chris Masonef8d037f2014-02-19 01:53:00 +0000202 if (USE_HWID_OVERRIDE) {
203 return HwidOverride::Read(base::FilePath("/"));
204 }
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700205 return ReadValueFromCrosSystem("hwid");
206}
207
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -0800208string Hardware::GetFirmwareVersion() const {
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700209 return ReadValueFromCrosSystem("fwid");
210}
211
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -0800212string Hardware::GetECVersion() const {
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700213 string input_line;
214 int exit_code = 0;
Alex Vakulenkod0fdfb32014-02-21 15:26:26 -0800215 vector<string> cmd = {"/usr/sbin/mosys", "-k", "ec", "info"};
J. Richard Barnette522d36f2013-10-28 17:22:12 -0700216
217 bool success = Subprocess::SynchronousExec(cmd, &exit_code, &input_line);
218 if (!success || exit_code) {
219 LOG(ERROR) << "Unable to read ec info from mosys (" << exit_code << ")";
220 return "";
221 }
222
223 return utils::ParseECVersion(input_line);
224}
225
Alex Deymoebbe7ef2014-10-30 13:02:49 -0700226int Hardware::GetPowerwashCount() const {
227 int powerwash_count;
228 string contents;
229 if (!utils::ReadFile(kPowerwashCountMarker, &contents))
230 return -1;
231 base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
232 if (!base::StringToInt(contents, &powerwash_count))
233 return -1;
234 return powerwash_count;
235}
236
Alex Deymo42432912013-07-12 20:21:15 -0700237} // namespace chromeos_update_engine