Merge branch 'jt/commit-graph-per-object-store'
[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 DISPLAY_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 *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                                     DISPLAY_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, DISPLAY_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", outbuf.len ?
85                                             "" : DISPLAY_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  */
110 void 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 }