diff --git a/firehose.c b/firehose.c index ebe9c52..a5c06e8 100644 --- a/firehose.c +++ b/firehose.c @@ -96,80 +96,61 @@ static xmlNode *firehose_response_parse(const void *buf, size_t len, int *error) return node; } -static void firehose_response_log(xmlNode *node) +static int firehose_generic_parser(xmlNode *node, void *data) { xmlChar *value; value = xmlGetProp(node, (xmlChar*)"value"); - printf("LOG: %s\n", value); + + if (xmlStrcmp(node->name, (xmlChar*)"log") == 0) { + printf("LOG: %s\n", value); + return 0; + } + + return xmlStrcmp(value, (xmlChar*)"ACK") == 0 ? 1 : -1; } -static int firehose_read(struct qdl_device *qdl, int wait, int (*response_parser)(xmlNode *node)) +static int firehose_read(struct qdl_device *qdl, bool wait, + int (*response_parser)(xmlNode *node, void *data), + void *data) { char buf[4096]; - xmlNode *nodes; xmlNode *node; int error; - char *msg; - char *end; - bool done = false; int ret = -ENXIO; int n; - int timeout = 1000; - - if (wait > 0) - timeout = wait; + int timeout = wait ? 10000 : 10; for (;;) { n = qdl_read(qdl, buf, sizeof(buf), timeout); if (n < 0) { - if (done) + if (!wait) break; warn("failed to read"); return -ETIMEDOUT; + } else if (n == 0) { + continue; } buf[n] = '\0'; if (qdl_debug) fprintf(stderr, "FIREHOSE READ: %s\n", buf); - for (msg = buf; msg[0]; msg = end) { - end = strstr(msg, ""); - if (!end) { - fprintf(stderr, "firehose response truncated\n"); - exit(1); - } - - end += strlen(""); - - nodes = firehose_response_parse(msg, end - msg, &error); - if (!nodes) { - fprintf(stderr, "unable to parse response\n"); - return error; - } - - for (node = nodes; node; node = node->next) { - if (xmlStrcmp(node->name, (xmlChar*)"log") == 0) { - firehose_response_log(node); - } else if (xmlStrcmp(node->name, (xmlChar*)"response") == 0) { - if (!response_parser) - fprintf(stderr, "received response with no parser\n"); - else - ret = response_parser(node); - done = true; - timeout = 1; - } - } - - xmlFreeDoc(nodes->doc); + node = firehose_response_parse(buf, n, &error); + if (!node) { + fprintf(stderr, "unable to parse response\n"); + return error; } - if (wait > 0) - timeout = 100; + ret = response_parser(node, data); + if (ret != 0) + break; + + xmlFreeDoc(node->doc); } - return ret; + return ret < 0 ? ret : 0; } static int firehose_write(struct qdl_device *qdl, xmlDoc *doc) @@ -190,7 +171,7 @@ static int firehose_write(struct qdl_device *qdl, xmlDoc *doc) return ret < 0 ? -saved_errno : 0; } -static int firehose_nop_parser(xmlNode *node) +static int firehose_nop_parser(xmlNode *node, void *data) { xmlChar *value; @@ -206,13 +187,18 @@ static size_t max_payload_size = 1048576; * * Return: max size supported by the remote, or negative errno on failure */ -static int firehose_configure_response_parser(xmlNode *node) +static int firehose_configure_response_parser(xmlNode *node, void *data) { xmlChar *payload; xmlChar *value; size_t max_size; value = xmlGetProp(node, (xmlChar*)"value"); + if (xmlStrcmp(node->name, (xmlChar*)"log") == 0) { + printf("LOG: %s\n", value); + return 0; + } + payload = xmlGetProp(node, (xmlChar*)"MaxPayloadSizeToTargetInBytes"); if (!value || !payload) return -EINVAL; @@ -257,7 +243,7 @@ static int firehose_send_configure(struct qdl_device *qdl, size_t payload_size, if (ret < 0) return ret; - return firehose_read(qdl, -1, firehose_configure_response_parser); + return firehose_read(qdl, true, firehose_configure_response_parser, NULL); } static int firehose_configure(struct qdl_device *qdl, bool skip_storage_init, const char *storage) @@ -340,7 +326,7 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int goto out; } - ret = firehose_read(qdl, -1, firehose_nop_parser); + ret = firehose_read(qdl, true, firehose_nop_parser, NULL); if (ret) { fprintf(stderr, "[PROGRAM] failed to setup programming\n"); goto out; @@ -372,7 +358,7 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int t = time(NULL) - t0; - ret = firehose_read(qdl, -1, firehose_nop_parser); + ret = firehose_read(qdl, true, firehose_nop_parser, NULL); if (ret) { fprintf(stderr, "[PROGRAM] failed\n"); } else if (t) { @@ -416,7 +402,7 @@ static int firehose_apply_patch(struct qdl_device *qdl, struct patch *patch) if (ret < 0) goto out; - ret = firehose_read(qdl, -1, firehose_nop_parser); + ret = firehose_read(qdl, true, firehose_nop_parser, NULL); if (ret) fprintf(stderr, "[APPLY PATCH] %d\n", ret); @@ -439,7 +425,7 @@ static int firehose_send_single_tag(struct qdl_device *qdl, xmlNode *node){ if (ret < 0) goto out; - ret = firehose_read(qdl, -1, firehose_nop_parser); + ret = firehose_read(qdl, true, firehose_nop_parser, NULL); if (ret) { fprintf(stderr, "[UFS] %s err %d\n", __func__, ret); ret = -EINVAL; @@ -538,7 +524,7 @@ static int firehose_set_bootable(struct qdl_device *qdl, int part) if (ret < 0) return ret; - ret = firehose_read(qdl, -1, firehose_nop_parser); + ret = firehose_read(qdl, true, firehose_nop_parser, NULL); if (ret) { fprintf(stderr, "failed to mark partition %d as bootable\n", part); return -1; @@ -567,7 +553,7 @@ static int firehose_reset(struct qdl_device *qdl) if (ret < 0) return ret; - return firehose_read(qdl, -1, firehose_nop_parser); + return firehose_read(qdl, true, firehose_nop_parser, NULL); } int firehose_run(struct qdl_device *qdl, const char *incdir, const char *storage) @@ -578,7 +564,7 @@ int firehose_run(struct qdl_device *qdl, const char *incdir, const char *storage /* Wait for the firehose payload to boot */ sleep(3); - firehose_read(qdl, 1000, NULL); + firehose_read(qdl, false, firehose_generic_parser, NULL); if(ufs_need_provisioning()) { ret = firehose_configure(qdl, true, storage);