#include "sm.h"
#include <ctype.h>
#ifdef STORAGE_DB
extern st_ret_t st_db_init(st_driver_t);
#endif
#ifdef STORAGE_FS
extern st_ret_t st_fs_init(st_driver_t);
#endif
#ifdef STORAGE_MYSQL
extern st_ret_t st_mysql_init(st_driver_t);
#endif
#ifdef STORAGE_PGSQL
extern st_ret_t st_pgsql_init(st_driver_t);
#endif
#ifdef STORAGE_ORACLE
extern st_ret_t st_oracle_init(st_driver_t);
#endif
#ifdef STORAGE_SQLITE
extern st_ret_t st_sqlite_init(st_driver_t);
#endif
static char *st_driver_names[] = {
#ifdef STORAGE_DB
"db",
#endif
#ifdef STORAGE_FS
"fs",
#endif
#ifdef STORAGE_MYSQL
"mysql",
#endif
#ifdef STORAGE_PGSQL
"pgsql",
#endif
#ifdef STORAGE_ORACLE
"oracle",
#endif
#ifdef STORAGE_SQLITE
"sqlite",
#endif
NULL
};
static st_driver_init_fn st_driver_inits[] = {
#ifdef STORAGE_DB
st_db_init,
#endif
#ifdef STORAGE_FS
st_fs_init,
#endif
#ifdef STORAGE_MYSQL
st_mysql_init,
#endif
#ifdef STORAGE_PGSQL
st_pgsql_init,
#endif
#ifdef STORAGE_ORACLE
st_oracle_init,
#endif
#ifdef STORAGE_SQLITE
st_sqlite_init,
#endif
NULL
};
storage_t storage_new(sm_t sm) {
storage_t st;
int i, j;
config_elem_t elem;
char *type;
st_ret_t ret;
st = (storage_t) malloc(sizeof(struct storage_st));
memset(st, 0, sizeof(struct storage_st));
st->sm = sm;
st->drivers = xhash_new(101);
st->types = xhash_new(101);
elem = config_get(sm->config, "storage.driver");
if(elem != NULL) {
for(i = 0; i < elem->nvalues; i++) {
type = j_attr((const char **) elem->attrs[i], "type");
for(j = 0; st_driver_names[j] != NULL; j++) {
if(strcmp(elem->values[i], st_driver_names[j]) == 0) {
if(type == NULL)
ret = storage_add_type(st, st_driver_names[j], NULL);
else
ret = storage_add_type(st, st_driver_names[j], type);
if (ret != st_SUCCESS) {
free(st);
return NULL;
}
}
}
}
}
return st;
}
static void _st_driver_reaper(xht drivers, const char *driver, void *val, void *arg) {
st_driver_t drv = (st_driver_t) val;
(drv->free)(drv);
free(drv);
}
void storage_free(storage_t st) {
xhash_walk(st->drivers, _st_driver_reaper, NULL);
xhash_free(st->drivers);
xhash_free(st->types);
free(st);
}
st_ret_t storage_add_type(storage_t st, const char *driver, const char *type) {
st_driver_t drv;
st_driver_init_fn init = NULL;
int i;
st_ret_t ret;
if(type == NULL) {
log_debug(ZONE, "adding arbitrary types to driver '%s'", driver);
if(st->default_drv != NULL) {
log_debug(ZONE, "we already have a default handler, ignoring this one");
return st_FAILED;
}
} else {
log_debug(ZONE, "adding type '%s' to driver '%s'", type, driver);
if(xhash_get(st->types, type) != NULL) {
log_debug(ZONE, "we already have a handler for type '%s', ignoring this one");
return st_FAILED;
}
}
drv = xhash_get(st->drivers, driver);
if(drv == NULL) {
log_debug(ZONE, "driver not loaded, trying to init");
for(i = 0; st_driver_names[i] != NULL; i++) {
if(strcmp(driver, st_driver_names[i]) == 0) {
init = st_driver_inits[i];
break;
}
}
if(init == NULL) {
log_debug(ZONE, "no init function for driver '%s'", driver);
return st_FAILED;
}
drv = (st_driver_t) malloc(sizeof(struct st_driver_st));
memset(drv, 0, sizeof(struct st_driver_st));
drv->st = st;
log_debug(ZONE, "calling driver initializer");
if((init)(drv) == st_FAILED) {
log_write(st->sm->log, LOG_NOTICE, "initialisation of storage driver '%s' failed", driver);
free(drv);
return st_FAILED;
}
drv->name = pstrdup(xhash_pool(st->drivers), driver);
xhash_put(st->drivers, drv->name, (void *) drv);
log_write(st->sm->log, LOG_NOTICE, "initialised storage driver '%s'", driver);
}
if(type == NULL) {
st->default_drv = drv;
return st_SUCCESS;
}
if(type != NULL && (ret = (drv->add_type)(drv, type)) != st_SUCCESS) {
log_debug(ZONE, "driver '%s' can't handle '%s' data", driver, type);
return ret;
}
xhash_put(st->types, pstrdup(xhash_pool(st->types), type), (void *) drv);
return st_SUCCESS;
}
st_ret_t storage_put(storage_t st, const char *type, const char *owner, os_t os) {
st_driver_t drv;
st_ret_t ret;
log_debug(ZONE, "storage_put: type=%s owner=%s os=%X", type, owner, os);
drv = xhash_get(st->types, type);
if(drv == NULL) {
drv = st->default_drv;
if(drv == NULL) {
log_debug(ZONE, "no driver associated with type, and no default driver");
return st_NOTIMPL;
}
ret = storage_add_type(st, drv->name, type);
if(ret != st_SUCCESS)
return ret;
}
return (drv->put)(drv, type, owner, os);
}
st_ret_t storage_get(storage_t st, const char *type, const char *owner, const char *filter, os_t *os) {
st_driver_t drv;
st_ret_t ret;
log_debug(ZONE, "storage_get: type=%s owner=%s filter=%s", type, owner, filter);
drv = xhash_get(st->types, type);
if(drv == NULL) {
drv = st->default_drv;
if(drv == NULL) {
log_debug(ZONE, "no driver associated with type, and no default driver");
return st_NOTIMPL;
}
ret = storage_add_type(st, drv->name, type);
if(ret != st_SUCCESS)
return ret;
}
return (drv->get)(drv, type, owner, filter, os);
}
st_ret_t storage_delete(storage_t st, const char *type, const char *owner, const char *filter) {
st_driver_t drv;
st_ret_t ret;
log_debug(ZONE, "storage_zap: type=%s owner=%s filter=%s", type, owner, filter);
drv = xhash_get(st->types, type);
if(drv == NULL) {
drv = st->default_drv;
if(drv == NULL) {
log_debug(ZONE, "no driver associated with type, and no default driver");
return st_NOTIMPL;
}
ret = storage_add_type(st, drv->name, type);
if(ret != st_SUCCESS)
return ret;
}
return (drv->delete)(drv, type, owner, filter);
}
st_ret_t storage_replace(storage_t st, const char *type, const char *owner, const char *filter, os_t os) {
st_driver_t drv;
st_ret_t ret;
log_debug(ZONE, "storage_replace: type=%s owner=%s filter=%s os=%X", type, owner, filter, os);
drv = xhash_get(st->types, type);
if(drv == NULL) {
drv = st->default_drv;
if(drv == NULL) {
log_debug(ZONE, "no driver associated with type, and no default driver");
return st_NOTIMPL;
}
ret = storage_add_type(st, drv->name, type);
if(ret != st_SUCCESS)
return ret;
}
return (drv->replace)(drv, type, owner, filter, os);
}
static st_filter_t _storage_filter(pool p, const char *f, int len) {
char *c, *key, *val, *sub;
int vallen;
st_filter_t res, sf;
if(f[0] != '(' && f[len] != ')')
return NULL;
if(isalpha(f[1])) {
key = strdup(f+1);
c = strchr(key, '=');
if(c == NULL) {
free(key);
return NULL;
}
*c = '\0'; c++;
val = c;
while (*c != ':' && *c != ')' && *c)
c++;
if (!*c) {
free(key);
return NULL;
}
if (*c == ':') {
*c = '\0';
vallen = atoi(val);
c++;
val = c;
c += vallen;
}
*c = '\0';
log_debug(ZONE, "extracted key %s val %s", key, val);
res = pmalloco(p, sizeof(struct st_filter_st));
res->p = p;
res->type = st_filter_type_PAIR;
res->key = pstrdup(p, key);
res->val = pstrdup(p, val);
free(key);
return res;
}
if(f[1] != '&' && f[1] != '|' && f[2] != '!')
return NULL;
res = pmalloco(p, sizeof(struct st_filter_st));
res->p = p;
switch(f[1]) {
case '&': res->type = st_filter_type_AND; break;
case '|': res->type = st_filter_type_OR; break;
case '!': res->type = st_filter_type_NOT; break;
}
c = (char *) &f[2];
while(*c == '(') {
sub = c;
c = strchr(sub, ')');
c++;
sf = _storage_filter(p, (const char *) sub, c - sub);
sf->next = res->sub;
res->sub = sf;
}
return res;
}
st_filter_t storage_filter(const char *filter) {
pool p;
st_filter_t f;
if(filter == NULL)
return NULL;
p = pool_new();
f = _storage_filter(p, filter, strlen(filter));
if(f == NULL)
pool_free(p);
return f;
}
int _storage_match(st_filter_t f, os_object_t o, os_t os) {
void *val;
os_type_t ot;
st_filter_t scan;
switch(f->type) {
case st_filter_type_PAIR:
if(!os_object_get(os, o, f->key, &val, os_type_UNKNOWN, &ot))
return 0;
switch(ot) {
case os_type_BOOLEAN:
if((atoi(f->val) != 0) == (((int) val) != 0))
return 1;
return 0;
case os_type_INTEGER:
if(atoi(f->val) == (int) val)
return 1;
return 0;
case os_type_STRING:
if(strcmp(f->val, val) == 0)
return 1;
return 0;
case os_type_NAD:
return 1;
case os_type_UNKNOWN:
return 0;
}
return 0;
case st_filter_type_AND:
for(scan = f->sub; scan != NULL; scan = scan->next)
if(!_storage_match(scan, o, os))
return 0;
return 1;
case st_filter_type_OR:
for(scan = f->sub; scan != NULL; scan = scan->next)
if(_storage_match(scan, o, os))
return 1;
return 0;
case st_filter_type_NOT:
if(_storage_match(f->sub, o, os))
return 0;
return 1;
}
return 0;
}
int storage_match(st_filter_t filter, os_object_t o, os_t os) {
if(filter == NULL)
return 1;
return _storage_match(filter, o, os);
}