aboutsummaryrefslogtreecommitdiffstats
path: root/common/sysutils.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2016-10-15 19:35:05 +0000
committerWerner Koch <[email protected]>2016-10-15 19:35:05 +0000
commit2f7d4c38c9e7bcc14e6e0bf219d688c40a4afecb (patch)
tree5b8d91c526f29c50a24c17492dc807ad9f3ee6f4 /common/sysutils.c
parentdirmngr: use gnupg_mkdtemp instead of mkstemp (diff)
downloadgnupg-2f7d4c38c9e7bcc14e6e0bf219d688c40a4afecb.tar.gz
gnupg-2f7d4c38c9e7bcc14e6e0bf219d688c40a4afecb.zip
agent: Move inotify code to common and improve it.
* common/sysutils.c: Include sys/inotify.h. (my_error_from_syserror, my_error): New. (gnupg_inotify_watch_socket): New. (gnupg_inotify_has_name): New. * agent/gpg-agent.c: Do not include sys/inotify.h. (my_inotify_is_name): Remove. (handle_connections): Remove HAVE_INOTIFY_INIT protected code and use the new functions. -- When removing not a simple socket file but the entire directory the old code missed most events and thus did not worked properly. IN_DELETE_SELF has also been added to the watch list to detect a removal of the directory. However, in all tests that event was not triggered. The only way it could be triggered was by not watching the socket dir but an arbitary directory and rmdir that. GnuPG-bug-id: 2756 Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'common/sysutils.c')
-rw-r--r--common/sysutils.c127
1 files changed, 127 insertions, 0 deletions
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. */
+}