diff --git a/Makefile b/Makefile index 5a4ae70..71a327f 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ install : $(PROGRAMS) cp $^ $(HOME)/bin/ dlight : dlight.o env.o http.o rss.o filter.o cconf.o dlhist.o -dlight-compile : compile.o env.o filter.o cconf.o +dlight-compile : compile.o env.o lockfile.o filter.o cconf.o dlight-read-config : read-config.o env.o cconf.o dlight-% : %.o diff --git a/compile.c b/compile.c index 9ea3f2a..cf4508b 100644 --- a/compile.c +++ b/compile.c @@ -10,6 +10,7 @@ #include #include "env.h" #include "cconf.h" +#include "lockfile.h" #include "filter.h" #define error(...) fprintf(stderr, "error: " __VA_ARGS__) @@ -237,48 +238,30 @@ static int parse_config_file(const char *file) { return -1; } -static int commit_lock(const char *file) { - - char target[4096]; - int len; - - len = strlen(file) - 5; /* .lock */ - - memcpy(target, file, len); - target[len] = '\0'; - - return rename(file, target); -} - int main(int argc, char **argv) { - int lockfd; - char lockfile[4096]; + int lockfd, force = 0; + struct lockfile lock = LOCKFILE_INIT; + char filename[4096]; - snprintf(lockfile, sizeof(lockfile), "%s/%s", - env_get_dir(), "config.lock"); + snprintf(filename, sizeof(filename), "%s/%s", + env_get_dir(), "config"); /* Remove lockfile if forced */ if (argc > 1 && !strcmp(argv[1], "-f")) - unlink(lockfile); + force = 1; - lockfd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (lockfd < 0) { - if (errno == EEXIST) { - error("config is locked\n"); - } else { - perror("unable to create new configfile"); - } + lockfd = hold_lock(&lock, filename, force); + if (lockfd < 0) return 1; - } if (parse_config_file("./config") < 0) goto error; if (!cconf_write(lockfd, &cconf) && - !commit_lock(lockfile)) + !commit_lock(&lock)) return 0; error: - unlink(lockfile); + release_lock(&lock); return 1; } diff --git a/lockfile.c b/lockfile.c new file mode 100644 index 0000000..ac0a233 --- /dev/null +++ b/lockfile.c @@ -0,0 +1,74 @@ + +#include +#include +#include +#include +#include +#include +#include +#include "lockfile.h" + +#define locked(x) ((x)->fd >= 0) + +int hold_lock(struct lockfile *lock, const char *filename, int force) { + + int rc, mask = O_WRONLY | O_CREAT | O_TRUNC; + + if (locked(lock)) + return -1; + + if (!force) + mask |= O_EXCL; + + rc = snprintf(lock->name, sizeof(lock->name), "%s.lock", filename); + if (rc > sizeof(lock->name)) + return -1; + + lock->fd = open(lock->name, mask, 0600); + if (lock->fd < 0) { + if (errno == EEXIST) { + fprintf(stderr, "'%s' is locked\n", lock->name); + } else { + fprintf(stderr, "unable to create lockfile '%s'", + lock->name); + } + return -1; + } + return lock->fd; +} + +int commit_lock(struct lockfile *lock) { + + char target[4096]; + int len; + + if (!locked(lock)) + return 0; + + len = strlen(lock->name) - 5; /* .lock */ + + memcpy(target, lock->name, len); + target[len] = '\0'; + + if (rename(lock->name, target)) + return -1; + lock->name[0] = '\0'; + close(lock->fd); + lock->fd = -1; + return 0; +} + +int release_lock(struct lockfile *lock) { + + int rc; + + if (!locked(lock)) + return 0; + rc = unlink(lock->name); + if (rc == 0) { + lock->name[0] = '\0'; + close(lock->fd); + lock->fd = -1; + } + return rc; +} diff --git a/lockfile.h b/lockfile.h new file mode 100644 index 0000000..7f6393c --- /dev/null +++ b/lockfile.h @@ -0,0 +1,18 @@ + +#ifndef LOCKFILE_H +#define LOCKFILE_H + +struct lockfile { + int fd; + char name[4096]; +}; + +#define LOCKFILE_INIT { -1, { 0 } } + +int hold_lock(struct lockfile *lock, const char *filename, int force); + +int commit_lock(struct lockfile *lock); + +int release_lock(struct lockfile *lock); + +#endif /* LOCKFILE_H */ \ No newline at end of file