summaryrefslogtreecommitdiff
path: root/serial.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2011-01-10 10:45:45 -0500
committerEric S. Raymond <esr@thyrsus.com>2011-01-10 10:51:33 -0500
commit32e99f3888c6b5690bb7ee18a6e6ad9ff1a3f87d (patch)
tree62443145b127492a022038eb6955bfd864db1c50 /serial.c
parent729d860096f96c5d1a7f5bc161967b90368d92e0 (diff)
downloadgpsd-32e99f3888c6b5690bb7ee18a6e6ad9ff1a3f87d.tar.gz
Under Linux, use /proc to avoid opening serial devices already open.
This will help prevent gpsd from consuming data from devices such as USB modems that happen to look like GPSes because they use a USB-to-serial adapter thar we have whitelisted. Relies on there being a /proc filesystem with Linux-like semantics.
Diffstat (limited to 'serial.c')
-rw-r--r--serial.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/serial.c b/serial.c
index 34c66f84..75effe1b 100644
--- a/serial.c
+++ b/serial.c
@@ -67,6 +67,46 @@ static sourcetype_t gpsd_classify(const char *path)
return source_unknown;
}
+#ifdef __linux__
+#include <dirent.h>
+#include <ctype.h>
+
+static bool anyopen(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];
+
+ if ((procd = opendir("/proc")) == NULL)
+ return false;
+ while ((procentry = readdir(procd)) != NULL) {
+ if (isdigit(procentry->d_name[0])==0)
+ continue;
+ (void)snprintf(procpath, sizeof(procpath),
+ "/proc/%s/fd/", procentry->d_name);
+ if ((fdd = opendir(procpath)) == NULL)
+ continue;
+ while ((fdentry = readdir(fdd)) != NULL) {
+ (void)strlcpy(fdpath, procpath, sizeof(fdpath));
+ (void)strlcat(fdpath, fdentry->d_name, sizeof(fdpath));
+ (void)memset(linkpath, '\0', sizeof(linkpath));
+ 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(procd);
+ return false;
+}
+#endif /* __linux__ */
+
void gpsd_tty_init(struct gps_device_t *session)
/* to be called on allocating a device */
{
@@ -331,6 +371,14 @@ int gpsd_open(struct gps_device_t *session)
} else
#endif /* BLUEZ */
{
+#ifdef __linux__
+ if (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) {