w32: Replace libiconv DLL by iconv feature of libgpg-error.
[gnupg.git] / common / exectool.c
1 /* 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  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <http://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <assert.h>
37 #include <gpg-error.h>
38
39 #include <assuan.h>
40 #include "i18n.h"
41 #include "logging.h"
42 #include "membuf.h"
43 #include "mischelp.h"
44 #include "exechelp.h"
45 #include "sysutils.h"
46 #include "util.h"
47
48 typedef struct
49 {
50   const char *pgmname;
51   int cont;
52   int used;
53   char buffer[256];
54 } read_and_log_buffer_t;
55
56
57 static inline gpg_error_t
58 my_error_from_syserror (void)
59 {
60   return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
61 }
62
63
64 static void
65 read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
66 {
67   gpg_error_t err;
68   int c;
69
70   if (!fderr)
71     {
72       /* Flush internal buffer.  */
73       if (state->used)
74         {
75           const char *pname;
76           int len;
77
78           state->buffer[state->used] = 0;
79           state->used = 0;
80
81           pname = strrchr (state->pgmname, '/');
82           if (pname && pname != state->pgmname && pname[1])
83             pname++;
84           else
85             pname = state->pgmname;
86           /* If our pgmname plus colon is identical to the start of
87              the output, print only the output.  */
88           len = strlen (pname);
89           if (!state->cont
90               && !strncmp (state->buffer, pname, len)
91               && strlen (state->buffer) > strlen (pname)
92               && state->buffer[len] == ':' )
93             log_info ("%s\n", state->buffer);
94           else
95             log_info ("%s%c %s\n",
96                       pname, state->cont? '+':':', state->buffer);
97         }
98       state->cont = 0;
99       return;
100     }
101   for (;;)
102     {
103       c = es_fgetc (fderr->stream);
104       if (c == EOF)
105         {
106           if (es_feof (fderr->stream))
107             {
108               fderr->ignore = 1; /* Not anymore needed.  */
109             }
110           else if (es_ferror (fderr->stream))
111             {
112               err = my_error_from_syserror ();
113               log_error ("error reading stderr of '%s': %s\n",
114                          state->pgmname, gpg_strerror (err));
115               fderr->ignore = 1; /* Disable.  */
116             }
117
118           break;
119         }
120       else if (c == '\n')
121         {
122           read_and_log_stderr (state, NULL);
123         }
124       else
125         {
126           if (state->used >= sizeof state->buffer - 1)
127             {
128               read_and_log_stderr (state, NULL);
129               state->cont = 1;
130             }
131           state->buffer[state->used++] = c;
132         }
133     }
134 }
135
136 \f
137
138 /* A buffer to copy from one stream to another.  */
139 struct copy_buffer
140 {
141   char buffer[4096];
142   char *writep;
143   size_t nread;
144 };
145
146
147 /* Initialize a copy buffer.  */
148 static void
149 copy_buffer_init (struct copy_buffer *c)
150 {
151   c->writep = c->buffer;
152   c->nread = 0;
153 }
154
155
156 /* Securely wipe a copy buffer.  */
157 static void
158 copy_buffer_shred (struct copy_buffer *c)
159 {
160   wipememory (c->buffer, sizeof c->buffer);
161   c->writep = NULL;
162   c->nread = ~0U;
163 }
164
165
166 /* Copy data from SOURCE to SINK using copy buffer C.  */
167 static gpg_error_t
168 copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
169 {
170   gpg_error_t err;
171   size_t nwritten;
172
173   if (c->nread == 0)
174     {
175       c->writep = c->buffer;
176       err = es_read (source, c->buffer, sizeof c->buffer, &c->nread);
177       if (err)
178         {
179           if (errno == EAGAIN)
180             return 0;   /* We will just retry next time.  */
181
182           return my_error_from_syserror ();
183         }
184
185       assert (c->nread <= sizeof c->buffer);
186     }
187
188   if (c->nread == 0)
189     return 0;   /* Done copying.  */
190
191   err = es_write (sink, c->writep, c->nread, &nwritten);
192   if (err)
193     {
194       if (errno == EAGAIN)
195         return 0;       /* We will just retry next time.  */
196
197       return my_error_from_syserror ();
198     }
199
200   assert (nwritten <= c->nread);
201   c->writep += nwritten;
202   c->nread -= nwritten;
203   assert (c->writep - c->buffer <= sizeof c->buffer);
204
205   if (es_fflush (sink) && errno != EAGAIN)
206     err = my_error_from_syserror ();
207
208   return err;
209 }
210
211
212 /* Flush the remaining data to SINK.  */
213 static gpg_error_t
214 copy_buffer_flush (struct copy_buffer *c, estream_t sink)
215 {
216   gpg_error_t err;
217
218   while (c->nread > 0)
219     {
220       err = copy_buffer_do_copy (c, NULL, sink);
221       if (err)
222         return err;
223     }
224
225   return 0;
226 }
227
228 \f
229
230 /* Run the program PGMNAME with the command line arguments given in
231    the NULL terminates array ARGV.  If INPUT is not NULL it will be
232    fed to stdin of the process.  stderr is logged using log_info and
233    the process' stdout is written to OUTPUT.  On error a diagnostic is
234    printed, and an error code returned.  */
235 gpg_error_t
236 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
237                         estream_t input,
238                         estream_t output)
239 {
240   gpg_error_t err;
241   pid_t pid;
242   estream_t infp = NULL;
243   estream_t outfp, errfp;
244   es_poll_t fds[3];
245   int count;
246   read_and_log_buffer_t fderrstate;
247   struct copy_buffer cpbuf[2];
248
249   memset (fds, 0, sizeof fds);
250   memset (&fderrstate, 0, sizeof fderrstate);
251   copy_buffer_init (&cpbuf[0]);
252   copy_buffer_init (&cpbuf[1]);
253
254   err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT,
255                              NULL, GNUPG_SPAWN_NONBLOCK,
256                              input? &infp : NULL,
257                              &outfp, &errfp, &pid);
258   if (err)
259     {
260       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
261       return err;
262     }
263
264   fderrstate.pgmname = pgmname;
265
266   fds[0].stream = infp;
267   fds[0].want_write = 1;
268   if (!input)
269     fds[0].ignore = 1;
270   fds[1].stream = outfp;
271   fds[1].want_read = 1;
272   fds[2].stream = errfp;
273   fds[2].want_read = 1;
274   /* Now read as long as we have something to poll.  We continue
275      reading even after EOF or error on stdout so that we get the
276      other error messages or remaining outut.  */
277   while (!fds[1].ignore && !fds[2].ignore)
278     {
279       count = es_poll (fds, DIM(fds), -1);
280       if (count == -1)
281         {
282           err = my_error_from_syserror ();
283           log_error ("error polling '%s': %s\n", pgmname, gpg_strerror (err));
284           goto leave;
285         }
286       if (!count)
287         {
288           log_debug ("unexpected timeout while polling '%s'\n", pgmname);
289           break;
290         }
291
292       if (fds[0].got_write)
293         {
294           err = copy_buffer_do_copy (&cpbuf[0], input, fds[0].stream);
295           if (err)
296             {
297               log_error ("error feeding data to '%s': %s\n",
298                          pgmname, gpg_strerror (err));
299               goto leave;
300             }
301
302           if (es_feof (input))
303             {
304               err = copy_buffer_flush (&cpbuf[0], fds[0].stream);
305               if (err)
306                 {
307                   log_error ("error feeding data to '%s': %s\n",
308                              pgmname, gpg_strerror (err));
309                   goto leave;
310                 }
311
312               fds[0].ignore = 1; /* ready.  */
313               es_fclose (infp); infp = NULL;
314             }
315         }
316
317       if (fds[1].got_read)
318         {
319           err = copy_buffer_do_copy (&cpbuf[1], fds[1].stream, output);
320           if (err)
321             {
322               log_error ("error reading data from '%s': %s\n",
323                          pgmname, gpg_strerror (err));
324               goto leave;
325             }
326         }
327
328       if (fds[2].got_read)
329         read_and_log_stderr (&fderrstate, fds + 2);
330     }
331
332   err = copy_buffer_flush (&cpbuf[1], output);
333   if (err)
334     {
335       log_error ("error reading data from '%s': %s\n",
336                  pgmname, gpg_strerror (err));
337       goto leave;
338     }
339
340   read_and_log_stderr (&fderrstate, NULL); /* Flush.  */
341   es_fclose (infp); infp = NULL;
342   es_fclose (outfp); outfp = NULL;
343   es_fclose (errfp); errfp = NULL;
344
345   err = gnupg_wait_process (pgmname, pid, 1, NULL);
346   pid = (pid_t)(-1);
347
348  leave:
349   if (err)
350     gnupg_kill_process (pid);
351
352   es_fclose (infp);
353   es_fclose (outfp);
354   es_fclose (errfp);
355   if (pid != (pid_t)(-1))
356     gnupg_wait_process (pgmname, pid, 1, NULL);
357   gnupg_release_process (pid);
358
359   copy_buffer_shred (&cpbuf[0]);
360   copy_buffer_shred (&cpbuf[1]);
361   return err;
362 }
363
364
365 /* A dummy free function to pass to 'es_mopen'.  */
366 static void
367 nop_free (void *ptr)
368 {
369   (void) ptr;
370 }
371
372 /* Run the program PGMNAME with the command line arguments given in
373    the NULL terminates array ARGV.  If INPUT_STRING is not NULL it
374    will be fed to stdin of the process.  stderr is logged using
375    log_info and the process' stdout is returned in a newly malloced
376    buffer RESULT with the length stored at RESULTLEN if not given as
377    NULL.  A hidden Nul is appended to the output.  On error NULL is
378    stored at RESULT, a diagnostic is printed, and an error code
379    returned.  */
380 gpg_error_t
381 gnupg_exec_tool (const char *pgmname, const char *argv[],
382                  const char *input_string,
383                  char **result, size_t *resultlen)
384 {
385   gpg_error_t err;
386   estream_t input = NULL;
387   estream_t output;
388   size_t len;
389   size_t nread;
390
391   *result = NULL;
392   if (resultlen)
393     *resultlen = 0;
394
395   if (input_string)
396     {
397       len = strlen (input_string);
398       input = es_mopen ((char *) input_string, len, len,
399                         0 /* don't grow */, NULL, nop_free, "rb");
400       if (! input)
401         return my_error_from_syserror ();
402     }
403
404   output = es_fopenmem (0, "wb");
405   if (! output)
406     {
407       err = my_error_from_syserror ();
408       goto leave;
409     }
410
411   err = gnupg_exec_tool_stream (pgmname, argv, input, output);
412   if (err)
413     goto leave;
414
415   len = es_ftello (output);
416   err = es_fseek (output, 0, SEEK_SET);
417   if (err)
418     goto leave;
419
420   *result = xtrymalloc (len + 1);
421   if (!*result)
422     {
423       err = my_error_from_syserror ();
424       goto leave;
425     }
426
427   if (len)
428     {
429       err = es_read (output, *result, len, &nread);
430       if (err)
431         goto leave;
432       if (nread != len)
433         log_fatal ("%s: short read from memstream\n", __func__);
434     }
435   (*result)[len] = 0;
436
437   if (resultlen)
438     *resultlen = len;
439
440  leave:
441   es_fclose (input);
442   es_fclose (output);
443   if (err)
444     {
445       xfree (*result);
446       *result = NULL;
447     }
448   return err;
449 }