[ale] how to redirect fds through telnet session in QNX?

Christopher Fowler cfowler at outpostsentinel.com
Sat Mar 24 19:00:35 EDT 2007


Here is the idea behind redirecting the output.  
I would write this in C so you could run in QNX but I don't have that
time.  I use PERL in this example to illustrate the idea.  If you can do
it in C there is a 99% chance you can do it in PERL.  I say 99% because
I've never ran into the times where the POSIX module has failed to give
me what I wanted.

This program will exec a program on a pseudo.  It will then read the
master and redirect all output to a client that has connected via TCP.
Could be a telnet client.  It will read from the client to simply get
any thing sent out of the buffers but will do nothing with that data.
It is a one-way program.  What is read from the child (your program) is
sent to the client (telnet).  You could easily expand this to add
clients in a list and feed to as many clients as you have.  Also if you
send SIGUSR1 (10) to this program it will terminate the child with
SIGKILL (9) and restart it.  You can also modify this idea to log all
output to a file as well.  You can do whatever you want "Use the source
Luke".


-- [ cut here ] --------------------------------------------------------
#!/usr/bin/perl

use IO::Pty;
use POSIX qw/dup2 WNOHANG/;
use IO::Select;
use IO::Socket;
use IO::Socket::INET;
use strict;

$| = 1;
my $USR1 = $1;


sub spawn {
  my $pty = shift;
  my $cmd = "@_";
  my $pid = fork();

  my $slave = $pty->slave;
  $slave->set_raw();

  # Child
  if($pid == 0) {
    my @args = ( "/bin/sh", "-c", "$ARGV[0]");
    dup2(fileno($slave),1);
    dup2(fileno($slave),2);
    dup2(fileno($slave),0);
    exec { $args[0] } @args or exit 1;
  }

  # In parent
  close $slave;  # Do not need this
  return $pid;
}

sub main {
  my $data = "";
  my $pty = new IO::Pty;
  my $client = undef;

  my $child = spawn $pty, "$ARGV[0]";

  my $serv = IO::Socket::INET->new( Listen => 5,
    LocalAddr => "0.0.0.0", LocalPort => 10000 ,
    Proto => 'tcp', ReuseAddr=> 1) or die "$!\n";


  $SIG{'USR1'} = sub { $USR1 = 1;};

  while(1) {
    my $selector = new IO::Select();
    $selector->add($pty);
    $selector->add($serv);
    $selector->add($client) if $client;

    my ($rr, undef, $er) = IO::Select->select($selector, undef,
$selector, 30) ;

    # Restart the child
    if($USR1) {
      $USR1 = undef;
      kill 9, ($child);
      $pty = new IO::Pty;
      $child = spawn $pty, "$ARGV[0]";
      my $k = undef;
      do { waitpid(-1, WNOHANG); } while ($k > 0)
    }

    foreach my $fh (@$rr) {
      if($fh == $pty) {
        my $num = sysread($pty, $data, 1024);
        if($num <= 0) { print "program terminated\n"; exit 0; }
        syswrite($client,$data,$num) if $client;
      }

      if($fh == $serv) {
        my $c = $serv->accept();
        if($client) {
          print $c "Server busy\n";
          close($c);
          next;
        }

        $client = $c;
      }

      if($client && ($fh == $client)) {
        my $num = sysread($fh, $data, 1024);

        # Client closed the connection
        if($num <= 0) {
          close $client;
          $client = undef;
        }
      }
    }
  }

  return 0;
}

exit main;
# vi: set ts=2 sw=2: #
-- [ cut here ] --------------------------------------------------------

[cfowler at shuttle ~]$ ./redirect.pl "tail -f /var/log/messages"
[cfowler at shuttle ~]$ telnet 127.0.0.1 10000
Trying 127.0.0.1...
Connected to shuttle.linxdev.com (127.0.0.1).
Escape character is '^]'.
Mar 24 18:30:01 shuttle crond(pam_unix)[30827]: session opened for user
cfowler by (uid=0)
Mar 24 18:30:32 shuttle crond(pam_unix)[30827]: session closed for user
cfowler
Mar 24 18:35:01 shuttle crond(pam_unix)[30838]: session opened for user
cfowler by (uid=0)
Mar 24 18:35:32 shuttle crond(pam_unix)[30838]: session closed for user
cfowler



On Sat, 2007-03-24 at 16:06 -0400, Christopher Fowler wrote:
> My guess is that the program runs on the console of the device and
> therefore wants to output to the console.  It seems to me that /dev/con1
> is QNX's version of Linux's virtual consoles so they are not useful.
> 
> If I had to have the output via IP then I might would do it this way.
> 
> #1.  Instead of running your code at startup I would run a program that
> would merge the output of your code to a TCP socket.
> 
> #2.  Simply telnet to that socket.
> 
> Now to restart your code do not restart the master program.  Send
> SIGUSR1 or SIGTERM to your code and the master program sill simply
> respawn your code.
> 
> If you are trying to redirect the output of your program to a pseudo
> that is not in use then that will not work.  A program must have an open
> FD to the master side of a pseudo before the slave can work.  
> 
> I would also look at user circular buffers to store debug messages on
> the device since you have little mem and no swap.  You can start filling
> up a file.  I doubt you have that type of capability in QNX to begin
> with.
> 
> 
> On Sat, 2007-03-24 at 15:48 -0400, Step wrote:
> > Here is the statement from wikipedia that caught my attention: "The
> > popularity and availability of faster information exchange systems
> > such as ethernet made the use of null-modem cables less common.
> > Nowadays, such a cable can still be useful to kernel hackers though,
> > since it allows the user to remotely debug a kernel with a minimum of
> > device drivers and code". 
> > 
> 
> Such a device is still useful when IP access fails due to any reason.
> 
> _______________________________________________
> Ale mailing list
> Ale at ale.org
> http://www.ale.org/mailman/listinfo/ale




More information about the Ale mailing list