diff options
-rw-r--r-- | src/internal.h | 7 | ||||
-rw-r--r-- | src/librcc.c | 90 | ||||
-rw-r--r-- | src/rccdb4.c | 26 |
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; |