#!/bin/sh -- # A comment mentioning perl eval 'exec perl -S $0 ${1+"$@"}' if 0; # # ptyexec: connect the STDIN and STDOUT of some command to a # pseudo terminal (e.g. /dev/ptyp2 (master) and /dev/ttyp2 (slave)) # # based on "ssh-ppp" (ppp over secure shell VPN hack) # # Usage: ptyexec # # Runs the command in background; writes to output what pseudoterminal # has been connected to it. # @cmd = @ARGV; if ( $cmd[0] eq '-d' ) { $debug = 1; shift(@cmd); } elsif ( $cmd[0] =~ /^-h/ ) { print <<"END"; Usage: ptyexec Connects the stdio of to a pseudoterminal. Returns something like: MASTER: /dev/ptyqa SLAVE: /dev/ttypa You should extract the SLAVE device and open it or pass it to the application for use. E.g. the i/o of could be a fake a "serial" device for a communications app, say pppd. END exit 0; } die "no command" unless @cmd; # loop over possible pseudoterminals until we can open one: foreach $m1 ("p" .. "z") { foreach $m2 ("0".."9", "a".."f") { &try("$m1$m2"); # exit takes place in try() on success } } exit 1; sub try { my ($dev) = @_; my $master = "/dev/pty$dev"; my $slave = "/dev/tty$dev"; # try to open the pseudoterminal read/write: if ( open(PTY, "+>$master") ) { # now fork off a child in background to exec @cmd: my $pid = fork(); die "cannot fork, $!" if ! defined($pid); if ( ! $pid ) { # child remaps his stdio to the pseudoterm: open(STDIN, "<&PTY") || die "reopen STDIN, $!"; open(STDOUT, ">&PTY") || die "reopen STDOUT, $!"; close(PTY); # and then runs the command: exec @cmd; # exec failed: die "exec: " . join(' ', @cmd) . ": $!"; } else { # parent tells the user what we have set up: close(PTY); sleep 1; print STDOUT "PID:$pid\n"; if ( ! kill 0, $pid ) { # see if the child is still alive: print STDOUT "WARNING: NO CHILD PID\n"; } print STDOUT "MASTER: $master\n"; print STDOUT "SLAVE: $slave\n"; if ( $debug ) { print STDERR `ps waux | grep $pid | grep -v grep`; print STDERR `ls -l $master $slave`; } exit 0; } } }