ee2b7fa84eaeefdc5e8c5defa26a77fd46d0ab14
[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_spawnl (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_spawnv (file, argv);
126   free (argv);
127   va_end (args);
128   return h;
129 }
130
131 mexp_h *
132 mexp_spawnv (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     struct termios terminal_settings;
165     struct sigaction sa;
166     int i, slave_fd, max_fd;
167
168     /* Remove all signal handlers.  See the justification here:
169      * https://www.redhat.com/archives/libvir-list/2008-August/msg00303.html
170      * We don't mask signal handlers yet, so this isn't completely
171      * race-free, but better than not doing it at all.
172      */
173     memset (&sa, 0, sizeof sa);
174     sa.sa_handler = SIG_DFL;
175     sa.sa_flags = 0;
176     sigemptyset (&sa.sa_mask);
177     for (i = 1; i < NSIG; ++i)
178       sigaction (i, &sa, NULL);
179
180     setsid ();
181
182     /* Open the slave side of the pty.  We must do this in the child
183      * after setsid so it becomes our controlling tty.
184      */
185     slave_fd = open (slave, O_RDWR);
186     if (slave_fd == -1)
187       goto error;
188
189     /* Set raw mode. */
190     tcgetattr (slave_fd, &terminal_settings);
191     cfmakeraw (&terminal_settings);
192     tcsetattr (slave_fd, TCSANOW, &terminal_settings);
193
194     /* Set up stdin, stdout, stderr to point to the pty. */
195     dup2 (slave_fd, 0);
196     dup2 (slave_fd, 1);
197     dup2 (slave_fd, 2);
198     close (slave_fd);
199
200     /* Close the master side of the pty - do this late to avoid a
201      * kernel bug, see sshpass source code.
202      */
203     close (fd);
204
205     /* Close all other file descriptors.  This ensures that we don't
206      * hold open (eg) pipes from the parent process.
207      */
208     max_fd = sysconf (_SC_OPEN_MAX);
209     if (max_fd == -1)
210       max_fd = 1024;
211     if (max_fd > 65536)
212       max_fd = 65536;        /* bound the amount of work we do here */
213     for (fd = 3; fd < max_fd; ++fd)
214       close (fd);
215
216     /* Run the subprocess. */
217     execvp (file, argv);
218     perror (file);
219     _exit (EXIT_FAILURE);
220   }
221
222   /* Parent. */
223
224   h->fd = fd;
225   h->pid = pid;
226   return h;
227
228  error:
229   err = errno;
230   if (fd >= 0)
231     close (fd);
232   if (pid > 0)
233     waitpid (pid, NULL, 0);
234   if (h != NULL)
235     mexp_close (h);
236   errno = err;
237   return NULL;
238 }
239
240 enum mexp_status
241 mexp_expect (mexp_h *h, const mexp_regexp *regexps, int *ovector, int ovecsize)
242 {
243   time_t start_t, now_t;
244   int timeout;
245   struct pollfd pfds[1];
246   int r;
247   ssize_t rs;
248
249   time (&start_t);
250
251   if (h->next_match == -1) {
252     /* Fully clear the buffer, then read. */
253     clear_buffer (h);
254   } else {
255     /* See the comment in the manual about h->next_match.  We have
256      * some data remaining in the buffer, so begin by matching that.
257      */
258     memmove (&h->buffer[0], &h->buffer[h->next_match], h->len - h->next_match);
259     h->len -= h->next_match;
260     h->buffer[h->len] = '\0';
261     h->next_match = -1;
262     goto try_match;
263   }
264
265   for (;;) {
266     /* If we've got a timeout then work out how many seconds are left.
267      * Timeout == 0 is not particularly well-defined, but it probably
268      * means "return immediately if there's no data to be read".
269      */
270     if (h->timeout >= 0) {
271       time (&now_t);
272       timeout = h->timeout - ((now_t - start_t) * 1000);
273       if (timeout < 0)
274         timeout = 0;
275     }
276     else
277       timeout = 0;
278
279     pfds[0].fd = h->fd;
280     pfds[0].events = POLLIN;
281     pfds[0].revents = 0;
282     r = poll (pfds, 1, timeout);
283 #if DEBUG
284     fprintf (stderr, "DEBUG: poll returned %d\n", r);
285 #endif
286     if (r == -1)
287       return MEXP_ERROR;
288
289     if (r == 0)
290       return MEXP_TIMEOUT;
291
292     /* Otherwise we expect there is something to read from the file
293      * descriptor.
294      */
295     if (h->alloc - h->len <= h->read_size) {
296       char *new_buffer;
297       /* +1 here allows us to store \0 after the data read */
298       new_buffer = realloc (h->buffer, h->alloc + h->read_size + 1);
299       if (new_buffer == NULL)
300         return MEXP_ERROR;
301       h->buffer = new_buffer;
302       h->alloc += h->read_size;
303     }
304     rs = read (h->fd, h->buffer + h->len, h->read_size);
305 #if DEBUG
306     fprintf (stderr, "DEBUG: read returned %zd\n", rs);
307 #endif
308     if (rs == -1) {
309       /* Annoyingly on Linux (I'm fairly sure this is a bug) if the
310        * writer closes the connection, the entire pty is destroyed,
311        * and read returns -1 / EIO.  Handle that special case here.
312        */
313       if (errno == EIO)
314         return MEXP_EOF;
315       return MEXP_ERROR;
316     }
317     if (rs == 0)
318       return MEXP_EOF;
319
320     /* We read something. */
321     h->len += rs;
322     h->buffer[h->len] = '\0';
323 #if DEBUG
324     fprintf (stderr, "DEBUG: read %zd bytes from pty\n", rs);
325     fprintf (stderr, "DEBUG: buffer content: %s\n", h->buffer);
326 #endif
327
328   try_match:
329     /* See if there is a full or partial match against any regexp. */
330     if (regexps) {
331       size_t i;
332       int can_clear_buffer = 1;
333
334       assert (h->buffer != NULL);
335
336       for (i = 0; regexps[i].r > 0; ++i) {
337         int options = regexps[i].options | PCRE_PARTIAL_SOFT;
338
339         r = pcre_exec (regexps[i].re, regexps[i].extra,
340                        h->buffer, (int)h->len, 0,
341                        options,
342                        ovector, ovecsize);
343         h->pcre_error = r;
344
345         if (r >= 0) {
346           /* A full match. */
347           if (ovector != NULL && ovecsize >= 1 && ovector[1] >= 0)
348             h->next_match = ovector[1];
349           else
350             h->next_match = -1;
351           return regexps[i].r;
352         }
353
354         else if (r == PCRE_ERROR_NOMATCH) {
355           /* No match at all. */
356           /* (nothing here) */
357         }
358
359         else if (r == PCRE_ERROR_PARTIAL) {
360           /* Partial match.  Keep the buffer and keep reading. */
361           can_clear_buffer = 0;
362         }
363
364         else {
365           /* An actual PCRE error. */
366           return MEXP_PCRE_ERROR;
367         }
368       }
369
370       /* If none of the regular expressions matched (not partially)
371        * then we can clear the buffer.  This is an optimization.
372        */
373       if (can_clear_buffer)
374         clear_buffer (h);
375
376     } /* if (regexps) */
377   }
378 }
379
380 int
381 mexp_printf (mexp_h *h, const char *fs, ...)
382 {
383   va_list args;
384   char *msg;
385   int len;
386   size_t n;
387   ssize_t r;
388   char *p;
389
390   va_start (args, fs);
391   len = vasprintf (&msg, fs, args);
392   va_end (args);
393
394   if (len < 0)
395     return -1;
396
397 #if DEBUG
398   fprintf (stderr, "DEBUG: writing: %s\n", msg);
399 #endif
400
401   n = len;
402   p = msg;
403   while (n > 0) {
404     r = write (h->fd, p, n);
405     if (r == -1) {
406       free (msg);
407       return -1;
408     }
409     n -= r;
410     p += r;
411   }
412
413   free (msg);
414   return len;
415 }