From 0aa6458d09d8a7a563dc6bf3a30abd12650bae48 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 4 May 2019 14:03:37 +0200 Subject: [PATCH 1/3] serial: atomically create lock files Previously, a different process could create the lock between both calls to open(2) with the result that two processes access the same serial port. Fix this by only opening the lock file with O_CREAT | O_EXCL. Signed-off-by: Ahmad Fatoum --- serial.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/serial.c b/serial.c index 0778fe1..37a606c 100644 --- a/serial.c +++ b/serial.c @@ -22,6 +22,7 @@ #include #include +#include #include #include "microcom.h" @@ -177,26 +178,28 @@ struct ios_ops * serial_init(char *device) exit(1); } - fd = open(lockfile, O_RDONLY); - if (fd >= 0 && !opt_force) { - close(fd); - main_usage(3, "lockfile for port exists", device); - } +relock: + fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0444); + if (fd < 0) { + if (errno == EEXIST) { + if (opt_force) { + printf("lockfile for port exists, ignoring\n"); + serial_unlock(); + goto relock; + } + + main_usage(3, "lockfile for port exists", device); + } + + if (opt_force) { + printf("cannot create lockfile. ignoring\n"); + lockfile = NULL; + goto force; + } - if (fd >= 0 && opt_force) { - close(fd); - printf("lockfile for port exists, ignoring\n"); - serial_unlock(); + main_usage(3, "cannot create lockfile", device); } - fd = open(lockfile, O_RDWR | O_CREAT, 0444); - if (fd < 0 && opt_force) { - printf("cannot create lockfile. ignoring\n"); - lockfile = NULL; - goto force; - } - if (fd < 0) - main_usage(3, "cannot create lockfile", device); /* Kermit wants binary pid */ pid = getpid(); write(fd, &pid, sizeof(long)); From 05c9da8a4510a403f75612ab1226223864ba13be Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 4 May 2019 14:03:37 +0200 Subject: [PATCH 2/3] serial: create lock files in HDB UUCP format This is the format specified by the FHS[1]. While at it remove the now outdated comment about kermit compatibility. It no longer applies to ckermit, which now follows the HDB UUCP format as well[2]. [1]: http://www.pathname.com/fhs/pub/fhs-2.3.html#VARLOCKLOCKFILES [2]: https://github.com/pengutronix/microcom/pull/9#discussion_r217924856 Signed-off-by: Ahmad Fatoum --- serial.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/serial.c b/serial.c index 37a606c..97b5448 100644 --- a/serial.c +++ b/serial.c @@ -200,9 +200,8 @@ struct ios_ops * serial_init(char *device) main_usage(3, "cannot create lockfile", device); } - /* Kermit wants binary pid */ pid = getpid(); - write(fd, &pid, sizeof(long)); + dprintf(fd, "%10ld\n", (long)pid); close(fd); force: /* open the device */ From 91a6aec5f56b22dfef863366314bc1b5f546db19 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 4 May 2019 14:03:37 +0200 Subject: [PATCH 3/3] serial: delete stale lock files If microcom crashes, e.g. due to the buffer underflow described in #10, it may leave a stale lock file behind. Teach microcom detection of these stale lock files. Note that this is racy, two processes may detect a stale lock file and one might unlink the other's lock. Signed-off-by: Ahmad Fatoum --- serial.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/serial.c b/serial.c index 97b5448..3fb9a9b 100644 --- a/serial.c +++ b/serial.c @@ -182,12 +182,34 @@ struct ios_ops * serial_init(char *device) fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0444); if (fd < 0) { if (errno == EEXIST) { + char pidbuf[12]; + ssize_t nbytes = 0; if (opt_force) { printf("lockfile for port exists, ignoring\n"); serial_unlock(); goto relock; } + fd = open(lockfile, O_RDONLY); + if (fd < 0) + main_usage(3, "lockfile for port can't be opened", device); + + do { + ret = read(fd, &pidbuf[nbytes], sizeof(pidbuf) - nbytes - 1); + nbytes += ret; + } while (ret > 0 && nbytes < sizeof (pidbuf) - 1); + + if (ret >= 0) { + pidbuf[nbytes] = '\0'; + ret = sscanf(pidbuf, "%10ld\n", &pid); + + if (ret == 1 && kill(pid, 0) < 0 && errno == ESRCH) { + printf("lockfile contains stale pid, ignoring\n"); + serial_unlock(); + goto relock; + } + } + main_usage(3, "lockfile for port exists", device); }