blob: 845f66b38ceda5264664b98052e4524a8f470e01 [file] [log] [blame]
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <iostream>
#include <algorithm>
#include <string>
#include <stdlib.h>
#include "memento_common.h"
#include "command_handler.h"
#include "general_installer.h"
#include "diskimage_installer.h"
using namespace chromeos_memento_updater;
using std::cerr;
using std::endl;
using std::pair;
using std::string;
using std::vector;
int parse_partition_option(const string& option,
GeneralInstaller* installer_ptr) {
int partition_option = -1;
if (!installer_ptr->AllowPartitionOptions() && !option.empty()) {
error_exit("Partition options are not allowed");
}
if (installer_ptr->AllowPartitionOptions()) {
if (!option.empty()) {
partition_option = strtol(option.c_str(), NULL, 10);
// strtol return 0 on failure
if (partition_option == 0) {
error_exit("Invalid partition option");
}
}
}
return partition_option;
}
void install_device(const string& option, PartitionNum partition,
CommandHandler& handler,
GeneralInstaller* installer_ptr) {
int source_partition = option.empty() ?
static_cast<int>(partition) :
parse_partition_option(option, installer_ptr);
installer_ptr->InstallDevice(source_partition,
handler.GetOutputDevicePartition(partition),
string());
}
void install_main_device(const string& option, PartitionNum rootfs,
PartitionNum kernel, CommandHandler& handler,
GeneralInstaller* installer_ptr) {
int kernel_source = static_cast<int>(kernel);
int rootfs_source = static_cast<int>(rootfs);
// Parse option, format is <kernel>:<rootfs>
if (!option.empty()) {
size_t colon;
if ((colon = option.find(':')) == string::npos) {
error_exit("Invalid partition option format, expect <kernel>:<rootfs>");
}
kernel_source = parse_partition_option(option.substr(0, colon),
installer_ptr);
rootfs_source = parse_partition_option(option.substr(colon + 1),
installer_ptr);
}
// For shopfloor/miniomaha, kernel are combined with rootfs
if (installer_ptr->CombinedKernel()) {
installer_ptr->InstallDevice(rootfs_source,
handler.GetOutputDevicePartition(rootfs),
handler.GetOutputDevicePartition(kernel));
} else {
installer_ptr->InstallDevice(rootfs_source,
handler.GetOutputDevicePartition(rootfs),
string());
installer_ptr->InstallDevice(kernel_source,
handler.GetOutputDevicePartition(kernel),
string());
}
}
void update_firmware(string option,
CommandHandler& handler,
GeneralInstaller* installer_ptr) {
bool release_mode = false;
string installer_path;
size_t colon;
// Option format <"release"/"factory">[:<updater_path>] or <updater_path>
if ((colon = option.find(":")) != string::npos) {
installer_path = option.substr(colon + 1);
option = option.substr(0, colon);
}
if (option == "release") {
release_mode = true;
} else if (option == "factory") {
// Do nothing
} else {
installer_path = option;
if (handler.ReleaseOnly()) {
release_mode = true;
}
}
// If there is only release image,
// then default to release mode, otherwise use factory mode.
if (release_mode) {
if (installer_path.empty()) {
installer_path = installer_ptr->PrepareFirmware(
handler.GetOutputDevicePartition(kReleasePartition));
}
installer_ptr->UpdateFirmware(installer_path, "release");
} else {
if (installer_path.empty()) {
installer_path = installer_ptr->PrepareFirmware(
handler.GetOutputDevicePartition(kFactoryPartition));
}
installer_ptr->UpdateFirmware(installer_path, "factory_install");
}
}
void activate_image(string& option, CommandHandler& handler,
GeneralInstaller* installer_ptr) {
if (option == "release" || handler.ReleaseOnly()) {
installer_ptr->ActivateImage(
handler.GetOutputDevicePartition(kReleasePartition));
} else {
installer_ptr->ActivateImage(
handler.GetOutputDevicePartition(kFactoryPartition));
}
}
int main(int argc, char** argv)
{
// memento_updater --to <dest-device>
// --from <type>:<location>
// --contents <content:option, ...>
// --board <board>
CommandHandler handler(argc, argv);
GeneralInstaller* installer_ptr = handler.GetInstallerPtr();
vector< pair<CommandHandler::InstallOption, string> > option_list;
option_list = handler.GetOptionList();
// We want options to be executed in order
std::sort(option_list.begin(), option_list.end());
for (size_t i = 0; i < option_list.size(); i++) {
switch (option_list[i].first) {
case CommandHandler::kResetDevice:
// TODO(chunyen): fill in this after the utility function for
// reset device is written
cerr << "Reset device is not supported yet." << endl;
break;
case CommandHandler::kResetPartition:
installer_ptr->ResetPartitionTable(
handler.GetOutputDevice());
break;
case CommandHandler::kFactory:
install_main_device(option_list[i].second, kFactoryPartition,
kFactoryKernelPartition, handler, installer_ptr);
break;
case CommandHandler::kRelease:
install_main_device(option_list[i].second, kReleasePartition,
kReleaseKernelPartition, handler, installer_ptr);
break;
case CommandHandler::kStateful:
if (option_list[i].second == "empty") {
installer_ptr->InitStatefulPartition(
handler.GetOutputDevicePartition(kStatefulPartition));
} else {
install_device(option_list[i].second, kStatefulPartition,
handler, installer_ptr);
}
break;
case CommandHandler::kOem:
install_device(option_list[i].second, kOemPartition,
handler, installer_ptr);
break;
case CommandHandler::kEfi:
install_device(option_list[i].second, kEfiPartition,
handler, installer_ptr);
break;
case CommandHandler::kFirmware:
update_firmware(option_list[i].second, handler, installer_ptr);
break;
case CommandHandler::kActivate:
activate_image(option_list[i].second, handler, installer_ptr);
break;
default:
error_exit("Should never be here");
}
}
return 0;
}