2 * Copyright (C) 2014 Red Hat Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <sys/types.h>
37 #include "miniexpect.h"
44 mexp_h *h = malloc (sizeof *h);
48 /* Initialize the fields to default values. */
54 h->len = h->alloc = 0;
55 h->user1 = h->user2 = h->user3 = NULL;
61 clear_buffer (mexp_h *h)
65 h->alloc = h->len = 0;
69 mexp_close (mexp_h *h)
78 if (waitpid (h->pid, &status, 0) == -1)
86 mexp_spawnl (const char *file, const char *arg, ...)
88 char **argv, **new_argv;
93 argv = malloc (sizeof (char *));
96 argv[0] = (char *) arg;
99 for (i = 1; arg != NULL; ++i) {
100 arg = va_arg (args, const char *);
101 new_argv = realloc (argv, sizeof (char *) * (i+1));
102 if (new_argv == NULL) {
107 argv[i] = (char *) arg;
110 h = mexp_spawnv (file, argv);
116 mexp_spawnv (const char *file, char **argv)
124 fd = posix_openpt (O_RDWR|O_NOCTTY);
128 if (grantpt (fd) == -1)
131 if (unlockpt (fd) == -1)
134 /* Get the slave pty name now, but don't open it in the parent. */
135 if (ptsname_r (fd, slave, sizeof slave) != 0)
138 /* Create the handle last before we fork. */
139 h = create_handle ();
147 if (pid == 0) { /* Child. */
148 struct termios terminal_settings;
153 /* Open the slave side of the pty. We must do this in the child
154 * after setsid so it becomes our controlling tty.
156 slave_fd = open (slave, O_RDWR);
161 tcgetattr (slave_fd, &terminal_settings);
162 cfmakeraw (&terminal_settings);
163 tcsetattr (slave_fd, TCSANOW, &terminal_settings);
165 /* Set up stdin, stdout, stderr to point to the pty. */
171 /* Close the master side of the pty - do this late to avoid a
172 * kernel bug, see sshpass source code.
176 /* Run the subprocess. */
179 _exit (EXIT_FAILURE);
193 waitpid (pid, NULL, 0);
199 mexp_expect (mexp_h *h, const pcre *code,
200 const pcre_extra *extra,
201 int options, int *ovector, int ovecsize,
204 time_t start_t, now_t;
206 struct pollfd pfds[1];
212 options |= PCRE_PARTIAL_SOFT;
214 /* Clear the read buffer. */
218 /* If we've got a timeout then work out how many seconds are left.
219 * Timeout == 0 is not particularly well-defined, but it probably
220 * means "return immediately if there's no data to be read".
222 if (h->timeout >= 0) {
224 timeout = h->timeout - ((now_t - start_t) * 1000);
232 pfds[0].events = POLLIN;
234 r = poll (pfds, 1, timeout);
236 fprintf (stderr, "DEBUG: poll returned %d\n", r);
244 /* Otherwise we expect there is something to read from the file
247 if (h->alloc - h->len <= h->read_size) {
249 /* +1 here allows us to store \0 after the data read */
250 new_buffer = realloc (h->buffer, h->alloc + h->read_size + 1);
251 if (new_buffer == NULL)
253 h->buffer = new_buffer;
254 h->alloc += h->read_size;
256 rs = read (h->fd, h->buffer + h->len, h->read_size);
258 fprintf (stderr, "DEBUG: read returned %zd\n", rs);
261 /* Annoyingly on Linux (I'm fairly sure this is a bug) if the
262 * writer closes the connection, the entire pty is destroyed,
263 * and read returns -1 / EIO. Handle that special case here.
272 /* We read something. */
274 h->buffer[h->len] = '\0';
276 fprintf (stderr, "DEBUG: read %zd bytes from pty\n", rs);
277 fprintf (stderr, "DEBUG: buffer content: %s\n", h->buffer);
280 /* See if there is a full or partial match against the regular expression. */
282 assert (h->buffer != NULL);
283 r = pcre_exec (code, extra, h->buffer, (int)h->len, 0,
284 options, ovector, ovecsize);
293 else if (r == PCRE_ERROR_NOMATCH) {
294 /* No match at all, so we can dump the input buffer. */
298 else if (r == PCRE_ERROR_PARTIAL) {
299 /* Partial match. Keep the buffer and keep reading. */
304 /* An actual PCRE error. */
305 return MEXP_PCRE_ERROR;
312 mexp_printf (mexp_h *h, const char *fs, ...)
322 len = vasprintf (&msg, fs, args);
329 fprintf (stderr, "DEBUG: writing: %s\n", msg);
335 r = write (h->fd, p, n);