summaryrefslogtreecommitdiff
path: root/serial.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2011-01-11 20:34:00 -0500
committerEric S. Raymond <esr@thyrsus.com>2011-01-11 20:34:00 -0500
commit6a98bb0028df6243d40ce538324305498870e66f (patch)
treef44aff3891d8cf0226f67f8eae2933353a7b4129 /serial.c
parent409ab1d850e41c8f029b3fd91b02b1be15a367a8 (diff)
downloadgpsd-6a98bb0028df6243d40ce538324305498870e66f.tar.gz
Re-commit the new device locking, previously removed by a finger error.
Diffstat (limited to 'serial.c')
-rw-r--r--serial.c57
1 files changed, 34 insertions, 23 deletions
diff --git a/serial.c b/serial.c
index 743c0283..eef91bd5 100644
--- a/serial.c
+++ b/serial.c
@@ -72,12 +72,13 @@ static sourcetype_t gpsd_classify(const char *path)
#include <dirent.h>
#include <ctype.h>
-static bool anyopen(const char *path)
+static int fusercount(const char *path)
/* return true if any process has the specified path open */
{
DIR *procd, *fdd;
struct dirent *procentry, *fdentry;
char procpath[32], fdpath[64], linkpath[64];
+ int cnt = 0;
if ((procd = opendir("/proc")) == NULL)
return false;
@@ -95,16 +96,15 @@ static bool anyopen(const char *path)
if (readlink(fdpath, linkpath, sizeof(linkpath)) == -1)
continue;
if (strcmp(linkpath, path) == 0) {
- (void)closedir(fdd);
(void)closedir(procd);
return true;
}
}
+ (void)closedir(fdd);
}
-
- (void)closedir(fdd);
(void)closedir(procd);
- return false;
+
+ return cnt;
}
#endif /* __linux__ */
@@ -375,20 +375,6 @@ int gpsd_open(struct gps_device_t *session)
} else
#endif /* BLUEZ */
{
-#ifdef __linux__
- /*
- * Don't touch devices already opened by another process. We
- * have to make an exception for ptys, which are intentionally
- * opened by another process on the master side, otherwise we'll
- * break all our regression tests.
- */
- if (session->sourcetype != source_pty && anyopen(session->gpsdata.dev.path)) {
- gpsd_report(LOG_ERROR,
- "%s already opened by another process\n",
- session->gpsdata.dev.path);
- return -1;
- }
-#endif /* __linux__ */
if ((session->gpsdata.gps_fd =
open(session->gpsdata.dev.path,
(int)(mode | O_NONBLOCK | O_NOCTTY))) == -1) {
@@ -408,11 +394,36 @@ int gpsd_open(struct gps_device_t *session)
}
/*
- * Try to block other processes from using this device while we
- * have it open (later opens should return EBUSY). Won't work
- * against anything with root privileges, alas.
+ * Ideally we want to exclusion-lock the device before doing any reads.
+ * It would have been best to do this at open(2) time, but O_EXCL
+ * doesn't work wuthout O_CREAT.
+ *
+ * We have to make an exception for ptys, which are intentionally
+ * opened by another process on the master side, otherwise we'll
+ * break all our regression tests.
*/
- (void)ioctl(session->gpsdata.gps_fd, TIOCEXCL);
+ if (session->sourcetype != source_pty) {
+ /*
+ * Try to block other processes from using this device while we
+ * have it open (later opens should return EBUSY). Won't work
+ * against anything with root privileges, alas.
+ */
+ (void)ioctl(session->gpsdata.gps_fd, TIOCEXCL);
+
+#ifdef __linux__
+ /*
+ * Don't touch devices already opened by another process.
+ */
+ if (fusercount(session->gpsdata.dev.path) > 1) {
+ gpsd_report(LOG_ERROR,
+ "%s already opened by another process\n",
+ session->gpsdata.dev.path);
+ (void)close(session->gpsdata.gps_fd);
+ session->gpsdata.gps_fd = -1;
+ return -1;
+ }
+#endif /* __linux__ */
+ }
#ifdef FIXED_PORT_SPEED
session->saved_baud = FIXED_PORT_SPEED;