From f33c58bd6ad8861e628ee00c97b76451758ef966 Mon Sep 17 00:00:00 2001 From: Antoni Adaszkiewicz Date: Thu, 27 Oct 2022 16:51:16 +0200 Subject: [PATCH] Add delta-verifier, a binary which will allow us to check delta-device compatibility both for update-manager and upgrade-trigger.sh (in upgrade-tools) Change-Id: I4f58c3380d8875240794ef839f1d8caca4538c33 --- CMakeLists.txt | 1 + delta-verifier/CMakeLists.txt | 22 +++ delta-verifier/delta-verifier.c | 337 ++++++++++++++++++++++++++++++++ delta-verifier/delta-verifier.h | 41 ++++ packaging/update-control.spec | 1 + 5 files changed, 402 insertions(+) create mode 100644 delta-verifier/CMakeLists.txt create mode 100644 delta-verifier/delta-verifier.c create mode 100644 delta-verifier/delta-verifier.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 934b817..32b0b07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,3 +70,4 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTAL ADD_SUBDIRECTORY(src/plugin) ADD_SUBDIRECTORY(update-manager) +ADD_SUBDIRECTORY(delta-verifier) diff --git a/delta-verifier/CMakeLists.txt b/delta-verifier/CMakeLists.txt new file mode 100644 index 0000000..1d60153 --- /dev/null +++ b/delta-verifier/CMakeLists.txt @@ -0,0 +1,22 @@ +ADD_DEFINITIONS("-DDEBUG") + +SET(SRCS + delta-verifier.c +) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${PROJECT_NAME}_pkgs REQUIRED capi-system-info) + +FOREACH(flag ${${PROJECT_NAME}_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -I./include") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") + +SET(EXECNAME "delta-verifier") +ADD_EXECUTABLE(${EXECNAME} ${SRCS}) + +TARGET_LINK_LIBRARIES(${EXECNAME} PRIVATE ${${PROJECT_NAME}_pkgs_LDFLAGS} "-g" "-pthread") +INSTALL(TARGETS ${EXECNAME} DESTINATION bin) diff --git a/delta-verifier/delta-verifier.c b/delta-verifier/delta-verifier.c new file mode 100644 index 0000000..1fe459c --- /dev/null +++ b/delta-verifier/delta-verifier.c @@ -0,0 +1,337 @@ +/* + +Copyright © 2022 Samsung Electronics Co., Ltd.. All rights reserved. + +Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute +this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear +in all copies of this software. + +IN NO EVENT SHALL SAMSUNG ELECTRONICS CO., LTD. BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF SAMSUNG ELECTRONICS CO., LTD. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +SAMSUNG ELECTRONICS CO., LTD. SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND SAMSUNG ELECTRONICS CO., LTD. HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*/ + + + +#include +#include +#include +#include +#include +#include +#include + +#include "delta-verifier.h" + +static void print_usage(const char* msg) +{ + if (msg) + printf("%s\n", msg); + + printf("\n\tprint_usage: --update_info_path filepath\n" + "\t\tfilepath -> filepath to update_info.ini file extracted from delta\n"); +} + +static int get_update_info_path(int argc, char** argv, char** dest) +{ + *dest = NULL; + if (argc != 3) { + print_usage("Invalid parameter count"); + return -1; + } + const struct option long_options[] = { + {"update_info_path", required_argument, NULL, 0}, + {0} + }; + while (1) { + int option = getopt_long(argc, argv, "", long_options, NULL); + if (option < 0) + break; + switch (option) { + case 0: + if (*dest != NULL) { + print_usage("Parameters repeated"); + free(*dest); + return -1; + } + *dest = strdup(optarg); + if (*dest == NULL) { + ERR_ERRNO("strdup()"); + return -1; + } + break; + default: + print_usage("Invalid parameters"); + if (*dest) + free(*dest); + return -1; + } + } + if (*dest == NULL) { + print_usage("Wrong parameters"); + return -1; + } + + return 0; +} + +static int write_variable_data_with_format(FILE* write_file, const char* var_name, char* var_value) +{ + char tmp[MAX_STRING]; + snprintf(tmp, MAX_STRING, "%s=%s\n", var_name, var_value); + if (fwrite(tmp, 1, strlen(tmp), write_file) != strlen(tmp)) { + ERR("fwrite() not successful"); + return -1; + } + return 0; +} + +static int write_info_from_api(FILE* write_file) +{ + const char* var_names[NO_OF_API_VARIABLES] = { + "model_name", + "manufacturer", + "device_type" + }; + + for (int i = 0; i < NO_OF_API_VARIABLES; i++) { + char* info; + char tmp_name[MAX_STRING]; + snprintf(tmp_name , MAX_STRING, "%s/%s", API_SYSTRM_PREFIX, var_names[i]); + if (system_info_get_platform_string(tmp_name, &info) < 0) { + ERR("system_info_get_platform_string() fail."); + return -1; + } + + if (write_variable_data_with_format(write_file, var_names[i], info)) { + free(info); + return -1; + } + + free(info); + } + return 0; +} + +static size_t get_file_size(FILE* file) +{ + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, 0 , SEEK_SET); + + return size; +} + +static int write_info_from_file(FILE* read_file, FILE* write_file) +{ + const char* var_names[NO_OF_CONFIG_VARIABLES] = { + "RELEASE_NAME", + "ARCH", + "DATE" + }; + + char full_var_names[NO_OF_CONFIG_VARIABLES][MAX_STRING]; + for (int i = 0; i < NO_OF_CONFIG_VARIABLES; i++) { + snprintf(full_var_names[i], MAX_STRING, "%s%s", TIZEN_BUILD_PREFIX, var_names[i]); + } + + size_t read_size = get_file_size(read_file); + char* read_buf = (char*)malloc(read_size); + if (read_buf == NULL) { + ERR_ERRNO("malloc()"); + return -1; + } + + if (fread(read_buf, 1, read_size, read_file) != read_size) { + ERR("fread() not successful"); + free(read_buf); + return -1; + } + + const char* separators = " =\n\""; + char* read_word = strtok(read_buf, separators); + int loop_iter = 0; + int processed = 0; + + while(read_word != NULL) { + if (processed == NO_OF_CONFIG_VARIABLES) + break; + + loop_iter++; + if (loop_iter % 2 == 1) { + for (int i = 0; i < NO_OF_API_VARIABLES; i++) { + if (strcmp(full_var_names[i], read_word) == 0) + { + processed++; + loop_iter++; + read_word = strtok(NULL, separators); + + char lowercase_name[MAX_STRING]; + strcpy(lowercase_name, full_var_names[i]); + for (int j = 0; j < strlen(lowercase_name); j++) + lowercase_name[j] = tolower(lowercase_name[j]); + + char to_write[MAX_STRING]; + if (snprintf(to_write, MAX_STRING, "%s=%s\n", lowercase_name, read_word) < 0) { + ERR_ERRNO("snprintf()"); + return -1; + } + + if (fwrite(to_write, 1, strlen(to_write), write_file) != strlen(to_write)) { + free(read_buf); + return -1; + } + break; + } + } + } + read_word = strtok(NULL, separators); + } + + free(read_buf); + return 0; +} + +int compare_info_files(FILE* update_info_file, FILE* device_info_file) +{ + size_t update_info_size, device_info_size; + update_info_size = get_file_size(update_info_file); + device_info_size = get_file_size(device_info_file); + + if (device_info_size != update_info_size) + return 1; + + int ret = 0; + char* device_read_buf = NULL; + char* update_read_buf = NULL; + + update_read_buf = (char*)malloc(update_info_size + 1); + if (update_read_buf == NULL) { + ERR_ERRNO("malloc()"); + ret = -1; + goto cleanup; + } + + device_read_buf = (char*)malloc(device_info_size + 1); + if (device_read_buf == NULL) { + ERR_ERRNO("malloc()"); + ret = -1; + goto cleanup; + } + + if (fread(update_read_buf, 1, update_info_size, update_info_file) != update_info_size) { + ERR("fread() not successful"); + ret = -1; + goto cleanup; + } + update_read_buf[update_info_size] = '\0'; + + if (fread(device_read_buf, 1, device_info_size, device_info_file) != device_info_size) { + ERR("fread() not successful"); + ret = -1; + goto cleanup; + } + device_read_buf[device_info_size] = '\0'; + + if (strcmp(update_read_buf, device_read_buf) != 0) { + ret = 1; + } + +cleanup: + if (update_read_buf) + free(update_read_buf); + if (device_read_buf) + free(device_read_buf); + return ret; +} + +int verify_delta_device_compatability(char* update_info_file_path) +{ + int ret = 0; + FILE* update_original = NULL, * tizen_build_conf = NULL, * device_info = NULL; + + if ((update_original = fopen(update_info_file_path, "r")) == NULL) { + ERR_ERRNO("fopen()"); + ret = -1; + goto cleanup; + } + + if ((device_info = fopen(DEVICE_INFO_PATH, "r")) == NULL) { + if ((device_info = fopen(DEVICE_INFO_PATH, "w+")) == NULL) { + ERR_ERRNO("fopen()"); + ret = -1; + goto cleanup; + } + + if ((tizen_build_conf = fopen(TIZEN_BUILD_CONFIG_PATH, "r")) == NULL) { + ERR_ERRNO("fopen()"); + ret = -1; + goto cleanup; + } + + if (write_info_from_api(device_info) < 0) { + ERR("write_info_from_api()"); + ret = -1; + goto cleanup; + } + + if (write_info_from_file(tizen_build_conf, device_info) < 0) { + ERR("write_info_from_api()"); + ret = -1; + goto cleanup; + } + } + + int comparison_result; + if ((comparison_result = compare_info_files(update_original, device_info)) < 0) { + ERR("compare_info_file()"); + ret = -1; + goto cleanup; + } else if (comparison_result == 0) { + // delete device info only if successful + fclose(device_info); + device_info = NULL; + unlink(DEVICE_INFO_PATH); + ret = 0; + } else { + ret = 1; + } + +cleanup: + if (update_original != NULL) + fclose(update_original); + + if (tizen_build_conf != NULL) + fclose(tizen_build_conf); + + if (device_info != NULL) + fclose(device_info); + + return ret; +} + +int main(int argc, char** argv) +{ + char* update_info_path; + if (get_update_info_path(argc, argv, &update_info_path) < 0) { + ERR("Parameter verification failed."); + return -1; + } + + int ret = verify_delta_device_compatability(update_info_path); + + free(update_info_path); + + if (ret < 0) + ERR("Delta verification failed due to an unexpected error."); + else if (ret == 0) + printf("Delta is compatible with this device\n"); + else + printf("Delta is not compatible with this device\n"); + + return ret; +} \ No newline at end of file diff --git a/delta-verifier/delta-verifier.h b/delta-verifier/delta-verifier.h new file mode 100644 index 0000000..a32222a --- /dev/null +++ b/delta-verifier/delta-verifier.h @@ -0,0 +1,41 @@ +/* + +Copyright © 2022 Samsung Electronics Co., Ltd.. All rights reserved. + +Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute +this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear +in all copies of this software. + +IN NO EVENT SHALL SAMSUNG ELECTRONICS CO., LTD. BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF SAMSUNG ELECTRONICS CO., LTD. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +SAMSUNG ELECTRONICS CO., LTD. SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND SAMSUNG ELECTRONICS CO., LTD. HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*/ + + + +#pragma once + +#ifdef DEBUG +#define ERR_ERRNO(source) (perror(source),\ + fprintf(stderr,"%s:%d\n",__FILE__,__LINE__)) +#define ERR(source) fprintf(stderr,"[%s:%d] %s\n",__FILE__,__LINE__, source) +#else +#define ERR_ERRNO(source) do {} while(0) +#define ERR(source) do {} while(0) +#endif + +#define TIZEN_BUILD_CONFIG_PATH "/etc/tizen-build.conf" +#define TMP_DIR "/tmp/" +#define DEVICE_INFO_PATH TMP_DIR "device-info.ini" + +#define API_TIZEN_PREFIX "http://tizen.org" +#define API_SYSTRM_PREFIX API_TIZEN_PREFIX "/system" +#define TIZEN_BUILD_PREFIX "TZ_BUILD_" + +#define NO_OF_API_VARIABLES 3 +#define NO_OF_CONFIG_VARIABLES 3 +#define MAX_STRING 100 \ No newline at end of file diff --git a/packaging/update-control.spec b/packaging/update-control.spec index 8f6f945..902d278 100644 --- a/packaging/update-control.spec +++ b/packaging/update-control.spec @@ -95,6 +95,7 @@ ln -s ../%{service_file} %{buildroot}/%{_unitdir}/multi-user.target.wants/%{serv %files daemon %{_bindir}/update-manager +%{_bindir}/delta-verifier %{dbus_conf_directory}/%{dbus_conf_file} %{_unitdir}/%{service_file} %{_unitdir}/multi-user.target.wants/%{service_file} -- 2.34.1