| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include "os/mynewt.h" |
| |
| #if MYNEWT_VAL(IMGMGR_CLI) |
| |
| #include <string.h> |
| |
| #include <flash_map/flash_map.h> |
| #include <hal/hal_bsp.h> |
| |
| #include <shell/shell.h> |
| |
| #include <bootutil/image.h> |
| #include <bootutil/bootutil.h> |
| |
| #include <base64/hex.h> |
| |
| #include <parse/parse.h> |
| |
| #include "imgmgr/imgmgr.h" |
| #include "img_mgmt/img_mgmt.h" |
| #include "imgmgr_priv.h" |
| |
| static int imgr_cli_cmd(const struct shell_cmd *cmd, int argc, char **argv, |
| struct streamer *streamer); |
| |
| #if MYNEWT_VAL(SHELL_CMD_HELP) |
| static const struct shell_cmd_help imgr_cli_help = { |
| .summary = "image management command", |
| .usage = "\n" |
| " imgr list\n" |
| " imgr test <slot | hash>\n" |
| " imgr confirm [slot | hash]" |
| }; |
| #endif |
| |
| static struct shell_cmd shell_imgr_cmd[] = { |
| SHELL_CMD_EXT("imgr", imgr_cli_cmd, &imgr_cli_help), |
| { 0 }, |
| }; |
| |
| static void |
| imgr_cli_too_few_args(struct streamer *streamer) |
| { |
| streamer_printf(streamer, "Too few args\n"); |
| } |
| |
| static const char * |
| imgr_cli_flags_str(uint32_t image_flags, uint8_t state_flags) |
| { |
| static char buf[8]; |
| char *p; |
| |
| memset(buf, ' ', sizeof buf); |
| p = buf; |
| |
| if (state_flags & IMG_MGMT_STATE_F_ACTIVE) { |
| *p = 'a'; |
| } |
| p++; |
| if (!(image_flags & IMAGE_F_NON_BOOTABLE)) { |
| *p = 'b'; |
| } |
| p++; |
| if (state_flags & IMG_MGMT_STATE_F_CONFIRMED) { |
| *p = 'c'; |
| } |
| p++; |
| if (state_flags & IMG_MGMT_STATE_F_PENDING) { |
| *p = 'p'; |
| } |
| p++; |
| |
| *p = '\0'; |
| |
| return buf; |
| } |
| |
| static void |
| imgr_cli_show_slot(int slot, struct streamer *streamer) |
| { |
| uint8_t hash[IMGMGR_HASH_LEN]; /* SHA256 hash */ |
| char hash_str[IMGMGR_HASH_LEN * 2 + 1]; |
| struct image_version ver; |
| char ver_str[IMGMGR_NMGR_MAX_VER]; |
| uint32_t flags; |
| uint8_t state_flags; |
| |
| if (img_mgmt_read_info(slot, &ver, hash, &flags)) { |
| return; |
| } |
| |
| state_flags = img_mgmt_state_flags(slot); |
| |
| (void)img_mgmt_ver_str(&ver, ver_str); |
| |
| streamer_printf(streamer, "%d %8s: %s %s\n", |
| slot, ver_str, |
| hex_format(hash, IMGMGR_HASH_LEN, hash_str, sizeof(hash_str)), |
| imgr_cli_flags_str(flags, state_flags)); |
| } |
| |
| static int |
| imgr_cli_hash_parse(const char *arg, int *out_slot) |
| { |
| uint8_t hash[IMGMGR_HASH_LEN]; |
| struct image_version ver; |
| int slot; |
| int rc; |
| |
| rc = hex_parse(arg, strlen(arg), hash, sizeof hash); |
| if (rc != sizeof hash) { |
| return SYS_EINVAL; |
| } |
| |
| slot = imgr_find_by_hash(hash, &ver); |
| if (slot == -1) { |
| return SYS_ENOENT; |
| } |
| |
| *out_slot = slot; |
| return 0; |
| } |
| |
| static int |
| imgr_cli_slot_or_hash_parse(const char *arg, int *out_slot, struct streamer *streamer) |
| { |
| int rc; |
| |
| /* First, parse argument as a slot number. Parts of the system assume slot |
| * is 0 or 1; enforce those bounds here. |
| */ |
| *out_slot = parse_ll_bounds(arg, 0, 1, &rc); |
| if (rc == 0) { |
| return 0; |
| } |
| |
| /* Try to parse as a hash string. */ |
| rc = imgr_cli_hash_parse(arg, out_slot); |
| switch (rc) { |
| case 0: |
| return 0; |
| |
| case SYS_ENOENT: |
| streamer_printf(streamer, "No image with hash: %s\n", arg); |
| return rc; |
| |
| default: |
| streamer_printf(streamer, "Invalid slot number or image hash: %s\n", arg); |
| return rc; |
| } |
| } |
| |
| static void |
| imgr_cli_set_pending(char *arg, int permanent, struct streamer *streamer) |
| { |
| int slot; |
| int rc; |
| |
| /* Parts of the system assume slot is 0 or 1; enforce here. */ |
| rc = imgr_cli_slot_or_hash_parse(arg, &slot, streamer); |
| if (rc != 0) { |
| return; |
| } |
| |
| rc = img_mgmt_state_set_pending(slot, permanent); |
| if (rc) { |
| streamer_printf(streamer, "Error setting slot %d to pending; rc=%d\n", slot, rc); |
| return; |
| } |
| } |
| |
| static void |
| imgr_cli_confirm(struct streamer *streamer) |
| { |
| int rc; |
| |
| rc = img_mgmt_state_confirm(); |
| if (rc != 0) { |
| streamer_printf(streamer, "Error confirming image state; rc=%d\n", rc); |
| return; |
| } |
| } |
| |
| static void |
| imgr_cli_erase(struct streamer *streamer) |
| { |
| const struct flash_area *fa; |
| int area_id; |
| int rc; |
| |
| area_id = imgmgr_find_best_area_id(); |
| if (area_id >= 0) { |
| rc = flash_area_open(area_id, &fa); |
| if (rc) { |
| streamer_printf(streamer, "Error opening area %d\n", area_id); |
| return; |
| } |
| rc = flash_area_erase(fa, 0, fa->fa_size); |
| flash_area_close(fa); |
| if (rc) { |
| streamer_printf(streamer, "Error erasing area rc=%d\n", rc); |
| } |
| } else { |
| /* |
| * No slot where to erase! |
| */ |
| streamer_printf(streamer, "No suitable area to erase\n"); |
| } |
| } |
| |
| static int |
| imgr_cli_cmd(const struct shell_cmd *cmd, int argc, char **argv, struct streamer *streamer) |
| { |
| int i; |
| |
| if (argc < 2) { |
| imgr_cli_too_few_args(streamer); |
| return 0; |
| } |
| if (!strcmp(argv[1], "list")) { |
| for (i = 0; i < 2; i++) { |
| imgr_cli_show_slot(i, streamer); |
| } |
| } else if (!strcmp(argv[1], "test")) { |
| if (argc < 3) { |
| imgr_cli_too_few_args(streamer); |
| return 0; |
| } else { |
| imgr_cli_set_pending(argv[2], 0, streamer); |
| } |
| } else if (!strcmp(argv[1], "confirm")) { |
| if (argc < 3) { |
| imgr_cli_confirm(streamer); |
| } else { |
| imgr_cli_set_pending(argv[2], 1, streamer); |
| } |
| } else if (!strcmp(argv[1], "erase")) { |
| imgr_cli_erase(streamer); |
| } else { |
| streamer_printf(streamer, "Unknown cmd\n"); |
| } |
| return 0; |
| } |
| |
| int |
| imgr_cli_register(void) |
| { |
| return shell_cmd_register(shell_imgr_cmd); |
| } |
| #endif /* MYNEWT_VAL(IMGMGR_CLI) */ |