summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meson.build1
-rw-r--r--src/lock.c71
-rw-r--r--src/lock.h8
-rw-r--r--src/main.c6
4 files changed, 86 insertions, 0 deletions
diff --git a/meson.build b/meson.build
index f56add3..9183dcf 100644
--- a/meson.build
+++ b/meson.build
@@ -103,6 +103,7 @@ common_sources = files(
'src/fuzzy_match.c',
'src/history.c',
'src/input.c',
+ 'src/lock.c',
'src/log.c',
'src/mkdirp.c',
'src/shm.c',
diff --git a/src/lock.c b/src/lock.c
new file mode 100644
index 0000000..133d327
--- /dev/null
+++ b/src/lock.c
@@ -0,0 +1,71 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/file.h>
+#include "log.h"
+#include "xmalloc.h"
+
+static const char *default_cache_dir = ".cache/";
+static const char *lock_filename = "tofi.lock";
+
+[[nodiscard("memory leaked")]]
+static char *get_lock_path() {
+ char *lock_name = NULL;
+ const char *runtime_path = getenv("XDG_RUNTIME_DIR");
+ if (runtime_path == NULL) {
+ runtime_path = getenv("XDG_CACHE_HOME");
+ }
+ if (runtime_path == NULL) {
+ const char *home = getenv("HOME");
+ if (home == NULL) {
+ log_error("Couldn't retrieve HOME from environment.\n");
+ return NULL;
+ }
+ size_t len = strlen(home) + 1
+ + strlen(default_cache_dir) + 1
+ + strlen(lock_filename) + 1;
+ lock_name = xmalloc(len);
+ snprintf(
+ lock_name,
+ len,
+ "%s/%s/%s",
+ home,
+ default_cache_dir,
+ lock_filename);
+ } else {
+ size_t len = strlen(runtime_path) + 1
+ + strlen(lock_filename) + 1;
+ lock_name = xmalloc(len);
+ snprintf(
+ lock_name,
+ len,
+ "%s/%s",
+ runtime_path,
+ lock_filename);
+ }
+ return lock_name;
+}
+
+bool lock_check(void)
+{
+ bool ret = false;
+ char *filename = get_lock_path();
+ errno = 0;
+ int fd = open(filename, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ log_error("Failed to open lock file %s: %s.\n", filename, strerror(errno));
+ } else if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
+ if (errno == EWOULDBLOCK) {
+ /*
+ * We can't lock the file because another tofi process
+ * already has.
+ */
+ ret = true;
+ }
+ }
+
+ free(filename);
+ return ret;
+}
diff --git a/src/lock.h b/src/lock.h
new file mode 100644
index 0000000..1ce402e
--- /dev/null
+++ b/src/lock.h
@@ -0,0 +1,8 @@
+#ifndef LOCK_H
+#define LOCK_H
+
+#include <stdbool.h>
+
+bool lock_check(void);
+
+#endif /* LOCK_H */
diff --git a/src/main.c b/src/main.c
index 2a9ce00..807f57c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -22,6 +22,7 @@
#include "input.h"
#include "log.h"
#include "nelem.h"
+#include "lock.h"
#include "shm.h"
#include "string_vec.h"
#include "string_vec.h"
@@ -905,6 +906,11 @@ int main(int argc, char *argv[])
parse_args(&tofi, argc, argv);
+ if (lock_check()) {
+ log_error("Another instance of tofi is already running.\n");
+ exit(EXIT_FAILURE);
+ }
+
/*
* Initial Wayland & XKB setup.
* The first thing to do is connect a listener to the global registry,