caf498dc1cc3da6998706807f44bd94f88a28af2
[miniexpect.git] / miniexpect.c
1 /* miniexpect
2  * Copyright (C) 2014 Red Hat Inc.
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <poll.h>
29 #include <errno.h>
30 #include <termios.h>
31 #include <time.h>
32 #include <assert.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <sys/time.h>
36
37 #include <pcre.h>
38
39 /* RHEL 6 pcre did not define PCRE_PARTIAL_SOFT.  However PCRE_PARTIAL
40  * is a synonym so use that.
41  */
42 #ifndef PCRE_PARTIAL_SOFT
43 #define PCRE_PARTIAL_SOFT PCRE_PARTIAL
44 #endif
45
46 #include "miniexpect.h"
47
48 #define DEBUG 0
49
50 static mexp_h *
51 create_handle (void)
52 {
53   mexp_h *h = malloc (sizeof *h);
54   if (h == NULL)
55     return NULL;
56
57   /* Initialize the fields to default values. */
58   h->fd = -1;
59   h->pid = 0;
60   h->timeout = 60000;
61   h->read_size = 1024;
62   h->pcre_error = 0;
63   h->buffer = NULL;
64   h->len = h->alloc = 0;
65   h->next_match = -1;
66   h->user1 = h->user2 = h->user3 = NULL;
67
68   return h;
69 }
70
71 static void
72 clear_buffer (mexp_h *h)
73 {
74   free (h->buffer);
75   h->buffer = NULL;
76   h->alloc = h->len = 0;
77   h->next_match = -1;
78 }
79
80 int
81 mexp_close (mexp_h *h)
82 {
83   int status = 0;
84
85   free (h->buffer);
86
87   if (h->fd >= 0)
88     close (h->fd);
89   if (h->pid > 0) {
90     if (waitpid (h->pid, &status, 0) == -1)
91       return -1;
92   }
93
94   free (h);
95
96   return status;
97 }
98
99 mexp_h *
100 mexp_spawnlf (unsigned flags, const char *file, const char *arg, ...)
101 {
102   char **argv, **new_argv;
103   size_t i;
104   va_list args;
105   mexp_h *h;
106
107   argv = malloc (sizeof (char *));
108   if (argv == NULL)
109     return NULL;
110   argv[0] = (char *) arg;
111
112   va_start (args, arg);
113   for (i = 1; arg != NULL; ++i) {
114     arg = va_arg (args, const char *);
115     new_argv = realloc (argv, sizeof (char *) * (i+1));
116     if (new_argv == NULL) {
117       free (argv);
118       va_end (args);
119       return NULL;
120     }
121     argv = new_argv;
122     argv[i] = (char *) arg;
123   }
124
125   h = mexp_spawnvf (flags, file, argv);
126   free (argv);
127   va_end (args);
128   return h;
129 }
130
131 mexp_h *
132 mexp_spawnvf (unsigned flags, const char *file, char **argv)
133 {
134   mexp_h *h = NULL;
135   int fd = -1;
136   int err;
137   char slave[1024];
138   pid_t pid = 0;
139
140   fd = posix_openpt (O_RDWR|O_NOCTTY);
141   if (fd == -1)
142     goto error;
143
144   if (grantpt (fd) == -1)
145     goto error;
146
147   if (unlockpt (fd) == -1)
148     goto error;
149
150   /* Get the slave pty name now, but don't open it in the parent. */
151   if (ptsname_r (fd, slave, sizeof slave) != 0)
152     goto error;
153
154   /* Create the handle last before we fork. */
155   h = create_handle ();
156   if (h == NULL)
157     goto error;
158
159   pid = fork ();
160   if (pid == -1)
161     goto error;
162
163   if (pid == 0) {               /* Child. */
164     int slave_fd;
165
166     if (!(flags & MEXP_SPAWN_KEEP_SIGNALS)) {
167       struct sigaction sa;
168       int i;
169
170       /* Remove all signal handlers.  See the justification here:
171        * https://www.redhat.com/archives/libvir-list/2008-August/msg00303.html
172        * We don't mask signal handlers yet, so this isn't completely
173        * race-free, but better than not doing it at all.
174        */
175       memset (&sa, 0, sizeof sa);
176       sa.sa_handler = SIG_DFL;
177       sa.sa_flags = 0;
178       sigemptyset (&sa.sa_mask);
179       for (i = 1; i < NSIG; ++i)
180         sigaction (i, &sa, NULL);
181     }
182
183     setsid ();
184
185     /* Open the slave side of the pty.  We must do this in the child
186      * after setsid so it becomes our controlling tty.
187      */
188     slave_fd = open (slave, O_RDWR);
189     if (slave_fd == -1)
190       goto error;
191
192     if (!(flags & MEXP_SPAWN_COOKED_MODE)) {
193       struct termios termios;
194
195       /* Set raw mode. */
196       tcgetattr (slave_fd, &termios);
197       cfmakeraw (&termios);
198       tcsetattr (slave_fd, TCSANOW, &termios);
199     }
200
201     /* Set up stdin, stdout, stderr to point to the pty. */
202     dup2 (slave_fd, 0);
203     dup2 (slave_fd, 1);
204     dup2 (slave_fd, 2);
205     close (slave_fd);
206
207     /* Close the master side of the pty - do this late to avoid a
208      * kernel bug, see sshpass source code.
209      */
210     close (fd);
211
212     if (!(flags & MEXP_SPAWN_KEEP_FDS)) {
213       int i, max_fd;
214
215       /* Close all other file descriptors.  This ensures that we don't
216        * hold open (eg) pipes from the parent process.
217        */
218       max_fd = sysconf (_SC_OPEN_MAX);
219       if (max_fd == -1)
220         max_fd = 1024;
221       if (max_fd > 65536)
222         max_fd = 65536;      /* bound the amount of work we do here */
223       for (i = 3; i < max_fd; ++i)
224         close (i);
225     }
226
227     /* Run the subprocess. */
228     execvp (file, argv);
229     perror (file);
230     _exit (EXIT_FAILURE);
231   }
232
233   /* Parent. */
234
235   h->fd = fd;
236   h->pid = pid;
237   return h;
238
239  error:
240   err = errno;
241   if (fd >= 0)
242     close (fd);
243   if (pid > 0)
244     waitpid (pid, NULL, 0);
245   if (h != NULL)
246     mexp_close (h);
247   errno = err;
248   return NULL;
249 }
250
251 enum mexp_status
252 mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
253 {
254   time_t start_t, now_t;
255   int timeout;
256   struct pollfd pfds[1];
257   int r;
258   ssize_t rs;
259
260   time (&start_t);
261
262   if (h->next_match == -1) {
263     /* Fully clear the buffer, then read. */
264     clear_buffer (h);
265   } else {
266     /* See the comment in the manual about h->next_match.  We have
267      * some data remaining in the buffer, so begin by matching that.
268      */
269     memmove (&h->buffer[0], &h->buffer[h->next_match], h->len - h->next_match);
270     h->len -= h->next_match;
271     h->buffer[h->len] = '\0';
272     h->next_match = -1;
273     goto try_match;
274   }
275
276   for (;;) {
277     /* If we've got a timeout then work out how many seconds are left.
278      * Timeout == 0 is not particularly well-defined, but it probably
279      * means "return immediately if there's no data to be read".
280      */
281     if (h->timeout >= 0) {
282       time (&now_t);
283       timeout = h->timeout - ((now_t - start_t) * 1000);
284       if (timeout < 0)
285         timeout = 0;
286     }
287     else
288       timeout = 0;
289
290     pfds[0].fd = h->fd;
291     pfds[0].events = POLLIN;
292     pfds[0].revents = 0;
293     r = poll (pfds, 1, timeout);
294 #if DEBUG
295     fprintf (stderr, "DEBUG: poll returned %d\n", r);
296 #endif
297     if (r == -1)
298       return MEXP_ERROR;
299
300     if (r == 0)
301       return MEXP_TIMEOUT;
302
303     /* Otherwise we expect there is something to read from the file
304      * descriptor.
305      */
306     if (h->alloc - h->len <= h->read_size) {
307       char *new_buffer;
308       /* +1 here allows us to store \0 after the data read */
309       new_buffer = realloc (h->buffer, h->alloc + h->read_size + 1);
310       if (new_buffer == NULL)
311         return MEXP_ERROR;
312       h->buffer = new_buffer;
313       h->alloc += h->read_size;
314     }
315     rs = read (h->fd, h->buffer + h->len, h->read_size);
316 #if DEBUG
317     fprintf (stderr, "DEBUG: read returned %zd\n", rs);
318 #endif
319     if (rs == -1) {
320       /* Annoyingly on Linux (I'm fairly sure this is a bug) if the
321        * writer closes the connection, the entire pty is destroyed,
322        * and read returns -1 / EIO.  Handle that special case here.
323        */
324       if (errno == EIO)
325         return MEXP_EOF;
326       return MEXP_ERROR;
327     }
328     if (rs == 0)
329       return MEXP_EOF;
330
331     /* We read something. */
332     h->len += rs;
333     h->buffer[h->len] = '\0';
334 #if DEBUG
335     fprintf (stderr, "DEBUG: read %zd bytes from pty\n", rs);
336     fprintf (stderr, "DEBUG: buffer content: %s\n", h->buffer);
337 #endif
338
339   try_match:
340     /* See if there is a full or partial match against any regexp. */
341     if (regexps) {
342       size_t i;
343       int can_clear_buffer = 1;
344
345       assert (h->buffer != NULL);
346
347       for (i = 0; regexps[i].r > 0; ++i) {
348         int options = regexps[i].options | PCRE_PARTIAL_SOFT;
349
350         r = pcre_exec (regexps[i].re, regexps[i].extra,
351                        h->buffer, (int)h->len, 0,
352                        options,
353                        ovector, ovecsize);
354         h->pcre_error = r;
355
356         if (r >= 0) {
357           /* A full match. */
358           if (ovector != NULL && ovecsize >= 1 && ovector[1] >= 0)
359             h->next_match = ovector[1];
360           else
361             h->next_match = -1;
362           return regexps[i].r;
363         }
364
365         else if (r == PCRE_ERROR_NOMATCH) {
366           /* No match at all. */
367           /* (nothing here) */
368         }
369
370         else if (r == PCRE_ERROR_PARTIAL) {
371           /* Partial match.  Keep the buffer and keep reading. */
372           can_clear_buffer = 0;
373         }
374
375         else {
376           /* An actual PCRE error. */
377           return MEXP_PCRE_ERROR;
378         }
379       }
380
381       /* If none of the regular expressions matched (not partially)
382        * then we can clear the buffer.  This is an optimization.
383        */
384       if (can_clear_buffer)
385         clear_buffer (h);
386
387     } /* if (regexps) */
388   }
389 }
390
391 int
392 mexp_printf (mexp_h *h, const char *fs, ...)
393 {
394   va_list args;
395   char *msg;
396   int len;
397   size_t n;
398   ssize_t r;
399   char *p;
400
401   va_start (args, fs);
402   len = vasprintf (&msg, fs, args);
403   va_end (args);
404
405   if (len < 0)
406     return -1;
407
408 #if DEBUG
409   fprintf (stderr, "DEBUG: writing: %s\n", msg);
410 #endif
411
412   n = len;
413   p = msg;
414   while (n > 0) {
415     r = write (h->fd, p, n);
416     if (r == -1) {
417       free (msg);
418       return -1;
419     }
420     n -= r;
421     p += r;
422   }
423
424   free (msg);
425   return len;
426 }
427
428 int
429 mexp_send_interrupt (mexp_h *h)
430 {
431   return write (h->fd, "\003", 1);
432 }