#include #include #include #include #include #include #include #include #include #include #include #include "lock.h" #include "util.h" #include "main.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((char*) 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; const 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 { unsigned long v; buf[n] = 0; sscanf(buf, "%lu", &v); pid = (pid_t) v; } if (pid > 0) { if (kill(pid, 0) < 0 && errno == ESRCH) { daemon_log(LOG_WARNING, "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", strerror(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)); } unlink(temp); 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; }