sideband.con commit Merge branch 'ab/commit-m-with-fixup' into maint (c1ab3b8)
   1#include "cache.h"
   2#include "pkt-line.h"
   3#include "sideband.h"
   4
   5/*
   6 * Receive multiplexed output stream over git native protocol.
   7 * in_stream is the input stream from the remote, which carries data
   8 * in pkt_line format with band designator.  Demultiplex it into out
   9 * and err and return error appropriately.  Band #1 carries the
  10 * primary payload.  Things coming over band #2 is not necessarily
  11 * error; they are usually informative message on the standard error
  12 * stream, aka "verbose").  A message over band #3 is a signal that
  13 * the remote died unexpectedly.  A flush() concludes the stream.
  14 */
  15
  16#define PREFIX "remote: "
  17
  18#define ANSI_SUFFIX "\033[K"
  19#define DUMB_SUFFIX "        "
  20
  21int recv_sideband(const char *me, int in_stream, int out)
  22{
  23        const char *suffix;
  24        char buf[LARGE_PACKET_MAX + 1];
  25        struct strbuf outbuf = STRBUF_INIT;
  26        int retval = 0;
  27
  28        if (isatty(2) && !is_terminal_dumb())
  29                suffix = ANSI_SUFFIX;
  30        else
  31                suffix = DUMB_SUFFIX;
  32
  33        while (!retval) {
  34                const char *b, *brk;
  35                int band, len;
  36                len = packet_read(in_stream, NULL, NULL, buf, LARGE_PACKET_MAX, 0);
  37                if (len == 0)
  38                        break;
  39                if (len < 1) {
  40                        strbuf_addf(&outbuf,
  41                                    "%s%s: protocol error: no band designator",
  42                                    outbuf.len ? "\n" : "", me);
  43                        retval = SIDEBAND_PROTOCOL_ERROR;
  44                        break;
  45                }
  46                band = buf[0] & 0xff;
  47                buf[len] = '\0';
  48                len--;
  49                switch (band) {
  50                case 3:
  51                        strbuf_addf(&outbuf, "%s%s%s", outbuf.len ? "\n" : "",
  52                                    PREFIX, buf + 1);
  53                        retval = SIDEBAND_REMOTE_ERROR;
  54                        break;
  55                case 2:
  56                        b = buf + 1;
  57
  58                        /*
  59                         * Append a suffix to each nonempty line to clear the
  60                         * end of the screen line.
  61                         *
  62                         * The output is accumulated in a buffer and
  63                         * each line is printed to stderr using
  64                         * write(2) to ensure inter-process atomicity.
  65                         */
  66                        while ((brk = strpbrk(b, "\n\r"))) {
  67                                int linelen = brk - b;
  68
  69                                if (!outbuf.len)
  70                                        strbuf_addstr(&outbuf, PREFIX);
  71                                if (linelen > 0) {
  72                                        strbuf_addf(&outbuf, "%.*s%s%c",
  73                                                    linelen, b, suffix, *brk);
  74                                } else {
  75                                        strbuf_addch(&outbuf, *brk);
  76                                }
  77                                xwrite(2, outbuf.buf, outbuf.len);
  78                                strbuf_reset(&outbuf);
  79
  80                                b = brk + 1;
  81                        }
  82
  83                        if (*b)
  84                                strbuf_addf(&outbuf, "%s%s",
  85                                            outbuf.len ? "" : PREFIX, b);
  86                        break;
  87                case 1:
  88                        write_or_die(out, buf + 1, len);
  89                        break;
  90                default:
  91                        strbuf_addf(&outbuf, "%s%s: protocol error: bad band #%d",
  92                                    outbuf.len ? "\n" : "", me, band);
  93                        retval = SIDEBAND_PROTOCOL_ERROR;
  94                        break;
  95                }
  96        }
  97
  98        if (outbuf.len) {
  99                strbuf_addch(&outbuf, '\n');
 100                xwrite(2, outbuf.buf, outbuf.len);
 101        }
 102        strbuf_release(&outbuf);
 103        return retval;
 104}
 105
 106/*
 107 * fd is connected to the remote side; send the sideband data
 108 * over multiplexed packet stream.
 109 */
 110void send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max)
 111{
 112        const char *p = data;
 113
 114        while (sz) {
 115                unsigned n;
 116                char hdr[5];
 117
 118                n = sz;
 119                if (packet_max - 5 < n)
 120                        n = packet_max - 5;
 121                if (0 <= band) {
 122                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 5);
 123                        hdr[4] = band;
 124                        write_or_die(fd, hdr, 5);
 125                } else {
 126                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 4);
 127                        write_or_die(fd, hdr, 4);
 128                }
 129                write_or_die(fd, p, n);
 130                p += n;
 131                sz -= n;
 132        }
 133}