From: Antoni Date: Thu, 4 Apr 2024 11:23:09 +0000 (+0200) Subject: Report upgrade progress for DELTA_IMAGE type deltas X-Git-Tag: accepted/tizen/unified/20240606.161520~2^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bdc9a0ecc14f272343371c42b734328c8565a000;p=platform%2Fcore%2Fsystem%2Fupgrade.git Report upgrade progress for DELTA_IMAGE type deltas This requires a new file (update-progress-info.ini) in archive. Change-Id: I8108bb69a1fd0e2bb41548c1003218f99df6b829 --- diff --git a/scripts/upgrade-support/upgrade-common.inc b/scripts/upgrade-support/upgrade-common.inc index 5b1455e..3b304b8 100644 --- a/scripts/upgrade-support/upgrade-common.inc +++ b/scripts/upgrade-support/upgrade-common.inc @@ -83,6 +83,19 @@ retrap() { trap 'echo "Aborting due to errexit on ${0##*/}:$LINENO. Exit code: $?" >&2' ERR } +check_if_file_in_archive() { + ARCHIVE_NAME="$1" + FILE_NAME="$2" + local RET=0 + tar tf "${ARCHIVE_NAME}" "${FILE_NAME}" >/dev/null 2>&1 || RET=$? + + if [ $RET -eq 0 ]; then + return $TRUE + else + return $FALSE + fi +} + verify_file_internal() { FILE_NAME="$1" FILE_PATH="$FOTA_DIR/$FILE_NAME" @@ -399,6 +412,14 @@ upgrade_images() { declare "LABEL_MAP_${LABEL}=${PARTLABEL}" done < <(sed -e '/^#/d' -e '/^$/d' "${LABEL_MAP_PATH}/${HAL_PART_MAP_FILE}") + local PROGRESS_INFO_FILE_PATH="$2" + local PROGRESS_INFO_FILE_ARG + if [ -n "$PROGRESS_INFO_FILE_PATH" ]; then + PROGRESS_INFO_FILE_ARG="--progress-info-file $PROGRESS_INFO_FILE_PATH" + else + PROGRESS_INFO_FILE_ARG="" + fi + # _OFFSET _SIZE _HASH1 _HASH2 while read -r LABEL_NAME DELTA_NAME TYPE DEV OFFSET OLD_SIZE NEW_SIZE OLD_SHA NEW_SHA do @@ -458,7 +479,8 @@ upgrade_images() { `"--kind ss_brotli_patch "` `"--patch-orig $CURR_PARTITION "` `"--no-write-all "` - `"--dest-sha1 $NEW_SHA" + `"--dest-sha1 $NEW_SHA "` + `"$PROGRESS_INFO_FILE_ARG" UP_RES=$? ;; DELTA_FS) diff --git a/scripts/upgrade-support/upgrade-partial.sh b/scripts/upgrade-support/upgrade-partial.sh index 1b3d2d0..22826a9 100755 --- a/scripts/upgrade-support/upgrade-partial.sh +++ b/scripts/upgrade-support/upgrade-partial.sh @@ -44,11 +44,20 @@ prepare_fota_update_dir check_ab_partition_scheme check_used_block_device check_args "$@" + unpack_file "$DELTA_TAR" "upgrade-apply" /bin/chmod +x "$FOTA_DIR/upgrade-apply" unpack_file "$DELTA_TAR" "upgrade-apply-deltafs" /bin/chmod +x "$FOTA_DIR/upgrade-apply-deltafs" -if ! upgrade_images "$DELTA_TAR"; then + +if check_if_file_in_archive "$DELTA_TAR" "update-progress-info.ini"; then + unpack_file "$DELTA_TAR" "update-progress-info.ini" + PROGRESS_INFO_FILE_PATH="$FOTA_DIR/update-progress-info.ini" +else + PROGRESS_INFO_FILE_PATH="" +fi + +if ! upgrade_images "$DELTA_TAR" "$PROGRESS_INFO_FILE_PATH"; then critical_log "[Error] Unable to upgrade_images" cleanup exit_error diff --git a/src/upgrade-apply/main.c b/src/upgrade-apply/main.c index d8fbe9b..343e4bc 100644 --- a/src/upgrade-apply/main.c +++ b/src/upgrade-apply/main.c @@ -58,6 +58,7 @@ struct parse_result { PARSE_REPEATED_ARGUMENT, PARSE_MISSING_ARGUMENT, PARSE_PATCH_MISTAKE, + PARSE_PROGRESS_BAD_KIND, PARSE_BAD_KIND, PARSE_BAD_SIZE, PARSE_NO_PARSE, @@ -68,6 +69,7 @@ struct parse_result { const char *archive_file; const char *patch_orig; const char *dest_sha1; + const char *progress_info_file; size_t dest_size; bool write_all; enum archive_kind kind; @@ -80,6 +82,7 @@ struct parse_result parse_args(int argc, char **argv) const char *archive_file = NULL; const char *patch_orig = NULL; const char *dest_sha1 = NULL; + const char *progress_info_file = NULL; long long int dest_size = 0; enum archive_kind kind = -1; bool help = false; @@ -87,15 +90,16 @@ struct parse_result parse_args(int argc, char **argv) for (;;) { const struct option long_options[] = { - {"archive", required_argument, NULL, 0 }, - {"dest", required_argument, NULL, 1 }, - {"archive-file", required_argument, NULL, 2 }, - {"kind", required_argument, NULL, 3 }, - {"patch-orig", required_argument, NULL, 4 }, - {"dest-sha1", required_argument, NULL, 5 }, - {"dest-size", required_argument, NULL, 6 }, - {"no-write-all", no_argument, NULL, 'n'}, - {"help", no_argument, NULL, 'h'}, + {"archive", required_argument, NULL, 0 }, + {"dest", required_argument, NULL, 1 }, + {"archive-file", required_argument, NULL, 2 }, + {"kind", required_argument, NULL, 3 }, + {"patch-orig", required_argument, NULL, 4 }, + {"dest-sha1", required_argument, NULL, 5 }, + {"dest-size", required_argument, NULL, 6 }, + {"progress-info-file", required_argument, NULL, 7 }, + {"no-write-all", no_argument, NULL, 'n'}, + {"help", no_argument, NULL, 'h'}, {0} }; int option = getopt_long(argc, argv, "hn", long_options, NULL); @@ -152,6 +156,12 @@ struct parse_result parse_args(int argc, char **argv) return (struct parse_result) { .result = PARSE_BAD_SIZE }; break; + case 7: // progress-info-file + if (progress_info_file != NULL) + return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT }; + progress_info_file = optarg; + break; + case 'n': // no-write-all if (!write_all) return (struct parse_result) { .result = PARSE_REPEATED_ARGUMENT }; @@ -189,6 +199,9 @@ struct parse_result parse_args(int argc, char **argv) if (patch_orig != NULL && kind == KIND_RAW) return (struct parse_result) { .result = PARSE_PATCH_MISTAKE }; + if (progress_info_file != NULL && kind == KIND_RAW) + return (struct parse_result) { .result = PARSE_PROGRESS_BAD_KIND }; + return (struct parse_result) { .result = PARSE_OK, .archive = archive, @@ -197,6 +210,7 @@ struct parse_result parse_args(int argc, char **argv) .patch_orig = patch_orig, .dest_sha1 = dest_sha1, .dest_size = dest_size, + .progress_info_file = progress_info_file, .kind = kind, .write_all = write_all, }; @@ -259,7 +273,8 @@ ssize_t gzip_write(__attribute__((unused)) int useless_fd, __attribute__((unused void help(char *name) { fprintf(stderr, - "Usage: %s --archive ARCHIVE --archive-file FILE --dest DESTINATION --kind KIND [--patch-orig ORIGIN] [--dest-sha1 SHA1] [--dest-size SIZE] [--no-write-all]\n" + "Usage: %s --archive ARCHIVE --archive-file FILE --dest DESTINATION --kind KIND \ + [--patch-orig ORIGIN] [--dest-sha1 SHA1] [--dest-size SIZE] [--no-write-all] [--progress-info-file FILE]\n" "\n" "Patches a partition using an archive.\n" "It will look for a file named FILE in an archive called ARCHIVE; the archive should have an extension\n" @@ -273,7 +288,8 @@ void help(char *name) "Additionally, if SIZE is provided, it is used as the destination size; this matters for SHA1 comparision,\n" "and also if ss_brotli_patch.\n" "In case the KIND is ss_brotli_path and the DESTINATION is the clone of the ORIGIN you can specify\n" - "the --no-write-all flag to not copy the data from the source, because it is already there.\n", + "the --no-write-all flag to not copy the data from the source, because it is already there.\n" + "Progress info file can be provided for deltas using ss_brotli_patch to report upgrade progress. The file contains block count of the delta.\n", name); } @@ -380,6 +396,79 @@ while_done:; return 0; } +int get_block_count_from_progress_file(const char* progress_info_file, const char *archive_file, uint64_t *block_count) +{ + const char *separators = " =\n"; + FILE *fp = NULL; + char *buf = NULL; + int ret = 0; + + fp = fopen(progress_info_file, "r"); + if (fp == NULL) { + fprintf(stderr, "Failed to open %s\n", progress_info_file); + return -1; + } + + fseek(fp, 0, SEEK_END); + off_t file_size = ftello(fp); + if (file_size == -1) { + fprintf(stderr, "Failed to check size of %s\n", progress_info_file); + ret = -1; + goto cleanup; + } + fseek(fp, 0 , SEEK_SET); + + buf = (char *)malloc(file_size + 1); + if (buf == NULL) { + fprintf(stderr, "Malloc error\n"); + ret = -1; + goto cleanup; + } + + if (fread(buf, 1, file_size, fp) != file_size) { + fprintf(stderr, "Failed to read %s\n", progress_info_file); + ret = -1; + goto cleanup; + } + + buf[file_size] = '\0'; + int iter = 0; + char *saveptr; + char *read_word = strtok_r(buf, separators, &saveptr); + + while (read_word) { + if (iter % 2 == 0) { + if (strcmp(read_word, archive_file) == 0) { + read_word = strtok_r(NULL, separators, &saveptr); + + if (read_word == NULL) { + fprintf(stderr, "%s file is not compatible - value missing\n", progress_info_file); + ret = -1; + } else { + *block_count = (uint64_t) atoi(read_word); + fprintf(stderr, "Block count for %s: %ld\n", archive_file, *block_count); + ret = 0; + } + + goto cleanup; + } + } + iter++; + read_word = strtok_r(NULL, separators, &saveptr); + } + + fprintf(stderr, "Block count for %s was not found in %s\n", archive_file, progress_info_file); + ret = -1; + +cleanup: + if (fp != NULL) + fclose(fp); + if (buf != NULL) + free(buf); + + return ret; +} + int main(int argc, char **argv) { struct parse_result parsed = parse_args(argc, argv); @@ -396,6 +485,10 @@ int main(int argc, char **argv) fprintf(stderr, "`patch-orig` parameter doesn't fit the kind\n"); help(argv[0]); return EXIT_FAILURE; + case PARSE_PROGRESS_BAD_KIND: + fprintf(stderr, "`progress-info-file` parameter is only supported for ss_brotli_patch\n"); + help(argv[0]); + return EXIT_FAILURE; case PARSE_BAD_KIND: fprintf(stderr, "Invalid `kind` parameter (possible: `raw`, `ss_brotli_patch`)\n"); help(argv[0]); @@ -485,8 +578,21 @@ int main(int argc, char **argv) case KIND_BROTLI_PATCH: { + uint64_t block_count; + uint64_t *block_count_ptr = &block_count; + if (parsed.progress_info_file != NULL) { + if (get_block_count_from_progress_file(parsed.progress_info_file, + parsed.archive_file, block_count_ptr) != 0) { + fprintf(stderr, "Failed to get block count for %s\n", parsed.archive_file); + return EXIT_FAILURE; + } + } else { + block_count_ptr = NULL; + } + struct dec_funcs funcs = { init_brotli, decompress_brotli, free_brotli }; - r = apply_patch(parsed.patch_orig, parsed.dest, tar, parsed.dest_size, NULL, parsed.write_all, &funcs); + r = apply_patch(parsed.patch_orig, parsed.dest, tar, parsed.dest_size, NULL, + parsed.write_all, &funcs, block_count_ptr); break; } } diff --git a/src/upgrade-apply/patch/patch.c b/src/upgrade-apply/patch/patch.c index 909007c..9fac82a 100644 --- a/src/upgrade-apply/patch/patch.c +++ b/src/upgrade-apply/patch/patch.c @@ -42,6 +42,8 @@ #define SSINT_LEN 8 #define BLOCK_COUNT_REPORT 5000 +#define PROGRESS_REPORT_FREQUENCY 300 + const char SSDIFF_MAGIC[] = "SSDIFF40"; static void free_data(struct bs_data *data, struct dec_funcs *funcs) @@ -342,7 +344,8 @@ int read_header(struct dec_funcs *funcs, struct bs_data *data, uint8_t **buff_ou return PF_OK; } -int apply_patch(const char *source_file, const char *dest_file, TAR *patch_tar, size_t dest_size, size_t *free_space, bool write_all, struct dec_funcs *funcs) +int apply_patch(const char *source_file, const char *dest_file, TAR *patch_tar, size_t dest_size, + size_t *free_space, bool write_all, struct dec_funcs *funcs, uint64_t *block_count) { assert(source_file); assert(dest_file); @@ -374,6 +377,15 @@ int apply_patch(const char *source_file, const char *dest_file, TAR *patch_tar, if ((res = remmap(&data.dest, 0)) != PF_OK) return res; + uint64_t progress_report_block_count = 0; + if (block_count != NULL) { + if (*block_count < PROGRESS_REPORT_FREQUENCY) { + progress_report_block_count = *block_count; + } else { + progress_report_block_count = *block_count / PROGRESS_REPORT_FREQUENCY; + } + } + uint64_t total_write = 0; while (total_write < data.dest.len) { @@ -457,11 +469,23 @@ int apply_patch(const char *source_file, const char *dest_file, TAR *patch_tar, total_write += write; blocks++; - if (blocks % BLOCK_COUNT_REPORT == 0) { - fprintf(stderr, "Number of processed patch blocks: %"PRIu64"\n", blocks); + + if (block_count != NULL) { + if (blocks % progress_report_block_count == 0) { + fprintf(stderr, "\rUpgrade progress: %.2f%%", (double) blocks / *block_count * 100); + fflush(stderr); + } + } else { + if (blocks % BLOCK_COUNT_REPORT == 0) { + fprintf(stderr, "Number of processed patch blocks: %"PRIu64"\n", blocks); + } } } + if (block_count != NULL) { + fprintf(stderr, "\rUpgrade progress: 100.00%%\n"); + } + result = PF_OK; exit: diff --git a/src/upgrade-apply/patch/patch.h b/src/upgrade-apply/patch/patch.h index 476e025..34ef2bd 100644 --- a/src/upgrade-apply/patch/patch.h +++ b/src/upgrade-apply/patch/patch.h @@ -66,4 +66,5 @@ struct dec_funcs { void (*clean)(struct bs_data *data); }; -extern int apply_patch(const char *source_file, const char *dest_file, TAR *patch_tar, size_t dest_size, size_t *free_space, bool write_all, struct dec_funcs *funcs); +extern int apply_patch(const char *source_file, const char *dest_file, TAR *patch_tar, size_t dest_size, + size_t *free_space, bool write_all, struct dec_funcs *funcs, uint64_t *block_count); diff --git a/src/upgrade-apply/patch/patch_helper.c b/src/upgrade-apply/patch/patch_helper.c index d71d454..f146b2e 100644 --- a/src/upgrade-apply/patch/patch_helper.c +++ b/src/upgrade-apply/patch/patch_helper.c @@ -21,5 +21,5 @@ int apply_patch_brotli(const char *source_file, const char *dest_file, TAR *patch_tar, size_t dest_size, size_t *free_space, bool write_all) { struct dec_funcs funcs = { init_brotli, decompress_brotli, free_brotli }; - return apply_patch(source_file, dest_file, patch_tar, dest_size, free_space, write_all, &funcs); + return apply_patch(source_file, dest_file, patch_tar, dest_size, free_space, write_all, &funcs, NULL); }