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 
CheckMode(const std::string & target_emmc)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 
FlashMode(const std::string & target_emmc,const std::string & source_file)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 
PatchMode(const std::string & target_emmc,const std::string & source_emmc,const std::string & patch_file,const std::string & bonus_file)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(), false) ? 0 : 1;
91 }
92 
Usage()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 
applypatch_modes(int argc,char * argv[])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