Support ro update during normal boot in delta.ua: 31/265631/15 accepted/tizen/unified/20211203.125407 submit/tizen/20211130.134324 submit/tizen/20211202.130243
authorErnest Borowski <e.borowski@samsung.com>
Mon, 25 Oct 2021 16:19:35 +0000 (16:19 +0000)
committerErnest Borowski <e.borowski@samsung.com>
Mon, 29 Nov 2021 17:01:46 +0000 (17:01 +0000)
1. Allow to use GPT partition labels rather than hardcoded partitions.
2. Allow to use specified block device rather than hardcoded one.
3. Add usage function.
4. Add function that translates errors into usable form for end user.
5. Add support for a|b slot partition scheme.
6. Fix bug when logging file was not opened before usage.
7. Change log file path from /last_update.log to
   /opt/data/update/last_update.log
8. Do not disable stdout && stderr

Add blkid-print application that is used to determine partition name
based on GPT LABEL.

Change-Id: Ifbc5aaa435791d4de91a896b5b34b874cb46fe8d
Signed-off-by: Ernest Borowski <e.borowski@samsung.com>
CMakeLists.txt
packaging/tota-ua.spec
src/blkid-api.c [new file with mode: 0644]
src/blkid-api.h [new file with mode: 0644]
src/blkid-print.c [new file with mode: 0644]
src/ua.c
src/ua.h

index 4e3de87..d669ab8 100755 (executable)
@@ -1,3 +1,21 @@
+#
+# tota-ua
+#
+# Copyright (c) 2021 Samsung Electronics Co., Ltd.
+#
+# Licensed 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.
+#
+
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 PROJECT(fota C)
 
@@ -8,8 +26,12 @@ SET(SRCS
        src/fota_util.c
        src/mmc_io.c
        src/ua.c
+       src/blkid-api.c
 )
 
+SET(BLKIDSRCS
+       src/blkid-print.c)
+
 STRING(FIND ${CMAKE_C_FLAGS} "mfloat-abi=hard" IFFOUND1)
 STRING(FIND ${CMAKE_C_FLAGS} "mhard-float" IFFOUND2)
 
@@ -22,6 +44,7 @@ SET(BINDIR "${PREFIX}/bin")
 SET(PKGDIR "${PREFIX}/share/fota")
 SET(RESDIR "${PKGDIR}/res")
 SET(EXECNAME "delta.ua")
+SET(BLKIDEXENAME "blkid-print")
 
 IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
        SET(CMAKE_BUILD_TYPE "Release")
@@ -32,6 +55,11 @@ INCLUDE(FindPkgConfig)
 pkg_check_modules(pkgs REQUIRED
        tota
        openssl1.1
+       blkid
+)
+
+pkg_check_modules(blkid_pkgs REQUIRED
+       blkid
 )
 
 FOREACH(flag ${pkgs_CFLAGS})
@@ -66,5 +94,10 @@ TARGET_LINK_LIBRARIES(${EXECNAME} ${pkgs_LDFLAGS})
 
 INSTALL(TARGETS ${EXECNAME} DESTINATION ${BINDIR})
 
+ADD_EXECUTABLE(${BLKIDEXENAME} ${BLKIDSRCS})
+TARGET_LINK_LIBRARIES(${BLKIDEXENAME} ${blkid_pkgs_LDFLAGS})
+
+INSTALL(TARGETS ${BLKIDEXENAME} DESTINATION ${BINDIR})
+
 ADD_SUBDIRECTORY(dmverity)
 ADD_SUBDIRECTORY(img-verifier)
index 3e16e1b..f7982f0 100755 (executable)
@@ -82,3 +82,6 @@ mkdir -p %{buildroot}%{img_verifier_root_ca_dir}
 
 # DM verity handler
 %{_bindir}/verity_handler
+
+# blkid-print
+%{_bindir}/blkid-print
diff --git a/src/blkid-api.c b/src/blkid-api.c
new file mode 100644 (file)
index 0000000..73b5df6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * tota-ua
+ *
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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 "blkid-api.h"
+#include <stdio.h>
+#include <string.h>
+
+blkid_partlist get_part_list(char *device_name) {
+       blkid_probe pr = blkid_new_probe_from_filename(device_name);
+       if (pr == NULL)
+               return NULL;
+       blkid_partlist ls = blkid_probe_get_partitions(pr);
+       blkid_free_probe(pr);
+       return ls;
+}
+
+int get_part_number_by_name(blkid_partlist ls, const char *part_name, const char *new_slot) {
+       int nparts = blkid_partlist_numof_partitions(ls);
+       char part_name_with_slot[MAX_PARTNAME_LEN];
+       int found_part_n = -1;
+
+       if (snprintf(part_name_with_slot, MAX_PARTNAME_LEN, "%s_%s", part_name, new_slot) < 0) {
+               return -1;
+       }
+
+       for (int it = 0; it < nparts; ++it) {
+               blkid_partition part = blkid_partlist_get_partition(ls, it);
+               const char *p;
+
+               p = blkid_partition_get_name(part);
+               if (!p)
+                       continue;
+
+               if (found_part_n < 0 && strncmp(p, part_name, strlen(part_name)+1) == 0)
+                       found_part_n = it + 1;
+               else if (strncmp(p, part_name_with_slot, strlen(part_name_with_slot)+1) == 0)
+                       found_part_n = it + 1;
+       }
+       if (found_part_n >= 0)
+               return found_part_n;
+
+       // nothing found
+       return -1;
+}
+
diff --git a/src/blkid-api.h b/src/blkid-api.h
new file mode 100644 (file)
index 0000000..0a404f8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * tota-ua
+ *
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#pragma once
+#include <blkid/blkid.h>
+
+#ifndef MAX_PARTNAME_LEN
+#define MAX_PARTNAME_LEN 10000
+#endif
+blkid_partlist get_part_list(char *device_name);
+int get_part_number_by_name(blkid_partlist ls, const char *part_name, const char *new_slot);
diff --git a/src/blkid-print.c b/src/blkid-print.c
new file mode 100644 (file)
index 0000000..bbb3f98
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * tota-ua
+ *
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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 <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "blkid-api.h"
+
+void usage(const char* msg) {
+       if (msg) {
+               printf("%s\n", msg);
+       }
+       printf("USAGE: blkid-print device_name partition_label suffix\n"
+       "device_name: block device e.g. /dev/mmcblk0\n"
+       "partition_label: partiton label to search for e.g. rootfs,ramdisk etc.\n"
+       "suffix: a|b partiton slot\n");
+}
+
+blkid_partition partition_for(char *device_name, char *part_name, char *new_slot) {
+       char part_name_with_slot[MAX_PARTNAME_LEN];
+       int found_part_n = -1;
+       if (!device_name || !part_name || !new_slot){
+               printf("partition_for: one or more argument is NULL\n");
+               return NULL;
+       }
+       if (snprintf(part_name_with_slot, MAX_PARTNAME_LEN, "%s_%s", part_name, new_slot) < 0) {
+               return NULL;
+       }
+       blkid_probe pr = blkid_new_probe_from_filename(device_name);
+       if (pr == NULL) {
+               printf("ERROR: blkid error for %s\n", device_name);
+               usage(NULL);
+               return NULL;
+       }
+       blkid_partlist ls = blkid_probe_get_partitions(pr);
+       if (!ls) {
+               printf("ERROR: unable to probe partitions.\n");
+               blkid_free_probe(pr);
+               return NULL;
+       }
+       int nparts = blkid_partlist_numof_partitions(ls);
+       if (nparts == -1) {
+               printf("ERROR: unable to get partition count\n");
+               blkid_free_probe(pr);
+               return NULL;
+       }
+
+
+       for (int i = 0; i < nparts; i++) {
+               blkid_partition part = blkid_partlist_get_partition(ls, i);
+               const char *p;
+
+               p = blkid_partition_get_name(part);
+               if (!p)
+                       continue;
+
+               if (found_part_n < 0 && strncmp(p, part_name, strlen(part_name)+1) == 0)
+                       found_part_n = i;
+               else if (strncmp(p, part_name_with_slot, strlen(part_name_with_slot)+1) == 0)
+                       found_part_n = i;
+       }
+
+       blkid_free_probe(pr);
+       if (found_part_n >= 0) {
+               blkid_partition par = blkid_partlist_get_partition(ls, found_part_n);
+               return par;
+       }
+       return NULL;
+}
+
+const char *get_part_label(blkid_partlist ls, int part_nr) {
+       blkid_partition part = blkid_partlist_get_partition(ls, part_nr);
+       return blkid_partition_get_name(part);
+}
+
+int main(int argc, char *argv[]) {
+       char device_name_path[PATH_MAX];
+       if (argc != 4) {
+               usage("Please specify correct argument number\n");
+               return 1;
+       }
+       char *device_name = realpath(argv[1], device_name_path);
+       if (!device_name) {
+               printf("ERROR: Unable to determine realpath for: %s\n", argv[1]);
+               usage(NULL);
+               return 1;
+       }
+       char *partition_label = argv[2];
+       char *suffix = argv[3];
+       blkid_partition part = partition_for(device_name, partition_label, suffix);
+       if (part == NULL) {
+               printf("ERROR: Partition '%s' not found.\n", partition_label);
+               usage(NULL);
+               return 2;
+       }
+       int part_nr = blkid_partition_get_partno(part);
+       if (part_nr < 0) {
+               printf("ERROR: Partition '%s' not found", partition_label);
+               return 3;
+       }
+       const char *part_label = blkid_partition_get_name(part);
+       char part_path[PATH_MAX];
+       // /dev/sda1 vs /dev/mmcblk0p1 /dev/nvme0n1p1
+       // no_separator vs "p" separator
+       if (strncmp("/dev/sd", device_name, strlen(device_name) + 1) == 0)
+               snprintf(part_path, PATH_MAX, "%s%d", device_name, part_nr);
+       else
+               snprintf(part_path, PATH_MAX, "%sp%d", device_name, part_nr);
+       printf("part_nr: %d (%s): %s\n", part_nr, part_label, part_path);
+               return 0;
+}
+
index d1412c9..557150b 100755 (executable)
--- a/src/ua.c
+++ b/src/ua.c
@@ -1,7 +1,7 @@
 /*
  * tota-ua
  *
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the License);
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -28,6 +30,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
+#include <blkid/blkid.h>
 
 #include "SS_Common.h"
 #include "fota_common.h"
@@ -38,6 +41,7 @@
 #include "fota_tar.h"
 #include "fota_util.h"
 #include "SS_UPI.h"
+#include "blkid-api.h"
 
 #define MAX_CFG_LEN    4096
 
@@ -45,6 +49,7 @@
 #define SYSTEM_LOG_DIR         "/opt/var/log"
 
 int ua_op_mode = UA_OP_MODE_FG;
+char ua_slot_mode = 0;
 int dm_verity_status = DM_VERITY_DISABLED;
 
 static char fota_result[MAX_FILE_PATH];
@@ -56,6 +61,7 @@ static char log_folder[MAX_FOLDER_PATH];
 static char result_folder[MAX_FOLDER_PATH];
 static char temp_folder[MAX_FOLDER_PATH];
 static char log_path[MAX_FILE_PATH];
+static char blk_dev_arg[MAX_FOLDER_PATH]="/dev/mmcblk0";
 
 static ua_part_info_t s_part_info[UA_PARTI_MAX];
 
@@ -79,6 +85,61 @@ static void save_cause(int cause);
 #define TMP_DIR "/tmp/upgrade"
 #define PROGRESS_FILE TMP_DIR "/ro_progress"
 
+void print_usage(const char *msg)
+{
+       if (msg) {
+               printf("%s\n", msg);
+       }
+       printf("USAGE: delta.ua delta_dir output_dir [operation_mode] [upgrade_slot block_device]\n"
+       "delta_dir: directory path where delta.tar file is located\n"
+       "output_dir: directory path for log file, result file, temporary file\n"
+       "operation_mode: run program in Background Mode: 0 or Foreground Mode: 1\n"
+       "upgrade_slot: upgrade slot number \"a\" or \"b\" It is used for A|B upgrade mode.\n"
+       "    When it is set delta.ua will not read hardcoded partitions from config file.\n"
+       "    Program will use libblkid to determine it based on GPT partition label.\n"
+       "    e.g. delta.ua will try to update rootfs from a slot, so it will search for rootfs_a label\n"
+       "    NOTE: if this argument is set block_device have to be specified.\n"
+       "block_device: block device that partitions for upgrade are on. e.g. /dev/mmcblk0\n"
+       "    NOTE: if this argument is set upgrade_slot have to be specified.\n"
+       );
+}
+
+void print_error_code(int err)
+{
+       char msg[]="delta.ua error:";
+       switch (err) {
+       case UPI_CONFIG_ERROR:
+               printf("%s config error.\n", msg);
+               break;
+       case UPI_DELTA_PATH_ERROR:
+               printf("%s delta path error.\n", msg);
+               break;
+       case UPI_DELTA_PATH_LENGTH_ERROR:
+               printf("%s delta path lenght error.\n", msg);
+               break;
+       case UPI_VERSION_ERROR:
+               printf("%s version error.\n", msg);
+               break;
+       case UPI_VERIFY_ERROR:
+               printf("%s verify error.\n", msg);
+               break;
+       case UPI_UPDATE_ERROR:
+               printf("%s update error.\n", msg);
+               break;
+       case UPI_INVALID_PARAM_ERROR:
+               printf("%s invalid parameter error.\n", msg);
+               break;
+       case UPI_DELTACOUNT_ERROR:
+               printf("%s delta count error.\n", msg);
+               break;
+       case UPI_PARTINFO_ERROR:
+               printf("%s partition information error.\n", msg);
+               break;
+       default:
+               printf("delta.ua unable to determine error code: %d\n", err);
+       }
+}
+
 void fota_gui_update_progress(int percent)
 {
        int ret;
@@ -949,19 +1010,43 @@ void fota_path_deinit(void)
  ----------------------------------------------------------------------------*/
 int check_ua_op_mode(int argc, char **argv)
 {
+       char blk_dev[PATH_MAX + 100];
+       ua_op_mode = -1;
+       ua_slot_mode=0;
        if (argc == 3) {
                ua_op_mode = UA_OP_MODE_FG;
-               return 0;
-       } else if (argc == 4) {
+       } else if (argc >= 4 && argc <= 6) {
                if (argv[3][0] == '0') {
                        ua_op_mode = UA_OP_MODE_FG;
-                       return 0;
                } else if (argv[3][0] == '1') {
                        ua_op_mode = UA_OP_MODE_BG;
-                       return 0;
+               }
+               if (argc == 6) {
+                       if (argv[4][0] == 'a') {
+                               ua_slot_mode='a';
+                       } else if (argv[4][0] == 'b') {
+                               ua_slot_mode='b';
+                       } else {
+                               ua_slot_mode=-1;
+                       }
+                       char *block_device = realpath(argv[5], blk_dev);
+                       if (!block_device) {
+                               snprintf(blk_dev, sizeof(blk_dev), "Unable to get realpath for: %s\n", argv[5]);
+                               print_usage(blk_dev);
+                               return -1;
+                       }
+                       // sizeof(blk_dev_arg) == PATH_MAX; PATH_MAX > MAX_FOLDER_PATH
+                       snprintf(blk_dev_arg, sizeof(blk_dev_arg), "%s", blk_dev);
+               }
+               else if (argc == 5) {
+                       print_usage("Unable to parse arguments, please specify upgrade_slot and block_device or none off them.\n");
+                       return -1;
                }
        }
+       if (ua_op_mode != -1 || ua_slot_mode == -1)
+               return 0;
 
+       print_usage("Unable to parse arguments.\n");
        return -1;
 }
 
@@ -1051,39 +1136,67 @@ int fota_blkid_update(void)
        int i, j;
        int id;
        char part_name[256];
-       char blk_name[256];
-
-       memset((void*)part_tbl_path, 0x00, sizeof(part_tbl_path));
-       snprintf(part_tbl_path, sizeof(part_tbl_path)-1, "%s/%s", temp_folder, PART_TBL_FILE);
-
-       fp = fopen(part_tbl_path, "r");
-       if (fp == NULL) {
-               LOG("fail to open partition table\n");
-               return -1;
-       }
+       char blk_name[PATH_MAX];
+       blkid_partlist pr = NULL;
+
+       // new mode: use libblkid rather than reading partitions from
+       // part_table configuration file.
+       if (ua_slot_mode == 'a' || ua_slot_mode == 'b') {
+               pr = get_part_list(blk_dev_arg);
+               if (!pr) {
+                       return -1;
+               }
+               for (j = 0; j < s_part_num; ++j) {
+                       memset((void*)blk_name, 0x00, sizeof(blk_name));
+                       id = get_part_number_by_name(pr, s_part_info[j].ua_parti_name, &ua_slot_mode);
+                       if (id == -1) {
+                               LOG("failed to get_part_number_by_name for: %s, slot: %c",
+                                               s_part_info[j].ua_parti_name, ua_slot_mode);
+                               return -1;
+                       }
+                       if (s_part_info[j].ua_blk_name) free(s_part_info[j].ua_blk_name);
+                       if (strncmp("/dev/sd", blk_dev_arg, strlen(blk_dev_arg) + 1) == 0)
+                               snprintf(blk_name, sizeof(blk_name)-1, "%s%d", blk_dev_arg, id);
+                       else
+                               snprintf(blk_name, sizeof(blk_name)-1, "%sp%d", blk_dev_arg, id);
+                       s_part_info[j].ua_blk_name = strdup(blk_name);
+               }
+       } else {
+       // legacy mode: get part numbers from file
+               memset((void*)part_tbl_path, 0x00, sizeof(part_tbl_path));
+               snprintf(part_tbl_path, sizeof(part_tbl_path)-1, "%s/%s", temp_folder,
+                               PART_TBL_FILE);
+
+               fp = fopen(part_tbl_path, "r");
+               if (fp == NULL) {
+                       LOG("fail to open partition table\n");
+                       return -1;
+               }
 
-       if ((fscanf(fp, "%d", &num_part) < 0) || (num_part <= 0) || (num_part >= MAX_PART_TBL_ITEM)) {
-               LOG("fail to fscanf() or num_part is 0\n");
-               fclose(fp);
-               return -1;
-       }
-       for (i = 0; i < num_part; i++) {
-               if (fscanf(fp, "%d %32s", &id, part_name) < 0) {
-                       LOG("fail to fscanf()\n");
-                       break;
+               if ((fscanf(fp, "%d", &num_part) < 0) || (num_part <= 0) ||
+                               (num_part >= MAX_PART_TBL_ITEM)) {
+                       LOG("fail to fscanf() or num_part is 0\n");
+                       fclose(fp);
+                       return -1;
                }
-               LOG("%s [%d]\n", part_name, id);
-               for (j = 0; j < s_part_num; j++) {
-                       if (strcmp(s_part_info[j].ua_parti_name, part_name) == 0) {
+               for (i = 0; i < num_part; i++) {
+                       if (fscanf(fp, "%d %32s", &id, part_name) < 0) {
+                               LOG("fail to fscanf()\n");
+                               break;
+                       }
+                       LOG("%s [%d]\n", part_name, id);
+                       for (j = 0; j < s_part_num; j++) {
                                memset((void*)blk_name, 0x00, sizeof(blk_name));
-                               snprintf(blk_name, sizeof(blk_name)-1, "/dev/mmcblk0p%d", id);
+                               if (strncmp("/dev/sd", blk_dev_arg, strlen(blk_dev_arg) + 1) == 0)
+                                       snprintf(blk_name, sizeof(blk_name)-1, "%s%d", blk_dev_arg, id);
+                               else
+                                       snprintf(blk_name, sizeof(blk_name)-1, "%sp%d", blk_dev_arg, id);
                                s_part_info[j].ua_blk_name = strdup(blk_name);
+                               }
                        }
-               }
+               fclose(fp);
        }
 
-       fclose(fp);
-
        return 0;
 }
 
@@ -1206,6 +1319,11 @@ int fota_configure_update(void)
   argv[1] : directory path for delta file
   argv[2] : directory path for log file, result file, temp file
   argv[3] : operation mode ("0" or none : Foreground Mode, "1" : Background Mode)
+  argv[4] : "a" or "b" upgrade slot number. This is optional parameter.
+  When it's set ua will not read hardcoded partitions numbers from config file.
+  Ua will use libblkid to determine it based on partition label e.g. rootfs_a which is rootfs from a slot.
+  argv[5]: path for blkid device e.g. /dev/mmcblk0
+
  ----------------------------------------------------------------------------*/
 int main(int argc, char **argv)
 {
@@ -1213,7 +1331,7 @@ int main(int argc, char **argv)
        int ret = FAIL;
        int i = 0;
 
-       _init_stdio();
+       log_init();
 
 #if defined(FEATURE_SUPPORT_CAPABILITY)
        SS_set_feature_support_capability(1);
@@ -1239,7 +1357,6 @@ int main(int argc, char **argv)
 
        snprintf(fota_result, sizeof(fota_result), "%s/%s", result_folder, "result");
 
-       log_init();
        fota_cfg_str_load();
 
        if (check_dm_verity_status() < 0) {
@@ -1296,6 +1413,8 @@ int main(int argc, char **argv)
        LOG("Result=%d\n", ret);
        save_result(ret);
        //remove_temp_files(); // TOTA
+       if (ret != SUCCESS)
+               print_error_code(ret);
 
        switch (ret) {
        /* Before initialize fota path */
index 696e0ee..a9cc34b 100755 (executable)
--- a/src/ua.h
+++ b/src/ua.h
@@ -29,7 +29,7 @@
 //#define USE_DELTA_DOWNLOAD
 //#define USE_DUALSBL
 
-#define LOG_FILE_PATH "/last_update.log"
+#define LOG_FILE_PATH "/opt/data/update/last_update.log"
 #define MAX_FILE_PATH           512
 #define MAX_FOLDER_PATH         384