vtysh: When the config file is close to the boundry of size of buffer vtysh hangs.
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index b55c671..2703bb9 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -87,9 +87,9 @@
/* Following filled with debug code to trace a problematic condition
* under load - it SHOULD handle it. */
-#define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): "
+#define ERR_WHERE_STRING "vtysh(): vtysh_client_execute(): "
static int
-vtysh_client_config (struct vtysh_client *vclient, char *line)
+vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp)
{
int ret;
char *buf;
@@ -100,6 +100,7 @@
int nbytes;
int i;
int readln;
+ int numnulls = 0;
if (vclient->fd < 0)
return CMD_SUCCESS;
@@ -145,111 +146,87 @@
XFREE(MTYPE_TMP, buf);
return CMD_SUCCESS;
}
+ /* If we have already seen 3 nulls, then current byte is ret code */
+ if ((numnulls == 3) && (nbytes == 1))
+ {
+ ret = pbuf[0];
+ break;
+ }
pbuf[nbytes] = '\0';
- if (nbytes >= 4)
- {
- i = nbytes - 4;
- if (pbuf[i] == '\0' && pbuf[i + 1] == '\0' && pbuf[i + 2] == '\0')
- {
- ret = pbuf[i + 3];
- break;
- }
- }
- pbuf += nbytes;
+ /* If the config needs to be written in file or stdout */
+ if (fp)
+ {
+ fputs(pbuf, fp);
+ fflush (fp);
+ }
- /* See if a line exists in buffer, if so parse and consume it, and
- * reset read position. */
- if ((eoln = strrchr(buf, '\n')) == NULL)
- continue;
+ /* At max look last four bytes */
+ if (nbytes >= 4)
+ {
+ i = nbytes - 4;
+ numnulls = 0;
+ }
+ else
+ i = 0;
- if (eoln >= ((buf + bufsz) - 1))
- {
- fprintf (stderr, ERR_WHERE_STRING \
- "warning - eoln beyond buffer end.\n");
- }
- vtysh_config_parse(buf);
+ /* Count the numnulls */
+ while (i < nbytes && numnulls <3)
+ {
+ if (pbuf[i++] == '\0')
+ numnulls++;
+ else
+ numnulls = 0;
+ }
+ /* We might have seen 3 consecutive nulls so store the ret code before updating pbuf*/
+ ret = pbuf[nbytes-1];
+ pbuf += nbytes;
- eoln++;
- left = (size_t)(buf + bufsz - eoln);
- memmove(buf, eoln, left);
- buf[bufsz-1] = '\0';
- pbuf = buf + strlen(buf);
+ /* See if a line exists in buffer, if so parse and consume it, and
+ * reset read position. If 3 nulls has been encountered consume the buffer before
+ * next read.
+ */
+ if (((eoln = strrchr(buf, '\n')) == NULL) && (numnulls<3))
+ continue;
+
+ if (eoln >= ((buf + bufsz) - 1))
+ {
+ fprintf (stderr, ERR_WHERE_STRING \
+ "warning - eoln beyond buffer end.\n");
+ }
+
+ /* If the config needs parsing, consume it */
+ if(!fp)
+ vtysh_config_parse(buf);
+
+ eoln++;
+ left = (size_t)(buf + bufsz - eoln);
+ /*
+ * This check is required since when a config line split between two consecutive reads,
+ * then buf will have first half of config line and current read will bring rest of the
+ * line. So in this case eoln will be 1 here, hence calculation of left will be wrong.
+ * In this case we don't need to do memmove, because we have already seen 3 nulls.
+ */
+ if(left < bufsz)
+ memmove(buf, eoln, left);
+
+ buf[bufsz-1] = '\0';
+ pbuf = buf + strlen(buf);
+ /* got 3 or more trailing NULs? */
+ if ((numnulls >=3) && (i < nbytes))
+ {
+ break;
+ }
}
- /* Parse anything left in the buffer. */
-
- vtysh_config_parse (buf);
+ if(!fp)
+ vtysh_config_parse (buf);
XFREE(MTYPE_TMP, buf);
return ret;
}
-
-static int
-vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp)
-{
- int ret;
- char buf[1001];
- int nbytes;
- int i;
- int numnulls = 0;
-
- if (vclient->fd < 0)
- return CMD_SUCCESS;
-
- ret = write (vclient->fd, line, strlen (line) + 1);
- if (ret <= 0)
- {
- vclient_close (vclient);
- return CMD_SUCCESS;
- }
-
- while (1)
- {
- nbytes = read (vclient->fd, buf, sizeof(buf)-1);
-
- if (nbytes <= 0 && errno != EINTR)
- {
- vclient_close (vclient);
- return CMD_SUCCESS;
- }
-
- if (nbytes > 0)
- {
- if ((numnulls == 3) && (nbytes == 1))
- return buf[0];
-
- buf[nbytes] = '\0';
- fputs (buf, fp);
- fflush (fp);
-
- /* check for trailling \0\0\0<ret code>,
- * even if split across reads
- * (see lib/vty.c::vtysh_read)
- */
- if (nbytes >= 4)
- {
- i = nbytes-4;
- numnulls = 0;
- }
- else
- i = 0;
-
- while (i < nbytes && numnulls < 3)
- {
- if (buf[i++] == '\0')
- numnulls++;
- else
- numnulls = 0;
- }
-
- /* got 3 or more trailing NULs? */
- if ((numnulls >= 3) && (i < nbytes))
- return (buf[nbytes-1]);
- }
- }
-}
+
void
vtysh_pager_init (void)
@@ -1735,7 +1712,7 @@
vty_out (vty, "!%s", VTY_NEWLINE);
for (i = 0; i < array_size(vtysh_client); i++)
- vtysh_client_config (&vtysh_client[i], line);
+ vtysh_client_execute (&vtysh_client[i], line, NULL);
/* Integrate vtysh specific configuration. */
vtysh_config_write ();
@@ -1836,7 +1813,7 @@
}
for (i = 0; i < array_size(vtysh_client); i++)
- vtysh_client_config (&vtysh_client[i], line);
+ vtysh_client_execute (&vtysh_client[i], line, NULL);
vtysh_config_dump (fp);