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 <sysexits.h>
18 #include <android/hardware/boot/1.0/IBootControl.h>
19 
20 using android::sp;
21 
22 using android::hardware::hidl_string;
23 using android::hardware::Return;
24 
25 using android::hardware::boot::V1_0::BoolResult;
26 using android::hardware::boot::V1_0::IBootControl;
27 using android::hardware::boot::V1_0::CommandResult;
28 using android::hardware::boot::V1_0::Slot;
29 
usage(FILE * where,int,char * argv[])30 static void usage(FILE* where, int /* argc */, char* argv[])
31 {
32     fprintf(where,
33             "%s - command-line wrapper for the boot HAL.\n"
34             "\n"
35             "Usage:\n"
36             "  %s COMMAND\n"
37             "\n"
38             "Commands:\n"
39             "  %s hal-info                       - Show info about boot_control HAL used.\n"
40             "  %s get-number-slots               - Prints number of slots.\n"
41             "  %s get-current-slot               - Prints currently running SLOT.\n"
42             "  %s mark-boot-successful           - Mark current slot as GOOD.\n"
43             "  %s set-active-boot-slot SLOT      - On next boot, load and execute SLOT.\n"
44             "  %s set-slot-as-unbootable SLOT    - Mark SLOT as invalid.\n"
45             "  %s is-slot-bootable SLOT          - Returns 0 only if SLOT is bootable.\n"
46             "  %s is-slot-marked-successful SLOT - Returns 0 only if SLOT is marked GOOD.\n"
47             "  %s get-suffix SLOT                - Prints suffix for SLOT.\n"
48             "\n"
49             "SLOT parameter is the zero-based slot-number.\n",
50             argv[0], argv[0], argv[0], argv[0], argv[0], argv[0],
51             argv[0], argv[0], argv[0], argv[0], argv[0]);
52 }
53 
do_hal_info(const sp<IBootControl> module)54 static int do_hal_info(const sp<IBootControl> module) {
55     module->interfaceDescriptor([&](const auto& descriptor) {
56         fprintf(stdout,
57                 "HAL Version: %s\n",
58                 descriptor.c_str());
59     });
60     return EX_OK;
61 }
62 
do_get_number_slots(sp<IBootControl> module)63 static int do_get_number_slots(sp<IBootControl> module)
64 {
65     uint32_t numSlots = module->getNumberSlots();
66     fprintf(stdout, "%u\n", numSlots);
67     return EX_OK;
68 }
69 
do_get_current_slot(sp<IBootControl> module)70 static int do_get_current_slot(sp<IBootControl> module)
71 {
72     Slot curSlot = module->getCurrentSlot();
73     fprintf(stdout, "%u\n", curSlot);
74     return EX_OK;
75 }
76 
generate_callback(CommandResult * crp)77 static std::function<void(CommandResult)> generate_callback(CommandResult *crp) {
78     return [=](CommandResult cr){
79         *crp = cr;
80     };
81 }
82 
handle_return(const Return<void> & ret,CommandResult cr,const char * errStr)83 static int handle_return(const Return<void> &ret, CommandResult cr, const char* errStr) {
84     if (!ret.isOk()) {
85         fprintf(stderr, errStr, ret.description().c_str());
86         return EX_SOFTWARE;
87     } else if (!cr.success) {
88         fprintf(stderr, errStr, cr.errMsg.c_str());
89         return EX_SOFTWARE;
90     }
91     return EX_OK;
92 }
93 
do_mark_boot_successful(sp<IBootControl> module)94 static int do_mark_boot_successful(sp<IBootControl> module)
95 {
96     CommandResult cr;
97     Return<void> ret = module->markBootSuccessful(generate_callback(&cr));
98     return handle_return(ret, cr, "Error marking as having booted successfully: %s\n");
99 }
100 
do_set_active_boot_slot(sp<IBootControl> module,Slot slot_number)101 static int do_set_active_boot_slot(sp<IBootControl> module,
102                                    Slot slot_number)
103 {
104     CommandResult cr;
105     Return<void> ret = module->setActiveBootSlot(slot_number, generate_callback(&cr));
106     return handle_return(ret, cr, "Error setting active boot slot: %s\n");
107 }
108 
do_set_slot_as_unbootable(sp<IBootControl> module,Slot slot_number)109 static int do_set_slot_as_unbootable(sp<IBootControl> module,
110                                      Slot slot_number)
111 {
112     CommandResult cr;
113     Return<void> ret = module->setSlotAsUnbootable(slot_number, generate_callback(&cr));
114     return handle_return(ret, cr, "Error setting slot as unbootable: %s\n");
115 }
116 
handle_return(const Return<BoolResult> & ret,const char * errStr)117 static int handle_return(const Return<BoolResult> &ret, const char* errStr) {
118     if (!ret.isOk()) {
119         fprintf(stderr, errStr, ret.description().c_str());
120         return EX_SOFTWARE;
121     } else if (ret == BoolResult::INVALID_SLOT) {
122         fprintf(stderr, errStr, "Invalid slot");
123         return EX_SOFTWARE;
124     } else if (ret == BoolResult::TRUE) {
125         return EX_OK;
126     }
127     return EX_SOFTWARE;
128 }
129 
do_is_slot_bootable(sp<IBootControl> module,Slot slot_number)130 static int do_is_slot_bootable(sp<IBootControl> module, Slot slot_number)
131 {
132     Return<BoolResult> ret = module->isSlotBootable(slot_number);
133     return handle_return(ret, "Error calling isSlotBootable(): %s\n");
134 }
135 
do_is_slot_marked_successful(sp<IBootControl> module,Slot slot_number)136 static int do_is_slot_marked_successful(sp<IBootControl> module,
137                                         Slot slot_number)
138 {
139     Return<BoolResult> ret = module->isSlotMarkedSuccessful(slot_number);
140     return handle_return(ret, "Error calling isSlotMarkedSuccessful(): %s\n");
141 }
142 
143 
do_get_suffix(sp<IBootControl> module,Slot slot_number)144 static int do_get_suffix(sp<IBootControl> module, Slot slot_number) {
145     std::function<void(hidl_string)> cb = [](hidl_string suffix){
146         fprintf(stdout, "%s\n", suffix.c_str());
147     };
148     Return<void> ret = module->getSuffix(slot_number, cb);
149     if (!ret.isOk()) {
150         fprintf(stderr, "Error calling getSuffix(): %s\n",
151                 ret.description().c_str());
152         return EX_SOFTWARE;
153     }
154     return EX_OK;
155 }
156 
parse_slot(int pos,int argc,char * argv[])157 static uint32_t parse_slot(int pos, int argc, char *argv[])
158 {
159     if (pos > argc - 1) {
160         usage(stderr, argc, argv);
161         exit(EX_USAGE);
162         return -1;
163     }
164     errno = 0;
165     uint64_t ret = strtoul(argv[pos], NULL, 10);
166     if (errno != 0 || ret > UINT_MAX) {
167         usage(stderr, argc, argv);
168         exit(EX_USAGE);
169         return -1;
170     }
171     return (uint32_t)ret;
172 }
173 
main(int argc,char * argv[])174 int main(int argc, char *argv[])
175 {
176     sp<IBootControl> module;
177     int ret;
178 
179     if (argc < 2) {
180         usage(stderr, argc, argv);
181         return EX_USAGE;
182     }
183 
184     module = IBootControl::getService();
185     if (module == NULL) {
186         fprintf(stderr, "Error getting bootctrl module.\n");
187         return EX_SOFTWARE;
188     }
189 
190     if (strcmp(argv[1], "hal-info") == 0) {
191         return do_hal_info(module);
192     } else if (strcmp(argv[1], "get-number-slots") == 0) {
193         return do_get_number_slots(module);
194     } else if (strcmp(argv[1], "get-current-slot") == 0) {
195         return do_get_current_slot(module);
196     } else if (strcmp(argv[1], "mark-boot-successful") == 0) {
197         return do_mark_boot_successful(module);
198     } else if (strcmp(argv[1], "set-active-boot-slot") == 0) {
199         return do_set_active_boot_slot(module, parse_slot(2, argc, argv));
200     } else if (strcmp(argv[1], "set-slot-as-unbootable") == 0) {
201         return do_set_slot_as_unbootable(module, parse_slot(2, argc, argv));
202     } else if (strcmp(argv[1], "is-slot-bootable") == 0) {
203         return do_is_slot_bootable(module, parse_slot(2, argc, argv));
204     } else if (strcmp(argv[1], "get-suffix") == 0) {
205         return do_get_suffix(module, parse_slot(2, argc, argv));
206     } else if (strcmp(argv[1], "is-slot-marked-successful") == 0) {
207         return do_is_slot_marked_successful(module, parse_slot(2, argc, argv));
208     } else {
209         usage(stderr, argc, argv);
210         return EX_USAGE;
211     }
212 
213     return 0;
214 }
215