/* * Yet another daemon library especially designed to be used * with libsxmp based daemons. * * (c) Alexander Vdolainen 2016 * * 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 ."; * */ #include #include #include #include #include #include #include #include #include #include #include #include #include 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; }