<commit_before>/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <sys/socket.h>
#include <sys/un.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#define DEBUG 0

#if DEBUG
#define TELCMDS
#define TELOPTS
#endif

#include <arpa/telnet.h>

#define SOCKET_FILE "/run/vpp/cli.sock"

volatile int window_resized = 0;
struct termios orig_tio;

static void
send_ttype (int sock_fd, int is_interactive)
{
  char *term;
  static char buf[2048];

  /* wipe the buffer so there is no potential
   * for inter-invocation leakage */
  memset (buf, 0, sizeof (buf));

  term = is_interactive ? getenv ("TERM") : "vppctl";
  if (term == NULL)
    term = "dumb";

  int len = snprintf (buf, sizeof (buf),
		      "%c%c%c"
		      "%c%s"
		      "%c%c",
		      IAC, SB, TELOPT_TTYPE, 0, term, IAC, SE);
  if (send (sock_fd, buf, len, 0) < 0)
    {
      perror ("send_ttype");
    }
}

static void
send_naws (int sock_fd)
{
  struct winsize ws;
  static char buf[2048];

  memset (buf, 0, sizeof (buf));
  if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
    {
      fprintf (stderr, "ioctl(TIOCGWINSZ)");
      return;
    }

  int len = snprintf (buf, sizeof (buf),
		      "%c%c%c"
		      "%c%c%c%c"
		      "%c%c",
		      IAC, SB, TELOPT_NAWS, ws.ws_col >> 8, ws.ws_col & 0xff,
		      ws.ws_row >> 8, ws.ws_row & 0xff, IAC, SE);
  int n_written = write (sock_fd, buf, len);
  if (n_written < len)
    {
      perror ("send_naws");
    }
}

static void
signal_handler_winch (int signum)
{
  window_resized = 1;
}

static void
signal_handler_term (int signum)
{
  tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_tio);
}

static int
process_input (int sock_fd, unsigned char *rx_buf, int rx_buf_len,
	       int is_interactive, int *sent_ttype)
{
  int i = 0;
  int j = 0;

  while (i < rx_buf_len)
    {
      if (rx_buf[i] == IAC)
	{
	  if (rx_buf[i + 1] == SB)
	    {
	      char opt = rx_buf[i + 2];
	      i += 3;
#if DEBUG
	      if (rx_buf[i] != IAC)
		{
		  fprintf (stderr, "SB ");
		}
	      while (rx_buf[i] != IAC && i < rx_buf_len)
		fprintf (stderr, "%02x ", rx_buf[i++]);
	      fprintf (stderr, "\n");
#else
	      while (rx_buf[i] != IAC && i < rx_buf_len)
		{
		  i++;
		}
#endif
	      i += 2;
	      if (opt == TELOPT_TTYPE)
		{
		  send_ttype (sock_fd, is_interactive);
		  *sent_ttype = 1;
		}
	      else if (is_interactive && opt == TELOPT_NAWS)
		send_naws (sock_fd);
	    }
	  else
	    {
#if DEBUG
	      fprintf (stderr, "IAC at %d, IAC %s %s", i,
		       TELCMD (rx_buf[i + 1]), TELOPT (rx_buf[i + 2]));
#endif
	      i += 3;
	    }
	}
      else
	{
	  /* i is always the same or ahead of j, so at worst this is a no-op */
	  rx_buf[j] = rx_buf[i];
	  i++;
	  j++;
	}
    }
  return j;
}


int
main (int argc, char *argv[])
{
  struct epoll_event event;
  struct sigaction sa;
  struct termios tio;
  int efd = -1;
  char *cmd = 0;
  int cmd_len = 0;
  int do_quit = 0;
  int is_interactive = 0;
  int acked = 1;		/* counts messages from VPP; starts at 1 */
  int sent_ttype = 0;
  char *sock_fname = SOCKET_FILE;
  int sock_fd = -1;
  int error = 0;
  int arg = 0;

  /* process command line */
  argc--;
  argv++;

  if (argc > 1 && strncmp (argv[0], "-s", 2) == 0)
    {
      sock_fname = argv[1];
      argc -= 2;
      argv += 2;
    }

  struct sockaddr_un saddr = { 0 };
  saddr.sun_family = AF_UNIX;

  if (strlen (sock_fname) > sizeof (saddr.sun_path) - 1)
    {
      perror ("socket path too long");
      exit (1);
    }

  strncpy (saddr.sun_path, sock_fname, sizeof (saddr.sun_path) - 1);

  sock_fd = socket (AF_UNIX, SOCK_STREAM, 0);
  if (sock_fd < 0)
    {
      perror ("socket");
      exit (1);
    }

  if (connect (sock_fd, (struct sockaddr *) &saddr, sizeof (saddr)) < 0)
    {
      perror ("connect");
      exit (1);
    }

  for (arg = 0; arg < argc; arg++)
    {
      cmd_len += strlen (argv[arg]) + 1;
    }
  if (cmd_len > 0)
    {
      cmd_len++; // account for \n in the end
      cmd = malloc (cmd_len);
      if (!cmd)
	{
	  error = errno;
	  perror ("malloc failed");
	  goto done;
	}
      memset (cmd, 0, cmd_len);
      while (argc--)
	{
	  strncat (cmd, *argv++, cmd_len);
	  strncat (cmd, " ", cmd_len);
	}
      cmd[cmd_len - 2] = '\n';
      cmd[cmd_len - 1] = 0;
    }

  is_interactive = isatty (STDIN_FILENO) && cmd == 0;

  if (is_interactive)
    {
      /* Capture terminal resize events */
      memset (&sa, 0, sizeof (struct sigaction));
      sa.sa_handler = signal_handler_winch;
      if (sigaction (SIGWINCH, &sa, 0) < 0)
	{
	  error = errno;
	  perror ("sigaction for SIGWINCH");
	  goto done;
	}

      /* Capture SIGTERM to reset tty settings */
      sa.sa_handler = signal_handler_term;
      if (sigaction (SIGTERM, &sa, 0) < 0)
	{
	  error = errno;
	  perror ("sigaction for SIGTERM");
	  goto done;
	}

      /* Save the original tty state so we can restore it later */
      if (tcgetattr (STDIN_FILENO, &orig_tio) < 0)<commit_msg>misc: vppctl - fix coverity warning<commit_after>/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <sys/socket.h>
#include <sys/un.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#define DEBUG 0

#if DEBUG
#define TELCMDS
#define TELOPTS
#endif

#include <arpa/telnet.h>

#define SOCKET_FILE "/run/vpp/cli.sock"

volatile int window_resized = 0;
struct termios orig_tio;

static void
send_ttype (int sock_fd, int is_interactive)
{
  char *term;
  static char buf[2048];

  /* wipe the buffer so there is no potential
   * for inter-invocation leakage */
  memset (buf, 0, sizeof (buf));

  term = is_interactive ? getenv ("TERM") : "vppctl";
  if (term == NULL)
    term = "dumb";

  int len = snprintf (buf, sizeof (buf),
		      "%c%c%c"
		      "%c%s"
		      "%c%c",
		      IAC, SB, TELOPT_TTYPE, 0, term, IAC, SE);
  if (send (sock_fd, buf, len, 0) < 0)
    {
      perror ("send_ttype");
    }
}

static void
send_naws (int sock_fd)
{
  struct winsize ws;
  static char buf[2048];

  memset (buf, 0, sizeof (buf));
  if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
    {
      fprintf (stderr, "ioctl(TIOCGWINSZ)");
      return;
    }

  int len = snprintf (buf, sizeof (buf),
		      "%c%c%c"
		      "%c%c%c%c"
		      "%c%c",
		      IAC, SB, TELOPT_NAWS, ws.ws_col >> 8, ws.ws_col & 0xff,
		      ws.ws_row >> 8, ws.ws_row & 0xff, IAC, SE);
  int n_written = write (sock_fd, buf, len);
  if (n_written < len)
    {
      perror ("send_naws");
    }
}

static void
signal_handler_winch (int signum)
{
  window_resized = 1;
}

static void
signal_handler_term (int signum)
{
  tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_tio);
}

static int
process_input (int sock_fd, unsigned char *rx_buf, int rx_buf_len,
	       int is_interactive, int *sent_ttype)
{
  int i = 0;
  int j = 0;

  while (i < rx_buf_len)
    {
      if (rx_buf[i] == IAC)
	{
	  if (rx_buf[i + 1] == SB)
	    {
	      char opt = rx_buf[i + 2];
	      i += 3;
#if DEBUG
	      if (rx_buf[i] != IAC)
		{
		  fprintf (stderr, "SB ");
		}
	      while (rx_buf[i] != IAC && i < rx_buf_len)
		fprintf (stderr, "%02x ", rx_buf[i++]);
	      fprintf (stderr, "\n");
#else
	      while (rx_buf[i] != IAC && i < rx_buf_len)
		{
		  i++;
		}
#endif
	      i += 2;
	      if (opt == TELOPT_TTYPE)
		{
		  send_ttype (sock_fd, is_interactive);
		  *sent_ttype = 1;
		}
	      else if (is_interactive && opt == TELOPT_NAWS)
		send_naws (sock_fd);
	    }
	  else
	    {
#if DEBUG
	      fprintf (stderr, "IAC at %d, IAC %s %s", i,
		       TELCMD (rx_buf[i + 1]), TELOPT (rx_buf[i + 2]));
#endif
	      i += 3;
	    }
	}
      else
	{
	  /* i is always the same or ahead of j, so at worst this is a no-op */
	  rx_buf[j] = rx_buf[i];
	  i++;
	  j++;
	}
    }
  return j;
}


int
main (int argc, char *argv[])
{
  struct epoll_event event;
  struct sigaction sa;
  struct termios tio;
  int efd = -1;
  char *cmd = 0;
  unsigned long cmd_len = 0;
  int do_quit = 0;
  int is_interactive = 0;
  int acked = 1;		/* counts messages from VPP; starts at 1 */
  int sent_ttype = 0;
  char *sock_fname = SOCKET_FILE;
  int sock_fd = -1;
  int error = 0;
  int arg = 0;

  /* process command line */
  argc--;
  argv++;

  if (argc > 1 && strncmp (argv[0], "-s", 2) == 0)
    {
      sock_fname = argv[1];
      argc -= 2;
      argv += 2;
    }

  struct sockaddr_un saddr = { 0 };
  saddr.sun_family = AF_UNIX;

  if (strlen (sock_fname) > sizeof (saddr.sun_path) - 1)
    {
      perror ("socket path too long");
      exit (1);
    }

  strncpy (saddr.sun_path, sock_fname, sizeof (saddr.sun_path) - 1);

  sock_fd = socket (AF_UNIX, SOCK_STREAM, 0);
  if (sock_fd < 0)
    {
      perror ("socket");
      exit (1);
    }

  if (connect (sock_fd, (struct sockaddr *) &saddr, sizeof (saddr)) < 0)
    {
      perror ("connect");
      exit (1);
    }

  for (arg = 0; arg < argc; arg++)
    {
      cmd_len += strlen (argv[arg]) + 1;
    }
  if (cmd_len > 0)
    {
      cmd_len++; // account for 0 at end
      cmd = malloc (cmd_len);
      if (!cmd)
	{
	  error = errno;
	  perror ("malloc failed");
	  goto done;
	}
      memset (cmd, 0, cmd_len);
      unsigned long space_left = cmd_len - 1; // reserve space for 0 at end
      while (argc--)
	{
	  strncat (cmd, *argv, space_left);
	  space_left -= strlen (*argv);
	  ++argv;
	  strncat (cmd, " ", space_left);
	  --space_left;
	}
      cmd[cmd_len - 2] = '\n';
      cmd[cmd_len - 1] = 0;
    }

  is_interactive = isatty (STDIN_FILENO) && cmd == 0;

  if (is_interactive)
    {
      /* Capture terminal resize events */
      memset (&sa, 0, sizeof (struct sigaction));
      sa.sa_handler = signal_handler_winch;
      if (sigaction (SIGWINCH, &sa, 0) < 0)
	{
	  error = errno;
	  perror ("sigaction for SIGWINCH");
	  goto done;
	}

      /* Capture SIGTERM to reset tty settings */
      sa.sa_handler = signal_handler_term;
      if (sigaction (SIGTERM, &sa, 0) < 0)
	{
	  error = errno;
	  perror ("sigaction for SIGTERM");
	  goto done;
	}

      /* Save the original tty state so we can restore it later */
      if (tcgetattr (STDIN_FILENO, &orig_tio) < 0)
{'fraction_non_alphanumeric': 0.1431324456902593, 'fraction_numerical': 0.014628591450595654, 'mean_word_length': 2.496784073506891, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4699165', 'n_tokens_mistral': 4740, 'n_tokens_neox': 4414, 'n_words': 1297}