summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2004-01-14 21:51:32 +0000
committerLennart Poettering <lennart@poettering.net>2004-01-14 21:51:32 +0000
commit2187fc7c62ffad7cb514d061899d57cfd95438dc (patch)
tree417667f8ef1175f703d6b86f73bdd9094187d51e /src
parent973391053d38096aa05933a61885c67cc07adbe6 (diff)
Add UUCP locking
Add documentation git-svn-id: file:///home/lennart/svn/public/bidilink/trunk@7 9cde1c1d-e4d0-0310-8a68-bf217395ea82
Diffstat (limited to 'src')
-rw-r--r--src/client-tty.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/client-tty.c b/src/client-tty.c
index 5f31249..59ddec5 100644
--- a/src/client-tty.c
+++ b/src/client-tty.c
@@ -30,17 +30,165 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <pwd.h>
#include "client-tty.h"
+#define LOCKDIR "/var/lock"
+
+static const char *lockfile(const char *dev) {
+ static char lockfile[PATH_MAX];
+ char *p = strrchr(dev, '/');
+ if (p)
+ p++;
+ else
+ p = (char*) dev;
+
+ snprintf(lockfile, sizeof(lockfile), "%s/LCK..%s", LOCKDIR, p);
+ return lockfile;
+}
+
+static const char *tempfile(const char *path) {
+ static char t[PATH_MAX];
+ snprintf(t, sizeof(t), "%s.tmp.%lu", path, (unsigned long) getpid());
+ return t;
+}
+
+static int device_lock(const char *dev) {
+ struct stat st;
+ int fd;
+ const char *path, *temp;
+ char buf[100];
+ char uidbuf[32];
+
+ if (stat(LOCKDIR, &st) != 0 || !S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "Failed to lock device, directory "LOCKDIR" not existent.\n");
+ return -1;
+ }
+
+ path = lockfile(dev);
+ temp = tempfile(path);
+
+ for (;;) {
+ mode_t u;
+ struct passwd* pw;
+ char *username;
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "Failed to open lock file: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ if (fd >= 0) {
+ ssize_t n;
+
+ n = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+
+ if (n < 0) {
+ close(fd);
+ fprintf(stderr, "Failed to read from lock file: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (n > 0) {
+ pid_t pid;
+
+ if (n == 4)
+ pid = (pid_t) *((uint32_t*) buf);
+ else {
+ unsigned long v;
+ buf[n] = 0;
+ sscanf(buf, "%lu", &v);
+ pid = (pid_t) v;
+ }
+
+ if (pid > 0) {
+ if (kill(pid, 0) < 0 && errno == ESRCH) {
+ fprintf(stderr, "Lockfile is stale. Overriding it.\n");
+ /* Yes, here is a race condition */
+ unlink(path);
+ } else
+ return 1;
+ }
+ }
+ }
+
+ u = umask(0033);
+ fd = open(temp, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ umask(u);
+
+ if (fd < 0) {
+ fprintf(stderr, "Failed to create temporary lock file: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if ((pw = getpwuid(getuid())))
+ username = pw->pw_name;
+ else
+ snprintf(username = uidbuf, sizeof(uidbuf), "%lu", (unsigned long) getuid());
+
+ snprintf(buf, sizeof(buf), "%10lu %s %.20s\n", (unsigned long) getpid(), "bidilink", username);
+ if (write(fd, buf, strlen(buf)) < 0) {
+ fprintf(stderr, "Failed to write to temporary lock file: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ if (link(temp, path) < 0) {
+ if (errno == EEXIST)
+ continue;
+
+ fprintf(stderr, "Failed to link temporary lock file: %s\n", strerror(errno));
+ }
+
+ unlink(temp);
+
+ return 0;
+ }
+}
+
+static int device_unlock(const char *dev) {
+ if (unlink(lockfile(dev)) < 0) {
+ fprintf(stderr, "Failed to remove lock file: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void destruct(struct stream *s) {
+ assert(s && s->user);
+
+ device_unlock((char*) s->user);
+ free(s->user);
+}
+
struct stream* stream_client_tty(const char *args) {
struct stream *s = NULL;
struct termios ts;
int fd = -1;
+ int r;
s = malloc(sizeof(struct stream));
assert(s);
memset(s, 0, sizeof(struct stream));
+
+ if ((r = device_lock(args)) != 0) {
+ if (r > 0)
+ fprintf(stderr, "Device locked.\n");
+ goto fail;
+ }
+
if ((fd = open(args, O_RDWR|O_NOCTTY)) < 0) {
fprintf(stderr, "open('%s', O_RDWR|O_NOCTTY): %s\n", args, strerror(errno));
@@ -67,6 +215,8 @@ struct stream* stream_client_tty(const char *args) {
goto fail;
}
+ s->user = strdup(args);
+ s->destruct = destruct;
s->input_fd = s->output_fd = fd;
return s;