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
34 #include <sys/types.h>
38 #define PCRE2_CODE_UNIT_WIDTH 8
41 #include "miniexpect.h"
43 static void debug_buffer (FILE *, const char *);
48 mexp_h *h = malloc (sizeof *h);
52 /* Initialize the fields to default values. */
59 h->len = h->alloc = 0;
62 h->user1 = h->user2 = h->user3 = NULL;
68 clear_buffer (mexp_h *h)
72 h->alloc = h->len = 0;
77 mexp_close (mexp_h *h)
86 if (waitpid (h->pid, &status, 0) == -1)
96 mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...)
98 char **argv, **new_argv;
103 argv = malloc (sizeof (char *));
106 argv[0] = (char *) arg;
108 va_start (args, arg);
109 for (i = 1; arg != NULL; ++i) {
110 arg = va_arg (args, const char *);
111 new_argv = realloc (argv, sizeof (char *) * (i+1));
112 if (new_argv == NULL) {
118 argv[i] = (char *) arg;
121 h = mexp_spawnvf (flags, file, argv);
128 mexp_spawnvf (unsigned flags, const char *file, char **argv)
136 fd = posix_openpt (O_RDWR|O_NOCTTY);
140 if (grantpt (fd) == -1)
143 if (unlockpt (fd) == -1)
146 /* Get the slave pty name now, but don't open it in the parent. */
147 if (ptsname_r (fd, slave, sizeof slave) != 0)
150 /* Create the handle last before we fork. */
151 h = create_handle ();
159 if (pid == 0) { /* Child. */
162 if (!(flags & MEXP_SPAWN_KEEP_SIGNALS)) {
166 /* Remove all signal handlers. See the justification here:
167 * https://www.redhat.com/archives/libvir-list/2008-August/msg00303.html
168 * We don't mask signal handlers yet, so this isn't completely
169 * race-free, but better than not doing it at all.
171 memset (&sa, 0, sizeof sa);
172 sa.sa_handler = SIG_DFL;
174 sigemptyset (&sa.sa_mask);
175 for (i = 1; i < NSIG; ++i)
176 sigaction (i, &sa, NULL);
181 /* Open the slave side of the pty. We must do this in the child
182 * after setsid so it becomes our controlling tty.
184 slave_fd = open (slave, O_RDWR);
188 if (!(flags & MEXP_SPAWN_COOKED_MODE)) {
189 struct termios termios;
192 tcgetattr (slave_fd, &termios);
193 cfmakeraw (&termios);
194 tcsetattr (slave_fd, TCSANOW, &termios);
197 /* Set up stdin, stdout, stderr to point to the pty. */
203 /* Close the master side of the pty - do this late to avoid a
204 * kernel bug, see sshpass source code.
208 if (!(flags & MEXP_SPAWN_KEEP_FDS)) {
211 /* Close all other file descriptors. This ensures that we don't
212 * hold open (eg) pipes from the parent process.
214 max_fd = sysconf (_SC_OPEN_MAX);
218 max_fd = 65536; /* bound the amount of work we do here */
219 for (i = 3; i < max_fd; ++i)
223 /* Run the subprocess. */
226 _exit (EXIT_FAILURE);
240 waitpid (pid, NULL, 0);
248 mexp_expect (mexp_h *h, const mexp_regexp *regexps,
249 pcre2_match_data *match_data)
251 time_t start_t, now_t;
253 struct pollfd pfds[1];
259 if (h->next_match == -1) {
260 /* Fully clear the buffer, then read. */
263 /* See the comment in the manual about h->next_match. We have
264 * some data remaining in the buffer, so begin by matching that.
266 memmove (&h->buffer[0], &h->buffer[h->next_match], h->len - h->next_match);
267 h->len -= h->next_match;
268 h->buffer[h->len] = '\0';
274 /* If we've got a timeout then work out how many seconds are left.
275 * Timeout == 0 is not particularly well-defined, but it probably
276 * means "return immediately if there's no data to be read".
278 if (h->timeout >= 0) {
280 timeout = h->timeout - ((now_t - start_t) * 1000);
288 pfds[0].events = POLLIN;
290 r = poll (pfds, 1, timeout);
292 fprintf (h->debug_fp, "DEBUG: poll returned %d\n", r);
299 /* Otherwise we expect there is something to read from the file
302 if (h->alloc - h->len <= h->read_size) {
304 /* +1 here allows us to store \0 after the data read */
305 new_buffer = realloc (h->buffer, h->alloc + h->read_size + 1);
306 if (new_buffer == NULL)
308 h->buffer = new_buffer;
309 h->alloc += h->read_size;
311 rs = read (h->fd, h->buffer + h->len, h->read_size);
313 fprintf (h->debug_fp, "DEBUG: read returned %zd\n", rs);
315 /* Annoyingly on Linux (I'm fairly sure this is a bug) if the
316 * writer closes the connection, the entire pty is destroyed,
317 * and read returns -1 / EIO. Handle that special case here.
326 /* We read something. */
328 h->buffer[h->len] = '\0';
330 fprintf (h->debug_fp, "DEBUG: read %zd bytes from pty\n", rs);
331 fprintf (h->debug_fp, "DEBUG: buffer content: ");
332 debug_buffer (h->debug_fp, h->buffer);
333 fprintf (h->debug_fp, "\n");
337 /* See if there is a full or partial match against any regexp. */
340 int can_clear_buffer = 1;
342 assert (h->buffer != NULL);
344 for (i = 0; regexps[i].r > 0; ++i) {
345 const int options = regexps[i].options | PCRE2_PARTIAL_SOFT;
347 r = pcre2_match (regexps[i].re,
348 (PCRE2_SPTR) h->buffer, (int)h->len, 0,
349 options, match_data, NULL);
354 const PCRE2_SIZE *ovector = NULL;
357 ovector = pcre2_get_ovector_pointer (match_data);
359 if (ovector != NULL && ovector[1] != ~(PCRE2_SIZE)0)
360 h->next_match = ovector[1];
364 fprintf (h->debug_fp, "DEBUG: next_match at buffer offset %zu\n",
369 else if (r == PCRE2_ERROR_NOMATCH) {
370 /* No match at all. */
374 else if (r == PCRE2_ERROR_PARTIAL) {
375 /* Partial match. Keep the buffer and keep reading. */
376 can_clear_buffer = 0;
380 /* An actual PCRE error. */
381 return MEXP_PCRE_ERROR;
385 /* If none of the regular expressions matched (not partially)
386 * then we can clear the buffer. This is an optimization.
388 if (can_clear_buffer)
395 static int mexp_vprintf (mexp_h *h, int password, const char *fs, va_list args)
396 __attribute__((format(printf,3,0)));
399 mexp_vprintf (mexp_h *h, int password, const char *fs, va_list args)
407 len = vasprintf (&msg, fs, args);
414 fprintf (h->debug_fp, "DEBUG: writing: ");
415 debug_buffer (h->debug_fp, msg);
416 fprintf (h->debug_fp, "\n");
419 fprintf (h->debug_fp, "DEBUG: writing the password\n");
425 r = write (h->fd, p, n);
439 mexp_printf (mexp_h *h, const char *fs, ...)
445 r = mexp_vprintf (h, 0, fs, args);
451 mexp_printf_password (mexp_h *h, const char *fs, ...)
457 r = mexp_vprintf (h, 1, fs, args);
463 mexp_send_interrupt (mexp_h *h)
465 return write (h->fd, "\003", 1);
468 /* Print escaped buffer to fp. */
470 debug_buffer (FILE *fp, const char *buf)
477 case '\0': fputs ("\\0", fp); break;
478 case '\a': fputs ("\\a", fp); break;
479 case '\b': fputs ("\\b", fp); break;
480 case '\f': fputs ("\\f", fp); break;
481 case '\n': fputs ("\\n", fp); break;
482 case '\r': fputs ("\\r", fp); break;
483 case '\t': fputs ("\\t", fp); break;
484 case '\v': fputs ("\\v", fp); break;
486 fprintf (fp, "\\x%x", (unsigned char) *buf);