summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/internal.h7
-rw-r--r--src/librcc.c90
-rw-r--r--src/rccdb4.c26
3 files changed, 122 insertions, 1 deletions
diff --git a/src/internal.h b/src/internal.h
index 5e64551..c5170be 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -5,6 +5,10 @@
# define LIBRCC_DATA_DIR "/usr/lib/rcc"
#endif /* LIBRCC_DATA_DIR */
+#ifndef LIBRCC_LOCK_WAIT
+# define LIBRCC_LOCK_WAIT 3000 /* ms */
+#endif /* LIBRCC_LOCK_WAIT */
+
#define RCC_MAX_LANGUAGE_PARRENTS 4
#define RCC_MAX_RELATIONS RCC_MAX_LANGUAGES
@@ -91,6 +95,9 @@ struct rcc_context_t {
};
typedef struct rcc_context_t rcc_context_s;
+int rccLock();
+void rccUnLock();
+
int rccConfigure(rcc_context ctx);
char *rccCreateResult(rcc_context ctx, size_t len);
diff --git a/src/librcc.c b/src/librcc.c
index 1ffe00b..6d3ce24 100644
--- a/src/librcc.c
+++ b/src/librcc.c
@@ -1,6 +1,8 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
#include "../config.h"
@@ -19,6 +21,11 @@
# include <pwd.h>
#endif /* HAVE_PWD_H */
+#ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+
#include "internal.h"
#include "rccconfig.h"
#include "rccenca.h"
@@ -135,6 +142,89 @@ void rccFree() {
initialized = 0;
}
+static int lockfd = -1;
+
+int rccLock() {
+# ifdef HAVE_SYS_FILE_H
+ int err, i;
+ int size;
+ char *stmp;
+ struct timespec wait = { 0, 10000000 };
+
+ if (lockfd>=0) return -1;
+
+ size = strlen(rcc_home_dir) + 32;
+ stmp = (char*)malloc(size*sizeof(char));
+ if (!stmp) return -1;
+
+ sprintf(stmp,"%s/.rcc/", rcc_home_dir);
+ mkdir(stmp, 00755);
+
+ sprintf(stmp,"%s/.rcc/locks/", rcc_home_dir);
+ mkdir(stmp, 00700);
+
+ sprintf(stmp,"%s/.rcc/locks/rcc.lock", rcc_home_dir);
+
+ lockfd = open(stmp, O_RDWR|O_CREAT, 0644);
+ if (lockfd >= 0) {
+ for (err = -1, i = 0; i < (LIBRCC_LOCK_WAIT/10); i++) {
+ err = flock(lockfd, LOCK_EX|LOCK_NB);
+ if ((err)&&(errno == EWOULDBLOCK)) nanosleep(&wait, NULL);
+ else break;
+ }
+
+ if (err) {
+ close(lockfd);
+
+ // Removing invalid lock
+ if (i == (LIBRCC_LOCK_WAIT/10)) {
+ remove(stmp);
+
+ lockfd = open(stmp, O_RDWR|O_CREAT, 0644);
+ if (lockfd >= 0) {
+ for (err = -1, i = 0; i < (LIBRCC_LOCK_WAIT/10); i++) {
+ err = flock(lockfd, LOCK_EX|LOCK_NB);
+ if ((err)&&(errno == EWOULDBLOCK)) nanosleep(&wait, NULL);
+ else break;
+ }
+
+ if (err) close(lockfd);
+ else return 0;
+ }
+ }
+
+ lockfd = -1;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ return -1;
+# else /* HAVE_SYS_FILE_H */
+ return 0;
+# endif /* HAVE_SYS_FILE_H */
+}
+
+void rccUnLock() {
+#ifdef HAVE_SYS_FILE_H
+ int size;
+ char *stmp;
+
+ if (lockfd<0) return;
+
+ size = strlen(rcc_home_dir) + 32;
+ stmp = (char*)malloc(size*sizeof(char));
+ if (!stmp) return;
+
+ sprintf(stmp,"%s/.rcc/locks/rcc.lock", rcc_home_dir);
+
+ flock(lockfd, LOCK_UN);
+ close(lockfd);
+ lockfd = -1;
+#endif /* HAVE_SYS_FILE_H */
+}
+
rcc_context rccCreateContext(const char *locale_variable, unsigned int max_languages, unsigned int max_classes, rcc_class_ptr defclasses, rcc_init_flags flags) {
unsigned int i;
diff --git a/src/rccdb4.c b/src/rccdb4.c
index 6a57a5f..a4e0976 100644
--- a/src/rccdb4.c
+++ b/src/rccdb4.c
@@ -15,11 +15,35 @@ db4_context rccDb4CreateContext(const char *dbpath, rcc_db4_flags flags) {
#ifdef HAVE_DB_H
DB_ENV *dbe;
DB *db;
+
+ char stmp[160];
err = db_env_create(&dbe, 0);
if (err) return NULL;
+
+ err = dbe->open(dbe, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 00644);
+ if (err == DB_VERSION_MISMATCH) {
+
+ if (!rccLock()) {
+ err = dbe->open(dbe, dbpath, DB_CREATE|DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN|DB_USE_ENVIRON|DB_PRIVATE|DB_RECOVER, 0);
+ rccUnLock();
+ } else err = -1;
+
+ dbe->close(dbe, 0);
+ if (err) return NULL;
+
+ if (strlen(dbpath)<128) {
+ sprintf(stmp, "%s/log.0000000001", dbpath);
+ remove(stmp);
+ }
+
+ err = db_env_create(&dbe, 0);
+ if (err) return NULL;
+
+ err = dbe->open(dbe, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 00644);
+
+ }
- err = dbe->open(dbe, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 00755);
if (err) {
dbe->close(dbe, 0);
return NULL;