#include "pkt-line.h"
#include "quote.h"
#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+/*
+ * Read all the refs from the other end
+ */
+struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match)
+{
+ *list = NULL;
+ for (;;) {
+ struct ref *ref;
+ unsigned char old_sha1[20];
+ static char buffer[1000];
+ char *name;
+ int len;
+
+ len = packet_read_line(in, buffer, sizeof(buffer));
+ if (!len)
+ break;
+ if (buffer[len-1] == '\n')
+ buffer[--len] = 0;
+
+ if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
+ die("protocol error: expected sha/ref, got '%s'", buffer);
+ name = buffer + 41;
+ if (nr_match && !path_match(name, nr_match, match))
+ continue;
+ ref = xmalloc(sizeof(*ref) + len - 40);
+ memcpy(ref->old_sha1, old_sha1, 20);
+ memset(ref->new_sha1, 0, 20);
+ memcpy(ref->name, buffer + 41, len - 40);
+ ref->next = NULL;
+ *list = ref;
+ list = &ref->next;
+ }
+ return list;
+}
int get_ack(int fd, unsigned char *result_sha1)
{
return 0;
}
+enum protocol {
+ PROTO_LOCAL = 1,
+ PROTO_SSH,
+ PROTO_GIT,
+};
+
+static enum protocol get_protocol(const char *name)
+{
+ if (!strcmp(name, "ssh"))
+ return PROTO_SSH;
+ if (!strcmp(name, "git"))
+ return PROTO_GIT;
+ die("I don't handle protocol '%s'", name);
+}
+
+#define STR_(s) # s
+#define STR(s) STR_(s)
+
+static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
+{
+ int sockfd = -1;
+ char *colon, *end;
+ char *port = STR(DEFAULT_GIT_PORT);
+ struct addrinfo hints, *ai0, *ai;
+ int gai;
+
+ if (host[0] == '[') {
+ end = strchr(host + 1, ']');
+ if (end) {
+ *end = 0;
+ end++;
+ host++;
+ } else
+ end = host;
+ } else
+ end = host;
+ colon = strchr(end, ':');
+
+ if (colon) {
+ *colon = 0;
+ port = colon + 1;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ gai = getaddrinfo(host, port, &hints, &ai);
+ if (gai)
+ die("Unable to look up %s (%s)", host, gai_strerror(gai));
+
+ for (ai0 = ai; ai; ai = ai->ai_next) {
+ sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sockfd < 0)
+ continue;
+ if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
+ close(sockfd);
+ sockfd = -1;
+ continue;
+ }
+ break;
+ }
+
+ freeaddrinfo(ai0);
+
+ if (sockfd < 0)
+ die("unable to connect a socket (%s)", strerror(errno));
+
+ fd[0] = sockfd;
+ fd[1] = sockfd;
+ packet_write(sockfd, "%s %s\n", prog, path);
+ return 0;
+}
+
/*
* Yeah, yeah, fixme. Need to pass in the heads etc.
*/
int git_connect(int fd[2], char *url, const char *prog)
{
char command[1024];
- const char *host, *path;
+ char *host, *path;
char *colon;
int pipefd[2][2];
pid_t pid;
+ enum protocol protocol;
host = NULL;
path = url;
colon = strchr(url, ':');
+ protocol = PROTO_LOCAL;
if (colon) {
*colon = 0;
host = url;
path = colon+1;
+ protocol = PROTO_SSH;
+ if (!memcmp(path, "//", 2)) {
+ char *slash = strchr(path + 2, '/');
+ if (slash) {
+ int nr = slash - path - 2;
+ memmove(path, path+2, nr);
+ path[nr] = 0;
+ protocol = get_protocol(url);
+ host = path;
+ path = slash;
+ }
+ }
}
+
+ if (protocol == PROTO_GIT)
+ return git_tcp_connect(fd, prog, host, path);
+
if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
die("unable to create pipe pair for communication");
pid = fork();
close(pipefd[0][1]);
close(pipefd[1][0]);
close(pipefd[1][1]);
- if (host)
+ if (protocol == PROTO_SSH)
execlp("ssh", "ssh", host, command, NULL);
else
execlp("sh", "sh", "-c", command, NULL);