int mgos_upd_file_end(struct mgos_upd_hal_ctx *ctx, const struct mgos_upd_file_info *fi, struct mg_str tail) { int r = tail.len; assert(tail.len == 0); if (ctx->cur_fn == (_u8 *) ctx->fs_container_file) { if (!cc32xx_vfs_dev_slfs_container_write_meta( ctx->cur_fh, FS_INITIAL_SEQ, ctx->fs_size, ctx->fs_block_size, ctx->fs_page_size, ctx->fs_erase_size)) { ctx->status_msg = "Failed to write fs meta"; r = -1; } } if (sl_FsClose(ctx->cur_fh, NULL, NULL, 0) != 0) { ctx->status_msg = "Close failed"; r = -1; } else { struct json_token sha1 = JSON_INVALID_TOKEN; json_scanf(ctx->cur_part.ptr, ctx->cur_part.len, "{cs_sha1: %T}", &sha1); if (!verify_checksum((const char *) ctx->cur_fn, fi->size, &sha1)) { ctx->status_msg = "Checksum mismatch"; r = -1; } } ctx->cur_fh = -1; ctx->cur_fn = NULL; return r; }
static int prepare_to_write(struct mgos_upd_hal_ctx *ctx, const struct mgos_upd_file_info *fi, const char *fname, uint32_t falloc, struct json_token *part) { struct json_token expected_sha1 = JSON_INVALID_TOKEN; json_scanf(part->ptr, part->len, "{cs_sha1: %T}", &expected_sha1); if (verify_checksum(fname, fi->size, &expected_sha1)) { LOG(LL_INFO, ("Digest matched for %s %u (%.*s)", fname, (unsigned int) fi->size, (int) expected_sha1.len, expected_sha1.ptr)); return 0; } LOG(LL_INFO, ("Storing %s %u -> %s %u (%.*s)", fi->name, (unsigned int) fi->size, fname, (unsigned int) falloc, (int) expected_sha1.len, expected_sha1.ptr)); ctx->cur_fn = (const _u8 *) fname; sl_FsDel(ctx->cur_fn, 0); _i32 r = sl_FsOpen(ctx->cur_fn, FS_MODE_OPEN_CREATE(falloc, 0), NULL, &ctx->cur_fh); if (r < 0) { ctx->status_msg = "Failed to create file"; return r; } return 1; }
static bool esp32_vfs_dev_partition_open(struct mgos_vfs_dev *dev, const char *opts) { char *label = NULL; int subtype = 0xff; /* any subtype */ json_scanf(opts, strlen(opts), "{name: %Q, label: %Q, subtype: %d}", &label, &label, &subtype); if (label == NULL) { LOG(LL_ERROR, ("Must specify partition label")); return false; } const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, subtype, label); if (part != NULL) { dev->dev_data = (void *) part; } free(label); return (part != NULL); }
static int tcmp(const struct json_token *tok, const char *str) { struct mg_str s = {.p = tok->ptr, .len = tok->len}; return mg_vcmp(&s, str); } enum mgos_upd_file_action mgos_upd_file_begin( struct mgos_upd_hal_ctx *ctx, const struct mgos_upd_file_info *fi) { struct mg_str part_name = MG_MK_STR(""); enum mgos_upd_file_action ret = MGOS_UPDATER_SKIP_FILE; struct find_part_info find_part_info = {fi->name, &part_name, &ctx->cur_part}; ctx->cur_part.len = part_name.len = 0; json_walk(ctx->parts->ptr, ctx->parts->len, find_part, &find_part_info); if (ctx->cur_part.len == 0) return ret; /* Drop any indexes from part name, we'll add our own. */ while (1) { char c = part_name.p[part_name.len - 1]; if (c != '.' && !(c >= '0' && c <= '9')) break; part_name.len--; } struct json_token type = JSON_INVALID_TOKEN; const char *fname = NULL; uint32_t falloc = 0; json_scanf(ctx->cur_part.ptr, ctx->cur_part.len, "{load_addr:%u, falloc:%u, type: %T}", &ctx->app_load_addr, &falloc, &type); if (falloc == 0) falloc = fi->size; if (tcmp(&type, "app") == 0) { struct boot_cfg cur_cfg; int r = read_boot_cfg(ctx->cur_boot_cfg_idx, &cur_cfg); if (r < 0) { ctx->status_msg = "Could not read current boot cfg"; return MGOS_UPDATER_ABORT; } #if CC3200_SAFE_CODE_UPDATE /* * When safe code update is enabled, we write code to a new file. * Otherwise we write to the same slot we're using currently, which is * unsafe, makes reverting code update not possible, but saves space. */ create_fname( mg_mk_str_n(cur_cfg.app_image_file, strlen(cur_cfg.app_image_file) - 2), ctx->new_boot_cfg_idx, ctx->app_image_file, sizeof(ctx->app_image_file)); #else { strncpy(ctx->app_image_file, cur_cfg.app_image_file, sizeof(ctx->app_image_file)); } #endif if (ctx->app_load_addr >= 0x20000000) { fname = ctx->app_image_file; } else { ctx->status_msg = "Bad/missing app load_addr"; ret = MGOS_UPDATER_ABORT; } } else if (tcmp(&type, "fs") == 0) { json_scanf( ctx->cur_part.ptr, ctx->cur_part.len, "{fs_size: %u, fs_block_size: %u, fs_page_size: %u, fs_erase_size: %u}", &ctx->fs_size, &ctx->fs_block_size, &ctx->fs_page_size, &ctx->fs_erase_size); if (ctx->fs_size > 0 && ctx->fs_block_size > 0 && ctx->fs_page_size > 0 && ctx->fs_erase_size > 0) { char fs_container_prefix[MAX_FS_CONTAINER_PREFIX_LEN]; create_fname(part_name, ctx->new_boot_cfg_idx, fs_container_prefix, sizeof(fs_container_prefix)); /* Delete container 1 (if any) so that 0 is the only one. */ cc32xx_vfs_dev_slfs_container_delete_container(fs_container_prefix, 1); cc32xx_vfs_dev_slfs_container_fname(fs_container_prefix, 0, (_u8 *) ctx->fs_container_file); fname = ctx->fs_container_file; if (fi->size > ctx->fs_size) { /* Assume meta has already been added. */ falloc = fi->size; } else { falloc = FS_CONTAINER_SIZE(fi->size); } } else { ctx->status_msg = "Missing FS parameters"; ret = MGOS_UPDATER_ABORT; } } if (fname != NULL) { int r = prepare_to_write(ctx, fi, fname, falloc, &ctx->cur_part); if (r < 0) { LOG(LL_ERROR, ("err = %d", r)); ret = MGOS_UPDATER_ABORT; } else { ret = (r > 0 ? MGOS_UPDATER_PROCESS_FILE : MGOS_UPDATER_SKIP_FILE); } } if (ret == MGOS_UPDATER_SKIP_FILE) { DBG(("Skipping %s %.*s", fi->name, (int) part_name.len, part_name.p)); } return ret; } int mgos_upd_file_data(struct mgos_upd_hal_ctx *ctx, const struct mgos_upd_file_info *fi, struct mg_str data) { _i32 r = sl_FsWrite(ctx->cur_fh, fi->processed, (_u8 *) data.p, data.len); if (r != data.len) { ctx->status_msg = "Write failed"; r = -1; } return r; }
static void handle_update_req(struct clubby_event *evt, void *user_data) { char *zip_url; struct json_token section = JSON_INVALID_TOKEN; struct json_token blob_url = JSON_INVALID_TOKEN; struct json_token args = evt->request.args; (void) user_data; LOG(LL_DEBUG, ("Update request received: %.*s", evt->request.args.len, evt->request.args.ptr)); const char *reply = "Malformed request"; if (evt->request.args.type != JSON_TYPE_OBJECT) { goto bad_request; } json_scanf(args.ptr, args.len, "{section: %T, blob_url: %T}", §ion, &blob_url); /* * TODO(alashkin): enable update for another files, not * firmware only */ if (section.len == 0 || section.type != JSON_TYPE_STRING || strncmp(section.ptr, "firmware", section.len) != 0 || blob_url.len == 0 || blob_url.type != JSON_TYPE_STRING) { goto bad_request; } LOG(LL_DEBUG, ("zip url: %.*s", blob_url.len, blob_url.ptr)); sj_clubby_free_reply(s_clubby_reply); s_clubby_reply = sj_clubby_create_reply(evt); /* * If user setup callback for updater, just call it. * User can start update with Sys.updater.start() */ zip_url = calloc(1, blob_url.len + 1); if (zip_url == NULL) { CONSOLE_LOG(LL_ERROR, ("Out of memory")); return; } memcpy(zip_url, blob_url.ptr, blob_url.len); if (!notify_js(UJS_GOT_REQUEST, zip_url)) { struct update_context *ctx = updater_context_create(); if (ctx == NULL) { reply = "Failed to init updater"; } else if (start_update_download(ctx, zip_url) < 0) { reply = ctx->status_msg; } } free(zip_url); return; bad_request: CONSOLE_LOG(LL_ERROR, ("Failed to start update: %s", reply)); sj_clubby_send_status_resp(evt, 1, reply); }