[core] Libydaemon added;

v0.5.xx
Alexander Vdolainen 9 years ago
parent 3ef4cece81
commit 77d0ee4a0b

@ -6,7 +6,7 @@ else
EXAMPLES =
endif
SUBDIRS = include tdata sexpr sxmp man $(EXAMPLES)
SUBDIRS = include tdata sexpr sxmp ydaemon man $(EXAMPLES)
libsxmpdocdir = ${prefix}/doc/libsxmp
libsxmpdoc_DATA = \

@ -3,6 +3,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(libsxmp, m4_esyscmd([tr -d '\n' < VERSION.sxmp]))
AC_SUBST([LIBTDATA_VERSION], m4_esyscmd([tr -d '\n' < tdata/VERSION]))
AC_SUBST([LIBSEXPR_VERSION], m4_esyscmd([tr -d '\n' < sexpr/VERSION]))
AC_SUBST([LIBYDAEMON_VERSION], m4_esyscmd([tr -d '\n' < ydaemon/VERSION]))
AC_CONFIG_HEADERS([config.h])
@ -107,6 +108,8 @@ sexpr/Makefile
sexpr/libsexpr.pc
tdata/Makefile
tdata/libtdata.pc
ydaemon/Makefile
ydaemon/libydaemon.pc
include/Makefile
man/Makefile
examples/Makefile])

@ -3,4 +3,5 @@ nobase_include_HEADERS = sxmp/sxmp.h sxmp/errno.h sxmp/limits.h sxmp/version.h \
sexpr/cstring.h sexpr/faststack.h sexpr/sexp_errors.h sexpr/sexp.h \
sexpr/sexp_memory.h sexpr/sexp_ops.h sexpr/sexp_vis.h \
tdata/bitwise.h tdata/idx_allocator.h tdata/macro.h tdata/tree.h \
tdata/usrtc.h tdata/list.h tdata/ctrie.h
tdata/usrtc.h tdata/list.h tdata/ctrie.h \
ydaemon/ydaemon.h

@ -0,0 +1,367 @@
/*
* 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/>.";
*
*/
#ifndef __YDAEMON_YDAEMON_H__
#define __YDAEMON_YDAEMON_H__
#include <stdint.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>
#include <tdata/usrtc.h>
#include <tdata/idx_allocator.h>
#include <sexpr/sexp.h>
/* some syntax */
/**
* --values (variables)
*/
#define VAR_CREATE_GROUP "create-var-group"
#define VAR_SET "var-set"
/**
* --modules
* (%MODULE_ADD_SX '<name> <type>) -- add a module to the list of available modules
* (%MODULE_SET_SX '<name> (:%MODULE_PREFIX|%MODULE_PATHNAME|%MODULE_CNFPATH *<value>))
* *value might be the following:
* a. in case of double or single quote - will be taken as is
* b. without quotes will be interpreted as variable (must be defined before this expression)
*/
#define MODULE_ADD_SX "module-add"
#define MODULE_SET_SX "module-set" /** { */
/* module config values for _SET_SX */
#define MODULE_PREFIX "prefix"
#define MODULE_PATHNAME "pathname"
#define MODULE_CNFPATH "config-path"
/** } */
#define MODULE_LOAD_SX "module-load"
#define MODULE_RUN_SX "module-run"
/* internal functions */
#define SCMOBJECT "object"
/* functions for the logs */
#define YDOPENLOGS "yd-open-logfile"
/* limits */
#define MAX_SCM_FUNCTIONS 16384
#define MAX_SERVICES 8192
#define MAX_MODULES 4096
enum {
SCINT = 0,
SCCSTR,
SCOBJECTPTR,
SCUNDEFINED,
};
typedef struct __scm_ret {
uint8_t serr;
uint8_t type;
uint32_t len;
union {
void *ret;
struct {
int32_t ec;
uint32_t ru32;
};
};
} scret_t;
#define RETURN_SRET_SERR(r, e) (r).serr = e; return r
#define RETURN_SRET_IRES(r, e) (r).serr = 0; (r).type = SCINT; (r).ec = e; \
return r
#define RETURN_SRET_ORES(r, e) (r).serr = 0; (r).type = SCOBJECTPTR; (r).ret = (e); \
return r
struct __ydaemon_context_type;
/**
* @brief Type used to describe scm function
*
* It contains name i.e. keyword, pointer to the
* function itself and optional pointer to the
* implementation specific data. It packs to usrtc
* search structure.
*/
typedef struct __scm_func {
char *name;
scret_t (*call)(struct __ydaemon_context_type *, sexp_t *, void *);
void *priv;
usrtc_node_t node;
} scm_function_t;
/**
* @brief Type used to describe a tree of scm functions
*
* It contains a search structure with packed
* scm_function_t set and also contain special
* private pointer that might be optionally used
* by implementation.
*/
typedef struct __scm_func_tree {
usrtc_t functions;
void *priv;
} scm_function_tree_t;
/**
* @brief Values types
*
* Describes the type of value
* @see zdc_conf_val_t
*/
typedef enum {
STRING = 0,
INT,
UINT,
LONG,
ULONG,
BLOB,
SEXPR,
CUSTOM,
} ydc_val_type_t;
/**
* @brief configuration event
*
* Type used to describe events occured with values
*/
typedef enum {
YC_EVENT_ADD,
YC_EVENT_MODIFY,
YC_EVENT_DESTROY,
YC_EVENT_ATTACH,
} ydc_event_t;
/**
* @brief Type used to fit all required parameters
*
* It contain mode, system settings and a lot of other
* config defined parameters.
*/
typedef struct __ym_conf {
/* parameters groups */
usrtc_t p_groups; /**< Parameters groups */
/* functions tree */
void *init_funcs;
/* locking */
pthread_rwlock_t grp_lock; /**< Locking for groups */
pthread_mutex_t conf_lock; /**< Locking for state change, function ops, system io */
} ydc_conf_t;
/**
* @brief Type of the parameters group
*
* Store values.
*/
typedef struct __ym_pgroup {
usrtc_t values;
usrtc_node_t unode;
char *name;
pthread_rwlock_t val_lock;
} ydc_pgroup_t;
/**
* @brief Type used to describe value
*
* Used to store value.
*/
typedef struct __ym_conf_value {
usrtc_node_t unode;
ydc_val_type_t type;
int len;
char *name;
void *value;
void (*on_eventv)(struct __ym_conf_value *,
struct __ym_conf_value *,
ydc_conf_t *, ydc_event_t);
void *priv;
} ydc_conf_val_t;
typedef struct __ydaemon_log_type {
FILE *logstream;
int verbose_level;
int se;
} yd_log_t;
typedef struct __ydaemon_context_type {
usrtc_t *services;
usrtc_t *modules;
scm_function_tree_t *func; /** < functions for configuration and processing */
ydc_conf_t *values; /** < values stored by the groups */
yd_log_t *logcontext;
int flags;
pthread_rwlock_t modlock;
pthread_mutex_t looplock;
int daemon;
} yd_context_t;
#define yd_mod_ctx_wrlock(n) pthread_rwlock_wrlock(&(n)->modlock)
#define yd_mod_ctx_rdlock(n) pthread_rwlock_rdlock(&(n)->modlock)
#define yd_mod_ctx_unlock(n) pthread_rwlock_unlock(&(n)->modlock)
typedef enum {
YD_SERVICE_MUX = 0,
YD_SXMP_MOD,
YD_DATASTORE_MOD,
YD_OTHER,
} yd_mod_type_t;
typedef struct __ydaemon_module {
char *name;
char *pathname;
char *cnfname;
char *prefix;
void *dlhandle;
void *(*getobject)(void *, const char *);
int (*shutdown)(yd_context_t *);
int (*preinit)(yd_context_t *);
int (*init)(yd_context_t *);
int (*run)(yd_context_t *);
yd_mod_type_t type;
int flags;
usrtc_node_t node;
} yd_mod_t;
/* functions defines for modules */
#define def_shutdown(PREFIX) int PREFIX ## _shutdown(yd_context_t *ctx)
#define def_preinit(PREFIX) int PREFIX ## _preinit(yd_context_t *ctx)
#define def_init(PREFIX) int PREFIX ## _init(yd_context_t *ctx)
#define def_run(PREFIX) int PREFIX ## _run(yd_context_t *ctx)
#define def_getobject(PREFIX) void* PREFIX ## _getobject(void *priv, const char *oname)
/* function arguments macros */
#define def_ctx ctx
#define defpriv priv
#define defoname oname
#define yd_mod_set_prefix(n, p) (n)->prefix = (p)
#define yd_mod_set_pathname(n, p) (n)->pathname = (p)
#define yd_mod_set_cfgpath(n, p) (n)->cnfname = (p)
#define yd_mod_preinit(n) \
{ memset((n), 0, sizeof(yd_mod_t)); usrtc_node_init((n)->node, (n)); }
int yd_mod_init(yd_context_t *, yd_mod_t *);
int yd_mod_get(yd_context_t *, const char *, yd_mod_t **);
int yd_mod_load(yd_context_t *, yd_mod_t *);
int yd_mod_run(yd_context_t *, yd_mod_t *);
int yd_mod_shutdown(yd_context_t *, yd_mod_t *);
void *yd_mod_getobject(yd_context_t *, yd_mod_t *, void *, const char *);
void *yd_mod_getsym(yd_context_t *, yd_mod_t *, const char *);
typedef struct __ydaemon_service {
char *name; /* name of the service */
void *ops; /* the subject to think about ... */
void *connection; /* as backends private data */
void *conf; /* special configuration */
usrtc_node_t node;
} yd_service_t;
#define yd_ctx_values(c) (c)->values
int yd_init_ctx(yd_context_t *);
int yd_eval_ctx(yd_context_t *, const char *);
scret_t yd_eval_sexp(yd_context_t *, sexp_t *);
int yd_mainloop(yd_context_t *);
void yd_mainloop_exit(yd_context_t *);
int yd_set_daemonize(yd_context_t *, int);
/* modules related functions */
int yd_mod_add(yd_context_t *, const char *, yd_mod_type_t);
/* internal functions API */
void scm_func_tree_free(scm_function_tree_t *pt);
int scm_func_tree_init(scm_function_tree_t **pt, void *priv);
int scm_func_tree_insert(yd_context_t *zdx, const char *name,
scret_t (*call)(yd_context_t *, sexp_t *, void *),
void *priv);
int scm_func_tree_insert_t(yd_context_t *zdx, scm_function_t *f);
scret_t scm_func_tree_call(yd_context_t *zdx, void *cnf, sexp_t *sx,
char *name);
int scm_func_tree_delete(yd_context_t *zdx, char *name);
/* variables related functions */
int ydc_conf_init(ydc_conf_t *);
int ydc_conf_create_pgroup(ydc_conf_t *, char *);
int ydc_conf_get_val(ydc_conf_t *, const char *, ydc_conf_val_t **);
int ydc_conf_add_val_p(ydc_conf_t *, const char *, int);
/* some internal stuff */
#define UNIT_TESTS 1
#ifdef UNIT_TESTS
#define blub printf("%d at %s\n", __LINE__, __FUNCTION__)
#endif
/* logging */
enum {
YL_DEBUG = 0,
YL_INFO,
YL_WARN,
YL_ERROR,
};
void ydlog(yd_context_t *ctx, int olvl, const char *fmt, ...);
void yddaemon(yd_context_t *ctx);
/* object storage */
#define MAX_OBJECTS 65535
typedef struct __ostore_type {
usrtc_t objects;
pthread_rwlock_t rwlock;
} obj_store_t;
typedef struct __ostore_node_type {
char *name;
void *objdata;
usrtc_node_t node;
} obj_store_node_t;
int obj_store_init(obj_store_t *);
int obj_store_set(obj_store_t *, const char *, void *);
int obj_store_get(obj_store_t *, const char *, void **);
int obj_store_remove(obj_store_t *, const char *);
#endif /* __YDAEMON_YDAEMON_H__ */

@ -0,0 +1,33 @@
## Process this file with automake to produce Makefile.in
AM_CPPFLAGS = \
-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
-DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \
$(LIBYDAEMON_CFLAGS) -I../include
AM_CFLAGS =\
-Wall\
-g
lib_LTLIBRARIES = libydaemon.la
libydaemon_la_SOURCES = \
values.c functions.c log.c module.c \
daemon.c context.c
libydaemon_la_LDFLAGS = -Wl,--export-dynamic
# where to find other libs ...
LIBTDATA_LIBSLA = ../tdata/.libs/libtdata.la
LIBSEXPR_LIBSLA = ../sexpr/.libs/libsexpr.la
libydaemon_la_LIBADD = -lpthread -lcrypto -ldl $(LIBTDATA_LIBSLA) $(LIBSEXPR_LIBSLA)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libydaemon.pc
EXTRA_DIST = \
libydaemon.pc.in

@ -0,0 +1,3 @@
0.0.1

@ -0,0 +1,472 @@
/*
* 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;
}

@ -0,0 +1,135 @@
/*
* 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 <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <ydaemon/ydaemon.h>
int yd_mainloop(yd_context_t *ctx)
{
usrtc_node_t *node = NULL;
yd_mod_t *mod;
/* we will locked here */
pthread_mutex_lock(&ctx->looplock);
/* if we're here ... somebody decide to end the loop */
yd_mod_ctx_wrlock(ctx);
for(node = usrtc_last(ctx->modules); ;node = usrtc_prev(ctx->modules, node)) {
mod = (yd_mod_t *)usrtc_node_getdata(node);
mod->shutdown(ctx);
/* for() */
if(node == usrtc_first(ctx->modules)) break;
}
yd_mod_ctx_unlock(ctx);
return 0;
}
void yd_mainloop_exit(yd_context_t *ctx)
{
pthread_mutex_unlock(&ctx->looplock);
return;
}
/*
* daemon workout
*/
void yddaemon(yd_context_t *ctx)
{
pid_t pid;
ydc_conf_val_t *rval;
/* fork the first time to detach the controlling terminal
* and avoid to be a group leader.
*/
pid = fork();
if(pid < 0) exit(EXIT_FAILURE); /* something goes wrong ... */
if(pid > 0) exit(EXIT_SUCCESS); /* parent can take a rest */
/* try to become a session leader */
if(setsid() < 0) exit(EXIT_FAILURE); /* something goes wrong ... */
/* ignore fucking signals */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
/* fork the second time, to avoid be a session leader - the goal is
* regain a terminal control never.
*/
pid = fork();
if(pid < 0) exit(EXIT_FAILURE); /* something goes wrong ... */
if(pid > 0) exit(EXIT_SUCCESS); /* parent can take a rest */
/* reset mask */
umask(0);
/* change working directory to root */
// chdir("/");
#if 0
/* test and change if set */
if(!ydc_conf_get_val(ctx->zvalues, "daemon/workingdir", &rval)) {
if(rval->type == STRING) chdir((const char *)rval->value);
}
#endif
/* let's a deal */
fclose(stdin);
fclose(stderr);
fclose(stdout);
/* if oe - mean we allowing to write a lof file thru standard prints ... */
stdin = fopen("/dev/null", "r");
#if 0
if(ctx->logcontext->se && !ydc_conf_get_val(ctx->zvalues, "daemon/logfile", &rval)) {
if(rval->type == STRING) {
stdout = fopen((char *)rval->value, "a");
stderr = fopen((char *)rval->value, "a");
}
} else {
#endif
stdout = fopen("/dev/null", "a");
stderr = fopen("/dev/null", "a");
#if 0
}
#endif
ctx->daemon = 1;
return;
}

@ -0,0 +1,184 @@
/*
* 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 <sys/stat.h>
#include <fcntl.h>
#include <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <ydaemon/ydaemon.h>
static long __cmp_cstrs(const void *a, const void *b)
{
return (long)(strcmp((const char *)a, (const char *)b));
}
static void __scm_func_tree_init(scm_function_tree_t *pt, void *priv)
{
usrtc_t *foost = (usrtc_t *)&(pt->functions);
usrtc_init(foost, USRTC_SPLAY, MAX_SCM_FUNCTIONS, __cmp_cstrs);
return;
}
static scm_function_tree_t *__scm_func_tree_alloc(void *priv)
{
scm_function_tree_t *t = malloc(sizeof(scm_function_tree_t));
if(!t) goto __fail;
else __scm_func_tree_init(t, priv);
__fail:
return t;
}
void scm_func_tree_free(scm_function_tree_t *pt)
{
usrtc_t *ftree = &(pt->functions);
usrtc_node_t *node = NULL;
scm_function_t *sf;
if(usrtc_count(ftree)) {
for(node = usrtc_first(ftree); node != NULL; node = usrtc_first(ftree)) {
sf = (scm_function_t *)usrtc_node_getdata(node);
/* remove from the tree first */
usrtc_delete(ftree, node);
/* free all */
free(sf->name);
free(sf);
}
}
free(pt);
return;
}
/* external API */
int scm_func_tree_init(scm_function_tree_t **pt, void *priv)
{
scm_function_tree_t *nt = __scm_func_tree_alloc(priv);
if(!nt) return ENOENT;
else *pt = nt;
return 0;
}
int scm_func_tree_insert(yd_context_t *zdx, const char *name,
scret_t (*call)(yd_context_t *, sexp_t *, void *),
void *priv)
{
scm_function_tree_t *pt = zdx->func;
usrtc_t *ftree = &(pt->functions);
scm_function_t *n_func = malloc(sizeof(scm_function_t));
usrtc_node_t *node = NULL;
int e = 0;
/* just check existence */
if(!n_func) return ENOMEM;
if(usrtc_count(ftree) >= MAX_SCM_FUNCTIONS) {
e = ENOMEM;
goto __end;
}
if((node = usrtc_lookup(ftree, (const void *)name))) {
e = EEXIST;
goto __end;
}
/* init structure */
if(!(n_func->name = strdup(name))) {
free(n_func);
return ENOMEM;
}
n_func->call = call;
n_func->priv = priv;
node = &(n_func->node);
usrtc_node_init(node, n_func);
/* insert to the tree */
usrtc_insert(ftree, node, (const void *)name);
__end:
if(e) free(n_func);
return e;
}
int scm_func_tree_insert_t(yd_context_t *zdx, scm_function_t *f)
{
scm_function_tree_t *pt = zdx->func;
usrtc_t *ftree = &(pt->functions);
usrtc_node_t *node = usrtc_lookup(ftree, (const void *)f->name);
if(node) return EEXIST;
else node = &(f->node);
if(usrtc_count(ftree) >= MAX_SCM_FUNCTIONS) return ENOMEM;
usrtc_node_init(node, f);
usrtc_insert(ftree, node, (const void *)f->name);
return 0;
}
scret_t scm_func_tree_call(yd_context_t *zdx, void *cnf, sexp_t *sx,
char *name)
{
scm_function_tree_t *pt = zdx->func;
usrtc_t *ftree = &(pt->functions);
usrtc_node_t *node = usrtc_lookup(ftree, (const void *)name);
scm_function_t *fn;
if(!node) {
scret_t rets;
RETURN_SRET_SERR(rets, ENOENT);
} else fn = (scm_function_t *)usrtc_node_getdata(node);
cnf = zdx;
return fn->call(cnf, sx, fn->priv);
}
int scm_func_tree_delete(yd_context_t *zdx, char *name)
{
scm_function_tree_t *pt = zdx->func;
usrtc_t *ftree = &(pt->functions);
usrtc_node_t *node = usrtc_lookup(ftree, (const void *)name);
scm_function_t *fn;
if(!node) return ENOENT;
else fn = (scm_function_t *)usrtc_node_getdata(node);
/* remove from tree first */
usrtc_delete(ftree, node);
/* free */
free(fn->name);
free(fn);
return 0;
}

@ -0,0 +1,13 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
datarootdir=@datarootdir@
datadir=@datadir@
includedir=@includedir@
Name: libydaemon
Description: yet another library for daemons
Version: @LIBYDAEMON_VERSION@
Requires:
Libs: -L${libdir} -lydaemon
Cflags: -I${includedir}

@ -0,0 +1,71 @@
/*
* 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 <stdarg.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include <dlfcn.h>
#include <time.h>
#include <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <ydaemon/ydaemon.h>
void ydlog(yd_context_t *ctx, int olvl, const char *fmt, ...)
{
yd_log_t *log = ctx->logcontext;
FILE *logstr = NULL;
char tbuf[32];
struct tm tmb;
time_t ctime;
va_list args;
if(!log) return;
if(!(logstr = log->logstream)) return;
if(olvl >= log->verbose_level) { /* we can output this */
/* take a time and output this */
time(&ctime);
localtime_r(&ctime, &tmb);
asctime_r(&tmb, tbuf);
/* remove trailing \n */
tbuf[strlen(tbuf) - 1] = '\0';
fprintf(logstr, "[%s] ", tbuf);
switch(olvl) { /* out prefix */
case YL_DEBUG: fprintf(logstr, "[DEBUG] "); break;
case YL_INFO: fprintf(logstr, "[INFO] "); break;
case YL_WARN: fprintf(logstr, "[WARNING] "); break;
case YL_ERROR: fprintf(logstr, "[ERROR] "); break;
default: return;
}
va_start(args, fmt);
vfprintf(logstr, fmt, args);
va_end(args);
}
return;
}

@ -0,0 +1,241 @@
/*
* 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 <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <ydaemon/ydaemon.h>
int yd_mod_add(yd_context_t *ctx, const char *name, yd_mod_type_t type)
{
yd_mod_t *mod = malloc(sizeof(yd_mod_t));
usrtc_node_t *node = NULL;
int r = 0;
if(!mod) return ENOMEM;
else if(!(mod->name = strdup(name))) {
free(mod);
return ENOMEM;
}
mod->type = type;
usrtc_node_init(&mod->node, mod);
yd_mod_ctx_wrlock(ctx);
node = usrtc_lookup(ctx->modules, mod->name);
if(node) r = EEXIST;
else usrtc_insert(ctx->modules, &mod->node, mod->name);
yd_mod_ctx_unlock(ctx);
return r;
}
int yd_mod_load(yd_context_t *ctx, yd_mod_t *mod)
{
char buf[256];
int r = 0;
/* let's try to find it and load */
if(!mod->pathname || !mod->name) return EINVAL;
if(!(mod->dlhandle = dlopen(mod->pathname, RTLD_LAZY|RTLD_GLOBAL)))
return ENOENT;
/* ok now we can resolve all symbols */
snprintf(buf, 256, "%s_preinit", mod->prefix);
mod->preinit = dlsym(mod->dlhandle, buf);
if(!mod->preinit) {
__einval:
dlclose(mod->dlhandle);
return EINVAL;
}
snprintf(buf, 256, "%s_init", mod->prefix);
if(!(mod->init = dlsym(mod->dlhandle, buf))) goto __einval;
snprintf(buf, 256, "%s_run", mod->prefix);
if(!(mod->run = dlsym(mod->dlhandle, buf))) goto __einval;
snprintf(buf, 256, "%s_shutdown", mod->prefix);
if(!(mod->shutdown = dlsym(mod->dlhandle, buf))) goto __einval;
snprintf(buf, 256, "%s_getobject", mod->prefix);
if(!(mod->getobject = dlsym(mod->dlhandle, buf))) goto __einval;
if((r = mod->preinit(ctx))) {
blub;
__fail:
dlclose(mod->dlhandle);
return r;
}
if(mod->cnfname) {
blub;
r = yd_eval_ctx(ctx, (const char *)mod->cnfname);
if(r) goto __fail;
}
if((r = mod->init(ctx))) goto __fail;
if(mod->type == YD_SERVICE_MUX) {
if((r = mod->run(ctx))) goto __fail;
}
return 0;
}
int yd_mod_get(yd_context_t *ctx, const char *name, yd_mod_t **rmod)
{
int r = 0;
usrtc_node_t *node;
yd_mod_ctx_rdlock(ctx);
node = usrtc_lookup(ctx->modules, name);
if(!node) r = ENOENT;
else *rmod = (yd_mod_t *)usrtc_node_getdata(node);
yd_mod_ctx_unlock(ctx);
return r;
}
int yd_mod_run(yd_context_t *ctx, yd_mod_t *mod)
{
return mod->run(ctx);
}
int yd_mod_shutdown(yd_context_t *ctx, yd_mod_t *mod)
{
return mod->shutdown(ctx);
}
void *yd_mod_getobject(yd_context_t *ctx, yd_mod_t *mod,
void *priv, const char *name)
{
return mod->getobject(priv, name);
}
void *yd_mod_getsym(yd_context_t *ctx, yd_mod_t *mod, const char *name)
{
return dlsym(mod->dlhandle, name);
}
/* object store */
static long __cmp_cstr(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
#define __obs_wrlock(s) pthread_rwlock_wrlock(&((s)->rwlock))
#define __obs_rdlock(s) pthread_rwlock_rdlock(&((s)->rwlock))
#define __obs_unlock(s) pthread_rwlock_unlock(&((s)->rwlock))
#define __obs_tree(s) &((s)->objects)
int obj_store_init(obj_store_t *st)
{
usrtc_t *tree = &st->objects;
if(pthread_rwlock_init(&(st->rwlock), NULL)) return ENOMEM;
else usrtc_init(tree, USRTC_SPLAY, MAX_OBJECTS, __cmp_cstr);
return 0;
}
int obj_store_set(obj_store_t *st, const char *nm, void *od)
{
usrtc_node_t *node = NULL;
obj_store_node_t *onode = NULL;
__obs_rdlock(st);
node = usrtc_lookup(__obs_tree(st), nm);
__obs_unlock(st);
if(!node) {
if(!(onode = malloc(sizeof(obj_store_node_t)))) return ENOMEM;
else memset(onode, 0, sizeof(obj_store_node_t));
if(!(onode->name = strdup(nm))) {
free(onode);
return ENOMEM;
}
onode->objdata = od;
node = &(onode->node);
usrtc_node_init(node, onode);
__obs_wrlock(st);
usrtc_insert(__obs_tree(st), node, (const void *)onode->name);
__obs_unlock(st);
} else {
onode = (obj_store_node_t *)usrtc_node_getdata(node);
__obs_wrlock(st);
onode->objdata = od;
__obs_unlock(st);
}
return 0;
}
int obj_store_get(obj_store_t *st, const char *nm, void **rod)
{
usrtc_node_t *node = NULL;
obj_store_node_t *onode = NULL;
__obs_rdlock(st);
node = usrtc_lookup(__obs_tree(st), nm);
__obs_unlock(st);
if(!node) return ENOENT;
else onode = (obj_store_node_t *)usrtc_node_getdata(node);
*rod = onode->objdata;
return 0;
}
int obj_store_remove(obj_store_t *st, const char *nm)
{
usrtc_node_t *node = NULL;
obj_store_node_t *onode = NULL;
__obs_rdlock(st);
node = usrtc_lookup(__obs_tree(st), nm);
__obs_unlock(st);
if(!node) return ENOENT;
else {
__obs_wrlock(st);
usrtc_delete(__obs_tree(st), node);
__obs_unlock(st);
onode = (obj_store_node_t *)usrtc_node_getdata(node);
if(onode->name) free(onode->name);
free(onode);
}
return 0;
}

@ -0,0 +1,636 @@
/*
* 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 <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <ydaemon/ydaemon.h>
#define _MAX_GROUPS 256
#define _MAX_VALUES 4096
/*
* TODO:
* - Optimize where it possible
*/
static long __cmp_strs(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
static void __destroy_val(ydc_conf_val_t *val)
{
if(val->on_eventv != NULL)
val->on_eventv(val, NULL, NULL, YC_EVENT_DESTROY);
/* ok, let's begin to free all memory */
if(val->type == SEXPR) sexp_t_deallocate((sexp_t *)val->priv);
free(val->value);
free(val->name);
return;
}
static int __ydc_conf_get_val_f(ydc_conf_t *c, const char *phvar, ydc_conf_val_t **rval,
ydc_pgroup_t **rgrp)
{
int err = 0;
int len = 0;
usrtc_t *ptree = &(c->p_groups), *tree = NULL;
usrtc_node_t *node;
char *group_name = NULL, *var_name = NULL;
ydc_conf_val_t *val = NULL;
ydc_pgroup_t *pgroup = NULL;
/* ok, first try to understand what to do */
if(!(var_name = strchr(phvar, '/'))) {
err = EINVAL;
goto __failure;
} else {
len = strlen(phvar) - strlen(var_name);
if(!(group_name = strndup(phvar, len))) {
err = ENOMEM;
goto __failure;
}
if(!(node = usrtc_lookup(ptree, (const void *)group_name))) {
err = ENOENT;
goto __failure;
} else {
pgroup = (ydc_pgroup_t *)usrtc_node_getdata(node);
pthread_rwlock_rdlock(&(pgroup->val_lock));
}
}
free(group_name);
/* we should know the value name now */
var_name += sizeof(char);
tree = &(pgroup->values);
if(!(node = usrtc_lookup(tree, (const void *)var_name))) {
err = ENOENT;
goto __failure_1;
}
val = (ydc_conf_val_t *)usrtc_node_getdata(node);
/* fill this */
if(rval) *rval = val;
if(rgrp) *rgrp = pgroup;
__failure_1:
pthread_rwlock_unlock(&(pgroup->val_lock));
__failure:
return err;
}
int ydc_conf_init(ydc_conf_t *c)
{
int err = ENOMEM;
usrtc_t *tree = &(c->p_groups);
/* zero all to keep it simple as possible */
memset(c, 0, sizeof(ydc_conf_t));
/* init locking */
if(pthread_rwlock_init(&(c->grp_lock), NULL)) goto __fail_0;
if(pthread_mutex_init(&(c->conf_lock), NULL)) goto __fail_0_1;
/* initialize tree structure */
usrtc_init(tree, USRTC_SPLAY, _MAX_GROUPS, __cmp_strs);
return 0;
__fail_0_1:
pthread_rwlock_destroy(&(c->grp_lock));
__fail_0:
return err;
}
int ydc_conf_create_pgroup(ydc_conf_t *c, char *nm)
{
int err = ENOMEM;
ydc_pgroup_t *pg = malloc(sizeof(ydc_pgroup_t));
usrtc_t *tree = NULL, *ptree = &(c->p_groups);
usrtc_node_t *node = NULL;
/* initialize */
if(!pg) {
err = ENOMEM;
goto __failure;
} else if(!(pg->name = strdup(nm))){
err = ENOMEM;
goto __failure_1;
}
/* check availability */
/* from here we will lock conf */
pthread_rwlock_wrlock(&(c->grp_lock));
if((node = usrtc_lookup(ptree, (const void *)nm))) {
err = EEXIST;
goto __failure_2;
}
if(usrtc_count(ptree) >= _MAX_GROUPS) {
err = ENOMEM;
goto __failure_2;
}
/* init rwlock */
if(pthread_rwlock_init(&(pg->val_lock), NULL)) {
err = ENOMEM;
goto __failure_2;
}
/* init tree structures */
tree = &(pg->values);
node = &(pg->unode);
usrtc_init(tree, USRTC_SPLAY, _MAX_VALUES, __cmp_strs);
usrtc_node_init(node, pg);
/* insert */
usrtc_insert(ptree, node, pg->name);
pthread_rwlock_unlock(&(c->grp_lock));
return 0;
__failure_2:
pthread_rwlock_unlock(&(c->grp_lock));
__failure_1:
free(pg);
__failure:
return err;
}
int ydc_conf_destroy_pgroup(ydc_conf_t *c, char *nm, int force)
{
int err = 0;
usrtc_t *ptree = &(c->p_groups), *tree;
usrtc_node_t *node = NULL, *nn = NULL;
ydc_pgroup_t *pg = NULL;
ydc_conf_val_t *val = NULL;
/* take an rwlock for write due to the our sirection to write somethings */
pthread_rwlock_wrlock(&(c->grp_lock));
node = usrtc_lookup(ptree, (const void *)nm);
if(!node) {
pthread_rwlock_unlock(&(c->grp_lock));
return ENOENT;
} else {
pg = (ydc_pgroup_t *)usrtc_node_getdata(node);
tree = &(pg->values);
pthread_rwlock_rdlock(&(pg->val_lock));
}
if(!force && usrtc_count(tree)) {
pthread_rwlock_unlock(&(c->grp_lock));
pthread_rwlock_unlock(&(pg->val_lock));
return ENOTEMPTY; /* auuhh ... */
}
/* let's retake lock */
pthread_rwlock_unlock(&(pg->val_lock));
pthread_rwlock_wrlock(&(pg->val_lock));
/* remove from the tree */
usrtc_delete(ptree, node);
pthread_rwlock_unlock(&(c->grp_lock));
for(nn = usrtc_first(tree); nn != NULL; nn = usrtc_first(tree)) {
val = usrtc_node_getdata(nn);
__destroy_val(val);
usrtc_delete(tree, nn);
}
/* free all */
pthread_rwlock_unlock(&(pg->val_lock));
pthread_rwlock_destroy(&(pg->val_lock));
free(pg->name);
free(pg);
return err;
}
int ydc_conf_add_val_p(ydc_conf_t *c, const char *phvar, int cstr)
{
int err = 0;
int len = 0, p1 = 0, p2 = 0;
unsigned long siv = 0; unsigned long uiv = 0;
usrtc_t *ptree = &(c->p_groups), *tree = NULL;
usrtc_node_t *node;
char *grp_name, *val_name, *value;
ydc_pgroup_t *pg = NULL;
ydc_conf_val_t *val = malloc(sizeof(ydc_conf_val_t)), *oldval = NULL;
if(!val) return ENOMEM;
else memset(val, 0, sizeof(ydc_conf_val_t));
/* take the path, group name first */
if(!(val_name = strchr(phvar, '/'))) {
err = EINVAL;
goto __failure;
} else {
grp_name = val_name;
len = strlen(phvar) - strlen(grp_name);
if(!(grp_name = strndup(phvar, len))) { /* we got it */
err = ENOMEM;
goto __failure;
} else {
/* looking for existence of the group */
pthread_rwlock_rdlock(&(c->grp_lock));
node = usrtc_lookup(ptree, (const void *)grp_name); free(grp_name);
pthread_rwlock_unlock(&(c->grp_lock));
if(!node) {
err = ENOENT; goto __failure;
} else {
pg = (ydc_pgroup_t *)usrtc_node_getdata(node);
pthread_rwlock_wrlock(&(pg->val_lock)); /* we apologize to change something */
}
tree = &(pg->values);
/* get the value name */
if(!(value = strchr(val_name, ':'))) {
err = EINVAL; goto __failure_0;
} else {
len = (strlen(val_name) - strlen(value)) - sizeof(char);
if(!(val_name = strndup(val_name + sizeof(char), len))) { /* gotcha ! */
err = ENOMEM; goto __failure_0;
} else if(!(value = strdup(value + sizeof(char)))) { /* take the value itself */
free(val_name); err = ENOMEM; goto __failure_0;
}
/* check out if we're have one */
if((node = usrtc_lookup(tree, (const void *)val_name))) { /* oops, then remove */
oldval = (ydc_conf_val_t *)usrtc_node_getdata(node);
usrtc_delete(tree, node);
}
if(usrtc_count(tree) >= _MAX_VALUES) { /* know your limits (c) British ale and beer stickers */
err = ENOMEM;
goto __failure_1;
}
/* ok, here we can create a new value */
/* detect the type */
len = strlen(value);
/* first for long values */
if(isdigit(value[0]) || (isdigit(value[1]) && (value[0] == '-'))) { /* looks like a digit */
if(value[0] == '-') { /* signed should be used */
if(len > 9) val->type = LONG;
else val->type = INT;
} else {
if(len > 9) val->type = ULONG;
else val->type = UINT;
}
} else if(value[0] == '(' && value[len - 1] == ')') { /* might be a sexp */
/* first, we must count parentes */
for(grp_name = strchr(value, '('); grp_name != NULL;
grp_name = strchr(grp_name + sizeof(char), '('))
p1++;
for(grp_name = strchr(value, ')'); grp_name != NULL;
grp_name = strchr(grp_name + sizeof(char), ')'))
p2++;
if(p1 != p2) val->type = STRING; /* looks like string */
else if((grp_name = strchr(value, ' '))) val->type = SEXPR; /* should be at least one space */
else val->type = STRING;
} else
val->type = STRING;
/* if forced cstring */
if(cstr) val->type = STRING;
/* let's decide what to do */
switch(val->type) {
case STRING:
val->len = len + sizeof(char);
val->value = (void *)value;
break;
case INT:
case LONG:
val->len = sizeof(unsigned long);
if(!(val->value = malloc(sizeof(unsigned long)))) {
err = ENOMEM;
goto __failure_2;
}
siv = strtoll(value, NULL, 0);
*(long *)val->value = siv;
#if 0 /* FIXME: */
if((siv != MAXINT64) || (siv != G_MININT64)) {
*(gint64 *)val->value = siv;
} else {
g_free(val->value);
err = EINVAL;
goto __failure_2;
}
#endif
free(value);
break;
case UINT:
case ULONG:
val->len = sizeof(unsigned long);
if(!(val->value = malloc(sizeof(unsigned long)))) {
err = ENOMEM;
goto __failure_2;
}
uiv = strtoull(value, NULL, 0);
*(unsigned long *)val->value = uiv;
#if 0
if(uiv != G_MAXUINT64) {
*(guint64 *)val->value = uiv;
} else {
g_free(val->value);
err = EINVAL;
goto __failure_2;
}
#endif
free(value);
break;
case SEXPR:
val->len = len;
val->value = value;
if(!(val->priv = (void *)parse_sexp(value, len))) {
errno = EINVAL;
goto __failure_2;
}
break;
default: /* just to keep gcc happy */
break;
}
val->name = val_name;
/* well, init tree and other stuff */
node = &(val->unode);
usrtc_node_init(node, val);
usrtc_insert(tree, node, (const void *)val->name);
if(oldval) {
if(oldval->on_eventv) {
oldval->on_eventv(val, oldval, c, YC_EVENT_MODIFY);
val->on_eventv = oldval->on_eventv;
}
__destroy_val(oldval);
free(oldval);
}
}
}
}
pthread_rwlock_unlock(&(pg->val_lock));
return 0;
__failure_2:
if(oldval) {
node = &(oldval->unode);
usrtc_insert(tree, node, (const void *)oldval->name);
}
__failure_1:
free(val_name);
free(value);
__failure_0:
pthread_rwlock_unlock(&(pg->val_lock));
__failure:
free(val);
return err;
}
int ydc_conf_rm_val(ydc_conf_t *c, const char *phvar)
{
int err = 0;
usrtc_node_t *node;
usrtc_t *tree;
ydc_conf_val_t *val = NULL;
ydc_pgroup_t *pgroup = NULL;
pthread_rwlock_rdlock(&(c->grp_lock));
if((err = __ydc_conf_get_val_f(c, phvar, &val, &pgroup))) goto __failure;
/* delete it */
pthread_rwlock_wrlock(&(pgroup->val_lock));
tree = &(pgroup->values);
node = &(val->unode);
usrtc_delete(tree, node);
pthread_rwlock_unlock(&(pgroup->val_lock));
__destroy_val(val);
free(val);
__failure:
pthread_rwlock_unlock(&(c->grp_lock));
return err;
}
int ydc_conf_get_val(ydc_conf_t *c, const char *phvar, ydc_conf_val_t **rval)
{
int err = 0;
ydc_conf_val_t *val = NULL;
pthread_rwlock_rdlock(&(c->grp_lock));
if((err = __ydc_conf_get_val_f(c, phvar, &val, NULL))) goto __failure;
/* fill this */
*rval = val;
__failure:
pthread_rwlock_unlock(&(c->grp_lock));
return err;
}
/* more code, but faster than double search */
void ydc_conf_destroy(ydc_conf_t *c)
{
usrtc_t *ptree = &(c->p_groups), *tree;
usrtc_node_t *node, *nnode;
ydc_pgroup_t *grp;
ydc_conf_val_t *val;
/* lock for all operations */
pthread_mutex_lock(&(c->conf_lock));
pthread_rwlock_wrlock(&(c->grp_lock));
if(!usrtc_count(ptree)) goto __e_out; /* all is clean*/
/* well let's clean all groups */
for(node = usrtc_first(ptree); node != NULL; node = usrtc_first(ptree)) {
grp = (ydc_pgroup_t *)usrtc_node_getdata(node);
pthread_rwlock_wrlock(&(grp->val_lock));
tree = &(grp->values);
if(usrtc_count(tree)) {
for(nnode = usrtc_first(tree); nnode != NULL; nnode = usrtc_first(tree)) {
val = (ydc_conf_val_t *)usrtc_node_getdata(nnode);
__destroy_val(val);
usrtc_delete(tree, nnode);
free(val);
}
}
usrtc_delete(ptree, node);
pthread_rwlock_destroy(&(grp->val_lock));
free(grp->name);
free(grp);
}
__e_out:
pthread_mutex_destroy(&(c->conf_lock));
pthread_rwlock_destroy(&(c->grp_lock));
/* secure */
memset(c, 0, sizeof(ydc_conf_t));
free(c);
return;
}
int ydc_conf_val_attach_event(ydc_conf_t *c, const char *phvar,
void (*on_eventv)(struct __ym_conf_value *,
struct __ym_conf_value *,
ydc_conf_t *, ydc_event_t))
{
int err = 0;
ydc_conf_val_t *val = NULL;
ydc_pgroup_t *grp;
pthread_rwlock_rdlock(&(c->grp_lock));
if((err = __ydc_conf_get_val_f(c, phvar, &val, &grp))) goto __failure;
pthread_rwlock_wrlock(&(grp->val_lock));
/* attach callback */
val->on_eventv = on_eventv;
val->on_eventv(val, NULL, c, YC_EVENT_ATTACH); /* yep, it's an event */
pthread_rwlock_unlock(&(grp->val_lock));
__failure:
pthread_rwlock_unlock(&(c->grp_lock));
return err;
}
int ydc_conf_modify_val(ydc_conf_t *c, const char *phvar, void *data, int len)
{
ydc_conf_val_t *val;
ydc_pgroup_t *grp;
char *t = NULL;
void *tb = NULL;
sexp_t *nsexp = NULL;
int err = 0;
pthread_rwlock_rdlock(&(c->grp_lock));
if((err = __ydc_conf_get_val_f(c, phvar, &val, &grp))) goto __failure;
pthread_rwlock_unlock(&(c->grp_lock));
/* take group lock */
pthread_rwlock_wrlock(&(grp->val_lock));
switch(val->type) {
case STRING:
t = val->value;
if(!(val->value = strndup((const char *)data, len))) {
err = ENOMEM;
val->value = t;
goto __failure_1;
} else free(t);
break;
case INT:
case LONG:
*(long *)val->value = *(long *)data;
break;
case ULONG:
case UINT:
*(unsigned long *)val->value = *(unsigned long *)data;
break;
case CUSTOM: /* that means we must call event callback before data change also */
if(val->on_eventv)
val->on_eventv(val, val, c, YC_EVENT_MODIFY); /* oldval is val, since it pre call */
case BLOB:
tb = val->value;
if(!(val->value = malloc(len))) {
err = ENOMEM;
val->value = tb;
goto __failure_1;
} else memcpy(data, val->value, len);
free(tb);
break;
case SEXPR:
t = val->value;
if(!(val->value = strndup((const char *)data, len))) {
err = ENOMEM;
val->value = t;
goto __failure_1;
}
if(!(nsexp = parse_sexp(val->value, len))) {
err = EINVAL;
val->value = t;
goto __failure_1;
} else { /* change it */
free(t);
sexp_t_deallocate((sexp_t *)val->priv);
val->priv = (void *)nsexp;
}
break;
}
/* well, run callback if exists */
if(val->on_eventv)
val->on_eventv(val, NULL, c, YC_EVENT_MODIFY); /* oldval is nil, incdicate
* post event for CUSTOM type
*/
__failure_1:
pthread_rwlock_unlock(&(grp->val_lock));
return err;
__failure:
pthread_rwlock_unlock(&(c->grp_lock));
return err;
}
int ydc_conf_clone_val(ydc_conf_val_t *s, ydc_conf_val_t *c)
{
int e = 0;
/* zeroing for our clone */
memset(c, 0, sizeof(ydc_conf_val_t));
/* clone name and data */
if((c->name = strdup(s->name))) {
e = ENOMEM; goto __fail;
}
if(!(c->value = malloc(s->len))) {
free(c->name); e = ENOMEM; goto __fail;
} else
memcpy(c->value, s->value, s->len);
/* clone others */
c->type = s->type;
c->priv = s->priv;
__fail:
return e;
}
void ydc_conf_val_destroy_clone(ydc_conf_val_t *c)
{
free(c->name);
free(c->value);
/* this function will not free structure itself, instead we will
* zero all stuff within structure, since we don't know how it was allocated,
* it's better to be sure about cloned data */
memset(c, 0, sizeof(ydc_conf_val_t));
return;
}
Loading…
Cancel
Save