1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
|
=head1 名前
miniexpect - A very simple expect library for C.
=head1 書式
#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 説明
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 ハンドル
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 ハンドルの閉じ方
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>.
注:
=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
注:
=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>.
注:
=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 関連項目
L<pcre(3)>, L<pcre_exec(3)>, L<pcreapi(3)>, L<waitpid(2)>, L<system(3)>.
=head1 著者
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.
|