| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # Documentation at the __END__ | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | package IO::Pty; | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 4 |  |  | 4 |  | 285838 | use strict; | 
|  | 4 |  |  |  |  | 38 |  | 
|  | 4 |  |  |  |  | 121 |  | 
| 6 | 4 |  |  | 4 |  | 23 | use Carp; | 
|  | 4 |  |  |  |  | 5 |  | 
|  | 4 |  |  |  |  | 233 |  | 
| 7 | 4 |  |  | 4 |  | 1772 | use IO::Tty qw(TIOCSCTTY TCSETCTTY TIOCNOTTY); | 
|  | 4 |  |  |  |  | 11 |  | 
|  | 4 |  |  |  |  | 17 |  | 
| 8 | 4 |  |  | 4 |  | 32 | use IO::File; | 
|  | 4 |  |  |  |  | 7 |  | 
|  | 4 |  |  |  |  | 532 |  | 
| 9 |  |  |  |  |  |  | require POSIX; | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 4 |  |  | 4 |  | 28 | use vars qw(@ISA $VERSION); | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 4156 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | $VERSION = '1.16';    # keep same as in Tty.pm | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | @ISA = qw(IO::Handle); | 
| 16 |  |  |  |  |  |  | eval { local $^W = 0; undef local $SIG{__DIE__}; require IO::Stty }; | 
| 17 |  |  |  |  |  |  | push @ISA, "IO::Stty" if ( not $@ );    # if IO::Stty is installed | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | sub new { | 
| 20 | 6 |  | 50 | 6 | 1 | 2776017 | my ($class) = $_[0] || "IO::Pty"; | 
| 21 | 6 | 50 |  |  |  | 171 | $class = ref($class) if ref($class); | 
| 22 | 6 | 50 |  |  |  | 77 | @_ <= 1 or croak 'usage: new $class'; | 
| 23 |  |  |  |  |  |  |  | 
| 24 | 6 |  |  |  |  | 6829 | my ( $ptyfd, $ttyfd, $ttyname ) = pty_allocate(); | 
| 25 |  |  |  |  |  |  |  | 
| 26 | 6 | 50 |  |  |  | 129 | croak "Cannot open a pty" if not defined $ptyfd; | 
| 27 |  |  |  |  |  |  |  | 
| 28 | 6 |  |  |  |  | 360 | my $pty = $class->SUPER::new_from_fd( $ptyfd, "r+" ); | 
| 29 | 6 | 50 |  |  |  | 2061 | croak "Cannot create a new $class from fd $ptyfd: $!" if not $pty; | 
| 30 | 6 |  |  |  |  | 252 | $pty->autoflush(1); | 
| 31 | 6 |  |  |  |  | 780 | bless $pty => $class; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 6 |  |  |  |  | 158 | my $slave = IO::Tty->new_from_fd( $ttyfd, "r+" ); | 
| 34 | 6 | 50 |  |  |  | 642 | croak "Cannot create a new IO::Tty from fd $ttyfd: $!" if not $slave; | 
| 35 | 6 |  |  |  |  | 124 | $slave->autoflush(1); | 
| 36 |  |  |  |  |  |  |  | 
| 37 | 6 |  |  |  |  | 388 | ${*$pty}{'io_pty_slave'}     = $slave; | 
|  | 6 |  |  |  |  | 98 |  | 
| 38 | 6 |  |  |  |  | 43 | ${*$pty}{'io_pty_ttyname'}   = $ttyname; | 
|  | 6 |  |  |  |  | 53 |  | 
| 39 | 6 |  |  |  |  | 17 | ${*$slave}{'io_tty_ttyname'} = $ttyname; | 
|  | 6 |  |  |  |  | 125 |  | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 6 |  |  |  |  | 45 | return $pty; | 
| 42 |  |  |  |  |  |  | } | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | sub ttyname { | 
| 45 | 0 | 0 |  | 0 | 1 | 0 | @_ == 1 or croak 'usage: $pty->ttyname();'; | 
| 46 | 0 |  |  |  |  | 0 | my $pty = shift; | 
| 47 | 0 |  |  |  |  | 0 | ${*$pty}{'io_pty_ttyname'}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | sub close_slave { | 
| 51 | 3 | 50 |  | 3 | 1 | 3144 | @_ == 1 or croak 'usage: $pty->close_slave();'; | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 3 |  |  |  |  | 32 | my $master = shift; | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 3 | 50 |  |  |  | 21 | if ( exists ${*$master}{'io_pty_slave'} ) { | 
|  | 3 |  |  |  |  | 148 |  | 
| 56 | 3 |  |  |  |  | 39 | close ${*$master}{'io_pty_slave'}; | 
|  | 3 |  |  |  |  | 85 |  | 
| 57 | 3 |  |  |  |  | 49 | delete ${*$master}{'io_pty_slave'}; | 
|  | 3 |  |  |  |  | 196 |  | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | sub slave { | 
| 62 | 2 | 50 |  | 2 | 1 | 898 | @_ == 1 or croak 'usage: $pty->slave();'; | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 2 |  |  |  |  | 27 | my $master = shift; | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 2 | 50 |  |  |  | 15 | if ( exists ${*$master}{'io_pty_slave'} ) { | 
|  | 2 |  |  |  |  | 85 |  | 
| 67 | 2 |  |  |  |  | 12 | return ${*$master}{'io_pty_slave'}; | 
|  | 2 |  |  |  |  | 48 |  | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 0 |  |  |  |  |  | my $tty = ${*$master}{'io_pty_ttyname'}; | 
|  | 0 |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 0 |  |  |  |  |  | my $slave = new IO::Tty; | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 0 | 0 |  |  |  |  | $slave->open( $tty, O_RDWR | O_NOCTTY ) | 
| 75 |  |  |  |  |  |  | || croak "Cannot open slave $tty: $!"; | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 0 |  |  |  |  |  | return $slave; | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | sub make_slave_controlling_terminal { | 
| 81 | 0 | 0 |  | 0 | 1 |  | @_ == 1 or croak 'usage: $pty->make_slave_controlling_terminal();'; | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 0 |  |  |  |  |  | my $self = shift; | 
| 84 | 0 |  |  |  |  |  | local (*DEVTTY); | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | # loose controlling terminal explicitly | 
| 87 | 0 | 0 |  |  |  |  | if ( defined TIOCNOTTY ) { | 
| 88 | 0 | 0 |  |  |  |  | if ( open( \*DEVTTY, "/dev/tty" ) ) { | 
| 89 | 0 |  |  |  |  |  | ioctl( \*DEVTTY, TIOCNOTTY, 0 ); | 
| 90 | 0 |  |  |  |  |  | close \*DEVTTY; | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | # Create a new 'session', lose controlling terminal. | 
| 95 | 0 | 0 |  |  |  |  | if ( POSIX::setsid() == -1 ) { | 
| 96 | 0 | 0 |  |  |  |  | warn "setsid() failed, strange behavior may result: $!\r\n" if $^W; | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 0 | 0 |  |  |  |  | if ( open( \*DEVTTY, "/dev/tty" ) ) { | 
| 100 | 0 | 0 |  |  |  |  | warn "Could not disconnect from controlling terminal?!\n" if $^W; | 
| 101 | 0 |  |  |  |  |  | close \*DEVTTY; | 
| 102 |  |  |  |  |  |  | } | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | # now open slave, this should set it as controlling tty on some systems | 
| 105 | 0 |  |  |  |  |  | my $ttyname = ${*$self}{'io_pty_ttyname'}; | 
|  | 0 |  |  |  |  |  |  | 
| 106 | 0 |  |  |  |  |  | my $slv     = new IO::Tty; | 
| 107 | 0 | 0 |  |  |  |  | $slv->open( $ttyname, O_RDWR ) | 
| 108 |  |  |  |  |  |  | or croak "Cannot open slave $ttyname: $!"; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 0 | 0 |  |  |  |  | if ( not exists ${*$self}{'io_pty_slave'} ) { | 
|  | 0 |  |  |  |  |  |  | 
| 111 | 0 |  |  |  |  |  | ${*$self}{'io_pty_slave'} = $slv; | 
|  | 0 |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  | else { | 
| 114 | 0 |  |  |  |  |  | $slv->close; | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | # Acquire a controlling terminal if this doesn't happen automatically | 
| 118 | 0 | 0 |  |  |  |  | if ( not open( \*DEVTTY, "/dev/tty" ) ) { | 
| 119 | 0 | 0 |  |  |  |  | if ( defined TIOCSCTTY ) { | 
|  |  | 0 |  |  |  |  |  | 
| 120 | 0 | 0 |  |  |  |  | if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TIOCSCTTY, 0 ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 121 | 0 | 0 |  |  |  |  | warn "warning: TIOCSCTTY failed, slave might not be set as controlling terminal: $!" if $^W; | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  | elsif ( defined TCSETCTTY ) { | 
| 125 | 0 | 0 |  |  |  |  | if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TCSETCTTY, 0 ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 126 | 0 | 0 |  |  |  |  | warn "warning: TCSETCTTY failed, slave might not be set as controlling terminal: $!" if $^W; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  | else { | 
| 130 | 0 | 0 |  |  |  |  | warn "warning: You have neither TIOCSCTTY nor TCSETCTTY on your system\n" if $^W; | 
| 131 | 0 |  |  |  |  |  | return 0; | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  | } | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 0 | 0 |  |  |  |  | if ( not open( \*DEVTTY, "/dev/tty" ) ) { | 
| 136 | 0 |  |  |  |  |  | warn "Error: could not connect pty as controlling terminal!\n"; | 
| 137 | 0 |  |  |  |  |  | return undef; | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  | else { | 
| 140 | 0 |  |  |  |  |  | close \*DEVTTY; | 
| 141 |  |  |  |  |  |  | } | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 0 |  |  |  |  |  | return 1; | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | *clone_winsize_from = \&IO::Tty::clone_winsize_from; | 
| 147 |  |  |  |  |  |  | *get_winsize        = \&IO::Tty::get_winsize; | 
| 148 |  |  |  |  |  |  | *set_winsize        = \&IO::Tty::set_winsize; | 
| 149 |  |  |  |  |  |  | *set_raw            = \&IO::Tty::set_raw; | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | 1; | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | __END__ |