mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 13:30:17 +00:00 
			
		
		
		
	* version.h.in: (pid_output*) add const qualifier.
	* command.h: Change DEFUN func to take const char *[] rather
          than char **, to begin process of fixing compile warnings in lib/.
          Nearly all other changes in this commit follow from this change.
        * buffer.{c,h}: (buffer_write) pointer-arithmetic is gccism, take
          const void * and cast an automatic const char *p to it.
          (buffer_putstr) add const
        * command.c: (zencrypt) const qualifier
          (cmd_execute_command_real) ditto
          (cmd_execute_command_strict) ditto
          (config_log_file) ditto.
          Fix leak of getcwd() returned string.
        * memory.{c,h}: Add MTYPE_DISTRIBUTE_IFNAME for struct dist ifname.
        * distribute.{c,h}: Update with const qualifier.
          (distribute_free) use MTYPE_DISTRIBUTE_IFNAME
          (distribute_lookup) Cast to char *, note that it's ok.
          (distribute_hash_alloc) use MTYPE_DISTRIBUTE_IFNAME.
          (distribute_get)  Cast to char *, note that it's ok.
        * filter.c: Update with const qualifier.
        * if.{c,h}: ditto.
        * if_rmap.{c,h}: ditto.
          (if_rmap_lookup) Cast to char *, note that it's ok.
          (if_rmap_get) ditto.
        * log.{c,h}: Update with const qualifier.
        * plist.{c,h}: ditto.
        * routemap.{c,h}: ditto.
        * smux.{c,h}: ditto. Fix some signed/unsigned comparisons.
        * sockopt.c: (getsockopt_cmsg_data) add return for error case.
        * vty.c: Update with const qualifier.
		
	
			
		
			
				
	
	
		
			569 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			569 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Buffering of output and input. 
 | 
						|
 * Copyright (C) 1998 Kunihiro Ishiguro
 | 
						|
 *
 | 
						|
 * This file is part of GNU Zebra.
 | 
						|
 *
 | 
						|
 * GNU Zebra is free software; you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License as published
 | 
						|
 * by the Free Software Foundation; either version 2, or (at your
 | 
						|
 * option) any later version.
 | 
						|
 * 
 | 
						|
 * GNU Zebra is distributed in the hope that it will be useful, but
 | 
						|
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with GNU Zebra; see the file COPYING.  If not, write to the
 | 
						|
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
						|
 * Boston, MA 02111-1307, USA. 
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "memory.h"
 | 
						|
#include "buffer.h"
 | 
						|
 | 
						|
/* Make buffer data. */
 | 
						|
struct buffer_data *
 | 
						|
buffer_data_new (size_t size)
 | 
						|
{
 | 
						|
  struct buffer_data *d;
 | 
						|
 | 
						|
  d = XMALLOC (MTYPE_BUFFER_DATA, sizeof (struct buffer_data));
 | 
						|
  memset (d, 0, sizeof (struct buffer_data));
 | 
						|
  d->data = XMALLOC (MTYPE_BUFFER_DATA, size);
 | 
						|
 | 
						|
  return d;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
buffer_data_free (struct buffer_data *d)
 | 
						|
{
 | 
						|
  if (d->data)
 | 
						|
    XFREE (MTYPE_BUFFER_DATA, d->data);
 | 
						|
  XFREE (MTYPE_BUFFER_DATA, d);
 | 
						|
}
 | 
						|
 | 
						|
/* Make new buffer. */
 | 
						|
struct buffer *
 | 
						|
buffer_new (size_t size)
 | 
						|
{
 | 
						|
  struct buffer *b;
 | 
						|
 | 
						|
  b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer));
 | 
						|
  memset (b, 0, sizeof (struct buffer));
 | 
						|
 | 
						|
  b->size = size;
 | 
						|
 | 
						|
  return b;
 | 
						|
}
 | 
						|
 | 
						|
/* Free buffer. */
 | 
						|
void
 | 
						|
buffer_free (struct buffer *b)
 | 
						|
{
 | 
						|
  struct buffer_data *d;
 | 
						|
  struct buffer_data *next;
 | 
						|
 | 
						|
  d = b->head;
 | 
						|
  while (d)
 | 
						|
    {
 | 
						|
      next = d->next;
 | 
						|
      buffer_data_free (d);
 | 
						|
      d = next;
 | 
						|
    }
 | 
						|
 | 
						|
  d = b->unused_head;
 | 
						|
  while (d)
 | 
						|
    {
 | 
						|
      next = d->next;
 | 
						|
      buffer_data_free (d);
 | 
						|
      d = next;
 | 
						|
    }
 | 
						|
  
 | 
						|
  XFREE (MTYPE_BUFFER, b);
 | 
						|
}
 | 
						|
 | 
						|
/* Make string clone. */
 | 
						|
char *
 | 
						|
buffer_getstr (struct buffer *b)
 | 
						|
{
 | 
						|
  return strdup ((char *)b->head->data);
 | 
						|
}
 | 
						|
 | 
						|
/* Return 1 if buffer is empty. */
 | 
						|
int
 | 
						|
buffer_empty (struct buffer *b)
 | 
						|
{
 | 
						|
  if (b->tail == NULL || b->tail->cp == b->tail->sp)
 | 
						|
    return 1;
 | 
						|
  else
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Clear and free all allocated data. */
 | 
						|
void
 | 
						|
buffer_reset (struct buffer *b)
 | 
						|
{
 | 
						|
  struct buffer_data *data;
 | 
						|
  struct buffer_data *next;
 | 
						|
  
 | 
						|
  for (data = b->head; data; data = next)
 | 
						|
    {
 | 
						|
      next = data->next;
 | 
						|
      buffer_data_free (data);
 | 
						|
    }
 | 
						|
  b->head = b->tail = NULL;
 | 
						|
  b->alloc = 0;
 | 
						|
  b->length = 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Add buffer_data to the end of buffer. */
 | 
						|
void
 | 
						|
buffer_add (struct buffer *b)
 | 
						|
{
 | 
						|
  struct buffer_data *d;
 | 
						|
 | 
						|
  d = buffer_data_new (b->size);
 | 
						|
 | 
						|
  if (b->tail == NULL)
 | 
						|
    {
 | 
						|
      d->prev = NULL;
 | 
						|
      d->next = NULL;
 | 
						|
      b->head = d;
 | 
						|
      b->tail = d;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      d->prev = b->tail;
 | 
						|
      d->next = NULL;
 | 
						|
 | 
						|
      b->tail->next = d;
 | 
						|
      b->tail = d;
 | 
						|
    }
 | 
						|
 | 
						|
  b->alloc++;
 | 
						|
}
 | 
						|
 | 
						|
/* Write data to buffer. */
 | 
						|
int
 | 
						|
buffer_write (struct buffer *b, const void *p, size_t size)
 | 
						|
{
 | 
						|
  struct buffer_data *data;
 | 
						|
  const char *ptr = p;
 | 
						|
  data = b->tail;
 | 
						|
  b->length += size;
 | 
						|
 | 
						|
  /* We use even last one byte of data buffer. */
 | 
						|
  while (size)    
 | 
						|
    {
 | 
						|
      /* If there is no data buffer add it. */
 | 
						|
      if (data == NULL || data->cp == b->size)
 | 
						|
	{
 | 
						|
	  buffer_add (b);
 | 
						|
	  data = b->tail;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Last data. */
 | 
						|
      if (size <= (b->size - data->cp))
 | 
						|
	{
 | 
						|
	  memcpy ((data->data + data->cp), ptr, size);
 | 
						|
 | 
						|
	  data->cp += size;
 | 
						|
	  size = 0;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  memcpy ((data->data + data->cp), ptr, (b->size - data->cp));
 | 
						|
 | 
						|
	  size -= (b->size - data->cp);
 | 
						|
	  ptr += (b->size - data->cp);
 | 
						|
 | 
						|
	  data->cp = b->size;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* Insert character into the buffer. */
 | 
						|
int
 | 
						|
buffer_putc (struct buffer *b, u_char c)
 | 
						|
{
 | 
						|
  buffer_write (b, &c, 1);
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* Insert word (2 octets) into ther buffer. */
 | 
						|
int
 | 
						|
buffer_putw (struct buffer *b, u_short c)
 | 
						|
{
 | 
						|
  buffer_write (b, (char *)&c, 2);
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* Put string to the buffer. */
 | 
						|
int
 | 
						|
buffer_putstr (struct buffer *b, const char *c)
 | 
						|
{
 | 
						|
  size_t size;
 | 
						|
 | 
						|
  size = strlen (c);
 | 
						|
  buffer_write (b, (void *) c, size);
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* Flush specified size to the fd. */
 | 
						|
void
 | 
						|
buffer_flush (struct buffer *b, int fd, size_t size)
 | 
						|
{
 | 
						|
  int iov_index;
 | 
						|
  struct iovec *iovec;
 | 
						|
  struct buffer_data *data;
 | 
						|
  struct buffer_data *out;
 | 
						|
  struct buffer_data *next;
 | 
						|
 | 
						|
  iovec = malloc (sizeof (struct iovec) * b->alloc);
 | 
						|
  iov_index = 0;
 | 
						|
 | 
						|
  for (data = b->head; data; data = data->next)
 | 
						|
    {
 | 
						|
      iovec[iov_index].iov_base = (char *)(data->data + data->sp);
 | 
						|
 | 
						|
      if (size <= (data->cp - data->sp))
 | 
						|
	{
 | 
						|
	  iovec[iov_index++].iov_len = size;
 | 
						|
	  data->sp += size;
 | 
						|
	  if (data->sp == data->cp)
 | 
						|
	    data = data->next;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  iovec[iov_index++].iov_len = data->cp - data->sp;
 | 
						|
	  size -= data->cp - data->sp;
 | 
						|
	  data->sp = data->cp;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  /* Write buffer to the fd. */
 | 
						|
  writev (fd, iovec, iov_index);
 | 
						|
 | 
						|
  /* Free printed buffer data. */
 | 
						|
  for (out = b->head; out && out != data; out = next)
 | 
						|
    {
 | 
						|
      next = out->next;
 | 
						|
      if (next)
 | 
						|
	next->prev = NULL;
 | 
						|
      else
 | 
						|
	b->tail = next;
 | 
						|
      b->head = next;
 | 
						|
 | 
						|
      buffer_data_free (out);
 | 
						|
      b->alloc--;
 | 
						|
    }
 | 
						|
 | 
						|
  free (iovec);
 | 
						|
}
 | 
						|
 | 
						|
/* Flush all buffer to the fd. */
 | 
						|
int
 | 
						|
buffer_flush_all (struct buffer *b, int fd)
 | 
						|
{
 | 
						|
  int ret;
 | 
						|
  struct buffer_data *d;
 | 
						|
  int iov_index;
 | 
						|
  struct iovec *iovec;
 | 
						|
 | 
						|
  if (buffer_empty (b))
 | 
						|
    return 0;
 | 
						|
 | 
						|
  iovec = malloc (sizeof (struct iovec) * b->alloc);
 | 
						|
  iov_index = 0;
 | 
						|
 | 
						|
  for (d = b->head; d; d = d->next)
 | 
						|
    {
 | 
						|
      iovec[iov_index].iov_base = (char *)(d->data + d->sp);
 | 
						|
      iovec[iov_index].iov_len = d->cp - d->sp;
 | 
						|
      iov_index++;
 | 
						|
    }
 | 
						|
  ret = writev (fd, iovec, iov_index);
 | 
						|
 | 
						|
  free (iovec);
 | 
						|
 | 
						|
  buffer_reset (b);
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
/* Flush all buffer to the fd. */
 | 
						|
int
 | 
						|
buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag,
 | 
						|
		      int no_more_flag)
 | 
						|
{
 | 
						|
  int nbytes;
 | 
						|
  int iov_index;
 | 
						|
  struct iovec *iov;
 | 
						|
  struct iovec small_iov[3];
 | 
						|
  char more[] = " --More-- ";
 | 
						|
  char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
 | 
						|
		   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 | 
						|
		   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
 | 
						|
  struct buffer_data *data;
 | 
						|
  struct buffer_data *out;
 | 
						|
  struct buffer_data *next;
 | 
						|
 | 
						|
  /* For erase and more data add two to b's buffer_data count.*/
 | 
						|
  if (b->alloc == 1)
 | 
						|
    iov = small_iov;
 | 
						|
  else
 | 
						|
    iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
 | 
						|
 | 
						|
  data = b->head;
 | 
						|
  iov_index = 0;
 | 
						|
 | 
						|
  /* Previously print out is performed. */
 | 
						|
  if (erase_flag)
 | 
						|
    {
 | 
						|
      iov[iov_index].iov_base = erase;
 | 
						|
      iov[iov_index].iov_len = sizeof erase;
 | 
						|
      iov_index++;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Output data. */
 | 
						|
  for (data = b->head; data; data = data->next)
 | 
						|
    {
 | 
						|
      iov[iov_index].iov_base = (char *)(data->data + data->sp);
 | 
						|
      iov[iov_index].iov_len = data->cp - data->sp;
 | 
						|
      iov_index++;
 | 
						|
    }
 | 
						|
 | 
						|
  /* In case of `more' display need. */
 | 
						|
  if (! buffer_empty (b) && !no_more_flag)
 | 
						|
    {
 | 
						|
      iov[iov_index].iov_base = more;
 | 
						|
      iov[iov_index].iov_len = sizeof more;
 | 
						|
      iov_index++;
 | 
						|
    }
 | 
						|
 | 
						|
  /* We use write or writev*/
 | 
						|
  nbytes = writev (fd, iov, iov_index);
 | 
						|
 | 
						|
  /* Error treatment. */
 | 
						|
  if (nbytes < 0)
 | 
						|
    {
 | 
						|
      if (errno == EINTR)
 | 
						|
	;
 | 
						|
      if (errno == EWOULDBLOCK)
 | 
						|
	;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Free printed buffer data. */
 | 
						|
  for (out = b->head; out && out != data; out = next)
 | 
						|
    {
 | 
						|
      next = out->next;
 | 
						|
      if (next)
 | 
						|
	next->prev = NULL;
 | 
						|
      else
 | 
						|
	b->tail = next;
 | 
						|
      b->head = next;
 | 
						|
 | 
						|
      buffer_data_free (out);
 | 
						|
      b->alloc--;
 | 
						|
    }
 | 
						|
 | 
						|
  if (iov != small_iov)
 | 
						|
    XFREE (MTYPE_TMP, iov);
 | 
						|
 | 
						|
  return nbytes;
 | 
						|
}
 | 
						|
 | 
						|
/* Flush buffer to the file descriptor.  Mainly used from vty
 | 
						|
   interface. */
 | 
						|
int
 | 
						|
buffer_flush_vty (struct buffer *b, int fd, unsigned int size, 
 | 
						|
		  int erase_flag, int no_more_flag)
 | 
						|
{
 | 
						|
  int nbytes;
 | 
						|
  int iov_index;
 | 
						|
  struct iovec *iov;
 | 
						|
  struct iovec small_iov[3];
 | 
						|
  char more[] = " --More-- ";
 | 
						|
  char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
 | 
						|
		   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 | 
						|
		   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
 | 
						|
  struct buffer_data *data;
 | 
						|
  struct buffer_data *out;
 | 
						|
  struct buffer_data *next;
 | 
						|
 | 
						|
#ifdef  IOV_MAX
 | 
						|
  int iov_size;
 | 
						|
  int total_size;
 | 
						|
  struct iovec *c_iov;
 | 
						|
  int c_nbytes;
 | 
						|
#endif /* IOV_MAX */
 | 
						|
 | 
						|
  /* For erase and more data add two to b's buffer_data count.*/
 | 
						|
  if (b->alloc == 1)
 | 
						|
    iov = small_iov;
 | 
						|
  else
 | 
						|
    iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
 | 
						|
 | 
						|
  data = b->head;
 | 
						|
  iov_index = 0;
 | 
						|
 | 
						|
  /* Previously print out is performed. */
 | 
						|
  if (erase_flag)
 | 
						|
    {
 | 
						|
      iov[iov_index].iov_base = erase;
 | 
						|
      iov[iov_index].iov_len = sizeof erase;
 | 
						|
      iov_index++;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Output data. */
 | 
						|
  for (data = b->head; data; data = data->next)
 | 
						|
    {
 | 
						|
      iov[iov_index].iov_base = (char *)(data->data + data->sp);
 | 
						|
 | 
						|
      if (size <= (data->cp - data->sp))
 | 
						|
	{
 | 
						|
	  iov[iov_index++].iov_len = size;
 | 
						|
	  data->sp += size;
 | 
						|
	  if (data->sp == data->cp)
 | 
						|
	    data = data->next;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  iov[iov_index++].iov_len = data->cp - data->sp;
 | 
						|
	  size -= (data->cp - data->sp);
 | 
						|
	  data->sp = data->cp;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  /* In case of `more' display need. */
 | 
						|
  if (!buffer_empty (b) && !no_more_flag)
 | 
						|
    {
 | 
						|
      iov[iov_index].iov_base = more;
 | 
						|
      iov[iov_index].iov_len = sizeof more;
 | 
						|
      iov_index++;
 | 
						|
    }
 | 
						|
 | 
						|
  /* We use write or writev*/
 | 
						|
 | 
						|
#ifdef IOV_MAX
 | 
						|
  /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
 | 
						|
     example: Solaris2.6 are defined IOV_MAX size at 16.     */
 | 
						|
  c_iov = iov;
 | 
						|
  total_size = iov_index;
 | 
						|
  nbytes = 0;
 | 
						|
 | 
						|
  while( total_size > 0 )
 | 
						|
    {
 | 
						|
       /* initialize write vector size at once */
 | 
						|
       iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size;
 | 
						|
 | 
						|
       c_nbytes = writev (fd, c_iov, iov_size );
 | 
						|
 | 
						|
       if( c_nbytes < 0 )
 | 
						|
         {
 | 
						|
           if(errno == EINTR)
 | 
						|
             ;
 | 
						|
             ;
 | 
						|
           if(errno == EWOULDBLOCK)
 | 
						|
             ;
 | 
						|
             ;
 | 
						|
           nbytes = c_nbytes;
 | 
						|
           break;
 | 
						|
 | 
						|
         }
 | 
						|
 | 
						|
        nbytes += c_nbytes;
 | 
						|
 | 
						|
       /* move pointer io-vector */
 | 
						|
       c_iov += iov_size;
 | 
						|
       total_size -= iov_size;
 | 
						|
    }
 | 
						|
#else  /* IOV_MAX */
 | 
						|
   nbytes = writev (fd, iov, iov_index);
 | 
						|
 | 
						|
  /* Error treatment. */
 | 
						|
  if (nbytes < 0)
 | 
						|
    {
 | 
						|
      if (errno == EINTR)
 | 
						|
	;
 | 
						|
      if (errno == EWOULDBLOCK)
 | 
						|
	;
 | 
						|
    }
 | 
						|
#endif /* IOV_MAX */
 | 
						|
 | 
						|
  /* Free printed buffer data. */
 | 
						|
  for (out = b->head; out && out != data; out = next)
 | 
						|
    {
 | 
						|
      next = out->next;
 | 
						|
      if (next)
 | 
						|
	next->prev = NULL;
 | 
						|
      else
 | 
						|
	b->tail = next;
 | 
						|
      b->head = next;
 | 
						|
 | 
						|
      buffer_data_free (out);
 | 
						|
      b->alloc--;
 | 
						|
    }
 | 
						|
 | 
						|
  if (iov != small_iov)
 | 
						|
    XFREE (MTYPE_TMP, iov);
 | 
						|
 | 
						|
  return nbytes;
 | 
						|
}
 | 
						|
 | 
						|
/* Calculate size of outputs then flush buffer to the file
 | 
						|
   descriptor. */
 | 
						|
int
 | 
						|
buffer_flush_window (struct buffer *b, int fd, int width, int height, 
 | 
						|
		     int erase, int no_more)
 | 
						|
{
 | 
						|
  unsigned long cp;
 | 
						|
  unsigned long size;
 | 
						|
  int lp;
 | 
						|
  int lineno;
 | 
						|
  struct buffer_data *data;
 | 
						|
 | 
						|
  if (height >= 2)
 | 
						|
    height--;
 | 
						|
 | 
						|
  /* We have to calculate how many bytes should be written. */
 | 
						|
  lp = 0;
 | 
						|
  lineno = 0;
 | 
						|
  size = 0;
 | 
						|
  
 | 
						|
  for (data = b->head; data; data = data->next)
 | 
						|
    {
 | 
						|
      cp = data->sp;
 | 
						|
 | 
						|
      while (cp < data->cp)
 | 
						|
	{
 | 
						|
	  if (data->data[cp] == '\n' || lp == width)
 | 
						|
	    {
 | 
						|
	      lineno++;
 | 
						|
	      if (lineno == height)
 | 
						|
		{
 | 
						|
		  cp++;
 | 
						|
		  size++;
 | 
						|
		  goto flush;
 | 
						|
		}
 | 
						|
	      lp = 0;
 | 
						|
	    }
 | 
						|
	  cp++;
 | 
						|
	  lp++;
 | 
						|
	  size++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  /* Write data to the file descriptor. */
 | 
						|
 flush:
 | 
						|
 | 
						|
  return buffer_flush_vty (b, fd, size, erase, no_more);
 | 
						|
}
 |