3 #include "run-command.h"
8 * 'command [arg1 [arg2 [...]]]' Invoke command with given arguments.
10 * '% ': Literal space in argument.
11 * '%%': Literal percent sign.
12 * '%S': Name of service (git-upload-pack/git-upload-archive/
14 * '%s': Same as \s, but with possible git- prefix stripped.
15 * '%G': Only allowed as first 'character' of argument. Do not pass this
16 * Argument to command, instead send this as name of repository
17 * in in-line git://-style request (also activates sending this
19 * '%V': Only allowed as first 'character' of argument. Used in
20 * conjunction with '%G': Do not pass this argument to command,
21 * instead send this as vhost in git://-style request (note: does
22 * not activate sending git:// style request).
26 static char *git_req_vhost;
28 static char *strip_escapes(const char *str, const char *service,
34 const char *service_noprefix = service;
35 struct strbuf ret = STRBUF_INIT;
37 skip_prefix(service_noprefix, "git-", &service_noprefix);
39 /* Pass the service to command. */
40 setenv("GIT_EXT_SERVICE", service, 1);
41 setenv("GIT_EXT_SERVICE_NOPREFIX", service_noprefix, 1);
43 /* Scan the length of argument. */
44 while (str[rpos] && (escape || str[rpos] != ' ')) {
57 /* Fall-through to error. */
59 die("Bad remote-ext placeholder '%%%c'.",
64 escape = (str[rpos] == '%');
67 if (escape && !str[rpos])
68 die("remote-ext command has incomplete placeholder");
71 ++*next; /* Skip over space */
74 * Do the actual placeholder substitution. The string will be short
75 * enough not to overflow integers.
77 rpos = special ? 2 : 0; /* Skip first 2 bytes in specials. */
79 while (str[rpos] && (escape || str[rpos] != ' ')) {
84 strbuf_addch(&ret, str[rpos]);
87 strbuf_addstr(&ret, service_noprefix);
90 strbuf_addstr(&ret, service);
100 strbuf_addch(&ret, str[rpos]);
107 git_req = strbuf_detach(&ret, NULL);
110 git_req_vhost = strbuf_detach(&ret, NULL);
113 return strbuf_detach(&ret, NULL);
117 static void parse_argv(struct argv_array *out, const char *arg, const char *service)
120 char *expanded = strip_escapes(arg, service, &arg);
122 argv_array_push(out, expanded);
127 static void send_git_request(int stdin_fd, const char *serv, const char *repo,
131 packet_write(stdin_fd, "%s %s%c", serv, repo, 0);
133 packet_write(stdin_fd, "%s %s%chost=%s%c", serv, repo, 0,
137 static int run_child(const char *arg, const char *service)
140 struct child_process child = CHILD_PROCESS_INIT;
145 parse_argv(&child.args, arg, service);
147 if (start_command(&child) < 0)
148 die("Can't run specified command");
151 send_git_request(child.in, service, git_req, git_req_vhost);
153 r = bidirectional_transfer_loop(child.out, child.in);
155 r = finish_command(&child);
157 finish_command(&child);
161 #define MAXCOMMAND 4096
163 static int command_loop(const char *child)
165 char buffer[MAXCOMMAND];
169 if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
171 die("Comammand input error");
174 /* Strip end of line characters. */
176 while (i > 0 && isspace(buffer[i - 1]))
179 if (!strcmp(buffer, "capabilities")) {
180 printf("*connect\n\n");
182 } else if (!strncmp(buffer, "connect ", 8)) {
185 return run_child(child, buffer + 8);
187 fprintf(stderr, "Bad command");
193 int cmd_remote_ext(int argc, const char **argv, const char *prefix)
196 die("Expected two arguments");
198 return command_loop(argv[2]);