Reworked the server commands.
authorWerner Koch <wk@gnupg.org>
Thu, 15 Oct 2009 17:20:41 +0000 (17:20 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 15 Oct 2009 17:20:41 +0000 (17:20 +0000)
Track mounts.
--create does now work as expected.

14 files changed:
g13/Makefile.am
g13/backend.c
g13/backend.h
g13/be-encfs.c
g13/be-encfs.h
g13/create.c
g13/g13.c
g13/mount.c
g13/mount.h
g13/mountinfo.c [new file with mode: 0644]
g13/mountinfo.h [new file with mode: 0644]
g13/runner.c
g13/runner.h
g13/server.c

index e65684c..3143e8a 100644 (file)
@@ -33,6 +33,7 @@ g13_SOURCES = \
        server.c server.h \
        create.c create.h \
        mount.c mount.h \
+       mountinfo.c mountinfo.h \
        call-gpg.c call-gpg.h \
        runner.c runner.h \
        backend.c backend.h \
index 08aec32..531e745 100644 (file)
@@ -101,14 +101,15 @@ be_create_new_keys (int conttype, membuf_t *mb)
 /*  Dispatcher to the backend's create function.  */
 gpg_error_t
 be_create_container (ctrl_t ctrl, int conttype, 
-                     const char *fname, int fd, tupledesc_t tuples)
+                     const char *fname, int fd, tupledesc_t tuples,
+                     unsigned int *r_id)
 {
   (void)fd;  /* Not yet used.  */
 
   switch (conttype)
     {
     case CONTTYPE_ENCFS: 
-      return be_encfs_create_container (ctrl, fname, tuples);
+      return be_encfs_create_container (ctrl, fname, tuples, r_id);
 
     default:
       return no_such_backend (conttype);
@@ -120,12 +121,12 @@ be_create_container (ctrl_t ctrl, int conttype,
 gpg_error_t
 be_mount_container (ctrl_t ctrl, int conttype, 
                     const char *fname,  const char *mountpoint,
-                    tupledesc_t tuples)
+                    tupledesc_t tuples, unsigned int *r_id)
 {
   switch (conttype)
     {
     case CONTTYPE_ENCFS: 
-      return be_encfs_mount_container (ctrl, fname, mountpoint, tuples);
+      return be_encfs_mount_container (ctrl, fname, mountpoint, tuples, r_id);
 
     default:
       return no_such_backend (conttype);
index 7cdde9e..2048697 100644 (file)
@@ -30,10 +30,12 @@ gpg_error_t be_create_new_keys (int conttype, membuf_t *mb);
 
 gpg_error_t be_create_container (ctrl_t ctrl, int conttype, 
                                  const char *fname, int fd,
-                                 tupledesc_t tuples);
+                                 tupledesc_t tuples,
+                                 unsigned int *r_id);
 gpg_error_t be_mount_container (ctrl_t ctrl, int conttype, 
                                 const char *fname, const char *mountpoint,
-                                tupledesc_t tuples);
+                                tupledesc_t tuples,
+                                unsigned int *r_id);
 
 
 #endif /*G13_BACKEND_H*/
index de3209a..06e8792 100644 (file)
@@ -211,7 +211,8 @@ encfs_handler_cleanup (void *opaque)
 /* Run the encfs tool.  */
 static gpg_error_t
 run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
-                const char *rawdir, const char *mountpoint, tupledesc_t tuples)
+                const char *rawdir, const char *mountpoint, tupledesc_t tuples,
+                unsigned int *r_id)
 {
   gpg_error_t err;
   encfs_parm_t parm;
@@ -240,15 +241,9 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
       goto leave;
     }
 
-  {
-    static int namecounter;
-    char buffer[50];
-
-    snprintf (buffer, sizeof buffer, "encfs-%d", ++namecounter);
-    err = runner_new (&runner, buffer);
-    if (err)
-      goto leave;
-  }
+  err = runner_new (&runner, "encfs");
+  if (err)
+    goto leave;
 
   err = gnupg_create_inbound_pipe (inbound);
   if (!err)
@@ -295,6 +290,7 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
   if (err)
     goto leave;
 
+  *r_id = runner_get_rid (runner);
   log_info ("running `%s' in the background\n", pgmname);
 
  leave:
@@ -400,7 +396,8 @@ be_encfs_create_new_keys (membuf_t *mb)
 /* Create the container described by the filename FNAME and the keyblob
    information in TUPLES. */
 gpg_error_t
-be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples)
+be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples,
+                           unsigned int *r_id)
 {
   gpg_error_t err;
   int dummy;
@@ -426,7 +423,7 @@ be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples)
     }
 
   err = run_encfs_tool (ctrl, ENCFS_CMD_CREATE, containername, mountpoint,
-                        tuples);
+                        tuples, r_id);
   
   /* In any case remove the temporary mount point.  */
   if (rmdir (mountpoint))
@@ -442,11 +439,11 @@ be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples)
 
 
 /* Mount the container described by the filename FNAME and the keyblob
-   information in TUPLES. */
+   information in TUPLES.  On success the runner id is stored at R_ID. */
 gpg_error_t
 be_encfs_mount_container (ctrl_t ctrl, 
                           const char *fname, const char *mountpoint,
-                          tupledesc_t tuples)
+                          tupledesc_t tuples, unsigned int *r_id)
 {
   gpg_error_t err;
   int dummy;
@@ -464,7 +461,7 @@ be_encfs_mount_container (ctrl_t ctrl,
     goto leave;
 
   err = run_encfs_tool (ctrl, ENCFS_CMD_MOUNT, containername, mountpoint,
-                        tuples);
+                        tuples, r_id);
   
  leave:
   xfree (containername);
index c6c8396..8ac35f9 100644 (file)
@@ -28,12 +28,14 @@ gpg_error_t be_encfs_create_new_keys (membuf_t *mb);
 
 gpg_error_t be_encfs_create_container (ctrl_t ctrl, 
                                        const char *fname,
-                                       tupledesc_t tuples);
+                                       tupledesc_t tuples,
+                                       unsigned int *r_id);
 
 gpg_error_t be_encfs_mount_container (ctrl_t ctrl,
                                       const char *fname, 
                                       const char *mountpoint,
-                                      tupledesc_t tuples);
+                                      tupledesc_t tuples,
+                                      unsigned int *r_id);
 
 
 #endif /*G13_BE_ENCFS_H*/
index 0279c33..9de9edc 100644 (file)
@@ -231,6 +231,7 @@ g13_create_container (ctrl_t ctrl, const char *filename)
   char *detachedname = NULL;
   int detachedisdir;
   tupledesc_t tuples = NULL;
+  unsigned int dummy_rid;
 
   /* A quick check to see that no container with that name already
      exists.  */
@@ -304,7 +305,8 @@ g13_create_container (ctrl_t ctrl, const char *filename)
   /* Create and append the container.  FIXME: We should pass the
      estream object in addition to the filename, so that the backend
      can append the container to the g13 file.  */
-  err = be_create_container (ctrl, ctrl->conttype, filename, -1, tuples);
+  err = be_create_container (ctrl, ctrl->conttype, filename, -1, tuples,
+                             &dummy_rid);
 
 
  leave:
index 2886894..453fa9e 100644 (file)
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -39,7 +39,8 @@
 #include "server.h"
 #include "runner.h"
 #include "create.h"
-#include "./mount.h"
+#include "mount.h"
+#include "mountinfo.h"
 
 
 enum cmd_and_opt_values {
@@ -707,6 +708,8 @@ main ( int argc, char **argv)
         if (err)
           log_error ("server exited with error: %s <%s>\n",
                      gpg_strerror (err), gpg_strsource (err));
+        else
+          shutdown_pending++;
       }
       break;
 
@@ -719,6 +722,8 @@ main ( int argc, char **argv)
         if (err)
           log_error ("error creating a new container: %s <%s>\n",
                      gpg_strerror (err), gpg_strsource (err));
+        else
+          shutdown_pending++;
       }
       break;
 
@@ -807,6 +812,7 @@ handle_signal (int signo)
     case SIGUSR1:
       log_info ("SIGUSR1 received - printing internal information:\n");
       pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
+      mountinfo_dump_all ();
       break;
 
     case SIGUSR2:
index 85851e9..dc23b6b 100644 (file)
@@ -35,6 +35,8 @@
 #include "utils.h"
 #include "call-gpg.h"
 #include "estream.h"
+#include "mountinfo.h"
+#include "runner.h"
 
 
 /* Parse the header prefix and return the length of the entire header.  */
@@ -89,28 +91,23 @@ parse_header (const char *filename,
 }
 
 
-
-/* Read the keyblob at FILENAME.  The caller should have acquired a
-   lockfile and checked that the file exists.  */
+/* Read the prefix of the keyblob and do some basic parsing.  On
+   success returns an open estream file at R_FP and the length of the
+   header at R_HEADERLEN.  */
 static gpg_error_t
-read_keyblob (const char *filename, 
-              void **r_enckeyblob, size_t *r_enckeybloblen)
+read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
 {
   gpg_error_t err;
   estream_t fp;
   unsigned char packet[32];
-  size_t headerlen, msglen;
-  void *msg = NULL;
   
-  *r_enckeyblob = NULL;
-  *r_enckeybloblen = 0;
+  *r_fp = NULL;
 
   fp = es_fopen (filename, "rb");
   if (!fp)
     {
       err = gpg_error_from_syserror ();
-      log_error ("error reading `%s': %s\n", 
-                 filename, gpg_strerror (err));
+      log_error ("error reading `%s': %s\n", filename, gpg_strerror (err));
       return err;
     }
   
@@ -120,10 +117,35 @@ read_keyblob (const char *filename,
       err = gpg_error_from_syserror ();
       log_error ("error reading the header of `%s': %s\n",
                  filename, gpg_strerror (err));
-      goto leave;
+      es_fclose (fp);
+      return err;
     }
   
-  err = parse_header (filename, packet, 32, &headerlen);
+  err = parse_header (filename, packet, 32, r_headerlen);
+  if (err)
+    es_fclose (fp);
+  else
+    *r_fp = fp;
+
+  return err;
+}
+
+
+/* Read the keyblob at FILENAME.  The caller should have acquired a
+   lockfile and checked that the file exists.  */
+static gpg_error_t
+read_keyblob (const char *filename, 
+              void **r_enckeyblob, size_t *r_enckeybloblen)
+{
+  gpg_error_t err;
+  estream_t fp = NULL;
+  size_t headerlen, msglen;
+  void *msg = NULL;
+  
+  *r_enckeyblob = NULL;
+  *r_enckeybloblen = 0;
+
+  err = read_keyblob_prefix (filename, &fp, &headerlen);
   if (err)
     goto leave;
   
@@ -227,6 +249,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
   size_t n;
   const unsigned char *value;
   int conttype;
+  unsigned int rid;
 
   /* A quick check to see whether the container exists.  */
   if (access (filename, R_OK))
@@ -292,7 +315,13 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       goto leave;
     }
-  err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples);
+  err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
+  if (!err)
+    {
+      err = mountinfo_add_mount (filename, mountpoint, conttype, rid);
+      /* Fixme: What shall we do if this fails?  Add a provisional
+         mountinfo entry first and remove it on error? */
+    }
 
  leave:
   destroy_tupledesc (tuples);
@@ -301,3 +330,56 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
   destroy_dotlock (lock);
   return err;
 }
+
+
+/* Unmount the container with name FILENAME or the one mounted at
+   MOUNTPOINT.  If both are given the FILENAME takes precedence.  */
+gpg_error_t
+g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
+{
+  gpg_error_t err;
+  unsigned int rid;
+  runner_t runner;
+
+  (void)ctrl;
+
+  if (!filename && !mountpoint)
+    return gpg_error (GPG_ERR_ENOENT);
+  err = mountinfo_find_mount (filename, mountpoint, &rid);
+  if (err)
+    return err;
+  
+  runner = runner_find_by_rid (rid);
+  if (!runner)
+    {
+      log_error ("runner %u not found\n", rid);
+      return gpg_error (GPG_ERR_NOT_FOUND);
+    }
+
+  runner_cancel (runner);
+  runner_release (runner);
+  
+  return 0;
+}
+
+
+/* Test whether the container with name FILENAME is a suitable G13
+   container.  This function may even be called on a mounted
+   container.  */
+gpg_error_t
+g13_is_container (ctrl_t ctrl, const char *filename)
+{
+  gpg_error_t err;
+  estream_t fp = NULL;
+  size_t dummy;
+
+  (void)ctrl;
+
+  /* Read just the prefix of the header.  */
+  err = read_keyblob_prefix (filename, &fp, &dummy);
+  if (!err)
+    es_fclose (fp);
+  return err;
+}
+
+
index 03b8264..f994264 100644 (file)
@@ -1,4 +1,4 @@
-/* mmount.h - Defs to mount a crypto container
+/* mount.h - Defs to mount a crypto container
  * Copyright (C) 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
 gpg_error_t g13_mount_container (ctrl_t ctrl, 
                                  const char *filename,
                                  const char *mountpoint);
+gpg_error_t g13_umount_container (ctrl_t ctrl,
+                                  const char *filename,
+                                  const char *mountpoint);
+
+gpg_error_t g13_is_container (ctrl_t ctrl, const char *filename);
 
 
 #endif /*G13_MOUNT_H*/
diff --git a/g13/mountinfo.c b/g13/mountinfo.c
new file mode 100644 (file)
index 0000000..100c1e4
--- /dev/null
@@ -0,0 +1,183 @@
+/* mountinfo.c - Track infos about mounts
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include "g13.h"
+#include "i18n.h"
+#include "mountinfo.h"
+
+#include "keyblob.h"
+#include "utils.h"
+
+
+
+/* The object to keep track of mount information.  */
+struct mounttable_s
+{
+  int in_use;        /* The slot is in use.  */
+  char *container;   /* Name of the container.  */
+  char *mountpoint;  /* Name of the mounttype.  */
+  int conttype;      /* Type of the container.  */
+  unsigned int rid;  /* Identifier of the runner task.  */
+};
+
+
+/* The allocated table of mounts and its size.  */
+static mtab_t mounttable;
+size_t mounttable_size;
+
+
+\f
+/* Add CONTAINER,MOUNTPOINT,CONTTYPE,RID to the mounttable.  */
+gpg_error_t
+mountinfo_add_mount (const char *container, const char *mountpoint,
+                     int conttype, unsigned int rid)
+{
+  size_t idx;
+  mtab_t m;
+
+  for (idx=0; idx < mounttable_size; idx++)
+    if (!mounttable[idx].in_use)
+      break;
+  if (!(idx < mounttable_size))
+    {
+      size_t nslots = mounttable_size;
+
+      mounttable_size += 10;
+      m = xtrycalloc (mounttable_size, sizeof *mounttable);
+      if (!m)
+        return gpg_error_from_syserror ();
+      if (mounttable)
+        {
+          for (idx=0; idx < nslots; idx++)
+            m[idx] = mounttable[idx];
+          xfree (mounttable);
+        }
+      mounttable = m;
+      m = mounttable + nslots;
+      assert (!m->in_use);
+    }
+  else
+    m = mounttable + idx;
+
+  m->container = xtrystrdup (container);
+  if (!m->container)
+    return gpg_error_from_syserror ();
+  m->mountpoint = xtrystrdup (mountpoint);
+  if (!m->mountpoint)
+    {
+      xfree (m->container);
+      m->container = NULL;
+      return gpg_error_from_syserror ();
+    }
+  m->conttype = conttype;
+  m->rid = rid;
+  m->in_use = 1;
+
+  return 0;
+}
+
+
+/* Remove a mount info.  Either the CONTAINER, the MOUNTPOINT or the
+   RID must be given.  The first argument given is used.  */
+gpg_error_t
+mountinfo_del_mount (const char *container, const char *mountpoint,
+                     unsigned int rid)
+{
+  gpg_error_t err;
+  size_t idx;
+  mtab_t m;
+
+  /* If a container or mountpint is givem search the RID via the
+     standard find fucntion.  */
+  if (container || mountpoint)
+    {
+      err = mountinfo_find_mount (container, mountpoint, &rid);
+      if (err)
+        return err;
+    }
+
+  /* Find via RID and delete. */
+  for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
+    if (m->in_use && m->rid == rid)
+      {
+        m->in_use = 0;
+        xfree (m->container);
+        m->container = NULL;
+        xfree (m->mountpoint);
+        m->mountpoint = NULL;
+        return 0;
+      }
+  return gpg_error (GPG_ERR_NOT_FOUND);
+}
+
+
+/* Find a mount and return its rid at R_RID.  If CONTAINER is given,
+   the search is done by the container name, if it is not given the
+   search is done by MOUNTPOINT.  */
+gpg_error_t
+mountinfo_find_mount (const char *container, const char *mountpoint,
+                      unsigned int *r_rid)
+{
+  size_t idx;
+  mtab_t m;
+
+  if (container)
+    {
+      for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
+        if (m->in_use && !strcmp (m->container, container))
+          break;
+    }
+  else if (mountpoint)
+    {
+      for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
+        if (m->in_use && !strcmp (m->mountpoint, mountpoint))
+          break;
+    }
+  else
+    idx = mounttable_size;
+  if (!(idx < mounttable_size))
+    return gpg_error (GPG_ERR_NOT_FOUND);
+
+  *r_rid = m->rid;
+  return 0;
+}
+
+
+/* Dump all info to the log stream.  */
+void
+mountinfo_dump_all (void)
+{
+  size_t idx;
+  mtab_t m;
+
+  for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
+    if (m->in_use)
+      log_info ("mtab[%d] %s on %s type %d rid %u\n", 
+                idx, m->container, m->mountpoint, m->conttype, m->rid);
+}
+
diff --git a/g13/mountinfo.h b/g13/mountinfo.h
new file mode 100644 (file)
index 0000000..187dff0
--- /dev/null
@@ -0,0 +1,40 @@
+/* mountinfo.h - Track infos about mounts
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef G13_MOUNTINFO_H
+#define G13_MOUNTINFO_H
+
+struct mounttable_s;
+typedef struct mounttable_s *mtab_t;
+
+gpg_error_t mountinfo_add_mount (const char *container,
+                                 const char *mountpoint,
+                                 int conttype, unsigned int rid);
+gpg_error_t mountinfo_del_mount (const char *container,
+                                 const char *mountpoint,
+                                 unsigned int rid);
+gpg_error_t mountinfo_find_mount (const char *container,
+                                  const char *mountpoint,
+                                  unsigned int *r_rid);
+
+void mountinfo_dump_all (void);
+
+
+#endif /*G13_MOUNTINFO_H*/
+
index 27d0370..6cf88c0 100644 (file)
 #include "keyblob.h"
 #include "runner.h"
 #include "../common/exechelp.h"
-
+#include "mountinfo.h"
 
 /* The runner object.  */
 struct runner_s
 {
-  char *name;   /* The name of this runner.  */
+  char *name;              /* The name of this runner.  */
+  unsigned int identifier; /* The runner identifier.  */
 
   int spawned;  /* True if runner_spawn has been called.  */
   pth_t threadid; /* The TID of the runner thread.  */
@@ -131,12 +132,19 @@ runner_get_threads (void)
 void
 runner_release (runner_t runner)
 {
+  gpg_error_t err;
+
   if (!runner)
     return;
 
   if (!--runner->refcount)
     return;
 
+  err = mountinfo_del_mount (NULL, NULL, runner->identifier);
+  if (err)
+    log_error ("failed to remove mount with rid %u from mtab: %s\n",
+               runner->identifier, gpg_strerror (err));
+
   es_fclose (runner->status_fp);
   if (runner->in_fd != -1)
     close (runner->in_fd);
@@ -171,14 +179,32 @@ runner_release (runner_t runner)
 gpg_error_t 
 runner_new (runner_t *r_runner, const char *name)
 {
-  runner_t runner;
+  static unsigned int namecounter; /* Global name counter.  */
+  char *namebuffer;
+  runner_t runner, r;
 
   *r_runner = NULL;
 
   runner = xtrycalloc (1, sizeof *runner);
   if (!runner)
     return gpg_error_from_syserror ();
-  runner->name = xtrystrdup (name? name: "[unknown]");
+
+  /* Bump up the namecounter.  In case we ever had an overflow we
+     check that this number is currently not in use.  The algorithm is
+     a bit lame but should be sufficient because such an wrap is not
+     very likely: Assuming that we do a mount 10 times a second, then
+     we would overwrap on a 32 bit system after 13 years.  */
+  do
+    {
+      namecounter++;
+      for (r = running_threads; r; r = r->next_running)
+        if (r->identifier == namecounter)
+          break;
+    }
+  while (r);
+
+  runner->identifier = namecounter;
+  runner->name = namebuffer = xtryasprintf ("%s-%d", name, namecounter);
   if (!runner->name)
     {
       xfree (runner);
@@ -189,13 +215,37 @@ runner_new (runner_t *r_runner, const char *name)
   runner->in_fd = -1;
   runner->out_fd = -1;
   
-
   *r_runner = runner;
   return 0;
 }
 
 
-/* A runner usually maintaines two file descriptors to control the
+/* Return the identifier of RUNNER.  */
+unsigned int 
+runner_get_rid (runner_t runner)
+{
+  return runner->identifier;
+}
+
+
+/* Find a runner by its rid.  Returns the runner object.  The caller
+   must release the runner object.  */
+runner_t
+runner_find_by_rid (unsigned int rid)
+{
+  runner_t r;
+
+  for (r = running_threads; r; r = r->next_running)
+    if (r->identifier == rid)
+      {
+        r->refcount++;
+        return r;
+      }
+  return NULL;
+}
+
+
+/* A runner usually maintains two file descriptors to control the
    backend engine.  This function is used to set these file
    descriptors.  The function takes ownership of these file
    descriptors.  IN_FD will be used to read from engine and OUT_FD to
@@ -382,8 +432,8 @@ runner_spawn (runner_t runner)
     }
 
   tattr = pth_attr_new ();
-  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
-  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
+  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
+  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 128*1024);
   pth_attr_set (tattr, PTH_ATTR_NAME, runner->name);
   
   tid = pth_spawn (tattr, runner_thread, runner);
index 88ebc7d..e68eca0 100644 (file)
@@ -40,6 +40,12 @@ gpg_error_t runner_new (runner_t *r_runner, const char *name);
 /* Free a runner object.  */
 void runner_release (runner_t runner);
 
+/* Return the identifier of RUNNER.  */
+unsigned int runner_get_rid (runner_t runner); 
+
+/* Find a runner by its rid.  */
+runner_t runner_find_by_rid (unsigned int rid);
+
 /* Functions to set properties of the runner.  */
 void runner_set_fds (runner_t runner, int in_fd, int out_fd);
 
index bdf214f..900dbc9 100644 (file)
@@ -40,42 +40,28 @@ struct server_local_s
   /* The Assuan contect we are working on.  */
   assuan_context_t assuan_ctx;
 
-  char *mountpoint;  /* Malloced current mountpoint.  */
+  char *containername;  /* Malloced active containername.  */
 
 };
 
 
-/* Cookie definition for assuan data line output.  */
-static ssize_t data_line_cookie_write (void *cookie,
-                                       const void *buffer, size_t size);
-static int data_line_cookie_close (void *cookie);
-static es_cookie_io_functions_t data_line_cookie_functions =
-  {
-    NULL,
-    data_line_cookie_write,
-    NULL,
-    data_line_cookie_close
-  };
-
-
-/* The filepointer for status message used in non-server mode.  */
-/* static FILE *statusfp;  FIXME; */
-
-
 
 \f
+/* Local prototypes.  */
 static int command_has_option (const char *cmd, const char *cmdopt);
 
 
 
 \f
-#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
+/*
+   Helper functions. 
+ */
 
+/* Set an error and a description.  */
+#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
 
-\f
-/* Skip over options.  
-   Blanks after the options are also removed.  */
+/* Skip over options.  Blanks after the options are also removed.  */
 static char *
 skip_options (const char *line)
 {
@@ -93,52 +79,41 @@ skip_options (const char *line)
 
 
 /* Check whether the option NAME appears in LINE.  */
-static int
-has_option (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
+/* static int */
+/* has_option (const char *line, const char *name) */
+/* { */
+/*   const char *s; */
+/*   int n = strlen (name); */
 
-  s = strstr (line, name);
-  if (s && s >= skip_options (line))
-    return 0;
-  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
+/*   s = strstr (line, name); */
+/*   if (s && s >= skip_options (line)) */
+/*     return 0; */
+/*   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
+/* } */
 
 
-/* A write handler used by es_fopencookie to write Assuan data
-   lines.  */
-static ssize_t
-data_line_cookie_write (void *cookie, const void *buffer, size_t size)
+/* Helper to print a message while leaving a command.  */
+static gpg_error_t
+leave_cmd (assuan_context_t ctx, gpg_error_t err)
 {
-  assuan_context_t ctx = cookie;
-
-  if (assuan_send_data (ctx, buffer, size))
+  if (err)
     {
-      errno = EIO;
-      return -1;
+      const char *name = assuan_get_command_name (ctx);
+      if (!name)
+        name = "?";
+      if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
+        log_error ("command '%s' failed: %s\n", name,
+                   gpg_strerror (err));
+      else
+        log_error ("command '%s' failed: %s <%s>\n", name,
+                   gpg_strerror (err), gpg_strsource (err));
     }
-
-  return size;
+  return err;
 }
 
-/* A close handler used by es_fopencookie to write Assuan data
-   lines.  */
-static int
-data_line_cookie_close (void *cookie)
-{
-  assuan_context_t ctx = cookie;
-
-  if (assuan_send_data (ctx, NULL, 0))
-    {
-      errno = EIO;
-      return -1;
-    }
-
-  return 0;
-}
 
 
+\f
 /* The handler for Assuan OPTION commands.  */
 static gpg_error_t
 option_handler (assuan_context_t ctx, const char *key, const char *value)
@@ -146,6 +121,8 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
 
+  (void)ctrl;
+
   if (!strcmp (key, "putenv"))
     {
       /* Change the session's environment to be used for the
@@ -213,84 +190,83 @@ reset_notify (assuan_context_t ctx)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
-  xfree (ctrl->server_local->mountpoint);
-  ctrl->server_local->mountpoint = NULL;
+  xfree (ctrl->server_local->containername);
+  ctrl->server_local->containername = NULL;
 
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 }
 
 
-/* Helper to print a message while leaving a command.  */
-static gpg_error_t
-leave_cmd (assuan_context_t ctx, gpg_error_t err)
-{
-  if (err)
-    {
-      const char *name = assuan_get_command_name (ctx);
-      if (!name)
-        name = "?";
-      if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
-        log_error ("command '%s' failed: %s\n", name,
-                   gpg_strerror (err));
-      else
-        log_error ("command '%s' failed: %s <%s>\n", name,
-                   gpg_strerror (err), gpg_strsource (err));
-    }
-  return err;
-}
-
-
 
-/* RECIPIENT <userID>
+/* OPEN [options] <filename>
 
-   FIXME - description. 
-   All RECIPIENT commands are cumulative until a RESET or an
-   successful CREATE command.
+   Open the container FILENAME.  FILENAME must be percent-plus
+   escaped.  A quick check to see whether this is a suitable G13
+   container file is done.  However no cryptographic check or any
+   other check is done.  This command is used to define the target for
+   further commands.  The filename is reset with the RESET command,
+   another OPEN or the CREATE command.
  */
 static gpg_error_t
-cmd_recipient (assuan_context_t ctx, char *line)
+cmd_open (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
-  gpg_error_t err;
-
-  (void)ctrl;
-  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-  /* err = gpgsm_add_to_certlist (ctrl, line, 0, */
-  /*                              &ctrl->server_local->recplist, 0); */
-  /* if (err) */
-  /*   { */
-  /*     gpgsm_status2 (ctrl, STATUS_INV_RECP, */
-  /*                    get_inv_recpsgnr_code (rc), line, NULL); */
-  /*   } */
-
-  return leave_cmd (ctx, err);
-}
+  gpg_error_t err = 0;
+  char *p, *pend;
+  size_t len;
 
+  /* In any case reset the active container.  */
+  xfree (ctrl->server_local->containername);
+  ctrl->server_local->containername = NULL;
 
-/* SIGNER <userID>
+  /* Parse the line.  */
+  line = skip_options (line);
+  for (p=line; *p && !spacep (p); p++)
+    ;
+  pend = p;
+  while (spacep(p))
+    p++;
+  if (*p || pend == line)
+    {
+      err = gpg_error (GPG_ERR_ASS_SYNTAX);
+      goto leave;
+    }
+  *pend = 0;
 
-   FIXME - description. 
- */
-static gpg_error_t
-cmd_signer (assuan_context_t ctx, char *line)
-{
-  ctrl_t ctrl = assuan_get_pointer (ctx);
-  gpg_error_t err;
+  /* Unescape the line and check for embedded Nul bytes.  */
+  len = percent_plus_unescape_inplace (line, 0);
+  line[len] = 0;
+  if (!len || memchr (line, 0, len))
+    {
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
 
-  (void)ctrl;
+  /* Do a basic check.  */
+  err = g13_is_container (ctrl, line);
+  if (err)
+    goto leave;
 
-  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  /* Store the filename.  */
+  ctrl->server_local->containername = xtrystrdup (line);
+  if (!ctrl->server_local->containername)
+    err = gpg_error_from_syserror ();
+  
+  
+ leave:
   return leave_cmd (ctx, err);
 }
 
 
-/* SETMOUNTPOINT [options] [<dirname>]
+/* MOUNT [options] [<mountpoint>]
 
-   Set DIRNAME as the new mount point for future operations.  
+   Mount the currently open file onto MOUNTPOINT.  If MOUNTPOINT is
+   not given the system picks an unused mountpoint.  MOUNTPOINT must
+   be percent-plus escaped to allow for arbitrary names.
  */
 static gpg_error_t
-cmd_setmountpoint (assuan_context_t ctx, char *line)
+cmd_mount (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
@@ -319,40 +295,28 @@ cmd_setmountpoint (assuan_context_t ctx, char *line)
       goto leave;
     }
 
-  xfree (ctrl->server_local->mountpoint);
-  if (!len)  /* Reset mountpoint.  */
-    ctrl->server_local->mountpoint = NULL;
-  else
+  if (!ctrl->server_local->containername)
     {
-      ctrl->server_local->mountpoint = xtrystrdup (line);
-      if (!ctrl->server_local->mountpoint)
-        err = gpg_error_from_syserror ();
+      err = gpg_error (GPG_ERR_MISSING_ACTION);
+      goto leave;
     }
 
-  if (!err)
-    log_debug ("mountpoint is now `%s'\n", 
-               ctrl->server_local->mountpoint
-               ? ctrl->server_local->mountpoint: "[none]");
+  /* Perform the mount.  */
+  err = g13_mount_container (ctrl, ctrl->server_local->containername, 
+                             *line? line : NULL);
 
  leave:
   return leave_cmd (ctx, err);
 }
 
 
-/* MOUNT [options] <containername>
+/* UMOUNT [options] [<mountpoint>]
 
-   Mount CONTAINERNAME onto the current mount point.  CONTAINERNAME is
-   the name of a file in the g13 format and must be percent-plus
-   escaped to allow for arbitrary names.  The mount poiunt must have
-   been set already.
-
-
-   A reason why we use a separate command for the mount point is to
-   allow for longer filenames (an assuan command line is limited to
-   ~1000 byte. 
+   Unmount the currently open file or the one opened at MOUNTPOINT.
+   MOUNTPOINT must be percent-plus escaped.
  */
 static gpg_error_t
-cmd_mount (assuan_context_t ctx, char *line)
+cmd_umount (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
@@ -365,7 +329,7 @@ cmd_mount (assuan_context_t ctx, char *line)
   pend = p;
   while (spacep(p))
     p++;
-  if (*p || pend == line)
+  if (*p)
     {
       err = gpg_error (GPG_ERR_ASS_SYNTAX);
       goto leave;
@@ -375,20 +339,89 @@ cmd_mount (assuan_context_t ctx, char *line)
   /* Unescape the line and check for embedded Nul bytes.  */
   len = percent_plus_unescape_inplace (line, 0);
   line[len] = 0;
-  if (!len || memchr (line, 0, len))
+  if (memchr (line, 0, len))
     {
       err = gpg_error (GPG_ERR_INV_NAME);
       goto leave;
     }
-    
-  /* Perform the mount.  */
-  err = g13_mount_container (ctrl, line, ctrl->server_local->mountpoint);
+
+  /* Perform the unmount.  */
+  err = g13_umount_container (ctrl, ctrl->server_local->containername, 
+                              *line? line : NULL);
 
  leave:
   return leave_cmd (ctx, err);
 }
 
 
+
+/* RECIPIENT <userID>
+
+   FIXME - description. 
+   All RECIPIENT commands are cumulative until a RESET or an
+   successful CREATE command.
+ */
+static gpg_error_t
+cmd_recipient (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+
+  (void)ctrl;
+  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  /* err = gpgsm_add_to_certlist (ctrl, line, 0, */
+  /*                              &ctrl->server_local->recplist, 0); */
+  /* if (err) */
+  /*   { */
+  /*     gpgsm_status2 (ctrl, STATUS_INV_RECP, */
+  /*                    get_inv_recpsgnr_code (rc), line, NULL); */
+  /*   } */
+
+  return leave_cmd (ctx, err);
+}
+
+
+/* SIGNER <userID>
+
+   FIXME - description. 
+ */
+static gpg_error_t
+cmd_signer (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+
+  (void)ctrl;
+
+  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  return leave_cmd (ctx, err);
+}
+
+
+/* CREATE [options] filename
+
+   Create a new container.  On success the OPEN command is done
+   implictly for the new container.
+ */
+static gpg_error_t
+cmd_create (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+
+  (void)ctrl;
+
+  /* First we close the active container.  */
+  xfree (ctrl->server_local->containername);
+  ctrl->server_local->containername = NULL;
+
+
+
+  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  return leave_cmd (ctx, err);
+}
+
+
 /* GETINFO <what>
 
    Multipurpose function to return a variety of information.
@@ -476,10 +509,12 @@ register_commands (assuan_context_t ctx)
     const char *name;
     gpg_error_t (*handler)(assuan_context_t, char *line);
   } table[] =  {
+    { "OPEN",          cmd_open },
+    { "MOUNT",         cmd_mount },
+    { "UMOUNT",        cmd_umount },
     { "RECIPIENT",     cmd_recipient },
     { "SIGNER",        cmd_signer },
-    { "MOUNT",         cmd_mount },
-    { "SETMOUNTPOINT", cmd_setmountpoint },
+    { "CREATE",        cmd_create },
     { "INPUT",         NULL }, 
     { "OUTPUT",        NULL }, 
     { "GETINFO",       cmd_getinfo },