| // 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; |
| } |