aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--agent/gpg-agent.c65
-rw-r--r--common/sysutils.c127
-rw-r--r--common/sysutils.h4
3 files changed, 140 insertions, 56 deletions
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 32e072b1e..16edae08a 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -47,9 +47,6 @@
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
-#ifdef HAVE_INOTIFY_INIT
-# include <sys/inotify.h>
-#endif /*HAVE_INOTIFY_INIT*/
#include <npth.h>
#define GNUPG_COMMON_NEED_AFLOCAL
@@ -2716,31 +2713,6 @@ start_connection_thread_ssh (void *arg)
}
-#ifdef HAVE_INOTIFY_INIT
-/* Read an inotify event and return true if it matches NAME. */
-static int
-my_inotify_is_name (int fd, const char *name)
-{
- union {
- struct inotify_event ev;
- char _buf[sizeof (struct inotify_event) + 100 + 1];
- } buf;
- int n;
-
- n = npth_read (fd, &buf, sizeof buf);
- if (n < sizeof (struct inotify_event))
- return 0;
- if (buf.ev.len < strlen (name)+1)
- return 0;
- if (strcmp (buf.ev.name, name))
- return 0; /* Not the desired file. */
-
- return 1; /* Found. */
-}
-#endif /*HAVE_INOTIFY_INIT*/
-
-
-
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
@@ -2749,6 +2721,7 @@ handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh)
{
+ gpg_error_t err;
npth_attr_t tattr;
struct sockaddr_un paddr;
socklen_t plen;
@@ -2764,9 +2737,7 @@ handle_connections (gnupg_fd_t listen_fd,
HANDLE events[2];
unsigned int events_set;
#endif
-#ifdef HAVE_INOTIFY_INIT
- int my_inotify_fd;
-#endif /*HAVE_INOTIFY_INIT*/
+ int my_inotify_fd = -1;
struct {
const char *name;
void *(*func) (void *arg);
@@ -2804,27 +2775,14 @@ handle_connections (gnupg_fd_t listen_fd,
# endif
#endif
-#ifdef HAVE_INOTIFY_INIT
if (disable_check_own_socket)
my_inotify_fd = -1;
- else if ((my_inotify_fd = inotify_init ()) == -1)
- log_info ("error enabling fast daemon termination: %s\n",
- strerror (errno));
- else
+ else if ((err = gnupg_inotify_watch_socket (&my_inotify_fd, socket_name)))
{
- /* We need to watch the directory for the file because there
- * won't be an IN_DELETE_SELF for a socket file. */
- char *slash = strrchr (socket_name, '/');
- log_assert (slash && slash[1]);
- *slash = 0;
- if (inotify_add_watch (my_inotify_fd, socket_name, IN_DELETE) == -1)
- {
- close (my_inotify_fd);
- my_inotify_fd = -1;
- }
- *slash = '/';
+ if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
+ log_info ("error enabling fast daemon termination: %s\n",
+ gpg_strerror (err));
}
-#endif /*HAVE_INOTIFY_INIT*/
/* On Windows we need to fire up a separate thread to listen for
requests from Putty (an SSH client), so we can replace Putty's
@@ -2867,14 +2825,12 @@ handle_connections (gnupg_fd_t listen_fd,
if (FD2INT (listen_fd_ssh) > nfd)
nfd = FD2INT (listen_fd_ssh);
}
-#ifdef HAVE_INOTIFY_INIT
if (my_inotify_fd != -1)
{
FD_SET (my_inotify_fd, &fdset);
if (my_inotify_fd > nfd)
nfd = my_inotify_fd;
}
-#endif /*HAVE_INOTIFY_INIT*/
listentbl[0].l_fd = listen_fd;
listentbl[1].l_fd = listen_fd_extra;
@@ -2949,14 +2905,13 @@ handle_connections (gnupg_fd_t listen_fd,
ctrl_t ctrl;
npth_t thread;
-#ifdef HAVE_INOTIFY_INIT
- if (my_inotify_fd != -1 && FD_ISSET (my_inotify_fd, &read_fdset)
- && my_inotify_is_name (my_inotify_fd, GPG_AGENT_SOCK_NAME))
+ if (my_inotify_fd != -1
+ && FD_ISSET (my_inotify_fd, &read_fdset)
+ && gnupg_inotify_has_name (my_inotify_fd, GPG_AGENT_SOCK_NAME))
{
shutdown_pending = 1;
log_info ("socket file has been removed - shutting down\n");
}
-#endif /*HAVE_INOTIFY_INIT*/
for (idx=0; idx < DIM(listentbl); idx++)
{
@@ -3004,10 +2959,8 @@ handle_connections (gnupg_fd_t listen_fd,
}
}
-#ifdef HAVE_INOTIFY_INIT
if (my_inotify_fd != -1)
close (my_inotify_fd);
-#endif /*HAVE_INOTIFY_INIT*/
cleanup ();
log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
npth_attr_destroy (&tattr);
diff --git a/common/sysutils.c b/common/sysutils.c
index 0f7b7f5cf..2e663bc8d 100644
--- a/common/sysutils.c
+++ b/common/sysutils.c
@@ -63,6 +63,9 @@
# endif
# include <windows.h>
#endif
+#ifdef HAVE_INOTIFY_INIT
+# include <sys/inotify.h>
+#endif /*HAVE_INOTIFY_INIT*/
#ifdef HAVE_NPTH
# include <npth.h>
#endif
@@ -78,6 +81,20 @@
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+static GPGRT_INLINE gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+static GPGRT_INLINE gpg_error_t
+my_error (int e)
+{
+ return gpg_err_make (default_errsource, (e));
+}
+
+
+
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
#warning using trap_unaligned
static int
@@ -929,3 +946,113 @@ w32_get_user_sid (void)
return sid;
}
#endif /*HAVE_W32_SYSTEM*/
+
+
+
+/* Support for inotify under Linux. */
+
+/* Store a new inotify file handle for SOCKET_NAME at R_FD or return
+ * an error code. */
+gpg_error_t
+gnupg_inotify_watch_socket (int *r_fd, const char *socket_name)
+{
+#if HAVE_INOTIFY_INIT
+ gpg_error_t err;
+ char *fname;
+ int fd;
+ char *p;
+
+ *r_fd = -1;
+
+ fname = xtrystrdup (socket_name);
+ if (!fname)
+ return my_error_from_syserror ();
+
+ fd = inotify_init ();
+ if (fd == -1)
+ {
+ err = my_error_from_syserror ();
+ xfree (fname);
+ return err;
+ }
+
+ /* We need to watch the directory for the file because there won't
+ * be an IN_DELETE_SELF for a socket file. To handle a removal of
+ * the directory we also watch the directory itself. */
+ p = strrchr (fname, '/');
+ if (p)
+ *p = 0;
+ if (inotify_add_watch (fd, fname,
+ (IN_DELETE|IN_DELETE_SELF|IN_EXCL_UNLINK)) == -1)
+ {
+ err = my_error_from_syserror ();
+ close (fd);
+ xfree (fname);
+ return err;
+ }
+
+ xfree (fname);
+
+ *r_fd = fd;
+ return 0;
+#else /*!HAVE_INOTIFY_INIT*/
+
+ (void)socket_name;
+ *r_fd = -1;
+ return my_error (GPG_ERR_NOT_SUPPORTED);
+
+#endif /*!HAVE_INOTIFY_INIT*/
+}
+
+
+/* Read an inotify event and return true if it matches NAME or if it
+ * sees an IN_DELETE_SELF event for the directory of NAME. */
+int
+gnupg_inotify_has_name (int fd, const char *name)
+{
+#if USE_NPTH && HAVE_INOTIFY_INIT
+ union {
+ struct inotify_event ev;
+ char _buf[sizeof (struct inotify_event) + 255 + 1];
+ } buf;
+ struct inotify_event *evp;
+ int n;
+
+ n = npth_read (fd, &buf, sizeof buf);
+ /* log_debug ("notify read: n=%d\n", n); */
+ evp = &buf.ev;
+ while (n >= sizeof (struct inotify_event))
+ {
+ /* log_debug (" mask=%x len=%u name=(%s)\n", */
+ /* evp->mask, (unsigned int)evp->len, evp->len? evp->name:""); */
+ if ((evp->mask & IN_UNMOUNT))
+ {
+ /* log_debug (" found (dir unmounted)\n"); */
+ return 3; /* Directory was unmounted. */
+ }
+ if ((evp->mask & IN_DELETE_SELF))
+ {
+ /* log_debug (" found (dir removed)\n"); */
+ return 2; /* Directory was removed. */
+ }
+ if ((evp->mask & IN_DELETE))
+ {
+ if (evp->len >= strlen (name) && !strcmp (evp->name, name))
+ {
+ /* log_debug (" found (file removed)\n"); */
+ return 1; /* File was removed. */
+ }
+ }
+ n -= sizeof (*evp) + evp->len;
+ evp = (struct inotify_event *)((char*)evp + sizeof (*evp) + evp->len);
+ }
+
+#else /*!(USE_NPTH && HAVE_INOTIFY_INIT)*/
+
+ (void)fd;
+ (void)name;
+
+#endif /*!(USE_NPTH && HAVE_INOTIFY_INIT)*/
+
+ return 0; /* Not found. */
+}
diff --git a/common/sysutils.h b/common/sysutils.h
index ba66ce616..ea92e4c32 100644
--- a/common/sysutils.h
+++ b/common/sysutils.h
@@ -67,6 +67,10 @@ int gnupg_setenv (const char *name, const char *value, int overwrite);
int gnupg_unsetenv (const char *name);
char *gnupg_getcwd (void);
+gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);
+int gnupg_inotify_has_name (int fd, const char *name);
+
+
#ifdef HAVE_W32_SYSTEM
void *w32_get_user_sid (void);