=encoding utf8

=head1 NAME

miniexpect - A very simple expect library for C.

=head1 SYNOPSIS

 #include <errno.h>
 #include <sys/wait.h>
 #include <pcre.h>
 #include <miniexpect.h>
 
 mexp_h *h;
 h = mexp_spawnl ("ssh", "ssh", "host", NULL);
 switch (mexp_expect (h, regexps, ovector, ovecsize)) {
   ...
 }
 mexp_close (h);

 cc prog.c -o prog -lminiexpect -lpcre

=head1 DESCRIPTION

Miniexpect is a very simple expect-like library for C.  Expect is a
way to control an external program that wants to be run interactively.

Miniexpect has a saner interface than libexpect, and doesn't depend on
Tcl.  It is also thread safe, const-correct and uses modern C
standards.

Miniexpect is a standalone library, except for a single dependency: it
requires the PCRE (Perl Compatible Regular Expressions) library from
L<http://www.pcre.org/>.  The PCRE dependency is fundamental because
we want to offer the most powerful regular expression syntax to match
on, but more importantly because PCRE has a convenient way to detect
partial matches which made this library very simple to implement.

This manual page documents the API.  Examples of how to use the API
can be found in the source directory.

=head1 CONCEPTS

Miniexpect lets you start up an external program, control it (by
sending commands to it), and close it down gracefully.  Two things
make this different from other APIs like L<popen(3)> and L<system(3)>:
Firstly miniexpect creates a pseudoterminal (pty).  Secondly
miniexpect lets you match the output of the program using regular
expressions.  Both of these are handy for controlling interactive
programs that might (for example) ask for passwords, but you can use
miniexpect on just about any external program.

You can control multiple programs at the same time.

=head1 SPAWNING THE SUBPROCESS

There are four calls for creating a subprocess:

B<mexp_h *mexp_spawnl (const char *file, const char *arg, ...);>

This creates a subprocess running the external program C<file> (the
current C<$PATH> is searched unless you give an absolute path).
C<arg, ...> are the arguments to the program.  You should terminate
the list of arguments with C<NULL>.  Usually the first argument should
be the name of the program.

The return value is a handle (see next section).

If there was an error running the subprocess, C<NULL> is returned and
the error is available in C<errno>.

For example, to run an ssh subprocess you could do:

 h = mexp_spawnl ("ssh", "ssh", "-l", "root", "host", NULL);

or to run a particular ssh binary:

 h = mexp_spawnl ("/usr/local/bin/ssh", "ssh", "-l", "root", "host", NULL);

An alternative to C<mexp_spawnl> is:

B<mexp_h *mexp_spawnv (const char *file, char **argv);>

This is the same as C<mexp_spawnl> except that you pass the arguments
in a NULL-terminated array.

There are also two versions of the above calls which take flags:

B<mexp_h *mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...);>

B<mexp_h *mexp_spawnvf (unsigned flags, const char *file, char **argv);>

The flags may contain the following values, logically ORed together:

=over 4

=item B<MEXP_SPAWN_KEEP_SIGNALS>

Do not reset signal handlers to C<SIG_DFL> in the subprocess.

=item B<MEXP_SPAWN_KEEP_FDS>

Do not close file descriptors E<ge> 3 in the subprocess.

=item B<MEXP_SPAWN_COOKED_MODE> or B<MEXP_SPAWN_RAW_MODE>

Configure the pty in cooked mode or raw mode.  Raw mode is the
default.

=back

=head1 HANDLES

After spawning a subprocess, you get back a handle which is a pointer
to a struct:

 struct mexp_h;
 typedef struct mexp_h mexp_h;

Various methods can be used on the handle:

B<int mexp_get_fd (mexp_h *h);>

Return the file descriptor of the pty of the subprocess.  You can read
and write to this if you want, although convenience functions are also
provided (see below).

B<pid_t mexp_get_pid (mexp_h *h);>

Return the process ID of the subprocess.  You can send it signals if
you want.

B<int mexp_get_timeout_ms (mexp_h *h);>

B<void mexp_set_timeout_ms (mexp_h *h, int millisecs);>

B<void mexp_set_timeout (mexp_h *h, int secs);>

Get or set the timeout used by C<mexp_expect> [see below].  The
resolution is milliseconds (1/1000th of a second).  Set this before
calling C<mexp_expect>.  Passing -1 to either of the C<set_> methods
means no timeout.  The default setting is 60000 milliseconds (60
seconds).

B<size_t mexp_get_read_size (mexp *h);>

B<void mexp_set_read_size (mexp *h, size_t read_size);>

Get or set the natural size (in bytes) for reads from the subprocess.
The default is 1024.  Most callers will not need to change this.

B<int mexp_get_pcre_error (mexp *h);>

When C<mexp_expect> [see below] calls the PCRE function
L<pcre_exec(3)>, it stashes the return value in the C<pcre_error>
field in the handle, and that field is returned by this method.

There are two uses for this:

=over 4

=item 1.

If C<mexp_expect> returns C<MEXP_PCRE_ERROR>, then the actual PCRE
error code returned by L<pcre_exec(3)> is available by calling this
method.  For a list of PCRE error codes, see L<pcreapi(3)>.

=item 2.

A more unusual use is if you ever need to get the captured substrings
from your regular expression (calling L<pcre_get_substring(3)>).  The
third parameter of that function (C<stringcount>) is the value
returned by L<pcre_exec(3)>, and so you can call it like this:

 pcre_get_substring (h->buffer, ovector,
                     mexp_get_pcre_error (h), 1, &matched);

=back

B<void mexp_set_debug_file (mexp *h, FILE *fp);>

B<FILE *mexp_get_debug_file (mexp *h);>

Set or get the debug file of the handle.  To enable debugging, pass a
non-C<NULL> file handle, eg. C<stderr>.  To disable debugging, pass
C<NULL>.  Debugging messages are printed on the file handle.

Note that all output and input gets printed, including passwords.  To
prevent passwords from being printed, modify your code to call
C<mexp_printf_password> instead of C<mexp_printf>.

The following fields in the handle do not have methods, but can be
accessed directly instead:

 char *buffer;
 size_t len;
 size_t alloc;

If C<mexp_expect> returns a match then these variables contain the
read buffer.  Note this buffer does not contain the full input from
the process, but it will contain at least the part matched by the
regular expression (and maybe some more).  C<buffer> is the read
buffer and C<len> is the number of bytes of data in the buffer.

 ssize_t next_match;

If C<mexp_expect> returns a match, then C<next_match> points to the
first byte in the buffer I<after> the fully matched expression.  (It
may be C<-1> which means it is invalid).  The next time that
C<mexp_expect> is called, it will start by consuming the data
C<buffer[next_match...len-1]>.  Callers may also need to read from
that point in the buffer before calling L<read(2)> on the file
descriptor.  Callers may also set this, for example setting it to
C<-1> in order to ignore the remainder of the buffer.  In most cases
callers can ignore this field, and C<mexp_expect> will just do the
right thing when called repeatedly.

 void *user1;
 void *user2;
 void *user3;

Opaque pointers for use by the caller.  The library will not touch
these.

=head1 CLOSING THE HANDLE

To close the handle and clean up the subprocess, call:

B<int mexp_close (mexp_h *h);>

This returns the status code from the subprocess.  This is in the form
of a L<waitpid(2)>/L<system(3)> status so you have to use the macros
C<WIFEXITED>, C<WEXITSTATUS>, C<WIFSIGNALED>, C<WTERMSIG> etc defined
in C<E<lt>sys/wait.hE<gt>> to parse it.

If there was a system call error, then C<-1> is returned.  The error
will be in C<errno>.

Notes:

=over 4

=item *

Even in error cases, the handle is always closed and its memory is
freed by this call.

=item *

It is normal for the kernel to send SIGHUP to the subprocess.

If the subprocess doesn't catch the SIGHUP, then it will die
with status:

 WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP

This case should not necessarily be considered an error.

=back

This is how code should check for and print errors from C<mexp_close>:

  status = mexp_close (h);
  if (status == -1) {
    perror ("mexp_close");
    return -1;
  }
  if (WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP)
    goto ignore; /* not an error */
  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
    /* You could use the W* macros to print a better error message. */
    fprintf (stderr, "error: subprocess failed, status = %d", status);
    return -1;
  }
 ignore:
  /* no error case */

=head1 EXPECT FUNCTION

Miniexpect contains a powerful regular expression matching function
based on L<pcre(3)>:

B<int mexp_expect (mexp_h *h, const mexp_regexp *regexps,
int *ovector, int ovecsize);>

The output of the subprocess is matched against the list of PCRE
regular expressions in C<regexps>.  C<regexps> is a list of regular
expression structures:

 struct mexp_regexp {
   int r;
   const pcre *re;
   const pcre_extra *extra;
   int options;
 };
 typedef struct mexp_regexp mexp_regexp;

C<r> is the integer code returned from C<mexp_expect> if this regular
expression matches.  It B<must> be E<gt> 0.  C<r == 0> indicates the
end of the list of regular expressions.  C<re> is the compiled regular
expression.

Possible return values are:

=over 4

=item C<MEXP_TIMEOUT>

No input matched before the timeout (C<h-E<gt>timeout>) was
reached.

=item C<MEXP_EOF>

The subprocess closed the connection.

=item C<MEXP_ERROR>

There was a system call error (eg. from the read call).  The error is
returned in C<errno>.

=item C<MEXP_PCRE_ERROR>

There was a C<pcre_exec> error.  C<h-E<gt>pcre_error> is set to the
error code.  See L<pcreapi(3)> for a list of the C<PCRE_*> error codes
and what they mean.

=item C<r> E<gt> 0

If any regexp matches, the associated integer code (C<regexps[].r>)
is returned.

=back

Notes:

=over 4

=item *

C<regexps> may be NULL or an empty list, which means we don't match
against a regular expression.  This is useful if you just want to wait
for EOF or timeout.

=item *

C<regexps[].re>, C<regexps[].extra>, C<regexps[].options>, C<ovector>
and C<ovecsize> are passed through to the L<pcre_exec(3)> function.

=item *

If multiple regular expressions are passed, then they are checked in
turn and the I<first> regular expression that matches is returned
I<even if the match happens later in the input than another regular
expression>.

For example if the input is C<"hello world"> and you pass the two
regular expressions:

 regexps[0].re = world
 regexps[1].re = hello

then the first regular expression (C<"world">) may match and the
C<"hello"> part of the input may be ignored.

In some cases this can even lead to unpredictable matching.  In the
case above, if we only happened to read C<"hello wor">, then the
second regular expression (C<"hello">) I<would> match.

If this is a concern, combine your regular expressions into a single
one, eg. C<(hello)|(world)>.

=back

=head2 mexp_expect example

It is easier to understand C<mexp_expect> by considering a simple
example.

In this example we are waiting for ssh to either send us a password
prompt, or (if no password was required) a command prompt, and based
on the output we will either send back a password or a command.

The unusual C<(mexp_regexp[]){...}> syntax is called a "compound
literal" and is available in C99.  If you need to use an older
compiler, you can just use a local variable instead.

 mexp_h *h;
 char *errptr;
 int offset;
 pcre *password_re, *prompt_re;
 const int ovecsize = 12;
 int ovector[ovecsize];
 
 password_re = pcre_compile ("assword", 0, &errptr, &offset, NULL);
 prompt_re = pcre_compile ("[$#] ", 0, &errptr, &offset, NULL);
 
 switch (mexp_expect (h,
                      (mexp_regexp[]) {
                        { 100, .re = password_re },
                        { 101, .re = prompt_re },
                        { 0 },
                      }, ovector, ovecsize)) {
  case 100:
    /* here you would send a password */
    break;
  case 101:
    /* here you would send a command */
    break;
  case MEXP_EOF:
    fprintf (stderr, "error: ssh closed the connection unexpectedly\n");
    exit (EXIT_FAILURE);
  case MEXP_TIMEOUT:
    fprintf (stderr, "error: timeout before reaching the prompt\n");
    exit (EXIT_FAILURE);
  case MEXP_ERROR:
    perror ("mexp_expect");
    exit (EXIT_FAILURE);
  case MEXP_PCRE_ERROR:
    fprintf (stderr, "error: PCRE error: %d\n", h->pcre_error);
    exit (EXIT_FAILURE);
 }

=head1 SENDING COMMANDS TO THE SUBPROCESS

You can write to the subprocess simply by writing to C<h-E<gt>fd>.
However we also provide a convenience function:

B<int mexp_printf (mexp_h *h, const char *fs, ...);>

B<int mexp_printf_password (mexp_h *h, const char *fs, ...);>

This returns the number of bytes, if the whole message was written OK.
If there was an error, -1 is returned and the error is available in
C<errno>.

Notes:

=over 4

=item *

C<mexp_printf> will not do a partial write.  If it cannot write all
the data, then it will return an error.

=item *

This function does not write a newline automatically.  If you want to
send a command followed by a newline you have to do something like:

 mexp_printf (h, "exit\n");

=item *

C<mexp_printf_password> works identically to C<mexp_printf> except
that the output is I<not> sent to the debugging file if debugging is
enabled.  As the name suggests, use this for passwords so that they
don't appear in debugging output.

=back

B<int mexp_send_interrupt (mexp_h *h);>

Send the interrupt character (C<^C>, Ctrl-C, C<\003>).  This is like
pressing C<^C> - the subprocess (or remote process, if using C<ssh>)
is gracefully killed.

Note this only works if the pty is in cooked mode
(ie. C<MEXP_SPAWN_COOKED_MODE> was passed to C<mexp_spawnlf> or
C<mexp_spawnvf>).  In raw mode, all characters are passed through
without any special interpretation.

=head1 SOURCE

Source is available from:
L<http://git.annexia.org/?p=miniexpect.git;a=summary>

=head1 SEE ALSO

L<pcre(3)>,
L<pcre_exec(3)>,
L<pcreapi(3)>,
L<waitpid(2)>,
L<system(3)>.

=head1 AUTHORS

Richard W.M. Jones (C<rjones at redhat dot com>)

=head1 LICENSE

The library is released under the Library GPL (LGPL) version 2 or at
your option any later version.

=head1 COPYRIGHT

Copyright (C) 2014 Red Hat Inc.
