941bf296b0d5a8ded60cea0ed61770dc909d2d88
[git.git] / connect.c
1 #include "cache.h"
2 #include <sys/wait.h>
3
4 int path_match(const char *path, int nr, char **match)
5 {
6         int i;
7         int pathlen = strlen(path);
8
9         for (i = 0; i < nr; i++) {
10                 char *s = match[i];
11                 int len = strlen(s);
12
13                 if (!len || len > pathlen)
14                         continue;
15                 if (memcmp(path + pathlen - len, s, len))
16                         continue;
17                 if (pathlen > len && path[pathlen - len - 1] != '/')
18                         continue;
19                 *s = 0;
20                 return 1;
21         }
22         return 0;
23 }
24
25 /*
26  * First, make it shell-safe.  We do this by just disallowing any
27  * special characters. Somebody who cares can do escaping and let
28  * through the rest. But since we're doing to feed this to ssh as
29  * a command line, we're going to be pretty damn anal for now.
30  */
31 static char *shell_safe(char *url)
32 {
33         char *n = url;
34         unsigned char c;
35         static const char flags[256] = {
36                 ['0'...'9'] = 1,
37                 ['a'...'z'] = 1,
38                 ['A'...'Z'] = 1,
39                 ['.'] = 1, ['/'] = 1,
40                 ['-'] = 1, ['+'] = 1,
41                 [':'] = 1
42         };
43
44         while ((c = *n++) != 0) {
45                 if (flags[c] != 1)
46                         die("I don't like '%c'. Sue me.", c);
47         }
48         return url;
49 }
50
51 /*
52  * Yeah, yeah, fixme. Need to pass in the heads etc.
53  */
54 int git_connect(int fd[2], char *url, const char *prog)
55 {
56         char command[1024];
57         const char *host, *path;
58         char *colon;
59         int pipefd[2][2];
60         pid_t pid;
61
62         url = shell_safe(url);
63         host = NULL;
64         path = url;
65         colon = strchr(url, ':');
66         if (colon) {
67                 *colon = 0;
68                 host = url;
69                 path = colon+1;
70         }
71         snprintf(command, sizeof(command), "%s %s", prog, path);
72         if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
73                 die("unable to create pipe pair for communication");
74         pid = fork();
75         if (!pid) {
76                 dup2(pipefd[1][0], 0);
77                 dup2(pipefd[0][1], 1);
78                 close(pipefd[0][0]);
79                 close(pipefd[0][1]);
80                 close(pipefd[1][0]);
81                 close(pipefd[1][1]);
82                 if (host)
83                         execlp("ssh", "ssh", host, command, NULL);
84                 else
85                         execlp("sh", "sh", "-c", command, NULL);
86                 die("exec failed");
87         }               
88         fd[0] = pipefd[0][0];
89         fd[1] = pipefd[1][1];
90         close(pipefd[0][1]);
91         close(pipefd[1][0]);
92         return pid;
93 }
94
95 int finish_connect(pid_t pid)
96 {
97         int ret;
98
99         for (;;) {
100                 ret = waitpid(pid, NULL, 0);
101                 if (!ret)
102                         break;
103                 if (errno != EINTR)
104                         break;
105         }
106         return ret;
107 }