diff --git a/program.c b/program.c index ad8aa4e..41237b2 100644 --- a/program.c +++ b/program.c @@ -422,3 +422,42 @@ void free_programs(void) programes = NULL; } + +int program_cmd_add(const char *address, const char *filename) +{ + unsigned int start_sector; + unsigned int num_sectors; + struct program *program; + int partition; + char buf[20]; + int ret; + + ret = parse_storage_address(address, &partition, &start_sector, &num_sectors); + if (ret < 0) + return ret; + + program = calloc(1, sizeof(struct program)); + + program->sector_size = 0; + program->file_offset = 0; + program->filename = filename ? strdup(filename) : NULL; + program->label = filename ? strdup(filename) : NULL; + program->num_sectors = num_sectors; + program->partition = partition; + program->sparse = false; + sprintf(buf, "%u", start_sector); + program->start_sector = strdup(buf); + program->last_sector = 0; + program->is_nand = false; + program->is_erase = false; + + if (programes) { + programes_last->next = program; + programes_last = program; + } else { + programes = program; + programes_last = program; + } + + return 0; +} diff --git a/program.h b/program.h index 1e07888..b3e53c3 100644 --- a/program.h +++ b/program.h @@ -35,6 +35,7 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, int erase_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program)); int program_find_bootable_partition(bool *multiple_found); int program_is_sec_partition_flashed(void); +int program_cmd_add(const char *address, const char *filename); void free_programs(void); diff --git a/qdl.c b/qdl.c index 43ee3f2..578e98b 100644 --- a/qdl.c +++ b/qdl.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "qdl.h" #include "patch.h" @@ -33,20 +34,32 @@ enum { QDL_FILE_READ, QDL_FILE_UFS, QDL_FILE_CONTENTS, + QDL_CMD_READ, + QDL_CMD_WRITE, }; bool qdl_debug; -static int detect_type(const char *xml_file) +static int detect_type(const char *verb) { xmlNode *root; xmlDoc *doc; xmlNode *node; int type = QDL_FILE_UNKNOWN; - doc = xmlReadFile(xml_file, NULL, 0); + if (!strcmp(verb, "read")) + return QDL_CMD_READ; + if (!strcmp(verb, "write")) + return QDL_CMD_WRITE; + + if (access(verb, F_OK)) { + ux_err("%s is not a verb and not a XML file\n", verb); + return -EINVAL; + } + + doc = xmlReadFile(verb, NULL, 0); if (!doc) { - ux_err("failed to parse XML file \"%s\"\n", xml_file); + ux_err("failed to parse XML file \"%s\"\n", verb); return -EINVAL; } @@ -249,6 +262,22 @@ int main(int argc, char **argv) if (ret < 0) errx(1, "ufs_load %s failed", argv[optind]); break; + case QDL_CMD_READ: + if (optind + 2 >= argc) + errx(1, "read command missing arguments"); + ret = read_cmd_add(argv[optind + 1], argv[optind + 2]); + if (ret < 0) + errx(1, "failed to add read command"); + optind += 2; + break; + case QDL_CMD_WRITE: + if (optind + 2 >= argc) + errx(1, "write command missing arguments"); + ret = program_cmd_add(argv[optind + 1], argv[optind + 2]); + if (ret < 0) + errx(1, "failed to add write command"); + optind += 2; + break; default: errx(1, "%s type not yet supported", argv[optind]); break; diff --git a/qdl.h b/qdl.h index 8e4b38a..e8ab75e 100644 --- a/qdl.h +++ b/qdl.h @@ -85,6 +85,9 @@ void ux_progress(const char *fmt, unsigned int value, unsigned int size, ...); void print_version(void); +int parse_storage_address(const char *address, int *_partition, + unsigned int *_sector, unsigned int *_length); + extern bool qdl_debug; #endif diff --git a/read.c b/read.c index 215f2f4..fd04d7d 100644 --- a/read.c +++ b/read.c @@ -106,3 +106,41 @@ int read_op_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, return 0; } + +int read_cmd_add(const char *address, const char *filename) +{ + unsigned int start_sector; + unsigned int num_sectors; + struct read_op *read_op; + int partition; + char buf[20]; + int ret; + + ret = parse_storage_address(address, &partition, &start_sector, &num_sectors); + if (ret < 0) + return ret; + + if (num_sectors == 0) { + ux_err("read command without length specifier not supported\n"); + return -1; + } + + read_op = calloc(1, sizeof(struct read_op)); + + read_op->sector_size = 0; + read_op->filename = strdup(filename); + read_op->partition = partition; + read_op->num_sectors = num_sectors; + sprintf(buf, "%u", start_sector); + read_op->start_sector = strdup(buf); + + if (read_ops) { + read_ops_last->next = read_op; + read_ops_last = read_op; + } else { + read_ops = read_op; + read_ops_last = read_op; + } + + return 0; +} diff --git a/read.h b/read.h index f64b334..cd56e14 100644 --- a/read.h +++ b/read.h @@ -19,5 +19,6 @@ int read_op_load(const char *read_op_file); int read_op_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct read_op *read_op, int fd), const char *incdir); +int read_cmd_add(const char *source, const char *filename); #endif diff --git a/util.c b/util.c index 268a16d..8dfb9b4 100644 --- a/util.c +++ b/util.c @@ -4,6 +4,7 @@ * All rights reserved. */ #include +#include #include #include #include @@ -115,3 +116,76 @@ bool attr_as_bool(xmlNode *node, const char *attr, int *errors) return xmlStrcmp(value, (xmlChar *)"true") == 0; } + +/*** + * parse_storage_address() - parse a storage address specifier + * @address: specifier to be parsed + * @physical_partition: physical partition + * @start_sector: start_sector + * @num_sectors: number of sectors + * + * This function parses the provided address specifier and detects the + * following patterns: + * + * N => physical partition N, sector 0 + * N/S => physical partition N, sector S + * N/S+L => physical partition N, L sectors at sector S + * + * Returns: 0 on success, -1 on failure + */ +int parse_storage_address(const char *address, int *physical_partition, + unsigned int *start_sector, unsigned int *num_sectors) +{ + unsigned long length = 0; + const char *ptr = address; + unsigned long sector = 0; + long partition; + char *end; + + errno = 0; + partition = strtol(ptr, &end, 10); + if (end == ptr) + return -1; + if ((errno == ERANGE && partition == LONG_MAX) || partition < 0) + return -1; + + if (end[0] == '\0') + goto done; + if (end[0] != '/') + return -1; + + ptr = end + 1; + + errno = 0; + sector = strtoul(ptr, &end, 10); + if (end == ptr) + return -1; + if (errno == ERANGE && sector == ULONG_MAX) + return -1; + + if (end[0] == '\0') + goto done; + if (end[0] != '+') + return -1; + + ptr = end + 1; + + errno = 0; + length = strtoul(ptr, &end, 10); + if (end == ptr) + return -1; + if (errno == ERANGE && length == ULONG_MAX) + return -1; + if (length == 0) + return -1; + + if (end[0] != '\0') + return -1; + +done: + *physical_partition = partition; + *start_sector = sector; + *num_sectors = length; + + return 0; +}