Merge pull request #1982 from qlyoung/fixup-vtysh-read

vtysh: fixup incorrect read logic
This commit is contained in:
Jafar Al-Gharaibeh 2018-04-10 13:20:00 +04:00 committed by GitHub
commit aa2fc55b20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -141,21 +141,22 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
bufvalid += nread; bufvalid += nread;
/*
* We expect string output from daemons, so instead of looking
* for the full 3 null bytes of the terminator, we check for
* just one instead and assume it is the first byte of the
* terminator. The presence of the full terminator is checked
* later.
*/
if (bufvalid - buf >= 4) if (bufvalid - buf >= 4)
end = memmem(bufvalid - 4, 4, terminator, end = memmem(bufvalid - 4, 4, "\0", 1);
sizeof(terminator));
if (end && end + sizeof(terminator) + 1 > bufvalid)
/* found \0\0\0 but return code hasn't been read yet */
end = NULL;
if (end)
ret = end[sizeof(terminator)];
/* /*
* calculate # bytes we have, up to & not including the * calculate # bytes we have, up to & not including the
* terminator if present * terminator if present
*/ */
size_t textlen = (end ? end : bufvalid) - buf; size_t textlen = (end ? end : bufvalid) - buf;
bool b = false;
/* feed line processing callback if present */ /* feed line processing callback if present */
while (callback && bufvalid > buf && (end > buf || !end)) { while (callback && bufvalid > buf && (end > buf || !end)) {
@ -165,16 +166,38 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
/* line break */ /* line break */
*eol++ = '\0'; *eol++ = '\0';
else if (end == buf) else if (end == buf)
/* no line break, end of input, no text left /*
* before end * no line break, end of input, no text left
* => don't insert an empty line at the end */ * before end; nothing to write
break; */
b = true;
else if (end) else if (end)
/* no line break, end of input, but some text /* no nl, end of input, but some text left */
* left */
eol = end; eol = end;
else else if (bufvalid == buf + bufsz) {
/* continue reading */ /*
* no nl, no end of input, no buffer space;
* realloc
*/
char *new;
bufsz *= 2;
if (buf == stackbuf) {
new = XMALLOC(MTYPE_TMP, bufsz);
memcpy(new, stackbuf, sizeof(stackbuf));
} else
new = XREALLOC(MTYPE_TMP, buf, bufsz);
bufvalid = bufvalid - buf + new;
buf = new;
/* if end != NULL, we won't be reading more
* data... */
assert(end == NULL);
b = true;
} else
b = true;
if (b)
break; break;
/* eol is at line end now, either \n => \0 or \0\0\0 */ /* eol is at line end now, either \n => \0 or \0\0\0 */
@ -187,10 +210,7 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
if (callback) if (callback)
callback(cbarg, buf); callback(cbarg, buf);
if (eol == end) /* shift back data and adjust bufvalid */
/* \n\0\0\0 */
break;
memmove(buf, eol, bufvalid - eol); memmove(buf, eol, bufvalid - eol);
bufvalid -= eol - buf; bufvalid -= eol - buf;
if (end) if (end)
@ -203,23 +223,28 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
fwrite(buf, 1, textlen, fp); fwrite(buf, 1, textlen, fp);
memmove(buf, buf + textlen, bufvalid - buf - textlen); memmove(buf, buf + textlen, bufvalid - buf - textlen);
bufvalid -= textlen; bufvalid -= textlen;
if (end)
end -= textlen;
/*
* ----------------------------------------------------
* At this point `buf` should be in one of two states:
* - Empty (i.e. buf == bufvalid)
* - Contains up to 4 bytes of the terminator
* ----------------------------------------------------
*/
assert(((buf == bufvalid)
|| (bufvalid - buf <= 4 && buf[0] == 0x00)));
} }
if (bufvalid == buf + bufsz) { /* if we have the terminator, break */
char *new; if (end && bufvalid - buf == 4) {
bufsz *= 2; assert(!memcmp(buf, terminator, 3));
if (buf == stackbuf) { ret = buf[3];
new = XMALLOC(MTYPE_TMP, bufsz); break;
memcpy(new, stackbuf, sizeof(stackbuf));
} else
new = XREALLOC(MTYPE_TMP, buf, bufsz);
bufvalid = bufvalid - buf + new;
buf = new;
/* if end != NULL, we won't be reading more data... */
assert(end == NULL);
} }
} while (!end);
} while (true);
goto out; goto out;
out_err: out_err: