--- /dev/null
+/*
+ * 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;
+}
+
/*
* 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>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
+#include <blkid/blkid.h>
#include "SS_Common.h"
#include "fota_common.h"
#include "fota_tar.h"
#include "fota_util.h"
#include "SS_UPI.h"
+#include "blkid-api.h"
#define MAX_CFG_LEN 4096
#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];
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];
#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;
----------------------------------------------------------------------------*/
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;
}
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;
}
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)
{
int ret = FAIL;
int i = 0;
- _init_stdio();
+ log_init();
#if defined(FEATURE_SUPPORT_CAPABILITY)
SS_set_feature_support_capability(1);
snprintf(fota_result, sizeof(fota_result), "%s/%s", result_folder, "result");
- log_init();
fota_cfg_str_load();
if (check_dm_verity_status() < 0) {
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 */