Remote helpers deadlock easily, so support debug mode which shows the interaction steps. Signed-off-by: Ilari Liusvaara <ilari.liusvaara@xxxxxxxxxxx> --- transport-helper.c | 110 ++++++++++++++++++++++++++++++++++------------------ 1 files changed, 72 insertions(+), 38 deletions(-) diff --git a/transport-helper.c b/transport-helper.c index 0e4da79..697f026 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -8,6 +8,8 @@ #include "quote.h" #include "remote.h" +static int debug = 0; + struct helper_data { const char *name; @@ -25,6 +27,47 @@ struct helper_data struct git_transport_options gitoptions; }; +static void sendline(struct helper_data *helper, struct strbuf *buffer) +{ + if(debug) + fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf); + if(write_in_full(helper->helper->in, buffer->buf, buffer->len) + != buffer->len) { + die_errno("Full write to remote helper failed"); + } +} + +static int recvline(struct helper_data *helper, struct strbuf *buffer, + int supress_finish) +{ + strbuf_reset(buffer); + if (strbuf_getline(buffer, helper->out, '\n') == EOF) { + if(debug) + fprintf(stderr, "Debug: Remote helper quit.\n"); + if(!supress_finish) + finish_command(helper->helper); + exit(128); + } + + if(debug) + fprintf(stderr, "Debug: Remote helper: <- %s\n", buffer->buf); + return 0; +} + +static void xchgline(struct helper_data *helper, struct strbuf *buffer) +{ + sendline(helper, buffer); + recvline(helper, buffer, 1); +} + +static void write_constant(int fd, const char *str) +{ + if(debug) + fprintf(stderr, "Debug: Remote helper: -> %s", str); + if(write_in_full(fd, str, strlen(str)) != strlen(str)) + die_errno("Full write to remote helper failed"); +} + static struct child_process* helper_disown(struct transport *transport) { struct helper_data *data = transport->data; @@ -99,23 +142,15 @@ static struct child_process *get_helper(struct transport *transport) data->out = xfdopen(duped, "r"); setvbuf(data->out, NULL, _IONBF, 0); - write_str_in_full(helper->in, "capabilities\n"); + write_constant(helper->in, "capabilities\n"); while (1) { - if (strbuf_getline(&buf, data->out, '\n') == EOF) { - /* If we haven't seen line yet, try to finish the - command so we get error message about failed - execution. */ - if(!seen_line) - finish_command(helper); - - exit(128); /* child died, message supplied already */ - } - + recvline(data, &buf, seen_line); seen_line = 1; if (!*buf.buf) break; + if(debug) fprintf(stderr, "Debug: Got cap %s\n", buf.buf); if (!strcmp(buf.buf, "fetch")) data->fetch = 1; if (!strcmp(buf.buf, "option")) @@ -145,14 +180,19 @@ static struct child_process *get_helper(struct transport *transport) free(refspecs); } strbuf_release(&buf); + if(debug) fprintf(stderr, "Debug: Capabilities complete.\n"); return data->helper; } static int disconnect_helper(struct transport *transport) { struct helper_data *data = transport->data; + struct strbuf buf = STRBUF_INIT; + if (data->helper) { - write_str_in_full(data->helper->in, "\n"); + if(debug) fprintf(stderr, "Debug: Disconnecting.\n"); + strbuf_addf(&buf, "\n"); + sendline(data, &buf); close(data->helper->in); close(data->helper->out); fclose(data->out); @@ -182,10 +222,11 @@ static int set_helper_option(struct transport *transport, const char *name, const char *value) { struct helper_data *data = transport->data; - struct child_process *helper = get_helper(transport); struct strbuf buf = STRBUF_INIT; int i, ret, is_bool = 0; + get_helper(transport); + if (!data->option) return 1; @@ -208,12 +249,7 @@ static int set_helper_option(struct transport *transport, quote_c_style(value, &buf, NULL, 0); strbuf_addch(&buf, '\n'); - if (write_in_full(helper->in, buf.buf, buf.len) != buf.len) - die_errno("cannot send option to %s", data->name); - - strbuf_reset(&buf); - if (strbuf_getline(&buf, data->out, '\n') == EOF) - exit(128); /* child died, message supplied already */ + xchgline(data, &buf); if (!strcmp(buf.buf, "ok")) ret = 0; @@ -273,13 +309,10 @@ static int fetch_with_fetch(struct transport *transport, } strbuf_addch(&buf, '\n'); - if (write_in_full(data->helper->in, buf.buf, buf.len) != buf.len) - die_errno("cannot send fetch to %s", data->name); + sendline(data, &buf); while (1) { - strbuf_reset(&buf); - if (strbuf_getline(&buf, data->out, '\n') == EOF) - exit(128); /* child died, message supplied already */ + recvline(data, &buf, 1); if (!prefixcmp(buf.buf, "lock ")) { const char *name = buf.buf + 5; @@ -314,12 +347,13 @@ static int fetch_with_import(struct transport *transport, int nr_heads, struct ref **to_fetch) { struct child_process fastimport; - struct child_process *helper = get_helper(transport); struct helper_data *data = transport->data; int i; struct ref *posn; struct strbuf buf = STRBUF_INIT; + get_helper(transport); + if (get_importer(transport, &fastimport)) die("Couldn't run fast-import"); @@ -329,7 +363,7 @@ static int fetch_with_import(struct transport *transport, continue; strbuf_addf(&buf, "import %s\n", posn->name); - write_in_full(helper->in, buf.buf, buf.len); + sendline(data, &buf); strbuf_reset(&buf); } disconnect_helper(transport); @@ -370,12 +404,12 @@ static int _process_connect_or_invoke(struct transport *transport, } else return 0; - write_in_full(helper->in, cmdbuf.buf, cmdbuf.len); - strbuf_reset(&cmdbuf); - if (strbuf_getline(&cmdbuf, data->out, '\n') == EOF) - exit(128); /* child died, message supplied already */ - if(!strcmp(cmdbuf.buf, "OK")) + xchgline(data, &cmdbuf); + if(!strcmp(cmdbuf.buf, "OK")) { + if(debug) fprintf(stderr, "Debug: Layer 6 link ready, " + "starting layer 7...\n"); return 1; + } else if(!strcmp(cmdbuf.buf, "FALLBACK")) return 0; else if(!strcmp(cmdbuf.buf, "ERROR")) @@ -508,17 +542,14 @@ static int push_refs(struct transport *transport, } strbuf_addch(&buf, '\n'); - if (write_in_full(helper->in, buf.buf, buf.len) != buf.len) - exit(128); + sendline(data, &buf); ref = remote_refs; while (1) { char *refname, *msg; int status; - strbuf_reset(&buf); - if (strbuf_getline(&buf, data->out, '\n') == EOF) - exit(128); /* child died, message supplied already */ + recvline(data, &buf, 1); if (!buf.len) break; @@ -608,8 +639,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) while (1) { char *eov, *eon; - if (strbuf_getline(&buf, data->out, '\n') == EOF) - exit(128); /* child died, message supplied already */ + recvline(data, &buf, 1); if (!*buf.buf) break; @@ -634,6 +664,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) } tail = &((*tail)->next); } + if(debug) fprintf(stderr, "Debug: Read ref listing.\n"); strbuf_release(&buf); for (posn = ret; posn; posn = posn->next) @@ -647,6 +678,9 @@ int transport_helper_init(struct transport *transport, const char *name) struct helper_data *data = xcalloc(sizeof(*data), 1); data->name = name; + if(getenv("GIT_TRANSPORT_HELPER_DEBUG")) + debug = 1; + transport->data = data; transport->set_option = set_helper_option; transport->get_refs_list = get_refs_list; -- 1.6.6.rc0.64.g5593e -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html