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.
473 lines
12 KiB
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;
|
|
}
|
|
|