diff options
Diffstat (limited to 'src/lock.c')
-rw-r--r-- | src/lock.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/lock.c b/src/lock.c new file mode 100644 index 0000000..48c409f --- /dev/null +++ b/src/lock.c @@ -0,0 +1,120 @@ +#include <unistd.h> +#include <sys/stat.h> +#include <stdio.h> +#include <limits.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> + +#include <libdaemon/dlog.h> + +#include "lock.h" + +/* Where do lockfiles reside? */ +#define LOCK_PATH "/var/lock" + +static const char *lockfile(const char *dev) { + static char lockfile[PATH_MAX]; + snprintf(lockfile, sizeof(lockfile), "%s/LCK..%s", LOCK_PATH, basename(dev)); + 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; +} + +int device_lock(const char *dev) { + struct stat st; + int fd; + char *path, *temp; + char buf[100]; + + if (stat(LOCK_PATH, &st) != 0 || !S_ISDIR(st.st_mode)) { + daemon_log(LOG_ERR, "Failed to lock device, directory "LOCK_PATH" not existent."); + return -1; + } + + path = lockfile(dev); + temp = tempfile(path); + + for (;;) { + + if ((fd = open(path, O_RDONLY)) < 0) { + if (errno != ENOENT) { + daemon_log(LOG_ERR, "Failed to open lock file: %s", strerror(errno)); + return -1; + } + } + + if (fd >= 0) { + ssize_t n; + + n = loop_read(fd, buf, sizeof(buf) - 1); + close(fd); + + if (n < 0) { + close(fd) + daemon_log(LOG_ERR, "Failed to read from lock file: %s", strerror(errno)); + return -1; + } + + if (n > 0) { + pid_t pid; + + if (n == 4) + pid = (pid_t) *((uint32_t*) buf); + else { + buf[n] = 0; + sscanf(buf, "%lu", &pid); + } + + if (pid > 0) { + if (kill(pid, 0) < 0 && errno == ESRCH) { + daemon_log(LOG_WARN, "Lockfile is stale. Overriding it."); + /* Yes, here is a race condition */ + unlink(path); + } else + return 1; + } + } + } + + if ((fd = open(temp, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0) { + daemon_log(LOG_ERR, "Failed to create temporary lock file: %s", strerror(errno)); + return -1; + } + + snprintf(buf, sizeof(buf), "%10lu %s %.20s\n", (unsigned long) getpid(), appname, username); + if (loop_write(fd, buf, strlen(buf)) < 0) { + daemon_log(LOG_ERR, "Failed to write to temporary lock file: %s", sterror(errno)); + close(fd); + return -1; + } + + close(fd); + + if (link(temp, path) < 0) { + if (errno == EEXIST) + continue; + + daemon_log(LOG_ERR, "Failed to link temporary lock file: %s", strerror(errno)); + } + + + return 0; + } +} + +int device_unlock(const char *dev) { + + if (unlink(lockfile(dev)) < 0) { + daemon_log(LOG_ERR, "Failed to remove lock file: %s", strerror(errno)); + return -1; + } + + return 0; +} |