#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/file.h>
#include <sys/mount.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <pakfire/util.h>
#define KEYSTORE_DIR "/etc/pakfire/trusted.keys.d"
+#define LOCK_PATH PAKFIRE_PRIVATE_DIR "/.lock"
#define CCACHE_DIR "/var/cache/ccache"
struct mountpoint {
int nrefs;
char path[PATH_MAX];
+ char lock_path[PATH_MAX];
char cache_path[PATH_MAX];
char arch[ARCH_MAX];
char keystore_path[PATH_MAX];
int flags;
+ // Lock
+ FILE* lock;
+
// Pool
Pool* pool;
if (pakfire->gpgctx)
pakfire_keystore_destroy(pakfire, &pakfire->gpgctx);
+ // Release lock (if not already done so)
+ pakfire_release_lock(pakfire);
+
// umount everything
pakfire_umount(pakfire);
if (*p->distro.slogan)
DEBUG(p, " slogan = %s\n", p->distro.slogan);
+ // Set lock path
+ r = pakfire_make_path(p, p->lock_path, LOCK_PATH);
+ if (r < 0) {
+ ERROR(p, "Could not set lock path: %m\n");
+ goto ERROR;
+ }
+
// Set cache path
pakfire_string_format(p->cache_path, "%s/%s/%s/%s",
PAKFIRE_CACHE_DIR, p->distro.id, p->distro.version_id, p->arch);
return pakfire->path;
}
+int pakfire_acquire_lock(struct pakfire* pakfire) {
+ int r;
+
+ // Check if the lock is already held
+ if (pakfire->lock) {
+ ERROR(pakfire, "Lock is already been acquired by this process\n");
+ errno = ENOLCK;
+ return 1;
+ }
+
+ DEBUG(pakfire, "Acquire lock...\n");
+
+ // Ensure the parent directory exists
+ pakfire_mkparentdir(pakfire->lock_path, 0);
+
+ // Open the lock file
+ pakfire->lock = fopen(pakfire->lock_path, "w");
+ if (!pakfire->lock) {
+ ERROR(pakfire, "Could not open lock file %s: %m\n", pakfire->lock_path);
+ return 1;
+ }
+
+ // Attempt to lock the file exclusively
+ while (1) {
+ r = flock(fileno(pakfire->lock), LOCK_EX|LOCK_NB);
+
+ // Success!
+ if (r == 0)
+ goto SUCCESS;
+
+ DEBUG(pakfire, "Could not acquire lock %s: %m\n", pakfire->lock_path);
+
+ // Wait 500ms until the next attempt
+ usleep(500000);
+ }
+
+SUCCESS:
+ DEBUG(pakfire, "Lock acquired\n");
+
+ return 0;
+}
+
+void pakfire_release_lock(struct pakfire* pakfire) {
+ if (!pakfire->lock)
+ return;
+
+ DEBUG(pakfire, "Releasing lock\n");
+
+ fclose(pakfire->lock);
+ pakfire->lock = NULL;
+
+ // Attempt to unlink the lock file
+ unlink(pakfire->lock_path);
+}
+
void pakfire_call_status_callback(struct pakfire* pakfire, const char* message, ...) {
char* buffer = NULL;
va_list args;
return 1;
}
+ // Acquire lock
+ r = pakfire_acquire_lock(pakfire);
+ if (r)
+ goto ERROR;
+
// Create a new request
r = pakfire_request_create(&request, pakfire, solver_flags);
if (r)
r = 0;
ERROR:
+ // Release lock
+ pakfire_release_lock(pakfire);
+
+ // Cleanup
if (problems) {
for (struct pakfire_problem** problem = problems; *problem; problem++)
pakfire_problem_unref(*problem);
struct pakfire_problem** problems = NULL;
int r = 1;
+ // Acquire lock
+ r = pakfire_acquire_lock(pakfire);
+ if (r)
+ goto ERROR;
+
// Create a new request
r = pakfire_request_create(&request, pakfire, solver_flags);
if (r)
r = 0;
ERROR:
+ // Release lock
+ pakfire_release_lock(pakfire);
+
if (problems) {
for (struct pakfire_problem** problem = problems; *problem; problem++)
pakfire_problem_unref(*problem);