Merge branch 'jk/tighten-alloc' into maint
[git] / sideband.c
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
21 int 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  */
111 void 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 }