[ create a new paste ] login | about

Link: http://codepad.org/6xqyeqvU    [ raw code | fork ]

diogenese - C, pasted on Nov 11:
/* linker requires -lutil for pty.h */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pty.h>
#include <errno.h>
#include <error.h>
#include <string.h>
#include <ctype.h>

#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define FALSE 0
#define TRUE 1
#define PTYIN 1
#define PTYOUT -1

int make_pty( char *cargv[] );
void ttyset( int reset, pid_t source, pid_t target );

int
main( int argc, char *argv[] )
{
  FILE *dfp;
  int  pty_fd;
  unsigned char c;
  unsigned char last_c;
  int  dir = 0;

  /* runs a command in a pty */
  if ( argc < 2 ) {
    printf( "Usage: %s <command> [optional paramters]\n", argv[0] );
    exit( EXIT_FAILURE );
  }
  if (( pty_fd = make_pty( &argv[1] )) == -1 ) {
    fprintf( stderr, "Failed to create pty for %s\n", argv[1] );
    exit( EXIT_FAILURE );
  }

  if ( !( dfp = fopen( "./debug.log", "w" ))) {
    fprintf( stderr, "Failed to open debug log\n" );
    exit( EXIT_FAILURE );
  }
  /* set stdin to ~raw mode and direct signals to child process */
  ttyset( FALSE, STDIN_FILENO, pty_fd );

  /* direct stdin fd to pty and pty to stdout fd */
  while ( TRUE ) {

    /* get char('s) from pty */
    while ( read( pty_fd, &c, 1 ) > 0 ) {
      /* output character */
      write( STDOUT_FILENO, &c, 1 );
      if ( dir != PTYIN ) {
	dir = PTYIN;
	fprintf( dfp, "\nPTYIN:  " );
      }
      if ( isprint( c )) 
	fprintf( dfp, "%c", c );
      else
	fprintf( dfp, " 0x%02X ", c );
      
    }
    if ( errno != EAGAIN && errno != EWOULDBLOCK ) {
      /* lost connection to child process */
      fprintf( stderr, "Lost connection to child pty: %s", strerror( errno ));
      break;
    }
    /* get char from stdin fd */
    if ( read( STDIN_FILENO, &c, 1 ) > 0 ) {

      /* look for enter key - break on no input */
      if ( c == 0x0A  && ( !last_c || c == last_c )) {
	printf( "\nDone processing\n" );
	break;
      }
      /* save last key - flag for break */
      last_c = c;

      /* write character to pty */
      write( pty_fd, &c, 1 );

      if ( dir != PTYOUT ) {
	dir = PTYOUT;
	fprintf( dfp, "\nPTYOUT: " );
      }
      if ( isprint( c )) 
	fprintf( dfp, "%c", c );
      else
	fprintf( dfp, " 0x%02X ", c );
    }
    fflush( dfp );

    /* give the system time to play */
    usleep( 1000 );
  }
  fprintf( dfp, "\n");
  fclose( dfp );
  ttyset( TRUE, STDIN_FILENO, pty_fd );
  return EXIT_SUCCESS;
} /* end main */

int
make_pty( char *cargv[] ) /* cargv must be a null terminated */
{
  int master_fd = -1;
  pid_t slave_fd;

  /* create slave pty and master controler */
  slave_fd = forkpty( &master_fd, NULL, NULL, NULL );
  
  switch( slave_fd ) {
  case -1:
    /* error */
    fprintf( stderr, "ERROR creating pty" );
    return -1;

  case 0:
    /* execute program in slave pty */
    if ( execvp( cargv[0], cargv ) == -1 ) {
      fprintf( stderr, "Child failed to execute command: %s\n", cargv[0] );
      return -1;
    }
    break;

  default:
    /* parent process - nothing to do */
    break;
  }
  return master_fd;
} /* end make_pty */

void
ttyset( int reset, pid_t source, pid_t target  )
{
  static struct termios old = { 0 };
  struct termios new;
  static int in_flags = 0;

  if ( reset ) {

    /* set source back to original setting */
    (void) tcsetattr( source, TCSANOW, &old );
    (void) fcntl( source, F_SETFL, in_flags );

  } else {

    /* get source termios structure and set to semi-raw input */
    (void) tcgetattr( source, &old );
    new = old;
    new.c_cc[VMIN]  =  1;
    new.c_cc[VTIME] =  0;
    new.c_lflag &= ~( ICANON | ECHO );
    new.c_iflag &= ~( ISTRIP | INPCK );
    (void) tcsetattr( source, TCSANOW, &new );

    /* set source for non blocking mode */
    in_flags = fcntl( source, F_GETFL );
    (void) fcntl( source, F_SETFL, in_flags | O_NONBLOCK );

    /* set target for non blocking mode - no need to save flags */
    (void) fcntl( target, F_SETFL, fcntl( target, F_GETFL ) | O_NONBLOCK );
  }  
} /* end ttyset */


Create a new paste based on this one


Comments: