• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 <optional>
18 #include <sstream>
19 
20 #include <BootControlClient.h>
21 #include <android/hardware/boot/1.2/IBootControl.h>
22 #include <sysexits.h>
23 
24 using android::sp;
25 
26 using aidl::android::hardware::boot::MergeStatus;
27 
28 using android::hal::BootControlClient;
29 using android::hal::BootControlVersion;
30 using android::hal::CommandResult;
31 
usage(FILE * where,BootControlVersion bootVersion,int,char * argv[])32 static void usage(FILE* where, BootControlVersion bootVersion, int /* argc */, char* argv[]) {
33     fprintf(where,
34             "%s - command-line wrapper for the boot HAL.\n"
35             "\n"
36             "Usage:\n"
37             "  %s COMMAND\n"
38             "\n"
39             "Commands:\n"
40             "  hal-info                       - Show info about boot_control HAL used.\n"
41             "  get-number-slots               - Prints number of slots.\n"
42             "  get-current-slot               - Prints currently running SLOT.\n"
43             "  mark-boot-successful           - Mark current slot as GOOD.\n"
44             "  get-active-boot-slot           - Prints the SLOT to load on next boot.\n"
45             "  set-active-boot-slot SLOT      - On next boot, load and execute SLOT.\n"
46             "  set-slot-as-unbootable SLOT    - Mark SLOT as invalid.\n"
47             "  is-slot-bootable SLOT          - Returns 0 only if SLOT is bootable.\n"
48             "  is-slot-marked-successful SLOT - Returns 0 only if SLOT is marked GOOD.\n"
49             "  get-suffix SLOT                - Prints suffix for SLOT.\n",
50             argv[0], argv[0]);
51     if (bootVersion >= BootControlVersion::BOOTCTL_V1_1) {
52         fprintf(where,
53                 "  set-snapshot-merge-status STAT - Sets whether a snapshot-merge of any dynamic\n"
54                 "                                   partition is in progress. Valid STAT values\n"
55                 "                                   are: none, unknown, snapshotted, merging,\n"
56                 "                                   or cancelled.\n"
57                 "  get-snapshot-merge-status      - Prints the current snapshot-merge status.\n");
58     }
59     fprintf(where,
60             "\n"
61             "SLOT parameter is the zero-based slot-number.\n");
62 }
63 
ToString(BootControlVersion ver)64 static constexpr auto ToString(BootControlVersion ver) {
65     switch (ver) {
66         case BootControlVersion::BOOTCTL_V1_0:
67             return "android.hardware.boot@1.0::IBootControl";
68         case BootControlVersion::BOOTCTL_V1_1:
69             return "android.hardware.boot@1.1::IBootControl";
70         case BootControlVersion::BOOTCTL_V1_2:
71             return "android.hardware.boot@1.2::IBootControl";
72         case BootControlVersion::BOOTCTL_AIDL:
73             return "android.hardware.boot@aidl::IBootControl";
74     }
75 }
76 
do_hal_info(const BootControlClient * module)77 static int do_hal_info(const BootControlClient* module) {
78     fprintf(stdout, "HAL Version: %s\n", ToString(module->GetVersion()));
79     return EX_OK;
80 }
81 
do_get_number_slots(BootControlClient * module)82 static int do_get_number_slots(BootControlClient* module) {
83     auto numSlots = module->GetNumSlots();
84     fprintf(stdout, "%u\n", numSlots);
85     return EX_OK;
86 }
87 
do_get_current_slot(BootControlClient * module)88 static int do_get_current_slot(BootControlClient* module) {
89     auto curSlot = module->GetCurrentSlot();
90     fprintf(stdout, "%u\n", curSlot);
91     return EX_OK;
92 }
93 
handle_return(CommandResult cr,const char * errStr)94 static int handle_return(CommandResult cr, const char* errStr) {
95     if (!cr.IsOk()) {
96         fprintf(stderr, errStr, cr.errMsg.c_str());
97         return EX_SOFTWARE;
98     } else if (!cr.success) {
99         fprintf(stderr, errStr, cr.errMsg.c_str());
100         return EX_SOFTWARE;
101     }
102     return EX_OK;
103 }
104 
do_mark_boot_successful(BootControlClient * module)105 static int do_mark_boot_successful(BootControlClient* module) {
106     auto ret = module->MarkBootSuccessful();
107     return handle_return(ret, "Error marking as having booted successfully: %s\n");
108 }
109 
do_get_active_boot_slot(BootControlClient * module)110 static int do_get_active_boot_slot(BootControlClient* module) {
111     uint32_t slot = module->GetActiveBootSlot();
112     fprintf(stdout, "%u\n", slot);
113     return EX_OK;
114 }
115 
do_set_active_boot_slot(BootControlClient * module,int32_t slot_number)116 static int do_set_active_boot_slot(BootControlClient* module, int32_t slot_number) {
117     const auto cr = module->SetActiveBootSlot(slot_number);
118     return handle_return(cr, "Error setting active boot slot: %s\n");
119 }
120 
do_set_slot_as_unbootable(BootControlClient * module,int32_t slot_number)121 static int do_set_slot_as_unbootable(BootControlClient* module, int32_t slot_number) {
122     const auto cr = module->MarkSlotUnbootable(slot_number);
123     return handle_return(cr, "Error setting slot as unbootable: %s\n");
124 }
125 
handle_return(const std::optional<bool> & ret,const char * errStr)126 static int handle_return(const std::optional<bool>& ret, const char* errStr) {
127     if (!ret.has_value()) {
128         fprintf(stderr, errStr, "");
129         return EX_SOFTWARE;
130     }
131     if (ret.value()) {
132         printf("%d\n", ret.value());
133         return EX_OK;
134     }
135     printf("%d\n", ret.value());
136     return EX_SOFTWARE;
137 }
138 
do_is_slot_bootable(BootControlClient * module,int32_t slot_number)139 static int do_is_slot_bootable(BootControlClient* module, int32_t slot_number) {
140     const auto ret = module->IsSlotBootable(slot_number);
141     return handle_return(ret, "Error calling isSlotBootable()\n");
142 }
143 
do_is_slot_marked_successful(BootControlClient * module,int32_t slot_number)144 static int do_is_slot_marked_successful(BootControlClient* module, int32_t slot_number) {
145     const auto ret = module->IsSlotMarkedSuccessful(slot_number);
146     return handle_return(ret, "Error calling isSlotMarkedSuccessful()\n");
147 }
148 
stringToMergeStatus(const std::string & status)149 std::optional<MergeStatus> stringToMergeStatus(const std::string& status) {
150     if (status == "cancelled") return MergeStatus::CANCELLED;
151     if (status == "merging") return MergeStatus::MERGING;
152     if (status == "none") return MergeStatus::NONE;
153     if (status == "snapshotted") return MergeStatus::SNAPSHOTTED;
154     if (status == "unknown") return MergeStatus::UNKNOWN;
155     return {};
156 }
157 
do_set_snapshot_merge_status(BootControlClient * module,BootControlVersion bootVersion,int argc,char * argv[])158 static int do_set_snapshot_merge_status(BootControlClient* module, BootControlVersion bootVersion,
159                                         int argc, char* argv[]) {
160     if (argc != 3) {
161         usage(stderr, bootVersion, argc, argv);
162         exit(EX_USAGE);
163         return -1;
164     }
165 
166     auto status = stringToMergeStatus(argv[2]);
167     if (!status.has_value()) {
168         usage(stderr, bootVersion, argc, argv);
169         exit(EX_USAGE);
170         return -1;
171     }
172 
173     const auto ret = module->SetSnapshotMergeStatus(status.value());
174     return handle_return(ret, "Failed to set snapshot merge status: %s\n");
175 }
176 
operator <<(std::ostream & os,MergeStatus state)177 std::ostream& operator<<(std::ostream& os, MergeStatus state) {
178     switch (state) {
179         case MergeStatus::CANCELLED:
180             return os << "cancelled";
181         case MergeStatus::MERGING:
182             return os << "merging";
183         case MergeStatus::NONE:
184             return os << "none";
185         case MergeStatus::SNAPSHOTTED:
186             return os << "snapshotted";
187         case MergeStatus::UNKNOWN:
188             return os << "unknown";
189         default:
190             return os;
191     }
192 }
193 
do_get_snapshot_merge_status(BootControlClient * module)194 static int do_get_snapshot_merge_status(BootControlClient* module) {
195     MergeStatus ret = module->getSnapshotMergeStatus();
196     std::stringstream ss;
197     ss << ret;
198     fprintf(stdout, "%s\n", ss.str().c_str());
199     return EX_OK;
200 }
201 
do_get_suffix(BootControlClient * module,int32_t slot_number)202 static int do_get_suffix(BootControlClient* module, int32_t slot_number) {
203     const auto ret = module->GetSuffix(slot_number);
204     if (ret.empty()) {
205         fprintf(stderr, "Error calling getSuffix()\n");
206         return EX_SOFTWARE;
207     }
208     printf("%s\n", ret.c_str());
209     return EX_OK;
210 }
211 
parse_slot(BootControlVersion bootVersion,int pos,int argc,char * argv[])212 static uint32_t parse_slot(BootControlVersion bootVersion, int pos, int argc, char* argv[]) {
213     if (pos > argc - 1) {
214         usage(stderr, bootVersion, argc, argv);
215         exit(EX_USAGE);
216         return -1;
217     }
218     errno = 0;
219     uint64_t ret = strtoul(argv[pos], NULL, 10);
220     if (errno != 0 || ret > UINT_MAX) {
221         usage(stderr, bootVersion, argc, argv);
222         exit(EX_USAGE);
223         return -1;
224     }
225     return (uint32_t)ret;
226 }
227 
main(int argc,char * argv[])228 int main(int argc, char* argv[]) {
229     const auto client = android::hal::BootControlClient::WaitForService();
230     if (client == nullptr) {
231         fprintf(stderr, "Failed to get bootctl module.\n");
232         return EX_SOFTWARE;
233     }
234     const auto bootVersion = client->GetVersion();
235 
236     if (argc < 2) {
237         usage(stderr, bootVersion, argc, argv);
238         return EX_USAGE;
239     }
240 
241     // Functions present from version 1.0
242     if (strcmp(argv[1], "hal-info") == 0) {
243         return do_hal_info(client.get());
244     } else if (strcmp(argv[1], "get-number-slots") == 0) {
245         return do_get_number_slots(client.get());
246     } else if (strcmp(argv[1], "get-current-slot") == 0) {
247         return do_get_current_slot(client.get());
248     } else if (strcmp(argv[1], "mark-boot-successful") == 0) {
249         return do_mark_boot_successful(client.get());
250     } else if (strcmp(argv[1], "set-active-boot-slot") == 0) {
251         return do_set_active_boot_slot(client.get(), parse_slot(bootVersion, 2, argc, argv));
252     } else if (strcmp(argv[1], "set-slot-as-unbootable") == 0) {
253         return do_set_slot_as_unbootable(client.get(), parse_slot(bootVersion, 2, argc, argv));
254     } else if (strcmp(argv[1], "is-slot-bootable") == 0) {
255         return do_is_slot_bootable(client.get(), parse_slot(bootVersion, 2, argc, argv));
256     } else if (strcmp(argv[1], "is-slot-marked-successful") == 0) {
257         return do_is_slot_marked_successful(client.get(), parse_slot(bootVersion, 2, argc, argv));
258     } else if (strcmp(argv[1], "get-suffix") == 0) {
259         return do_get_suffix(client.get(), parse_slot(bootVersion, 2, argc, argv));
260     }
261 
262     // Functions present from version 1.1
263     if (strcmp(argv[1], "set-snapshot-merge-status") == 0 ||
264         strcmp(argv[1], "get-snapshot-merge-status") == 0) {
265         if (bootVersion < BootControlVersion::BOOTCTL_V1_1) {
266             fprintf(stderr, "Error getting bootctrl v1.1 module.\n");
267             return EX_SOFTWARE;
268         }
269         if (strcmp(argv[1], "set-snapshot-merge-status") == 0) {
270             return do_set_snapshot_merge_status(client.get(), bootVersion, argc, argv);
271         } else if (strcmp(argv[1], "get-snapshot-merge-status") == 0) {
272             return do_get_snapshot_merge_status(client.get());
273         }
274     }
275 
276     if (strcmp(argv[1], "get-active-boot-slot") == 0) {
277         if (bootVersion < BootControlVersion::BOOTCTL_V1_2) {
278             fprintf(stderr, "Error getting bootctrl v1.2 module.\n");
279             return EX_SOFTWARE;
280         }
281 
282         return do_get_active_boot_slot(client.get());
283     }
284 
285     // Parameter not matched, print usage
286     usage(stderr, bootVersion, argc, argv);
287     return EX_USAGE;
288 }
289