1
0
Fork 0
umcumgr/src/image.c

150 lines
3.9 KiB
C
Raw Normal View History

//
// Created by nock on 26/03/19.
//
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "base64.h"
#include "image.h"
#include "nmgr.h"
#include "cbor.h"
static int serial_fd = -1;
void image_help(void){
printf("umcumgr image [version|upload]\n");
}
static char *hex(char in) {
static char out[3] = {0};
static char lookup[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
out[0] = lookup[in >> 4];
out[1] = lookup[in & 0xf];
out[2] = 0;
return out;
}
static void hex_print(char *in, size_t len) {
char tmp[len*2+1];
tmp[len] = 0;
for (int i = 0; i < len; i++) {
strcat(tmp, hex(in[i]));
}
printf("%s\n", tmp);
}
static void printlen(uint8_t *src, size_t len){
for (size_t i = 0; i < len; i++) {
putchar(src[i]);
}
putchar('\n');
}
static void assert_pkt_start(uint8_t *buf){
assert(buf[0] == SHELL_NLIP_PKT_START1);
assert(buf[1] == SHELL_NLIP_PKT_START2);
}
static void cbor_require_type(CborValue *it, CborType type) {
CborType actual_type = cbor_value_get_type(it);
if (actual_type != type) {
fprintf(stderr, "Cbor deserialization error. Expected type %d, received %d\n", type, actual_type);
exit(1);
}
}
static void do_version(void) {
int rc = write(serial_fd, IMAGE_LIST_CMD, sizeof(IMAGE_LIST_CMD) - 1);
if (rc < sizeof(IMAGE_LIST_CMD) - 1) {
fprintf(stderr, "Failed to send command: %s", strerror(errno));
return;
}
uint8_t tmp[BOOT_SERIAL_IN_MAX];
int in_len;
while (1) {
if ((in_len = read(serial_fd, tmp, BOOT_SERIAL_IN_MAX)) < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "non-blocking\n");
continue;
}
fprintf(stderr, "Reading from serial failed: %s\n", strerror(errno));
return;
}
break;
}
// Process the response
CborParser parser;
CborValue it;
assert_pkt_start(tmp);
size_t out_len;
uint8_t *decoded_buf = base64_decode(tmp+2, in_len-2, &out_len);
// Unclear why this would be useful in a line oriented (cannonical mode) program
uint8_t *p = decoded_buf;
uint16_t pkt_len = ntohs(*(uint16_t *)p);
fflush(stdout);
p += sizeof(pkt_len);
// Hdr also seems a bit pointless, maybe could check for success before CBOR deserialization?
struct nmgr_hdr hdr;
memcpy(&hdr, p, sizeof(struct nmgr_hdr));
p += sizeof(struct nmgr_hdr);
cbor_parser_init(p, out_len, 0, &parser, &it);
cbor_require_type(&it, CborMapType);
CborValue map;
cbor_value_enter_container(&it, &map);
cbor_require_type(&map, CborTextStringType);
cbor_value_advance(&map);
cbor_require_type(&map, CborArrayType);
CborValue img_array;
cbor_value_enter_container(&map, &img_array);
while (!cbor_value_at_end(&img_array)) {
assert(cbor_value_get_type(&img_array) == CborMapType);
CborValue version_tag;
CborError err = cbor_value_map_find_value(&img_array, "version", &version_tag);
if (err) {
// There's no version key for this slot, probably an error
fprintf(stderr, "Failed to find version info: %s", cbor_error_string(err));
cbor_value_advance(&img_array);
continue;
}
char *version;
size_t len;
cbor_value_dup_text_string(&version_tag, &version, &len, NULL);
printf("%s\n", version);
free(version);
break;
}
free(decoded_buf);
}
void do_upload(void){
return;
}
void image_main(int fd, int argc, char **argv){
serial_fd = fd;
if (argc < 1) {
image_help();
return;
}
if (!strcmp(argv[0], "version")) {
do_version();
} else if (!strcmp(argv[0], "upload")) {
do_upload();
} else {
image_help();
}
}