File: miniexpect.pod

package info (click to toggle)
libguestfs 1%3A1.40.2-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 123,660 kB
  • sloc: ansic: 460,074; ml: 63,059; sh: 14,955; java: 9,512; makefile: 9,133; cs: 6,300; haskell: 5,652; python: 3,856; perl: 3,619; erlang: 2,435; xml: 1,683; ruby: 350; pascal: 255; lex: 135; yacc: 128; cpp: 10
file content (481 lines) | stat: -rw-r--r-- 14,300 bytes parent folder | download
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.