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
20using android::sp;
21
22using android::hardware::hidl_string;
23using android::hardware::Return;
24
25using android::hardware::boot::V1_0::BoolResult;
26using android::hardware::boot::V1_0::IBootControl;
27using android::hardware::boot::V1_0::CommandResult;
28using android::hardware::boot::V1_0::Slot;
29
30static 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
54static 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
63static 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
70static 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
77static std::function<void(CommandResult)> generate_callback(CommandResult *crp) {
78    return [=](CommandResult cr){
79        *crp = cr;
80    };
81}
82
83static 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
94static 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
101static 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
109static 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
117static 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
130static 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
136static 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
144static 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
157static 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
174int main(int argc, char *argv[])
175{
176    sp<IBootControl> module;
177
178    if (argc < 2) {
179        usage(stderr, argc, argv);
180        return EX_USAGE;
181    }
182
183    module = IBootControl::getService();
184    if (module == NULL) {
185        fprintf(stderr, "Error getting bootctrl module.\n");
186        return EX_SOFTWARE;
187    }
188
189    if (strcmp(argv[1], "hal-info") == 0) {
190        return do_hal_info(module);
191    } else if (strcmp(argv[1], "get-number-slots") == 0) {
192        return do_get_number_slots(module);
193    } else if (strcmp(argv[1], "get-current-slot") == 0) {
194        return do_get_current_slot(module);
195    } else if (strcmp(argv[1], "mark-boot-successful") == 0) {
196        return do_mark_boot_successful(module);
197    } else if (strcmp(argv[1], "set-active-boot-slot") == 0) {
198        return do_set_active_boot_slot(module, parse_slot(2, argc, argv));
199    } else if (strcmp(argv[1], "set-slot-as-unbootable") == 0) {
200        return do_set_slot_as_unbootable(module, parse_slot(2, argc, argv));
201    } else if (strcmp(argv[1], "is-slot-bootable") == 0) {
202        return do_is_slot_bootable(module, parse_slot(2, argc, argv));
203    } else if (strcmp(argv[1], "get-suffix") == 0) {
204        return do_get_suffix(module, parse_slot(2, argc, argv));
205    } else if (strcmp(argv[1], "is-slot-marked-successful") == 0) {
206        return do_is_slot_marked_successful(module, parse_slot(2, argc, argv));
207    } else {
208        usage(stderr, argc, argv);
209        return EX_USAGE;
210    }
211
212    return 0;
213}
214