common: Add header file and build the new code.
[gnupg.git] / common / sh-exectool.c
1 /* sh-exectool.c - Utility functions to execute a helper tool
2  * Copyright (C) 2015 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include <assuan.h>
29 #include "i18n.h"
30 #include "logging.h"
31 #include "membuf.h"
32 #include "exechelp.h"
33 #include "sysutils.h"
34
35 typedef struct
36 {
37   const char *pgmname;
38   int cont;
39   int used;
40   char buffer[256];
41 } read_and_log_buffer_t;
42
43
44 static void
45 read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
46 {
47   gpg_error_t err;
48   int c;
49
50   if (!fderr)
51     {
52       /* Flush internal buffer.  */
53       if (state->used)
54         {
55           const char *pname;
56           int len;
57
58           state->buffer[state->used] = 0;
59           state->used = 0;
60
61           pname = strrchr (state->pgmname, '/');
62           if (pname && pname != state->pgmname && pname[1])
63             pname++;
64           else
65             pname = state->pgmname;
66           /* If our pgmname plus colon is identical to the start of
67              the output, print only the output.  */
68           len = strlen (pname);
69           if (!state->cont
70               && !strncmp (state->buffer, pname, len)
71               && strlen (state->buffer) > strlen (pname)
72               && state->buffer[len] == ':' )
73             log_info ("%s\n", state->buffer);
74           else
75             log_info ("%s%c %s\n",
76                       pname, state->cont? '+':':', state->buffer);
77         }
78       state->cont = 0;
79       return;
80     }
81   for (;;)
82     {
83       c = es_fgetc (fderr->stream);
84       if (c == EOF)
85         {
86           if (es_feof (fderr->stream))
87             {
88               fderr->ignore = 1; /* Not anymore needed.  */
89             }
90           else if (es_ferror (fderr->stream))
91             {
92               err = gpg_error_from_syserror ();
93               log_error ("error reading stderr of '%s': %s\n",
94                          state->pgmname, gpg_strerror (err));
95               fderr->ignore = 1; /* Disable.  */
96             }
97
98           break;
99         }
100       else if (c == '\n')
101         {
102           read_and_log_stderr (state, NULL);
103         }
104       else
105         {
106           if (state->used >= sizeof state->buffer - 1)
107             {
108               read_and_log_stderr (state, NULL);
109               state->cont = 1;
110             }
111           state->buffer[state->used++] = c;
112         }
113     }
114 }
115
116
117 static gpg_error_t
118 read_stdout (membuf_t *mb, es_poll_t *fdout, const char *pgmname)
119 {
120   gpg_error_t err = 0;
121   int c;
122
123   for (;;)
124     {
125       c = es_fgetc (fdout->stream);
126       if (c == EOF)
127         {
128           if (es_feof (fdout->stream))
129             {
130               fdout->ignore = 1; /* Ready.  */
131             }
132           else if (es_ferror (fdout->stream))
133             {
134               err = gpg_error_from_syserror ();
135               log_error ("error reading stdout of '%s': %s\n",
136                          pgmname, gpg_strerror (err));
137               fdout->ignore = 1; /* Disable.  */
138             }
139
140           break;
141         }
142       else
143         {
144           char buf[1];
145           *buf = c;
146           put_membuf (mb, buf, 1);
147         }
148     }
149
150   return err;
151 }
152
153
154 /* Run the program PGMNAME with the command line arguments given in
155    the NULL terminates array ARGV.  If INPUT_STRING is not NULL it
156    will be fed to stdin of the process.  stderr is logged using
157    log_info and the process' stdout is returned in a newly malloced
158    buffer RESULT with the length stored at RESULTLEN if not given as
159    NULL.  A hidden Nul is appended to the output.  On error NULL is
160    stored at RESULT, a diagnostic is printed, and an error code
161    returned.  */
162 gpg_error_t
163 sh_exec_tool (const char *pgmname, const char *argv[],
164               const char *input_string,
165               char **result, size_t *resultlen)
166 {
167   gpg_error_t err;
168   pid_t pid;
169   estream_t infp = NULL;
170   estream_t outfp, errfp;
171   es_poll_t fds[3];
172   int count;
173   read_and_log_buffer_t fderrstate;
174   membuf_t fdout_mb;
175   size_t len, nwritten;
176
177   *result = NULL;
178   if (resultlen)
179     *resultlen = 0;
180   memset (fds, 0, sizeof fds);
181   memset (&fderrstate, 0, sizeof fderrstate);
182   init_membuf (&fdout_mb, 4096);
183
184   err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT,
185                              NULL, GNUPG_SPAWN_NONBLOCK,
186                              input_string? &infp : NULL,
187                              &outfp, &errfp, &pid);
188   if (err)
189     {
190       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
191       return err;
192     }
193
194   fderrstate.pgmname = pgmname;
195
196   fds[0].stream = infp;
197   fds[0].want_write = 1;
198   if (!input_string)
199     fds[0].ignore = 1;
200   fds[1].stream = outfp;
201   fds[1].want_read = 1;
202   fds[2].stream = errfp;
203   fds[2].want_read = 1;
204   /* Now read as long as we have something to poll.  We continue
205      reading even after EOF or error on stdout so that we get the
206      other error messages or remaining outout.  */
207   while (!fds[1].ignore && !fds[2].ignore)
208     {
209       count = es_poll (fds, DIM(fds), -1);
210       if (count == -1)
211         {
212           err = gpg_error_from_syserror ();
213           log_error ("error polling '%s': %s\n", pgmname, gpg_strerror (err));
214           goto leave;
215         }
216       if (!count)
217         {
218           log_debug ("unexpected timeout while polling '%s'\n", pgmname);
219           break;
220         }
221
222       if (fds[0].got_write)
223         {
224           len = strlen (input_string);
225           log_debug ("writing '%s'\n", input_string);
226           if (es_write (fds[0].stream, input_string, len, &nwritten))
227             {
228               if (errno != EAGAIN)
229                 {
230                   err = gpg_error_from_syserror ();
231                   log_error ("error writing '%s': %s\n",
232                              pgmname, gpg_strerror (err));
233                   goto leave;
234                 }
235               else
236                 log_debug ("  .. EAGAIN\n");
237             }
238           else
239             {
240               assert (nwritten <= len);
241               input_string += nwritten;
242             }
243
244           if (es_fflush (fds[0].stream) && errno != EAGAIN)
245             {
246               err = gpg_error_from_syserror ();
247               log_error ("error writing '%s' (flush): %s\n",
248                          pgmname, gpg_strerror (err));
249               if (gpg_err_code (err) == GPG_ERR_EPIPE && !*input_string)
250                 {
251                   /* fixme: How can we tell whether estream has
252                      pending bytes after a HUP - which is an
253                      error?  */
254                 }
255               else
256                 goto leave;
257             }
258           if (!*input_string)
259             {
260               fds[0].ignore = 1; /* ready.  */
261               es_fclose (infp); infp = NULL;
262             }
263         }
264
265       if (fds[1].got_read)
266         read_stdout (&fdout_mb, fds + 1, pgmname); /* FIXME: Add error
267                                                       handling.  */
268       if (fds[2].got_read)
269         read_and_log_stderr (&fderrstate, fds + 2);
270
271     }
272
273   read_and_log_stderr (&fderrstate, NULL); /* Flush.  */
274   es_fclose (infp); infp = NULL;
275   es_fclose (outfp); outfp = NULL;
276   es_fclose (errfp); errfp = NULL;
277
278   err = gnupg_wait_process (pgmname, pid, 1, NULL);
279   pid = (pid_t)(-1);
280
281  leave:
282   if (err)
283     {
284       gnupg_kill_process (pid);
285       xfree (get_membuf (&fdout_mb, NULL));
286     }
287   else
288     {
289       put_membuf (&fdout_mb, "", 1); /* Make sure it is a string.  */
290       *result = get_membuf (&fdout_mb, resultlen);
291       if (!*result)
292         err = gpg_error_from_syserror ();
293     }
294
295   es_fclose (infp);
296   es_fclose (outfp);
297   es_fclose (errfp);
298   if (pid != (pid_t)(-1))
299     gnupg_wait_process (pgmname, pid, 1, NULL);
300   gnupg_release_process (pid);
301
302   return err;
303 }