1763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo//
2763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// Copyright (C) 2015 The Android Open Source Project
3763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo//
4763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// you may not use this file except in compliance with the License.
6763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// You may obtain a copy of the License at
7763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo//
8763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo//
10763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// Unless required by applicable law or agreed to in writing, software
11763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// See the License for the specific language governing permissions and
14763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// limitations under the License.
15763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo//
16763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
171b03f9f983a22fabb8d53e036abf1b192e7d5811Alex Deymo#include "update_engine/boot_control_chromeos.h"
18763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
19763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo#include <string>
20763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
21aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo#include <base/bind.h>
22763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo#include <base/files/file_path.h>
23763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo#include <base/files/file_util.h>
24763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo#include <base/strings/string_util.h>
253f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/make_unique_ptr.h>
26763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo#include <rootdev/rootdev.h>
27763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
28763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymoextern "C" {
29763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo#include <vboot/vboot_host.h>
30763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
31763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
3239910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/boot_control.h"
3339910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/subprocess.h"
3439910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
35763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
36763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymousing std::string;
37763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
38763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymonamespace {
39763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
40763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymoconst char* kChromeOSPartitionNameKernel = "kernel";
41763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymoconst char* kChromeOSPartitionNameRoot = "root";
42763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymoconst char* kAndroidPartitionNameKernel = "boot";
43763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymoconst char* kAndroidPartitionNameRoot = "system";
44763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
45763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// Returns the currently booted rootfs partition. "/dev/sda3", for example.
46763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymostring GetBootDevice() {
47763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  char boot_path[PATH_MAX];
48763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // Resolve the boot device path fully, including dereferencing through
49763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // dm-verity.
50763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int ret = rootdev(boot_path, sizeof(boot_path), true, false);
51763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (ret < 0) {
52763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    LOG(ERROR) << "rootdev failed to find the root device";
53763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return "";
54763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
55763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  LOG_IF(WARNING, ret > 0) << "rootdev found a device name with no device node";
56763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
57763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // This local variable is used to construct the return string and is not
58763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // passed around after use.
59763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return boot_path;
60763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
61763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
62aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo// ExecCallback called when the execution of setgoodkernel finishes. Notifies
63aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo// the caller of MarkBootSuccessfullAsync() by calling |callback| with the
64aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo// result.
65aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymovoid OnMarkBootSuccessfulDone(base::Callback<void(bool)> callback,
66aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo                              int return_code,
67aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo                              const string& output) {
68aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo  callback.Run(return_code == 0);
69aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo}
70aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo
71763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}  // namespace
72763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
73763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymonamespace chromeos_update_engine {
74763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
75b17327ce55e7132da1f64039040df93a8c260fefAlex Deymonamespace boot_control {
76b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
77b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// Factory defined in boot_control.h.
78b17327ce55e7132da1f64039040df93a8c260fefAlex Deymostd::unique_ptr<BootControlInterface> CreateBootControl() {
79b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo  std::unique_ptr<BootControlChromeOS> boot_control_chromeos(
80b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo      new BootControlChromeOS());
81b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo  if (!boot_control_chromeos->Init()) {
82b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo    LOG(ERROR) << "Ignoring BootControlChromeOS failure. We won't run updates.";
83b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo  }
84ce8c8ee8f9df9bea3b5aedf930dfeba5da46031cAlex Vakulenko  return std::move(boot_control_chromeos);
85b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}
86b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
87b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}  // namespace boot_control
88b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
89763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymobool BootControlChromeOS::Init() {
90763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  string boot_device = GetBootDevice();
91763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (boot_device.empty())
92763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
93763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
94763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int partition_num;
95763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (!utils::SplitPartitionName(boot_device, &boot_disk_name_, &partition_num))
96763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
97763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
98763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // All installed Chrome OS devices have two slots. We don't update removable
99763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // devices, so we will pretend we have only one slot in that case.
100763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (IsRemovableDevice(boot_disk_name_)) {
101763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    LOG(INFO)
102763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo        << "Booted from a removable device, pretending we have only one slot.";
103763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    num_slots_ = 1;
104763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  } else {
105763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    // TODO(deymo): Look at the actual number of slots reported in the GPT.
106763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    num_slots_ = 2;
107763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
108763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
109763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // Search through the slots to see which slot has the partition_num we booted
110763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // from. This should map to one of the existing slots, otherwise something is
111763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // very wrong.
112763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  current_slot_ = 0;
113763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  while (current_slot_ < num_slots_ &&
114763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo         partition_num !=
115763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo             GetPartitionNumber(kChromeOSPartitionNameRoot, current_slot_)) {
116763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    current_slot_++;
117763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
118763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (current_slot_ >= num_slots_) {
119763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    LOG(ERROR) << "Couldn't find the slot number corresponding to the "
120763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo                  "partition " << boot_device
121763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo               << ", number of slots: " << num_slots_
122763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo               << ". This device is not updateable.";
123763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    num_slots_ = 1;
124763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    current_slot_ = BootControlInterface::kInvalidSlot;
125763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
126763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
127763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
128763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  LOG(INFO) << "Booted from slot " << current_slot_ << " (slot "
12931d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo            << SlotName(current_slot_) << ") of " << num_slots_
13031d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo            << " slots present on disk " << boot_disk_name_;
131763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return true;
132763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
133763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
134763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymounsigned int BootControlChromeOS::GetNumSlots() const {
135763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return num_slots_;
136763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
137763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
138763e7dbaac735da0ae802933a1015b6b7874bce2Alex DeymoBootControlInterface::Slot BootControlChromeOS::GetCurrentSlot() const {
139763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return current_slot_;
140763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
141763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
142763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymobool BootControlChromeOS::GetPartitionDevice(const string& partition_name,
143763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo                                             unsigned int slot,
144763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo                                             string* device) const {
145763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int partition_num = GetPartitionNumber(partition_name, slot);
146763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (partition_num < 0)
147763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
148763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
149763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  string part_device = utils::MakePartitionName(boot_disk_name_, partition_num);
150763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (part_device.empty())
151763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
152763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
153763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  *device = part_device;
154763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return true;
155763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
156763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
157763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymobool BootControlChromeOS::IsSlotBootable(Slot slot) const {
158763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int partition_num = GetPartitionNumber(kChromeOSPartitionNameKernel, slot);
159763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (partition_num < 0)
160763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
161763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
162763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  CgptAddParams params;
163763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  memset(&params, '\0', sizeof(params));
164763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
165763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.partition = partition_num;
166763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
167763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int retval = CgptGetPartitionDetails(&params);
168763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (retval != CGPT_OK)
169763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
170763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
171763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return params.successful || params.tries > 0;
172763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
173763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
174763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymobool BootControlChromeOS::MarkSlotUnbootable(Slot slot) {
17531d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  LOG(INFO) << "Marking slot " << SlotName(slot) << " unbootable";
176763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
177763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (slot == current_slot_) {
178763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    LOG(ERROR) << "Refusing to mark current slot as unbootable.";
179763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
180763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
181763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
182763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int partition_num = GetPartitionNumber(kChromeOSPartitionNameKernel, slot);
183763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (partition_num < 0)
184763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
185763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
186763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  CgptAddParams params;
187763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  memset(&params, 0, sizeof(params));
188763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
189763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
190763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.partition = partition_num;
191763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
192763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.successful = false;
193763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.set_successful = true;
194763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
195763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.tries = 0;
196763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  params.set_tries = true;
197763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
198763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int retval = CgptSetAttributes(&params);
199763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (retval != CGPT_OK) {
200763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    LOG(ERROR) << "Marking kernel unbootable failed.";
201763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
202763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
203763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
204763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return true;
205763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
206763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
20731d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymobool BootControlChromeOS::SetActiveBootSlot(Slot slot) {
20831d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  LOG(INFO) << "Marking slot " << SlotName(slot) << " active.";
20931d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
21031d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  int partition_num = GetPartitionNumber(kChromeOSPartitionNameKernel, slot);
21131d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  if (partition_num < 0)
21231d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    return false;
21331d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
21431d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  CgptPrioritizeParams prio_params;
21531d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  memset(&prio_params, 0, sizeof(prio_params));
21631d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
21731d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  prio_params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
21831d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  prio_params.set_partition = partition_num;
21931d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
22031d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  prio_params.max_priority = 0;
22131d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
22231d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  int retval = CgptPrioritize(&prio_params);
22331d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  if (retval != CGPT_OK) {
22431d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    LOG(ERROR) << "Unable to set highest priority for slot " << SlotName(slot)
22531d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo               << " (partition " << partition_num << ").";
22631d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    return false;
22731d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  }
22831d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
22931d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  CgptAddParams add_params;
23031d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  memset(&add_params, 0, sizeof(add_params));
23131d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
23231d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  add_params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
23331d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  add_params.partition = partition_num;
23431d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
23531d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  add_params.tries = 6;
23631d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  add_params.set_tries = true;
23731d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
23831d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  retval = CgptSetAttributes(&add_params);
23931d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  if (retval != CGPT_OK) {
24031d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    LOG(ERROR) << "Unable to set NumTriesLeft to " << add_params.tries
24131d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo               << " for slot " << SlotName(slot) << " (partition "
24231d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo               << partition_num << ").";
24331d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    return false;
24431d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  }
24531d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
24631d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  return true;
24731d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo}
24831d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
249aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymobool BootControlChromeOS::MarkBootSuccessfulAsync(
250aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo    base::Callback<void(bool)> callback) {
251aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo  return Subprocess::Get().Exec(
252aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo             {"/usr/sbin/chromeos-setgoodkernel"},
253aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo             base::Bind(&OnMarkBootSuccessfulDone, callback)) != 0;
254aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo}
255aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo
256763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// static
257763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymostring BootControlChromeOS::SysfsBlockDevice(const string& device) {
258763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  base::FilePath device_path(device);
259763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (device_path.DirName().value() != "/dev") {
260763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return "";
261763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
262763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return base::FilePath("/sys/block").Append(device_path.BaseName()).value();
263763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
264763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
265763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo// static
266763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymobool BootControlChromeOS::IsRemovableDevice(const string& device) {
267763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  string sysfs_block = SysfsBlockDevice(device);
268763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  string removable;
269763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (sysfs_block.empty() ||
270763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo      !base::ReadFileToString(base::FilePath(sysfs_block).Append("removable"),
271763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo                              &removable)) {
272763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return false;
273763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
274763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  base::TrimWhitespaceASCII(removable, base::TRIM_ALL, &removable);
275763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return removable == "1";
276763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
277763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
278763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymoint BootControlChromeOS::GetPartitionNumber(
279763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    const string partition_name,
280763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    BootControlInterface::Slot slot) const {
281763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (slot >= num_slots_) {
282763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    LOG(ERROR) << "Invalid slot number: " << slot << ", we only have "
283763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo               << num_slots_ << " slot(s)";
284763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return -1;
285763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  }
286763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
287763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // In Chrome OS, the partition numbers are hard-coded:
288763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  //   KERNEL-A=2, ROOT-A=3, KERNEL-B=4, ROOT-B=4, ...
289763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // To help compatibility between different we accept both lowercase and
290763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // uppercase names in the ChromeOS or Brillo standard names.
291763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  // See http://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format
2920103c36caa2e38e034e0d22185736b9ccfb35c58Alex Vakulenko  string partition_lower = base::ToLowerASCII(partition_name);
293763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  int base_part_num = 2 + 2 * slot;
294763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (partition_lower == kChromeOSPartitionNameKernel ||
295763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo      partition_lower == kAndroidPartitionNameKernel)
296763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return base_part_num + 0;
297763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  if (partition_lower == kChromeOSPartitionNameRoot ||
298763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo      partition_lower == kAndroidPartitionNameRoot)
299763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo    return base_part_num + 1;
300763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  LOG(ERROR) << "Unknown Chrome OS partition name \"" << partition_name << "\"";
301763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo  return -1;
302763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}
303763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo
304763e7dbaac735da0ae802933a1015b6b7874bce2Alex Deymo}  // namespace chromeos_update_engine
305