Stefan O'Rear
and 1 contributors

NAME

IO::Pty::HalfDuplex - Treat interactive programs like subroutines

SYNOPSIS

    use IO::Pty::HalfDuplex;

    my $pty = IO::Pty::HalfDuplex->new;

    $pty->spawn("nethack");

    $pty->read;
    # => "\nNetHack, copyright...for you? [ynq] "

    $pty->write("nvd");
    $pty->read;

    # => "... Velkommen sorear, you are a lawful dwarven Valkyrie.--More--"

DESCRIPTION

IO::Pty::HalfDuplex is designed to perform impedence matching between driving programs which expect commands and responses, and driven programs which use a terminal in full-duplex mode. In this vein it is somewhat like expect, but less general and more robust (but see CAVEATS below).

This module is used in object-oriented style. IO::Pty::HalfDuplex objects are connected to exactly one system pseudoterminal, which is allocated on creation; input and output are done using methods. The interface is deliberately kept similar to Jesse Luehrs' IO::Pty::Easy module; notable incompatibilities from the latter are:

  • The spawn() method reports failure to exec inline, on output followed by an exit. I see no reason why exec failures should be different from post-exec failures such as "dynamic library not found", and it considerably simplifes the code.

  • write() does not immediately write anything, but merely queues data to be released all at once by read(). It does not have a timeout parameter.

  • read() should generally not be passed a timeout, as it finds the end of output automatically.

  • The two-argument form of kill() interprets its second argument in the opposite sense.

METHODS

new()

Allocates and returns a IO::Pty::HalfDuplex object.

spawn(LIST)

Starts a subprocess under the control of IO::Pty::HalfDuplex. LIST may be a single string or list of strings as per Perl exec.

recv([TIMEOUT])

Reads all output that the subprocess will send. If TIMEOUT is specified and the process has not finished writing, undef is returned and the existing output is retained in the read buffer for use by subsequent recv calls.

TIMEOUT is in (possibly fractional) seconds.

write(TEXT)

Appends TEXT to the write buffer to be sent on the next recv.

is_active()

Returns true if the slave process currently exists.

kill()

Sends a signal to the process currently running on the pty (if any). Optionally blocks until the process dies.

kill() takes an even number of arguments. They are interpreted as pairs of signals and a length of time to wait after each one, or 0 to not wait at all. Signals may be in any format that the Perl kill() command recognizes. Any output generated while waiting is discarded.

Returns 1 immediately if the process exited during a wait, 0 if it was successfully signalled but did not exit, and undef if the signalling failed.

kill() (with no arguments) is equivalent to kill(TERM => 3, KILL => 3).

close()

Kills any subprocesses and closes the pty. No other operations are valid after this call.

CAVEATS

IO::Pty::HalfDuplex is implemented using POSIX job control, and as such it requires foreground access to a controlling terminal. Programs which interfere with process hierarchies, such as strace -f, will break IO::Pty::HalfDuplex.

Certain ioctls used by terminal-aware programs are treated as reads by POSIX job control. If this is done while the input buffer is empty, it may cause a spurious stop by IO::Pty::HalfDuplex. Under normal circumstances this manifests as a need to transmit at least one character before the starting screen is displayed.

IO::Pty::HalfDuplex relies on a forked-but-not-execed process to mediate job control, and as such any files open at spawn time will be closed until the slave is killed.

IO::Pty::HalfDuplex sends many continue signals to the slave process. If the slave catches SIGCONT, you may see many spurious redraws. If possible, modify your child to handle SIGTSTP instead.

IO::Pty::HalfDuplex won't work with programs that rely on non-blocking input or generate output in other threads after blocking for input in one.

While this module will theoretically work on any POSIX.1 compliant operating system, in practice it exercises many dark corners and has required bug-workaround code everywhere it has been tested. It is known to work on Mac OS 10.5.7 and Linux 2.6.16. On FreeBSD 7.0 it passes tests but is extremely slow due to a kernel bug with no obvious workaround.

AUTHOR

Stefan O'Rear, <stefanor@cox.net>

BUGS

No known bugs.

Please report any bugs through RT: email bug-io-halfduplex at rt.cpan.org, or browse http://rt.cpan.org/NoAuth/ReportBug.html?Queue=IO-HalfDuplex.

COPYRIGHT AND LICENSE

Copyright 2008-2009 Stefan O'Rear.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.