Add verify function
[gpgme.git] / gpgme / rungpg.c
index 6353ad2..ac6ba11 100644 (file)
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <sys/wait.h>
 #include <signal.h>
+#include <fcntl.h>
 
 #include "gpgme.h"
 #include "util.h"
@@ -84,6 +85,7 @@ struct gpg_object_s {
 
 static void kill_gpg ( GpgObject gpg );
 static void free_argv ( char **argv );
+static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
 static int gpg_status_handler ( void *opaque, pid_t pid, int fd );
 static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd );
 static int gpg_outbound_handler ( void *opaque, pid_t pid, int fd );
@@ -96,7 +98,6 @@ GpgmeError
 _gpgme_gpg_new_object ( GpgObject *r_gpg )
 {
     GpgObject gpg;
-    char buf[20];
     int rc = 0;
 
     gpg = xtrycalloc ( 1, sizeof *gpg );
@@ -109,9 +110,6 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg )
     gpg->status.fd[0] = -1;
     gpg->status.fd[1] = -1;
 
-    /* The name of the beast will be gpg - so put it into argv[0] */
-    _gpgme_gpg_add_arg ( gpg, "gpg" );
-
     /* allocate the read buffer for the status pipe */
     gpg->status.bufsize = 1024;
     gpg->status.readpos = 0;
@@ -128,8 +126,13 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg )
     }
     gpg->status.eof = 0;
     _gpgme_gpg_add_arg ( gpg, "--status-fd" );
-    sprintf ( buf, "%d", gpg->status.fd[1]);
-    _gpgme_gpg_add_arg ( gpg, buf );
+    {
+        char buf[25];
+        sprintf ( buf, "%d", gpg->status.fd[1]);
+        _gpgme_gpg_add_arg ( gpg, buf );
+    }
+    _gpgme_gpg_add_arg ( gpg, "--batch" );
+    _gpgme_gpg_add_arg ( gpg, "--no-tty" );
 
  leave:
     if (rc) {
@@ -153,8 +156,7 @@ _gpgme_gpg_release_object ( GpgObject gpg )
         close (gpg->status.fd[0]);
     if (gpg->status.fd[1] != -1 )
         close (gpg->status.fd[1]);
-    /* fixme: walk over the data map and close all fds */
-    xfree (gpg->fd_data_map);
+    free_fd_data_map (gpg->fd_data_map);
     kill_gpg (gpg); /* fixme: should be done asyncronously */
     xfree (gpg);
 }
@@ -162,6 +164,7 @@ _gpgme_gpg_release_object ( GpgObject gpg )
 static void
 kill_gpg ( GpgObject gpg )
 {
+  #if 0
     if ( gpg->running ) {
         /* still running? Must send a killer */
         kill ( gpg->pid, SIGTERM);
@@ -172,6 +175,7 @@ kill_gpg ( GpgObject gpg )
         }
         gpg->running = 0;
     }
+  #endif
 }
 
 
@@ -238,6 +242,21 @@ free_argv ( char **argv )
     xfree (argv);
 }
 
+static void
+free_fd_data_map ( struct fd_data_map_s *fd_data_map )
+{
+    int i;
+
+    for (i=0; fd_data_map[i].data; i++ ) {
+        if ( fd_data_map[i].fd != -1 )
+            close (fd_data_map[i].fd);
+        if ( fd_data_map[i].peer_fd != -1 )
+            close (fd_data_map[i].peer_fd);
+        /* don't realease data because this is only a reference */
+    }
+    xfree (fd_data_map);
+}
+
 
 static GpgmeError
 build_argv ( GpgObject gpg )
@@ -246,22 +265,32 @@ build_argv ( GpgObject gpg )
     struct fd_data_map_s *fd_data_map;
     size_t datac=0, argc=0;  
     char **argv;
+    int need_special = 0;
        
     if ( gpg->argv ) {
         free_argv ( gpg->argv );
         gpg->argv = NULL;
     }
-    /* fixme: release fd_data_map */
+    if (gpg->fd_data_map) {
+        free_fd_data_map (gpg->fd_data_map);
+        gpg->fd_data_map = NULL;
+    }
 
+    argc++; /* for argv[0] */
     for ( a=gpg->arglist; a; a = a->next ) {
         argc++;
         if (a->data) {
-            fprintf (stderr, "build_argv: data\n" );
+            /*fprintf (stderr, "build_argv: data\n" );*/
             datac++;
+            if ( a->dup_to == -1 )
+                need_special = 1;
+        }
+        else {
+            /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
         }
-        else
-            fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );
     }
+    if ( need_special )
+        argc++;
 
     argv = xtrycalloc ( argc+1, sizeof *argv );
     if (!argv)
@@ -273,6 +302,22 @@ build_argv ( GpgObject gpg )
     }
 
     argc = datac = 0;
+    argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */
+    if (!argv[argc]) {
+        xfree (fd_data_map);
+        free_argv (argv);
+        return mk_error (Out_Of_Core);
+    }
+    argc++;
+    if ( need_special ) {
+        argv[argc] = xtrystrdup ( "--enable-special-filenames" );
+        if (!argv[argc]) {
+            xfree (fd_data_map);
+            free_argv (argv);
+            return mk_error (Out_Of_Core);
+        }
+        argc++;
+    }
     for ( a=gpg->arglist; a; a = a->next ) {
         if ( a->data ) {
             switch ( _gpgme_query_data_mode (a->data) ) {
@@ -328,6 +373,16 @@ build_argv ( GpgObject gpg )
             }
             fd_data_map[datac].data = a->data;
             fd_data_map[datac].dup_to = a->dup_to;
+            if ( a->dup_to == -1 ) {
+                argv[argc] = xtrymalloc ( 25 );
+                if (!argv[argc]) {
+                    xfree (fd_data_map);
+                    free_argv (argv);
+                    return mk_error (Out_Of_Core);
+                }
+                sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd );
+                argc++;
+            }
             datac++;
         }
         else {
@@ -337,8 +392,8 @@ build_argv ( GpgObject gpg )
                 free_argv (argv);
                 return mk_error (Out_Of_Core);
             }
+            argc++;
         }
-        argc++;
     }
 
     gpg->argv = argv;
@@ -372,6 +427,11 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
     }
         
     if ( !pid ) { /* child */
+        int duped_stdin = 0;
+        int duped_stderr = 0;
+
+        close (gpg->status.fd[0]);
+            
         for (i=0; gpg->fd_data_map[i].data; i++ ) {
             close (gpg->fd_data_map[i].fd);
             gpg->fd_data_map[i].fd = -1;
@@ -382,20 +442,49 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
                              strerror (errno));
                     _exit (8);
                 }
+                if ( gpg->fd_data_map[i].dup_to == 0 )
+                    duped_stdin=1;
+                if ( gpg->fd_data_map[i].dup_to == 2 )
+                    duped_stderr=1;
                 close ( gpg->fd_data_map[i].peer_fd );
             }
         }
-        
-        if ( gpg->status.fd[0] != -1 )
-            close (gpg->status.fd[0]);
 
-        /* FIXME: dup /dev/null to stdin if nothing is connected to stdin */
-        execv ("/usr/local/bin/gpg", gpg->argv );
-        fprintf (stderr,"exec of gpg failed\n"); fflush (stderr);
+        if( !duped_stdin || !duped_stderr ) {
+            int fd = open ( "/dev/null", O_RDONLY );
+            if ( fd == -1 ) {
+                fprintf (stderr,"can't open `/dev/null': %s\n",
+                         strerror (errno) );
+                _exit (8);
+            }
+            /* Make sure that gpg has a connected stdin */
+            if ( !duped_stdin ) {
+                if ( dup2 ( fd, 0 ) == -1 ) {
+                    fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n",
+                             strerror (errno) );
+                    _exit (8);
+                }
+            }
+            /* We normally don't want all the normal output */
+            if ( !duped_stderr ) {
+                if ( dup2 ( fd, 2 ) == -1 ) {
+                    fprintf (stderr,"dup2(dev/null, 2) failed: %s\n",
+                             strerror (errno) );
+                    _exit (8);
+                }
+            }
+            close (fd);
+        }
+
+        execv ("./gpg", gpg->argv );
+        fprintf (stderr,"exec of gpg failed\n");
         _exit (8);
     }
+    /* parent */
     gpg->pid = pid;
 
+    /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
+
     if ( gpg->status.fd[1] != -1 )
         close (gpg->status.fd[1]);
     if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
@@ -424,7 +513,6 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
 
     gpg->running = 1;
     return 0;
-
 }
 
 
@@ -432,6 +520,7 @@ static int
 gpg_inbound_handler ( void *opaque, pid_t pid, int fd )
 {
     GpgmeData dh = opaque;
+    GpgmeError err;
     int nread;
     char buf[200];
 
@@ -448,7 +537,19 @@ gpg_inbound_handler ( void *opaque, pid_t pid, int fd )
     }
     else if (!nread)
         return 1; /* eof */
+
+    /* We could improve this with a GpgmeData function which takes
+     * the read function or provides a memory area for writing to it.
+     */
     
+    err = _gpgme_append_data ( dh, buf, nread );
+    if ( err ) {
+        fprintf (stderr, "_gpgme_append_data failed: %s\n",
+                 gpgme_strerror(err));
+        /* Fixme: we should close the pipe or read it to /dev/null in
+         * this case. Returnin EOF is not sufficient */
+        return 1;
+    }
 
     return 0;
 }
@@ -520,8 +621,11 @@ gpg_status_handler ( void *opaque, pid_t pid, int fd )
 
 
 static int
-status_cmp (const struct status_table_s *a, const struct status_table_s *b)
+status_cmp (const void *ap, const void *bp)
 {
+    const struct status_table_s *a = ap;
+    const struct status_table_s *b = bp;
+
     return strcmp (a->name, b->name);
 }