sideband.con commit Merge branch 'jk/doc-the-this' into next (6625e50)
   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 *term, *suffix;
  24        char buf[LARGE_PACKET_MAX + 1];
  25        struct strbuf outbuf = STRBUF_INIT;
  26        int retval = 0;
  27
  28        term = getenv("TERM");
  29        if (isatty(2) && term && strcmp(term, "dumb"))
  30                suffix = ANSI_SUFFIX;
  31        else
  32                suffix = DUMB_SUFFIX;
  33
  34        while (!retval) {
  35                const char *b, *brk;
  36                int band, len;
  37                len = packet_read(in_stream, NULL, NULL, buf, LARGE_PACKET_MAX, 0);
  38                if (len == 0)
  39                        break;
  40                if (len < 1) {
  41                        strbuf_addf(&outbuf,
  42                                    "%s%s: protocol error: no band designator",
  43                                    outbuf.len ? "\n" : "", me);
  44                        retval = SIDEBAND_PROTOCOL_ERROR;
  45                        break;
  46                }
  47                band = buf[0] & 0xff;
  48                buf[len] = '\0';
  49                len--;
  50                switch (band) {
  51                case 3:
  52                        strbuf_addf(&outbuf, "%s%s%s", outbuf.len ? "\n" : "",
  53                                    PREFIX, buf + 1);
  54                        retval = SIDEBAND_REMOTE_ERROR;
  55                        break;
  56                case 2:
  57                        b = buf + 1;
  58
  59                        /*
  60                         * Append a suffix to each nonempty line to clear the
  61                         * end of the screen line.
  62                         *
  63                         * The output is accumulated in a buffer and
  64                         * each line is printed to stderr using
  65                         * write(2) to ensure inter-process atomicity.
  66                         */
  67                        while ((brk = strpbrk(b, "\n\r"))) {
  68                                int linelen = brk - b;
  69
  70                                if (!outbuf.len)
  71                                        strbuf_addstr(&outbuf, PREFIX);
  72                                if (linelen > 0) {
  73                                        strbuf_addf(&outbuf, "%.*s%s%c",
  74                                                    linelen, b, suffix, *brk);
  75                                } else {
  76                                        strbuf_addch(&outbuf, *brk);
  77                                }
  78                                xwrite(2, outbuf.buf, outbuf.len);
  79                                strbuf_reset(&outbuf);
  80
  81                                b = brk + 1;
  82                        }
  83
  84                        if (*b)
  85                                strbuf_addf(&outbuf, "%s%s",
  86                                            outbuf.len ? "" : PREFIX, b);
  87                        break;
  88                case 1:
  89                        write_or_die(out, buf + 1, len);
  90                        break;
  91                default:
  92                        strbuf_addf(&outbuf, "%s%s: protocol error: bad band #%d",
  93                                    outbuf.len ? "\n" : "", me, band);
  94                        retval = SIDEBAND_PROTOCOL_ERROR;
  95                        break;
  96                }
  97        }
  98
  99        if (outbuf.len) {
 100                strbuf_addch(&outbuf, '\n');
 101                xwrite(2, outbuf.buf, outbuf.len);
 102        }
 103        strbuf_release(&outbuf);
 104        return retval;
 105}
 106
 107/*
 108 * fd is connected to the remote side; send the sideband data
 109 * over multiplexed packet stream.
 110 */
 111void send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max)
 112{
 113        const char *p = data;
 114
 115        while (sz) {
 116                unsigned n;
 117                char hdr[5];
 118
 119                n = sz;
 120                if (packet_max - 5 < n)
 121                        n = packet_max - 5;
 122                if (0 <= band) {
 123                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 5);
 124                        hdr[4] = band;
 125                        write_or_die(fd, hdr, 5);
 126                } else {
 127                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 4);
 128                        write_or_die(fd, hdr, 4);
 129                }
 130                write_or_die(fd, p, n);
 131                p += n;
 132                sz -= n;
 133        }
 134}