summaryrefslogtreecommitdiffstats
path: root/src/lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lock.c')
-rw-r--r--src/lock.c120
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;
+}