/* miniexpect
- * Copyright (C) 2014 Red Hat Inc.
+ * Copyright (C) 2014-2022 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/* ** NOTE ** All API documentation is in the manual page.
+ *
+ * To read the manual page from the source directory, do:
+ * man ./miniexpect.3
+ * If you have installed miniexpect, do:
+ * man 3 miniexpect
+ *
+ * The source for the manual page is miniexpect.pod.
+ */
+
#ifndef MINIEXPECT_H_
#define MINIEXPECT_H_
+#include <stdio.h>
#include <unistd.h>
-#include <pcre.h>
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
/* This handle is created per subprocess that is spawned. */
struct mexp_h {
- int fd; /* File descriptor pointing to pty. */
- pid_t pid; /* Subprocess PID. */
-
- /* Timeout (milliseconds, 1/1000th seconds). The caller may set
- * this before calling mexp_expect. Set it to -1 to mean no
- * timeout. The default is 60000 (= 60 seconds).
- */
+ int fd;
+ pid_t pid;
int timeout;
-
- /* The read buffer is allocated by the library when mexp_expect is
- * called. It is available so you can examine the buffer to see
- * what part of the regexp matched. 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).
- */
- char *buffer; /* Read buffer. */
- size_t len; /* Length of data in the buffer. */
- size_t alloc; /* Allocated size of the buffer. */
-
- /* The caller may set this to set the size (in bytes) for reads from
- * the subprocess. The default is 1024.
- */
+ char *buffer;
+ size_t len;
+ size_t alloc;
+ ssize_t next_match;
size_t read_size;
-
- /* Opaque pointers for use of the caller. The library will not
- * touch these.
- */
+ int pcre_error;
+ FILE *debug_fp;
void *user1;
void *user2;
void *user3;
};
typedef struct mexp_h mexp_h;
-/* Spawn a subprocess.
- *
- * If successful it returns a handle. If it fails, it returns NULL
- * and sets errno.
+/* Methods to access (some) fields in the handle. */
+#define mexp_get_fd(h) ((h)->fd)
+#define mexp_get_pid(h) ((h)->pid)
+#define mexp_get_timeout_ms(h) ((h)->timeout)
+#define mexp_set_timeout_ms(h, ms) ((h)->timeout = (ms))
+/* If secs == -1, then this sets h->timeout to -1000, but the main
+ * code handles this since it only checks for h->timeout < 0.
*/
-extern mexp_h *mexp_spawnv (const char *file, char **argv);
+#define mexp_set_timeout(h, secs) ((h)->timeout = 1000 * (secs))
+#define mexp_get_read_size(h) ((h)->read_size)
+#define mexp_set_read_size(h, size) ((h)->read_size = (size))
+#define mexp_get_pcre_error(h) ((h)->pcre_error)
+#define mexp_set_debug_file(h, fp) ((h)->debug_fp = (fp))
+#define mexp_get_debug_file(h) ((h)->debug_fp)
-/* Same as mexp_spawnv, but it uses a NULL-terminated variable length
- * list of arguments.
- */
-extern mexp_h *mexp_spawnl (const char *file, const char *arg, ...);
+/* Spawn a subprocess. */
+extern mexp_h *mexp_spawnvf (unsigned flags, const char *file, char **argv);
+extern mexp_h *mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...);
+#define mexp_spawnv(file,argv) mexp_spawnvf (0, (file), (argv))
+#define mexp_spawnl(file,...) mexp_spawnlf (0, (file), __VA_ARGS__)
-/* Close the handle and clean up the subprocess.
- *
- * This returns:
- * 0: successful close, subprocess exited cleanly.
- * -1: error in system call, see errno.
- * > 0: exit status of subprocess if it didn't exit cleanly. Use
- * WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG etc macros to
- * examine this.
- *
- * Notes:
- *
- * - Even in the error cases, the handle is always closed and
- * freed by this call.
- *
- * - It is normal for the kernel to send SIGHUP to the subprocess.
- * If the subprocess doesn't catch the SIGHUP, then it will die
- * (WIFSIGNALED (status) && WTERMSIG (status) == SIGHUP). This
- * case should not necessarily be considered an error.
- */
+#define MEXP_SPAWN_KEEP_SIGNALS 1
+#define MEXP_SPAWN_KEEP_FDS 2
+#define MEXP_SPAWN_COOKED_MODE 4
+#define MEXP_SPAWN_RAW_MODE 0
+
+/* Close the handle. */
extern int mexp_close (mexp_h *h);
+/* Expect. */
+struct mexp_regexp {
+ int r;
+ const pcre2_code *re;
+ int options;
+};
+typedef struct mexp_regexp mexp_regexp;
+
enum mexp_status {
- MEXP_EOF = 0,
- MEXP_ERROR = 1,
- MEXP_TIMEOUT = 2,
- MEXP_MATCHED = 3,
- MEXP_PCRE_ERROR = 4,
+ MEXP_EOF = 0,
+ MEXP_ERROR = -1,
+ MEXP_PCRE_ERROR = -2,
+ MEXP_TIMEOUT = -3,
};
-/* Expect some output from the subprocess. Match the output against
- * the PCRE regular expression.
- *
- * 'code', 'extra', 'options', 'ovector' and 'ovecsize' are passed
- * through to the pcre_exec function. See pcreapi(3).
- *
- * If you want to match multiple strings, you have to combine them
- * into a single regexp, eg. "([Pp]assword)|([Ll]ogin)|([Ff]ailed)".
- * Then examine ovector[2], ovector[4], ovector[6] to see if they
- * contain '>= 0' or '-1'. See the pcreapi(3) man page for further
- * information.
- *
- * 'code' may be NULL, which means we don't match against a regular
- * expression. This is useful if you just want to wait for EOF or
- * timeout.
- *
- * This can return:
- *
- * MEXP_MATCHED:
- * The input matched the regular expression. Use ovector
- * to find out what matched in the buffer (mexp_h->buffer).
- * MEXP_TIMEOUT:
- * No input matched before the timeout (mexp_h->timeout) was reached.
- * MEXP_EOF:
- * The subprocess closed the connection.
- * MEXP_ERROR:
- * There was a system call error (eg. from the read call). See errno.
- * MEXP_PCRE_ERROR
- * There was a pcre_exec error. *pcre_ret is set to the error code
- * (see pcreapi(3) for a list of PCRE_* error codes and what they mean).
- */
-extern enum mexp_status mexp_expect (mexp_h *h, const pcre *code,
- const pcre_extra *extra,
- int options, int *ovector, int ovecsize,
- int *pcre_ret);
+extern int mexp_expect (mexp_h *h, const mexp_regexp *regexps,
+ pcre2_match_data *match_data);
-/* This is a convenience function for writing something (eg. a
- * password or command) to the subprocess. You could do this by
- * writing directly to 'h->fd', but this function does all the error
- * checking for you.
- *
- * Returns the number of bytes if the whole message was written OK
- * (partial writes are not possible with this function), or -1 if
- * there was an error (check errno).
- */
+/* Sending commands, keypresses. */
extern int mexp_printf (mexp_h *h, const char *fs, ...)
__attribute__((format(printf,2,3)));
+extern int mexp_printf_password (mexp_h *h, const char *fs, ...)
+ __attribute__((format(printf,2,3)));
+extern int mexp_send_interrupt (mexp_h *h);
#endif /* MINIEXPECT_H_ */