Home | History | Annotate | Download | only in applypatch
      1 /*
      2  * Copyright (C) 2009 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  */
     16 
     17 #include "applypatch_modes.h"
     18 
     19 #include <getopt.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <unistd.h>
     24 
     25 #include <memory>
     26 #include <string>
     27 #include <vector>
     28 
     29 #include <android-base/file.h>
     30 #include <android-base/logging.h>
     31 #include <android-base/parseint.h>
     32 #include <android-base/strings.h>
     33 #include <openssl/sha.h>
     34 
     35 #include "applypatch/applypatch.h"
     36 #include "edify/expr.h"
     37 
     38 static int CheckMode(const std::string& target_emmc) {
     39   std::string err;
     40   auto target = Partition::Parse(target_emmc, &err);
     41   if (!target) {
     42     LOG(ERROR) << "Failed to parse target \"" << target_emmc << "\": " << err;
     43     return 2;
     44   }
     45   return CheckPartition(target) ? 0 : 1;
     46 }
     47 
     48 static int FlashMode(const std::string& target_emmc, const std::string& source_file) {
     49   std::string err;
     50   auto target = Partition::Parse(target_emmc, &err);
     51   if (!target) {
     52     LOG(ERROR) << "Failed to parse target \"" << target_emmc << "\": " << err;
     53     return 2;
     54   }
     55   return FlashPartition(target, source_file) ? 0 : 1;
     56 }
     57 
     58 static int PatchMode(const std::string& target_emmc, const std::string& source_emmc,
     59                      const std::string& patch_file, const std::string& bonus_file) {
     60   std::string err;
     61   auto target = Partition::Parse(target_emmc, &err);
     62   if (!target) {
     63     LOG(ERROR) << "Failed to parse target \"" << target_emmc << "\": " << err;
     64     return 2;
     65   }
     66 
     67   auto source = Partition::Parse(source_emmc, &err);
     68   if (!source) {
     69     LOG(ERROR) << "Failed to parse source \"" << source_emmc << "\": " << err;
     70     return 2;
     71   }
     72 
     73   std::string patch_contents;
     74   if (!android::base::ReadFileToString(patch_file, &patch_contents)) {
     75     PLOG(ERROR) << "Failed to read patch file \"" << patch_file << "\"";
     76     return 1;
     77   }
     78 
     79   Value patch(Value::Type::BLOB, std::move(patch_contents));
     80   std::unique_ptr<Value> bonus;
     81   if (!bonus_file.empty()) {
     82     std::string bonus_contents;
     83     if (!android::base::ReadFileToString(bonus_file, &bonus_contents)) {
     84       PLOG(ERROR) << "Failed to read bonus file \"" << bonus_file << "\"";
     85       return 1;
     86     }
     87     bonus = std::make_unique<Value>(Value::Type::BLOB, std::move(bonus_contents));
     88   }
     89 
     90   return PatchPartition(target, source, patch, bonus.get()) ? 0 : 1;
     91 }
     92 
     93 static void Usage() {
     94   printf(
     95       "Usage: \n"
     96       "check mode\n"
     97       "  applypatch --check EMMC:<target-file>:<target-size>:<target-sha1>\n\n"
     98       "flash mode\n"
     99       "  applypatch --flash <source-file>\n"
    100       "             --target EMMC:<target-file>:<target-size>:<target-sha1>\n\n"
    101       "patch mode\n"
    102       "  applypatch [--bonus <bonus-file>]\n"
    103       "             --patch <patch-file>\n"
    104       "             --target EMMC:<target-file>:<target-size>:<target-sha1>\n"
    105       "             --source EMMC:<source-file>:<source-size>:<source-sha1>\n\n"
    106       "show license\n"
    107       "  applypatch --license\n"
    108       "\n\n");
    109 }
    110 
    111 int applypatch_modes(int argc, char* argv[]) {
    112   static constexpr struct option OPTIONS[]{
    113     // clang-format off
    114     { "bonus", required_argument, nullptr, 0 },
    115     { "check", required_argument, nullptr, 0 },
    116     { "flash", required_argument, nullptr, 0 },
    117     { "license", no_argument, nullptr, 0 },
    118     { "patch", required_argument, nullptr, 0 },
    119     { "source", required_argument, nullptr, 0 },
    120     { "target", required_argument, nullptr, 0 },
    121     { nullptr, 0, nullptr, 0 },
    122     // clang-format on
    123   };
    124 
    125   std::string check_target;
    126   std::string source;
    127   std::string target;
    128   std::string patch;
    129   std::string bonus;
    130 
    131   bool check_mode = false;
    132   bool flash_mode = false;
    133   bool patch_mode = false;
    134 
    135   optind = 1;
    136 
    137   int arg;
    138   int option_index;
    139   while ((arg = getopt_long(argc, argv, "", OPTIONS, &option_index)) != -1) {
    140     switch (arg) {
    141       case 0: {
    142         std::string option = OPTIONS[option_index].name;
    143         if (option == "bonus") {
    144           bonus = optarg;
    145         } else if (option == "check") {
    146           check_target = optarg;
    147           check_mode = true;
    148         } else if (option == "flash") {
    149           source = optarg;
    150           flash_mode = true;
    151         } else if (option == "license") {
    152           return ShowLicenses();
    153         } else if (option == "patch") {
    154           patch = optarg;
    155           patch_mode = true;
    156         } else if (option == "source") {
    157           source = optarg;
    158         } else if (option == "target") {
    159           target = optarg;
    160         }
    161         break;
    162       }
    163       case '?':
    164       default:
    165         LOG(ERROR) << "Invalid argument";
    166         Usage();
    167         return 2;
    168     }
    169   }
    170 
    171   if (check_mode) {
    172     return CheckMode(check_target);
    173   }
    174   if (flash_mode) {
    175     if (!bonus.empty()) {
    176       LOG(ERROR) << "bonus file not supported in flash mode";
    177       return 1;
    178     }
    179     return FlashMode(target, source);
    180   }
    181   if (patch_mode) {
    182     return PatchMode(target, source, patch, bonus);
    183   }
    184 
    185   Usage();
    186   return 2;
    187 }
    188