1 #include "git-compat-util.h"
3 #include "run-command.h"
7 * 'command [arg1 [arg2 [...]]]' Invoke command with given arguments.
9 * '% ': Literal space in argument.
10 * '%%': Literal percent sign.
11 * '%S': Name of service (git-upload-pack/git-upload-archive/
13 * '%s': Same as \s, but with possible git- prefix stripped.
14 * '%G': Only allowed as first 'character' of argument. Do not pass this
15 * Argument to command, instead send this as name of repository
16 * in in-line git://-style request (also activates sending this
18 * '%V': Only allowed as first 'character' of argument. Used in
19 * conjunction with '%G': Do not pass this argument to command,
20 * instead send this as vhost in git://-style request (note: does
21 * not activate sending git:// style request).
25 static char *git_req_vhost
;
27 static char *strip_escapes(const char *str
, const char *service
,
36 struct strbuf ret
= STRBUF_INIT
;
38 /* Calculate prefix length for \s and lengths for \s and \S */
39 if (!strncmp(service
, "git-", 4))
41 pSlen
= strlen(service
);
42 pslen
= pSlen
- psoff
;
44 /* Pass the service to command. */
45 setenv("GIT_EXT_SERVICE", service
, 1);
46 setenv("GIT_EXT_SERVICE_NOPREFIX", service
+ psoff
, 1);
48 /* Scan the length of argument. */
49 while (str
[rpos
] && (escape
|| str
[rpos
] != ' ')) {
62 /* Fall-through to error. */
64 die("Bad remote-ext placeholder '%%%c'.",
69 escape
= (str
[rpos
] == '%');
72 if (escape
&& !str
[rpos
])
73 die("remote-ext command has incomplete placeholder");
76 ++*next
; /* Skip over space */
79 * Do the actual placeholder substitution. The string will be short
80 * enough not to overflow integers.
82 rpos
= special
? 2 : 0; /* Skip first 2 bytes in specials. */
84 while (str
[rpos
] && (escape
|| str
[rpos
] != ' ')) {
89 strbuf_addch(&ret
, str
[rpos
]);
92 strbuf_addstr(&ret
, service
+ psoff
);
95 strbuf_addstr(&ret
, service
);
105 strbuf_addch(&ret
, str
[rpos
]);
112 git_req
= strbuf_detach(&ret
, NULL
);
115 git_req_vhost
= strbuf_detach(&ret
, NULL
);
118 return strbuf_detach(&ret
, NULL
);
122 /* Should be enough... */
123 #define MAXARGUMENTS 256
125 static const char **parse_argv(const char *arg
, const char *service
)
130 char *temparray
[MAXARGUMENTS
+ 1];
134 if (arguments
== MAXARGUMENTS
)
135 die("remote-ext command has too many arguments");
136 expanded
= strip_escapes(arg
, service
, &arg
);
138 temparray
[arguments
++] = expanded
;
141 ret
= xmalloc((arguments
+ 1) * sizeof(char *));
142 for (i
= 0; i
< arguments
; i
++)
143 ret
[i
] = temparray
[i
];
144 ret
[arguments
] = NULL
;
148 static void send_git_request(int stdin_fd
, const char *serv
, const char *repo
,
156 * Request needs 12 bytes extra if there is vhost (xxxx \0host=\0) and
157 * 6 bytes extra (xxxx \0) if there is no vhost.
160 bufferspace
= strlen(serv
) + strlen(repo
) + strlen(vhost
) + 12;
162 bufferspace
= strlen(serv
) + strlen(repo
) + 6;
164 if (bufferspace
> 0xFFFF)
165 die("Request too large to send");
166 buffer
= xmalloc(bufferspace
);
168 /* Make the packet. */
169 wpos
= sprintf(buffer
, "%04x%s %s%c", (unsigned)bufferspace
,
172 /* Add vhost if any. */
174 sprintf(buffer
+ wpos
, "host=%s%c", vhost
, 0);
176 /* Send the request */
177 if (write_in_full(stdin_fd
, buffer
, bufferspace
) < 0)
178 die_errno("Failed to send request");
183 static int run_child(const char *arg
, const char *service
)
186 struct child_process child
;
188 memset(&child
, 0, sizeof(child
));
192 child
.argv
= parse_argv(arg
, service
);
194 if (start_command(&child
) < 0)
195 die("Can't run specified command");
198 send_git_request(child
.in
, service
, git_req
, git_req_vhost
);
200 r
= bidirectional_transfer_loop(child
.out
, child
.in
);
202 r
= finish_command(&child
);
204 finish_command(&child
);
208 #define MAXCOMMAND 4096
210 static int command_loop(const char *child
)
212 char buffer
[MAXCOMMAND
];
216 if (!fgets(buffer
, MAXCOMMAND
- 1, stdin
)) {
218 die("Comammand input error");
221 /* Strip end of line characters. */
223 while (i
> 0 && isspace(buffer
[i
- 1]))
226 if (!strcmp(buffer
, "capabilities")) {
227 printf("*connect\n\n");
229 } else if (!strncmp(buffer
, "connect ", 8)) {
232 return run_child(child
, buffer
+ 8);
234 fprintf(stderr
, "Bad command");
240 int cmd_remote_ext(int argc
, const char **argv
, const char *prefix
)
243 die("Expected two arguments");
245 return command_loop(argv
[2]);