You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libsxmp/ydaemon/context.c

473 lines
12 KiB
C

/*
* Yet another daemon library especially designed to be used
* with libsxmp based daemons.
*
* (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
*
* libsxmp is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libsxmp is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <ydaemon/ydaemon.h>
static long __cmp_cstr(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
/* config entries */
static scret_t __ymconf_create_pgroup(yd_context_t *cnf, sexp_t *sx, void *priv)
{
char *grp_name;
scret_t rets;
int r = EINVAL;
/* get the group name */
sx->list = sx->list->next;
if(!(sx->list)) { RETURN_SRET_IRES(rets, r); }
else grp_name = sx->list->val;
/* now we will add this */
r = ydc_conf_create_pgroup(cnf->values, (char *)grp_name);
RETURN_SRET_IRES(rets, r);
}
static scret_t __module_add(yd_context_t *ctx, sexp_t *sx, void *priv)
{
char *mod_name, *mod_type;
yd_mod_type_t type;
scret_t rets;
int r = 0;
/* get the name */
sx->list = sx->list->next;
if(!(sx->list)) { r = EINVAL; goto __fail; }
else mod_name = sx->list->val;
sx->list = sx->list->next;
if(!(sx->list)) { r = EINVAL; goto __fail; }
else mod_type = sx->list->val;
if(!strcmp(mod_type, "service")) type = YD_SERVICE_MUX;
else if(!strcmp(mod_type, "sxmp")) type = YD_SXMP_MOD;
else if(!strcmp(mod_type, "datastore")) type = YD_DATASTORE_MOD;
else if(!strcmp(mod_type, "other")) type = YD_OTHER;
else r = EINVAL;
if(!r) r = yd_mod_add(ctx, mod_name, type);
__fail:
RETURN_SRET_IRES(rets, r);
}
static scret_t __object(yd_context_t *ctx, sexp_t *sx, void *priv)
{
char *mod_name, *mod_obj;
yd_mod_t *lmod;
scret_t rets;
int r = 0;
void *fdata;
/* get the name */
sx->list = sx->list->next;
if(!(sx->list)) { r = EINVAL; goto __fail; }
else mod_name = sx->list->val;
sx->list = sx->list->next;
if(!(sx->list)) { r = EINVAL; goto __fail; }
else mod_obj = sx->list->val;
r = yd_mod_get(ctx, mod_name, &lmod);
if(r) {
RETURN_SRET_SERR(rets, r);
} else fdata = yd_mod_getobject(ctx, lmod, NULL, mod_obj);
if(!fdata) {
r = ENOENT;
goto __fail;
}
RETURN_SRET_ORES(rets, fdata);
__fail:
RETURN_SRET_IRES(rets, r);
}
static scret_t __module_load(yd_context_t *ctx, sexp_t *sx, void *priv)
{
register int state = 0;
register int idx;
yd_mod_t *lmod;
sexp_t *isx;
int r = EINVAL;
scret_t rets;
SEXP_ITERATE_LIST(sx, isx, idx) {
if(isx->ty == SEXP_LIST) goto __fail;
else {
if(!state) {
if(strcmp(isx->val, MODULE_LOAD_SX)) goto __fail;
else state++;
} else { /* find module */
if(isx->aty != SEXP_SQUOTE) goto __fail;
r = yd_mod_get(ctx, (const char *)isx->val, &lmod);
if(r) goto __fail;
/* load it */
r = yd_mod_load(ctx, lmod);
}
}
}
__fail:
RETURN_SRET_IRES(rets, r);
}
static scret_t __module_run(yd_context_t *ctx, sexp_t *sx, void *priv)
{
register int state = 0;
register int idx;
yd_mod_t *lmod;
sexp_t *isx;
int r = EINVAL;
scret_t rets;
SEXP_ITERATE_LIST(sx, isx, idx) {
if(isx->ty == SEXP_LIST) goto __fail;
else {
if(!state) {
if(strcmp(isx->val, MODULE_RUN_SX)) goto __fail;
else state++;
} else { /* find module */
if(isx->aty != SEXP_SQUOTE) goto __fail;
r = yd_mod_get(ctx, (const char *)isx->val, &lmod);
if(r) goto __fail;
/* load it */
r = yd_mod_run(ctx, lmod);
}
}
}
__fail:
RETURN_SRET_IRES(rets, r);
}
static scret_t __module_set(yd_context_t *ctx, sexp_t *sx, void *priv)
{
register int state = 0; /* states - 0 begin, 1 - rpc function checked, 2 - module found */
register int pst = 0; /* 0 - nothing, 1 - name set */
char *pname, *pval, *pss;
yd_mod_t *lmod;
int r = 0, idx, pidx;
sexp_t *isx, *pisx;
ydc_conf_val_t *rval;
scret_t rets;
r = EINVAL; /* invalid syntax */
SEXP_ITERATE_LIST(sx, isx, idx) {
if(isx->ty == SEXP_LIST) {
r = EINVAL;
if(state < 2) goto __err_fail;
pst = 0;
SEXP_ITERATE_LIST(isx, pisx, pidx) {
if(pisx->ty != SEXP_VALUE) { /* values are not acceptable */
goto __err_fail;
}
if(!pst && *(pisx->val) != ':') goto __err_fail; /* syntax error */
if(!pst) {
pname = pisx->val + sizeof(char); pst++;
} else {
if(pisx->aty == SEXP_DQUOTE || pisx->aty == SEXP_SQUOTE) pval = pisx->val;
else if((pisx->aty == SEXP_BASIC) && (pss = strchr((const char *)pisx->val, '/'))) {
/* it's a variable */
r = ydc_conf_get_val(ctx->values, (const char *)pisx->val, &rval);
if(r) goto __err_fail;
if(rval->type != STRING) goto __err_fail;
else pval = (char *)rval->value;
} else goto __err_fail;
/* set the right part of the module */
if(!strcmp(pname, MODULE_PREFIX)) yd_mod_set_prefix(lmod, pval);
else if(!strcmp(pname, MODULE_PATHNAME)) yd_mod_set_pathname(lmod, pval);
else if(!strcmp(pname, MODULE_CNFPATH)) yd_mod_set_cfgpath(lmod, pval);
else goto __err_fail;
}
}
} else if(isx->ty == SEXP_VALUE) { /* got the value */
switch(state) {
case 0:
if(strcmp((const char *)isx->val, MODULE_SET_SX)) goto __err_fail;
else state++;
break;
case 1:
if(isx->aty != SEXP_SQUOTE) goto __err_fail;
else {
r = yd_mod_get(ctx, (const char *)isx->val, &lmod);
if(r) goto __err_fail;
else state++;
}
break;
default:
goto __err_fail;
}
}
}
r = 0;
__err_fail:
RETURN_SRET_IRES(rets, r);
}
static scret_t __ymconf_set_cv(yd_context_t *cnf, sexp_t *sx, void *priv)
{
char *value_expression, *value;
char *buf = priv;
scret_t rets;
int r = EINVAL;
int cstr = 0;
/* skip keyword */
sx->list = sx->list->next;
/* check out this */
if(sx->ty != SEXP_LIST) { RETURN_SRET_IRES(rets, r); }
else sx = sx->list;
value_expression = sx->list->val;
sx->list = sx->list->next;
//if(sx->ty == SEXP_LIST) return -EINVAL;
value = sx->list->val;
/* check for the forcing of cstring */
if(sx->list->aty == SEXP_DQUOTE) cstr = 1;
snprintf(buf, sizeof(char)*4096, "%s:%s", value_expression, value);
r = ydc_conf_add_val_p(cnf->values, (const char *)buf, cstr);
RETURN_SRET_IRES(rets, r);
}
static scret_t __ymconf_uselogfile(yd_context_t *cnf, sexp_t *sx, void *priv)
{
char *logfile;
FILE *ls;
ydc_conf_val_t *rval;
scret_t rets;
int r = EINVAL;
r = ydc_conf_get_val(cnf->values, "daemon/logfile", &rval);
if(r) goto __fini;
if(rval->type != STRING) goto __fini;
else logfile = (char *)rval->value;
ls = fopen(logfile, "a+");
if(!ls) r = errno;
else {
cnf->logcontext->logstream = ls;
setbuf(ls, NULL);
r = 0;
}
if(cnf->daemon && !r) {
fclose(stdout);
fclose(stderr);
stdout = fopen(logfile, "a+");
stderr = fopen(logfile, "a+");
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
__fini:
RETURN_SRET_IRES(rets, r);
}
int yd_init_ctx(yd_context_t *ctx)
{
int r = 0;
usrtc_t *services = malloc(sizeof(usrtc_t));
usrtc_t *modules = malloc(sizeof(usrtc_t));
scm_function_tree_t *ft = NULL;
ydc_conf_t *c = malloc(sizeof(ydc_conf_t));
yd_log_t *zdl = malloc(sizeof(yd_log_t));
char *pbuf = malloc(sizeof(char)*4096);
if(!ctx) return EINVAL;
else memset(ctx, 0, sizeof(yd_context_t));
if((r = pthread_rwlock_init(&ctx->modlock, NULL))) goto __fini;
if((r = pthread_mutex_init(&ctx->looplock, NULL))) {
pthread_rwlock_destroy(&ctx->modlock);
goto __fini;
}
if(!zdl) goto __fail;
/* init trees */
if(!services || !modules) goto __fail;
else {
usrtc_init(services, USRTC_SPLAY, MAX_SERVICES, __cmp_cstr);
usrtc_init(modules, USRTC_SPLAY, MAX_MODULES, __cmp_cstr);
ctx->services = services;
ctx->modules = modules;
ctx->daemon = 0;
ctx->logcontext = zdl;
zdl->logstream = stdout;
zdl->verbose_level = YL_INFO;
zdl->se = 1;
}
r = scm_func_tree_init(&ft, ctx);
if(r) goto __fail;
else { /* fill up with default functions */
if(!pbuf) goto __fail;
if(!c) goto __fail; /* let's init config */
r = ydc_conf_init(c);
if(r) goto __fail;
else {
ctx->values = c;
ctx->func = ft;
}
/* defaults ones */
scm_func_tree_insert(ctx, VAR_CREATE_GROUP,
__ymconf_create_pgroup, NULL);
scm_func_tree_insert(ctx, VAR_SET,
__ymconf_set_cv, pbuf);
scm_func_tree_insert(ctx, MODULE_ADD_SX,
__module_add, NULL);
scm_func_tree_insert(ctx, MODULE_SET_SX,
__module_set, NULL);
scm_func_tree_insert(ctx, MODULE_LOAD_SX,
__module_load, NULL);
scm_func_tree_insert(ctx, MODULE_RUN_SX,
__module_run, NULL);
scm_func_tree_insert(ctx, SCMOBJECT,
__object, NULL);
scm_func_tree_insert(ctx, YDOPENLOGS,
__ymconf_uselogfile, NULL);
}
if(!r) pthread_mutex_lock(&ctx->looplock);
__fini:
return r;
__fail:
pthread_rwlock_destroy(&ctx->modlock);
pthread_mutex_destroy(&ctx->looplock);
if(c) free(c);
if(zdl) free(zdl);
if(pbuf) free(pbuf);
if(services) free(services);
if(modules) free(modules);
if(ft) scm_func_tree_free(ft);
return r;
}
scret_t yd_eval_sexp(yd_context_t *ctx, sexp_t *sx)
{
scret_t rets;
int r;
char *keyw;
char ibuf[64];
if(sx->ty == SEXP_LIST) keyw = sx->list->val;
else {
r = EINVAL;
RETURN_SRET_SERR(rets, r);
}
rets = scm_func_tree_call(ctx, ctx, sx, keyw);
if(rets.type == SCINT && rets.ec != 0) {
r = rets.ec;
print_sexp(ibuf, 63, sx);
if(strlen(ibuf) >= 63) ydlog(ctx, YL_WARN, "%s... return %d (%s)\n", ibuf, r, strerror(r));
else ydlog(ctx, YL_WARN, "%s return %d (%s)\n", ibuf, r, strerror(r));
}
return rets;
}
int yd_eval_ctx(yd_context_t *ctx, const char *confpath)
{
sexp_t *sx;
sexp_iowrap_t *iow;
int fd, r = 0;
char *keyw;
scret_t ret;
char ibuf[64];
/* try to open it */
if((fd = open(confpath, O_RDONLY)) < 0) {
r = errno;
return r;
}
if(!(iow = init_iowrap(fd))) {
r = errno;
close(fd);
return r;
}
/* now load the configuration scenario */
while((sx = read_one_sexp(iow)) != NULL) {
if(sx->ty == SEXP_LIST) keyw = sx->list->val;
else keyw = sx->val;
ret = scm_func_tree_call(ctx, ctx, sx, keyw);
/* not found */
if(ret.serr) {
close(fd);
ydlog(ctx, YL_ERROR, "%s: unknown keyword ``%s''\n", __FUNCTION__, keyw);
return r;
}
/* more information */
if(ret.type == SCINT && ret.ec != 0) {
r = ret.ec;
print_sexp(ibuf, 63, sx);
if(strlen(ibuf) >= 63) ydlog(ctx, YL_WARN, "%s... return %d (%s)\n", ibuf, r, strerror(r));
else ydlog(ctx, YL_WARN, "%s return %d (%s)\n", ibuf, r, strerror(r));
}
}
r = 0;
close(fd);
return r;
}