connect.con commit Move refspec parser from connect.c and cache.h to remote.{c,h} (6b62816)
   1#include "git-compat-util.h"
   2#include "cache.h"
   3#include "pkt-line.h"
   4#include "quote.h"
   5#include "refs.h"
   6#include "run-command.h"
   7#include "remote.h"
   8
   9static char *server_capabilities;
  10
  11static int check_ref(const char *name, int len, unsigned int flags)
  12{
  13        if (!flags)
  14                return 1;
  15
  16        if (len < 5 || memcmp(name, "refs/", 5))
  17                return 0;
  18
  19        /* Skip the "refs/" part */
  20        name += 5;
  21        len -= 5;
  22
  23        /* REF_NORMAL means that we don't want the magic fake tag refs */
  24        if ((flags & REF_NORMAL) && check_ref_format(name) < 0)
  25                return 0;
  26
  27        /* REF_HEADS means that we want regular branch heads */
  28        if ((flags & REF_HEADS) && !memcmp(name, "heads/", 6))
  29                return 1;
  30
  31        /* REF_TAGS means that we want tags */
  32        if ((flags & REF_TAGS) && !memcmp(name, "tags/", 5))
  33                return 1;
  34
  35        /* All type bits clear means that we are ok with anything */
  36        return !(flags & ~REF_NORMAL);
  37}
  38
  39/*
  40 * Read all the refs from the other end
  41 */
  42struct ref **get_remote_heads(int in, struct ref **list,
  43                              int nr_match, char **match,
  44                              unsigned int flags)
  45{
  46        *list = NULL;
  47        for (;;) {
  48                struct ref *ref;
  49                unsigned char old_sha1[20];
  50                static char buffer[1000];
  51                char *name;
  52                int len, name_len;
  53
  54                len = packet_read_line(in, buffer, sizeof(buffer));
  55                if (!len)
  56                        break;
  57                if (buffer[len-1] == '\n')
  58                        buffer[--len] = 0;
  59
  60                if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
  61                        die("protocol error: expected sha/ref, got '%s'", buffer);
  62                name = buffer + 41;
  63
  64                name_len = strlen(name);
  65                if (len != name_len + 41) {
  66                        if (server_capabilities)
  67                                free(server_capabilities);
  68                        server_capabilities = xstrdup(name + name_len + 1);
  69                }
  70
  71                if (!check_ref(name, name_len, flags))
  72                        continue;
  73                if (nr_match && !path_match(name, nr_match, match))
  74                        continue;
  75                ref = xcalloc(1, sizeof(*ref) + len - 40);
  76                hashcpy(ref->old_sha1, old_sha1);
  77                memcpy(ref->name, buffer + 41, len - 40);
  78                *list = ref;
  79                list = &ref->next;
  80        }
  81        return list;
  82}
  83
  84int server_supports(const char *feature)
  85{
  86        return server_capabilities &&
  87                strstr(server_capabilities, feature) != NULL;
  88}
  89
  90int get_ack(int fd, unsigned char *result_sha1)
  91{
  92        static char line[1000];
  93        int len = packet_read_line(fd, line, sizeof(line));
  94
  95        if (!len)
  96                die("git-fetch-pack: expected ACK/NAK, got EOF");
  97        if (line[len-1] == '\n')
  98                line[--len] = 0;
  99        if (!strcmp(line, "NAK"))
 100                return 0;
 101        if (!prefixcmp(line, "ACK ")) {
 102                if (!get_sha1_hex(line+4, result_sha1)) {
 103                        if (strstr(line+45, "continue"))
 104                                return 2;
 105                        return 1;
 106                }
 107        }
 108        die("git-fetch_pack: expected ACK/NAK, got '%s'", line);
 109}
 110
 111int path_match(const char *path, int nr, char **match)
 112{
 113        int i;
 114        int pathlen = strlen(path);
 115
 116        for (i = 0; i < nr; i++) {
 117                char *s = match[i];
 118                int len = strlen(s);
 119
 120                if (!len || len > pathlen)
 121                        continue;
 122                if (memcmp(path + pathlen - len, s, len))
 123                        continue;
 124                if (pathlen > len && path[pathlen - len - 1] != '/')
 125                        continue;
 126                *s = 0;
 127                return (i + 1);
 128        }
 129        return 0;
 130}
 131
 132enum protocol {
 133        PROTO_LOCAL = 1,
 134        PROTO_SSH,
 135        PROTO_GIT,
 136};
 137
 138static enum protocol get_protocol(const char *name)
 139{
 140        if (!strcmp(name, "ssh"))
 141                return PROTO_SSH;
 142        if (!strcmp(name, "git"))
 143                return PROTO_GIT;
 144        if (!strcmp(name, "git+ssh"))
 145                return PROTO_SSH;
 146        if (!strcmp(name, "ssh+git"))
 147                return PROTO_SSH;
 148        die("I don't handle protocol '%s'", name);
 149}
 150
 151#define STR_(s) # s
 152#define STR(s)  STR_(s)
 153
 154#ifndef NO_IPV6
 155
 156/*
 157 * Returns a connected socket() fd, or else die()s.
 158 */
 159static int git_tcp_connect_sock(char *host, int flags)
 160{
 161        int sockfd = -1, saved_errno = 0;
 162        char *colon, *end;
 163        const char *port = STR(DEFAULT_GIT_PORT);
 164        struct addrinfo hints, *ai0, *ai;
 165        int gai;
 166
 167        if (host[0] == '[') {
 168                end = strchr(host + 1, ']');
 169                if (end) {
 170                        *end = 0;
 171                        end++;
 172                        host++;
 173                } else
 174                        end = host;
 175        } else
 176                end = host;
 177        colon = strchr(end, ':');
 178
 179        if (colon) {
 180                *colon = 0;
 181                port = colon + 1;
 182                if (!*port)
 183                        port = "<none>";
 184        }
 185
 186        memset(&hints, 0, sizeof(hints));
 187        hints.ai_socktype = SOCK_STREAM;
 188        hints.ai_protocol = IPPROTO_TCP;
 189
 190        if (flags & CONNECT_VERBOSE)
 191                fprintf(stderr, "Looking up %s ... ", host);
 192
 193        gai = getaddrinfo(host, port, &hints, &ai);
 194        if (gai)
 195                die("Unable to look up %s (port %s) (%s)", host, port, gai_strerror(gai));
 196
 197        if (flags & CONNECT_VERBOSE)
 198                fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
 199
 200        for (ai0 = ai; ai; ai = ai->ai_next) {
 201                sockfd = socket(ai->ai_family,
 202                                ai->ai_socktype, ai->ai_protocol);
 203                if (sockfd < 0) {
 204                        saved_errno = errno;
 205                        continue;
 206                }
 207                if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
 208                        saved_errno = errno;
 209                        close(sockfd);
 210                        sockfd = -1;
 211                        continue;
 212                }
 213                break;
 214        }
 215
 216        freeaddrinfo(ai0);
 217
 218        if (sockfd < 0)
 219                die("unable to connect a socket (%s)", strerror(saved_errno));
 220
 221        if (flags & CONNECT_VERBOSE)
 222                fprintf(stderr, "done.\n");
 223
 224        return sockfd;
 225}
 226
 227#else /* NO_IPV6 */
 228
 229/*
 230 * Returns a connected socket() fd, or else die()s.
 231 */
 232static int git_tcp_connect_sock(char *host, int flags)
 233{
 234        int sockfd = -1, saved_errno = 0;
 235        char *colon, *end;
 236        char *port = STR(DEFAULT_GIT_PORT), *ep;
 237        struct hostent *he;
 238        struct sockaddr_in sa;
 239        char **ap;
 240        unsigned int nport;
 241
 242        if (host[0] == '[') {
 243                end = strchr(host + 1, ']');
 244                if (end) {
 245                        *end = 0;
 246                        end++;
 247                        host++;
 248                } else
 249                        end = host;
 250        } else
 251                end = host;
 252        colon = strchr(end, ':');
 253
 254        if (colon) {
 255                *colon = 0;
 256                port = colon + 1;
 257        }
 258
 259        if (flags & CONNECT_VERBOSE)
 260                fprintf(stderr, "Looking up %s ... ", host);
 261
 262        he = gethostbyname(host);
 263        if (!he)
 264                die("Unable to look up %s (%s)", host, hstrerror(h_errno));
 265        nport = strtoul(port, &ep, 10);
 266        if ( ep == port || *ep ) {
 267                /* Not numeric */
 268                struct servent *se = getservbyname(port,"tcp");
 269                if ( !se )
 270                        die("Unknown port %s\n", port);
 271                nport = se->s_port;
 272        }
 273
 274        if (flags & CONNECT_VERBOSE)
 275                fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
 276
 277        for (ap = he->h_addr_list; *ap; ap++) {
 278                sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
 279                if (sockfd < 0) {
 280                        saved_errno = errno;
 281                        continue;
 282                }
 283
 284                memset(&sa, 0, sizeof sa);
 285                sa.sin_family = he->h_addrtype;
 286                sa.sin_port = htons(nport);
 287                memcpy(&sa.sin_addr, *ap, he->h_length);
 288
 289                if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
 290                        saved_errno = errno;
 291                        close(sockfd);
 292                        sockfd = -1;
 293                        continue;
 294                }
 295                break;
 296        }
 297
 298        if (sockfd < 0)
 299                die("unable to connect a socket (%s)", strerror(saved_errno));
 300
 301        if (flags & CONNECT_VERBOSE)
 302                fprintf(stderr, "done.\n");
 303
 304        return sockfd;
 305}
 306
 307#endif /* NO_IPV6 */
 308
 309
 310static void git_tcp_connect(int fd[2], char *host, int flags)
 311{
 312        int sockfd = git_tcp_connect_sock(host, flags);
 313
 314        fd[0] = sockfd;
 315        fd[1] = dup(sockfd);
 316}
 317
 318
 319static char *git_proxy_command;
 320static const char *rhost_name;
 321static int rhost_len;
 322
 323static int git_proxy_command_options(const char *var, const char *value)
 324{
 325        if (!strcmp(var, "core.gitproxy")) {
 326                const char *for_pos;
 327                int matchlen = -1;
 328                int hostlen;
 329
 330                if (git_proxy_command)
 331                        return 0;
 332                /* [core]
 333                 * ;# matches www.kernel.org as well
 334                 * gitproxy = netcatter-1 for kernel.org
 335                 * gitproxy = netcatter-2 for sample.xz
 336                 * gitproxy = netcatter-default
 337                 */
 338                for_pos = strstr(value, " for ");
 339                if (!for_pos)
 340                        /* matches everybody */
 341                        matchlen = strlen(value);
 342                else {
 343                        hostlen = strlen(for_pos + 5);
 344                        if (rhost_len < hostlen)
 345                                matchlen = -1;
 346                        else if (!strncmp(for_pos + 5,
 347                                          rhost_name + rhost_len - hostlen,
 348                                          hostlen) &&
 349                                 ((rhost_len == hostlen) ||
 350                                  rhost_name[rhost_len - hostlen -1] == '.'))
 351                                matchlen = for_pos - value;
 352                        else
 353                                matchlen = -1;
 354                }
 355                if (0 <= matchlen) {
 356                        /* core.gitproxy = none for kernel.org */
 357                        if (matchlen == 4 && 
 358                            !memcmp(value, "none", 4))
 359                                matchlen = 0;
 360                        git_proxy_command = xmalloc(matchlen + 1);
 361                        memcpy(git_proxy_command, value, matchlen);
 362                        git_proxy_command[matchlen] = 0;
 363                }
 364                return 0;
 365        }
 366
 367        return git_default_config(var, value);
 368}
 369
 370static int git_use_proxy(const char *host)
 371{
 372        rhost_name = host;
 373        rhost_len = strlen(host);
 374        git_proxy_command = getenv("GIT_PROXY_COMMAND");
 375        git_config(git_proxy_command_options);
 376        rhost_name = NULL;
 377        return (git_proxy_command && *git_proxy_command);
 378}
 379
 380static void git_proxy_connect(int fd[2], char *host)
 381{
 382        const char *port = STR(DEFAULT_GIT_PORT);
 383        char *colon, *end;
 384        const char *argv[4];
 385        struct child_process proxy;
 386
 387        if (host[0] == '[') {
 388                end = strchr(host + 1, ']');
 389                if (end) {
 390                        *end = 0;
 391                        end++;
 392                        host++;
 393                } else
 394                        end = host;
 395        } else
 396                end = host;
 397        colon = strchr(end, ':');
 398
 399        if (colon) {
 400                *colon = 0;
 401                port = colon + 1;
 402        }
 403
 404        argv[0] = git_proxy_command;
 405        argv[1] = host;
 406        argv[2] = port;
 407        argv[3] = NULL;
 408        memset(&proxy, 0, sizeof(proxy));
 409        proxy.argv = argv;
 410        proxy.in = -1;
 411        proxy.out = -1;
 412        if (start_command(&proxy))
 413                die("cannot start proxy %s", argv[0]);
 414        fd[0] = proxy.out; /* read from proxy stdout */
 415        fd[1] = proxy.in;  /* write to proxy stdin */
 416}
 417
 418#define MAX_CMD_LEN 1024
 419
 420/*
 421 * This returns 0 if the transport protocol does not need fork(2),
 422 * or a process id if it does.  Once done, finish the connection
 423 * with finish_connect() with the value returned from this function
 424 * (it is safe to call finish_connect() with 0 to support the former
 425 * case).
 426 *
 427 * Does not return a negative value on error; it just dies.
 428 */
 429pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
 430{
 431        char *host, *path = url;
 432        char *end;
 433        int c;
 434        int pipefd[2][2];
 435        pid_t pid;
 436        enum protocol protocol = PROTO_LOCAL;
 437        int free_path = 0;
 438
 439        /* Without this we cannot rely on waitpid() to tell
 440         * what happened to our children.
 441         */
 442        signal(SIGCHLD, SIG_DFL);
 443
 444        host = strstr(url, "://");
 445        if(host) {
 446                *host = '\0';
 447                protocol = get_protocol(url);
 448                host += 3;
 449                c = '/';
 450        } else {
 451                host = url;
 452                c = ':';
 453        }
 454
 455        if (host[0] == '[') {
 456                end = strchr(host + 1, ']');
 457                if (end) {
 458                        *end = 0;
 459                        end++;
 460                        host++;
 461                } else
 462                        end = host;
 463        } else
 464                end = host;
 465
 466        path = strchr(end, c);
 467        if (c == ':') {
 468                if (path) {
 469                        protocol = PROTO_SSH;
 470                        *path++ = '\0';
 471                } else
 472                        path = host;
 473        }
 474
 475        if (!path || !*path)
 476                die("No path specified. See 'man git-pull' for valid url syntax");
 477
 478        /*
 479         * null-terminate hostname and point path to ~ for URL's like this:
 480         *    ssh://host.xz/~user/repo
 481         */
 482        if (protocol != PROTO_LOCAL && host != url) {
 483                char *ptr = path;
 484                if (path[1] == '~')
 485                        path++;
 486                else {
 487                        path = xstrdup(ptr);
 488                        free_path = 1;
 489                }
 490
 491                *ptr = '\0';
 492        }
 493
 494        if (protocol == PROTO_GIT) {
 495                /* These underlying connection commands die() if they
 496                 * cannot connect.
 497                 */
 498                char *target_host = xstrdup(host);
 499                if (git_use_proxy(host))
 500                        git_proxy_connect(fd, host);
 501                else
 502                        git_tcp_connect(fd, host, flags);
 503                /*
 504                 * Separate original protocol components prog and path
 505                 * from extended components with a NUL byte.
 506                 */
 507                packet_write(fd[1],
 508                             "%s %s%chost=%s%c",
 509                             prog, path, 0,
 510                             target_host, 0);
 511                free(target_host);
 512                if (free_path)
 513                        free(path);
 514                return 0;
 515        }
 516
 517        if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
 518                die("unable to create pipe pair for communication");
 519        pid = fork();
 520        if (pid < 0)
 521                die("unable to fork");
 522        if (!pid) {
 523                char command[MAX_CMD_LEN];
 524                char *posn = command;
 525                int size = MAX_CMD_LEN;
 526                int of = 0;
 527
 528                of |= add_to_string(&posn, &size, prog, 0);
 529                of |= add_to_string(&posn, &size, " ", 0);
 530                of |= add_to_string(&posn, &size, path, 1);
 531
 532                if (of)
 533                        die("command line too long");
 534
 535                dup2(pipefd[1][0], 0);
 536                dup2(pipefd[0][1], 1);
 537                close(pipefd[0][0]);
 538                close(pipefd[0][1]);
 539                close(pipefd[1][0]);
 540                close(pipefd[1][1]);
 541                if (protocol == PROTO_SSH) {
 542                        const char *ssh, *ssh_basename;
 543                        ssh = getenv("GIT_SSH");
 544                        if (!ssh) ssh = "ssh";
 545                        ssh_basename = strrchr(ssh, '/');
 546                        if (!ssh_basename)
 547                                ssh_basename = ssh;
 548                        else
 549                                ssh_basename++;
 550                        execlp(ssh, ssh_basename, host, command, NULL);
 551                }
 552                else {
 553                        unsetenv(ALTERNATE_DB_ENVIRONMENT);
 554                        unsetenv(DB_ENVIRONMENT);
 555                        unsetenv(GIT_DIR_ENVIRONMENT);
 556                        unsetenv(GRAFT_ENVIRONMENT);
 557                        unsetenv(INDEX_ENVIRONMENT);
 558                        execlp("sh", "sh", "-c", command, NULL);
 559                }
 560                die("exec failed");
 561        }
 562        fd[0] = pipefd[0][0];
 563        fd[1] = pipefd[1][1];
 564        close(pipefd[0][1]);
 565        close(pipefd[1][0]);
 566        if (free_path)
 567                free(path);
 568        return pid;
 569}
 570
 571int finish_connect(pid_t pid)
 572{
 573        if (pid == 0)
 574                return 0;
 575
 576        while (waitpid(pid, NULL, 0) < 0) {
 577                if (errno != EINTR)
 578                        return -1;
 579        }
 580        return 0;
 581}