diff options
author | Lennart Poettering <lennart@poettering.net> | 2004-01-14 21:51:32 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2004-01-14 21:51:32 +0000 |
commit | 2187fc7c62ffad7cb514d061899d57cfd95438dc (patch) | |
tree | 417667f8ef1175f703d6b86f73bdd9094187d51e /src/client-tty.c | |
parent | 973391053d38096aa05933a61885c67cc07adbe6 (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/client-tty.c')
-rw-r--r-- | src/client-tty.c | 150 |
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; |