Core: removed ydaemon, ydaemon is standalone now;
parent
9b3ccae35b
commit
08b3807d09
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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 2.1 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 __YDATA_CACHE_H__
|
||||
#define __YDATA_CACHE_H__
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define YD_CACHE_SPACER_MAGIC 0xbeafbeef
|
||||
|
||||
/* item flags */
|
||||
#define YDC_INVALIDATE (1 << 1)
|
||||
#define YDC_UNUSED (1 << 2)
|
||||
#define YDC_DIRTY (1 << 3)
|
||||
|
||||
typedef struct __ydata_cache_item_type {
|
||||
oid_t oid;
|
||||
uint32_t idx;
|
||||
uint8_t attr;
|
||||
usrtc_node_t idxnode;
|
||||
list_node_t listnode;
|
||||
} ydata_cache_item_t;
|
||||
|
||||
#define yd_item_idx(item) (item)->idx
|
||||
#define yd_item_setoid(it, id) (it)->oid = id
|
||||
|
||||
typedef struct __ydata_qitem_type {
|
||||
ydata_cache_item_t *item;
|
||||
list_node_t node;
|
||||
} ydata_qitem_t;
|
||||
|
||||
#define YDC_SYNCTHRESHOLD 64
|
||||
#define YDC_SYNCDELTASEC 30
|
||||
|
||||
typedef struct __ydata_cache_t {
|
||||
usrtc_t idx_tree;
|
||||
list_head_t free_poll;
|
||||
list_head_t dirty_poll;
|
||||
list_head_t pending_poll;
|
||||
void *cache;
|
||||
size_t object_size;
|
||||
size_t objects_amount;
|
||||
size_t cache_size;
|
||||
size_t dirties;
|
||||
pthread_t syncthread;
|
||||
pthread_rwlock_t rwlock;
|
||||
pthread_mutex_t dirtlock;
|
||||
} ydata_cache_t;
|
||||
|
||||
#define yd_cache_rdlock(c) pthread_rwlock_rdlock(&(c)->rwlock)
|
||||
#define yd_cache_wrlock(c) pthread_rwlock_wrlock(&(c)->rwlock)
|
||||
#define yd_cache_unlock(c) pthread_rwlock_unlock(&(c)->rwlock)
|
||||
|
||||
#define yd_cache_ptrbyidx(c, n) (char *)(c)->cache + n*((c)->object_size + sizeof(uint32_t))
|
||||
|
||||
/* API, mostly internally used, but might be useful */
|
||||
ydata_cache_t *yd_cache_init(dataobject_t *, size_t);
|
||||
|
||||
void *yd_cache_alloc_item(ydata_cache_t *, ydata_cache_item_t **);
|
||||
|
||||
void yd_cache_discard_alloc_item(ydata_cache_t *, ydata_cache_item_t *);
|
||||
|
||||
void yd_cache_confirm_alloc_item(ydata_cache_t *, ydata_cache_item_t *, oid_t);
|
||||
|
||||
void *yd_cache_lookup(ydata_cache_t *, oid_t);
|
||||
|
||||
list_head_t *yd_cache_getrslist(ydata_cache_t *, uint8_t);
|
||||
|
||||
void yd_cache_qitems_pullback(ydata_cache_t *, list_head_t *);
|
||||
|
||||
void yd_cache_item_dirtyoid(ydata_cache_t *, oid_t);
|
||||
|
||||
void yd_cache_item_invalidateoid(ydata_cache_t *, oid_t);
|
||||
|
||||
int yd_cache_start_thread(domx_t *);
|
||||
|
||||
#endif /* __YDATA_CACHE_H__ */
|
@ -1,287 +0,0 @@
|
||||
/*
|
||||
* 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 2.1 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 __DM_DATAOBJECT_H__
|
||||
#define __DM_DATAOBJECT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <tdata/usrtc.h>
|
||||
#include <tdata/list.h>
|
||||
|
||||
#define MAX_ITEM_NAME 32
|
||||
#define MAX_ITEMS 255
|
||||
|
||||
typedef uint64_t oid_t;
|
||||
|
||||
enum {
|
||||
U8 = 0,
|
||||
S8,
|
||||
U16,
|
||||
S16,
|
||||
U32,
|
||||
S32,
|
||||
U64,
|
||||
S64,
|
||||
CSTR,
|
||||
TBLOB,
|
||||
TACRT,
|
||||
};
|
||||
|
||||
struct typelen {
|
||||
uint8_t type;
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
typedef struct __access_rights_type {
|
||||
uint32_t ouid;
|
||||
uint32_t ogid;
|
||||
uint8_t domainid;
|
||||
uint8_t sal;
|
||||
uint8_t amask;
|
||||
uint8_t reserve;
|
||||
}__attribute__((packed)) acc_right_t;
|
||||
|
||||
typedef struct __dataacc_pemctx_type {
|
||||
acc_right_t *uobj;
|
||||
uint32_t gids[16];
|
||||
} dataacc_pemctx_t;
|
||||
|
||||
#ifdef DMUX_USE
|
||||
static struct typelen tltable[] = {
|
||||
{.type = U8, .len = 1},
|
||||
{.type = S8, .len = 1},
|
||||
{.type = U16, .len = 2},
|
||||
{.type = S16, .len = 2},
|
||||
{.type = U32, .len = 4},
|
||||
{.type = S32, .len = 4},
|
||||
{.type = U64, .len = 8},
|
||||
{.type = S64, .len = 8},
|
||||
{.type = CSTR, .len = 0},
|
||||
{.type = TBLOB, .len = 0},
|
||||
{.type = TACRT, .len = sizeof(acc_right_t) },
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct __dataobject_item_type {
|
||||
uint8_t id;
|
||||
uint8_t type;
|
||||
uint64_t len;
|
||||
char name[MAX_ITEM_NAME];
|
||||
list_node_t node;
|
||||
}__attribute__ ((packed)) dataobject_item_t;
|
||||
|
||||
typedef struct __item_idx_type {
|
||||
void *key;
|
||||
dataobject_item_t *dtr;
|
||||
usrtc_node_t node;
|
||||
} item_idx_t;
|
||||
|
||||
typedef struct __dataobject_type {
|
||||
char name[MAX_ITEMS];
|
||||
list_head_t description; /* description of the data */
|
||||
usrtc_t id_index;
|
||||
usrtc_t name_index;
|
||||
} dataobject_t;
|
||||
|
||||
/* API */
|
||||
dataobject_t *dotr_create(const char *name);
|
||||
|
||||
int dotr_set_item(dataobject_t *dotr, uint8_t type, uint64_t len, const char *name);
|
||||
|
||||
uint8_t dotr_item_type(dataobject_t *obj, const char *name, uint64_t *len);
|
||||
|
||||
char *dotr_item_nameptr(dataobject_t *obj, const char *name);
|
||||
|
||||
int dotr_item_nameidx(dataobject_t *obj, const char *name);
|
||||
|
||||
void dotr_destroy(dataobject_t *dotr);
|
||||
|
||||
/* dataobject misc operations */
|
||||
int dtocmp(const dataobject_t *src, const dataobject_t *dst);
|
||||
|
||||
size_t dtolen(const dataobject_t *src);
|
||||
|
||||
/*
|
||||
* Filtering used for access to the data stream.
|
||||
*/
|
||||
typedef enum {
|
||||
YDM_NO_FILTER = 0, /* no access right filter */
|
||||
YDM_DOMAIN_FILTER, /* filter only by domain */
|
||||
YDM_USERDAC_FILTER, /* filter by domain and user with DAC */
|
||||
YDM_FULL_FILTER, /* all above filter plus additional filtering */
|
||||
} ydm_access_filter_t;
|
||||
|
||||
typedef struct __sxmp_ch_entry_type {
|
||||
char instance[32];
|
||||
uint16_t chtid;
|
||||
ydm_access_filter_t filter;
|
||||
list_node_t node;
|
||||
} sxmp_ch_entry_t;
|
||||
|
||||
struct __domx_dsbe_type;
|
||||
|
||||
/* some intermodular structures */
|
||||
typedef struct __domx_type {
|
||||
dataobject_t *dox;
|
||||
char *name;
|
||||
list_head_t sxmp_channels;
|
||||
struct __domx_dsbe_type *be;
|
||||
void *cache;
|
||||
} domx_t;
|
||||
|
||||
/* initialization */
|
||||
int domx_init(domx_t *dt, dataobject_t *dodesc);
|
||||
int domx_set_be(domx_t *dt, void *be, const char *key);
|
||||
int domx_set_cache(domx_t *dt, size_t size);
|
||||
int domx_set_sxmpchannel(domx_t *dt, const char *instance, int typeid, int access);
|
||||
|
||||
/* data operations */
|
||||
int domx_get(domx_t *dt, uint64_t oid, void **refdata);
|
||||
int domx_set(domx_t *dt, uint64_t oid, const void *refdata);
|
||||
int domx_remove(domx_t *dt, uint64_t oid);
|
||||
int domx_creat(domx_t *dt, uint64_t *oid, const void *refdata);
|
||||
|
||||
/* cache ops for backends */
|
||||
int domx_cache_invalidate(domx_t *dt, uint64_t oid);
|
||||
int domx_cache_invalidate_list(domx_t *dt, list_head_t *oids);
|
||||
int domx_cache_getdirtylist(domx_t *dt, uint16_t amount, list_head_t **list);
|
||||
int domx_cache_freelist(domx_t *dt, list_head_t *list);
|
||||
int domx_cache_freeitems(domx_t *dt, uint16_t amount);
|
||||
|
||||
/* data filters */
|
||||
typedef enum {
|
||||
YDEQUAL = 0,
|
||||
YDNOTEQUAL,
|
||||
YDGREATER,
|
||||
YDLESS,
|
||||
YDEQOGREATER,
|
||||
YDEQOLESS,
|
||||
YDINRANGE,
|
||||
YDINLIST,
|
||||
} filt_t;
|
||||
|
||||
typedef struct __yd_inlist_item_type {
|
||||
union {
|
||||
uint64_t val;
|
||||
char *dta;
|
||||
};
|
||||
list_node_t node;
|
||||
}__attribute__((packed)) yd_inlist_item_t;
|
||||
|
||||
typedef struct __yd_filter_item_type {
|
||||
char *name; /* dataobject item name ptr */
|
||||
filt_t ftype; /* filtering type */
|
||||
union {
|
||||
struct {
|
||||
uint64_t vf; /* first value */
|
||||
uint64_t vc; /* second value if applicable */
|
||||
};
|
||||
struct {
|
||||
char *cstr;
|
||||
list_head_t *inlist;
|
||||
};
|
||||
};
|
||||
list_node_t node;
|
||||
}__attribute__((packed)) yd_filter_item_t;
|
||||
|
||||
typedef struct __yd_filter_type {
|
||||
domx_t *domx;
|
||||
list_head_t filter;
|
||||
} yd_filter_t;
|
||||
|
||||
yd_filter_t *yd_filter_create(domx_t *refobj);
|
||||
void yd_filter_destroy(yd_filter_t *f);
|
||||
int yd_filter_add_sf(yd_filter_t *f, const char *name, filt_t ftype,
|
||||
uint64_t vf, uint64_t vc);
|
||||
int yd_filter_add_str(yd_filter_t *f, const char *name, const char *value, int eq);
|
||||
int yd_filter_add_inlist(yd_filter_t *f, const char *name, int length, void **array);
|
||||
|
||||
#define YD_CHUNK_AMOUNT 128
|
||||
|
||||
typedef struct __yd_wlist_node_type {
|
||||
oid_t oid;
|
||||
list_node_t node;
|
||||
} yd_wlist_node_t;
|
||||
|
||||
typedef struct __yd_index_stream_type {
|
||||
yd_filter_t *filter;
|
||||
uint32_t offset;
|
||||
uint8_t amount;
|
||||
list_head_t entries_wlist;
|
||||
void *priv;
|
||||
} yd_idx_stream_t;
|
||||
|
||||
#define yd_index_stream_setfilter(sw, filt) (sw)->filter = (filt)
|
||||
#define yd_index_stream_setpriv(sw, prv) (sw)->priv = prv
|
||||
#define yd_index_stream_getpriv(sw) (sw)->priv
|
||||
|
||||
yd_idx_stream_t *yd_index_stream_init(void);
|
||||
void yd_index_stream_destroy(yd_idx_stream_t *);
|
||||
void yd_index_stream_emptylist(yd_idx_stream_t *);
|
||||
|
||||
typedef struct __yd_index_stream_window_type {
|
||||
uint8_t amount;
|
||||
list_head_t *wlist;
|
||||
} yd_idx_stream_win_t;
|
||||
|
||||
#define yd_idx_stream_win_size(sw) (sw)->amount
|
||||
|
||||
/* domx stream operations */
|
||||
yd_idx_stream_t *domx_idxl_open(domx_t *dt, ydm_access_filter_t afilter,
|
||||
dataacc_pemctx_t *dacc, yd_filter_t *datafilter);
|
||||
|
||||
void domx_idxl_close(domx_t *dt, yd_idx_stream_t *idxl);
|
||||
|
||||
yd_idx_stream_win_t *domx_idxl_read(domx_t *dt, yd_idx_stream_t *idxl);
|
||||
|
||||
struct be_ops;
|
||||
|
||||
#define BEMAGIC 0xffffbeef
|
||||
|
||||
typedef struct __domx_dsbe_type {
|
||||
domx_t *domx;
|
||||
void *priv;
|
||||
struct be_ops *f;
|
||||
} domx_dsbe_t;
|
||||
|
||||
struct be_ops {
|
||||
uint32_t be_magic;
|
||||
/* initialization part */
|
||||
int (*init)(domx_dsbe_t *, const char *);
|
||||
/* data manipulation */
|
||||
int (*get)(domx_dsbe_t *, oid_t, void *);
|
||||
int (*set)(domx_dsbe_t *, oid_t, void *);
|
||||
oid_t (*creat)(domx_dsbe_t *, const void *);
|
||||
int (*remove)(domx_dsbe_t *, oid_t);
|
||||
/* list requesting */
|
||||
yd_idx_stream_t* (*create_idx_stream)(domx_dsbe_t *, ydm_access_filter_t,
|
||||
dataacc_pemctx_t *, yd_filter_t *);
|
||||
void (*destroy_idx_stream)(yd_idx_stream_t *);
|
||||
yd_idx_stream_win_t* (*getportion_idx_stream)(yd_idx_stream_t *);
|
||||
};
|
||||
|
||||
#endif /* __YD_DATAOBJECT_H__ */
|
@ -1,367 +0,0 @@
|
||||
/*
|
||||
* 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 2.1 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__ */
|
@ -1,34 +0,0 @@
|
||||
## 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 data.c cache.c \
|
||||
domx.c filter.c idxstream.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
|
||||
|
@ -1,3 +0,0 @@
|
||||
0.0.1
|
||||
|
||||
|
@ -1,465 +0,0 @@
|
||||
/*
|
||||
* 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 <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <ydaemon/dataobject.h>
|
||||
#include <ydaemon/cache.h>
|
||||
|
||||
static long __cmp_oids(const void *a, const void *b)
|
||||
{
|
||||
return (long)(*(oid_t *)a - *(oid_t *)b);
|
||||
}
|
||||
|
||||
static ydata_cache_item_t *__alloc_ydcitem(uint32_t idx)
|
||||
{
|
||||
ydata_cache_item_t *out = malloc(sizeof(ydata_cache_item_t));
|
||||
|
||||
if(out) {
|
||||
memset(out, 0, sizeof(ydata_cache_item_t));
|
||||
out->idx = idx;
|
||||
out->attr |= YDC_UNUSED;
|
||||
list_init_node(&out->listnode);
|
||||
usrtc_node_init(&out->idxnode, out);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void *__sync_thread(void *p);
|
||||
|
||||
int yd_cache_start_thread(domx_t *domx)
|
||||
{
|
||||
ydata_cache_t *cc;
|
||||
|
||||
if(!domx || !(cc = (ydata_cache_t *)domx->cache)) return EINVAL;
|
||||
|
||||
return pthread_create(&cc->syncthread, NULL, __sync_thread, (void *)domx);
|
||||
}
|
||||
|
||||
static void *__sync_thread(void *p)
|
||||
{
|
||||
domx_t *domx = (domx_t *)p;
|
||||
ydata_cache_t *cc;
|
||||
domx_dsbe_t *be;
|
||||
list_node_t *iter, *siter;
|
||||
ydata_cache_item_t *citem;
|
||||
struct timespec tio;
|
||||
int r, c, o;
|
||||
|
||||
/* check up, we shouldn't falls to segmentation */
|
||||
if(!p || !(cc = (ydata_cache_t *)domx->cache)) goto __fini;
|
||||
if(!(be = domx->be)) goto __fini;
|
||||
|
||||
/* everyday life is here */
|
||||
while(1) {
|
||||
/* get our tio, yes it's not so green ... but it works */
|
||||
tio.tv_sec = time(NULL) + YDC_SYNCDELTASEC;
|
||||
/* lock on mutex for a time being or will wake up on request */
|
||||
r = pthread_mutex_timedlock(&cc->dirtlock, &tio);
|
||||
|
||||
__retrywolock:
|
||||
yd_cache_rdlock(cc);
|
||||
if(!cc->dirties) {
|
||||
yd_cache_unlock(cc);
|
||||
goto __again;
|
||||
}
|
||||
yd_cache_unlock(cc);
|
||||
|
||||
yd_cache_wrlock(cc);
|
||||
c = 0;
|
||||
list_for_each_safe(&cc->dirty_poll, iter, siter) {
|
||||
citem = container_of(iter, ydata_cache_item_t, listnode);
|
||||
list_del(&citem->listnode);
|
||||
|
||||
if(citem->attr & YDC_INVALIDATE) { /* invalidated item, just pullback it */
|
||||
citem->attr = 0;
|
||||
citem->attr |= YDC_UNUSED;
|
||||
list_add2tail(&cc->free_poll, &citem->listnode);
|
||||
usrtc_delete(&cc->idx_tree, &citem->idxnode);
|
||||
} else {
|
||||
o = be->f->set(be, citem->oid, yd_cache_ptrbyidx(cc, citem->idx));
|
||||
if(o != 0) { /* invalidate */
|
||||
citem->attr = 0;
|
||||
citem->attr |= YDC_UNUSED;
|
||||
list_add2tail(&cc->free_poll, &citem->listnode);
|
||||
usrtc_delete(&cc->idx_tree, &citem->idxnode);
|
||||
} else citem->attr &= ~YDC_DIRTY; /* just remove this flag */
|
||||
}
|
||||
cc->dirties--;
|
||||
c++;
|
||||
if(c >= YDC_SYNCTHRESHOLD) break;
|
||||
}
|
||||
yd_cache_unlock(cc);
|
||||
|
||||
if(c >= YDC_SYNCTHRESHOLD) {
|
||||
usleep(100); /* looks like a huge load, let's wait and retry without lock */
|
||||
goto __retrywolock;
|
||||
}
|
||||
|
||||
__again:
|
||||
if(r != ETIMEDOUT) pthread_mutex_lock(&cc->dirtlock); /* acquire lock again */
|
||||
}
|
||||
|
||||
__fini:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ydata_cache_t *yd_cache_init(dataobject_t *object, size_t cache_size)
|
||||
{
|
||||
ydata_cache_t *cache = NULL;
|
||||
char *iter;
|
||||
ydata_cache_item_t *zcitem;
|
||||
list_node_t *it, *sit;
|
||||
int r = 0;
|
||||
size_t i;
|
||||
|
||||
if(!object || !cache_size) {
|
||||
errno = EINVAL;
|
||||
goto __fail;
|
||||
}
|
||||
|
||||
/* allocate and zero structure */
|
||||
if(!(cache = malloc(sizeof(ydata_cache_t)))) {
|
||||
errno = ENOMEM;
|
||||
goto __fail;
|
||||
} else memset(cache, 0, sizeof(ydata_cache_t));
|
||||
|
||||
/* map a memory buffer */
|
||||
cache->cache = mmap(NULL, cache_size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if(cache->cache == MAP_FAILED) {
|
||||
errno = ENOMEM;
|
||||
goto __fail;
|
||||
}
|
||||
|
||||
/* allocate all the locks */
|
||||
if((r = pthread_rwlock_init(&cache->rwlock, NULL))) {
|
||||
errno = r;
|
||||
goto __fail;
|
||||
}
|
||||
if((r = pthread_mutex_init(&cache->dirtlock, NULL))) {
|
||||
pthread_rwlock_destroy(&cache->rwlock);
|
||||
errno = r;
|
||||
goto __fail;
|
||||
}
|
||||
|
||||
/* init other values */
|
||||
cache->cache_size = cache_size;
|
||||
cache->object_size = dtolen(object);
|
||||
|
||||
/* some paranoic check up */
|
||||
if(!cache->object_size) {
|
||||
pthread_rwlock_destroy(&cache->rwlock);
|
||||
pthread_mutex_destroy(&cache->dirtlock);
|
||||
errno = EINVAL;
|
||||
goto __fail;
|
||||
}
|
||||
/* well, able to continue ... */
|
||||
cache->objects_amount = cache->cache_size/(cache->object_size + sizeof(uint32_t));
|
||||
|
||||
/* init structures */
|
||||
usrtc_init(&cache->idx_tree, USRTC_SPLAY, cache->objects_amount, __cmp_oids); /* indexing one */
|
||||
list_init_head(&cache->free_poll);
|
||||
list_init_head(&cache->dirty_poll);
|
||||
list_init_head(&cache->pending_poll);
|
||||
|
||||
/* mark i.e. format our memory buffer, also it will populate the pages */
|
||||
for(i = 0, iter = (char *)cache->cache; i < cache->objects_amount;
|
||||
i++, iter += cache->object_size + sizeof(uint32_t)) {
|
||||
/* mark with spacer */
|
||||
*(uint32_t *)iter = YD_CACHE_SPACER_MAGIC;
|
||||
zcitem = __alloc_ydcitem(i);
|
||||
if(!zcitem) { errno = ENOMEM; goto __failall; }
|
||||
|
||||
list_add2tail(&cache->free_poll, &zcitem->listnode);
|
||||
}
|
||||
|
||||
/* lock the mutex */
|
||||
pthread_mutex_lock(&cache->dirtlock);
|
||||
|
||||
return cache;
|
||||
|
||||
__failall:
|
||||
pthread_rwlock_destroy(&cache->rwlock);
|
||||
pthread_mutex_destroy(&cache->dirtlock);
|
||||
|
||||
__fail:
|
||||
/* failcase freeing */
|
||||
if(cache) {
|
||||
/* memory buffer */
|
||||
if(cache->cache != MAP_FAILED || cache->cache != NULL) {
|
||||
/* if we have a buffer, we might have some items already allocated ... */
|
||||
list_for_each_safe(&cache->free_poll, it, sit) {
|
||||
zcitem = container_of(it, ydata_cache_item_t, listnode);
|
||||
list_del(&zcitem->listnode);
|
||||
free(zcitem);
|
||||
}
|
||||
|
||||
munmap(cache->cache, cache_size);
|
||||
}
|
||||
|
||||
free(cache);
|
||||
}
|
||||
|
||||
return NULL; /* sadly ... */
|
||||
}
|
||||
|
||||
/* allocating is quite simple:
|
||||
* we're trying to get a free item, if it
|
||||
* exists, we're moving this the the pending poll,
|
||||
* otherwise return nil.
|
||||
*/
|
||||
void *yd_cache_alloc_item(ydata_cache_t *cache, ydata_cache_item_t **item)
|
||||
{
|
||||
char *data = NULL;
|
||||
list_node_t *listnode;
|
||||
ydata_cache_item_t *zcitem;
|
||||
|
||||
yd_cache_rdlock(cache);
|
||||
listnode = list_node_first(&cache->free_poll);
|
||||
if(listnode) {
|
||||
yd_cache_unlock(cache); /* retake locks */
|
||||
yd_cache_wrlock(cache);
|
||||
zcitem = container_of(listnode, ydata_cache_item_t, listnode);
|
||||
list_del(&zcitem->listnode); /* delete from free poll */
|
||||
list_add2tail(&cache->pending_poll, &zcitem->listnode); /* add to the pending poll */
|
||||
/* do the magic */
|
||||
data = yd_cache_ptrbyidx(cache, zcitem->idx);
|
||||
/* mark it invalidate - since we don't know what will be in future */
|
||||
zcitem->attr |= YDC_INVALIDATE;
|
||||
*item = zcitem;
|
||||
}
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
/* ok. we'll do some automagically check for the near items safety */
|
||||
if(data && *(uint32_t *)data != YD_CACHE_SPACER_MAGIC ) { /* currupted - mark near elements invalidated ! */
|
||||
/* TODO: do it */
|
||||
}
|
||||
|
||||
if(data) {
|
||||
data += sizeof(uint32_t); /* bypass magic spacer */
|
||||
|
||||
return (void *)data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void yd_cache_discard_alloc_item(ydata_cache_t *cache, ydata_cache_item_t *item)
|
||||
{
|
||||
if(!(item->attr & YDC_INVALIDATE)) return; /* some shit happens */
|
||||
|
||||
yd_cache_wrlock(cache);
|
||||
list_del(&item->listnode); /* delete from panding poll - guess, u can use API ugly and dirty */
|
||||
list_add2tail(&cache->free_poll, &item->listnode); /* add to the pending poll */
|
||||
item->attr &= ~YDC_INVALIDATE; /* clear the invalidate bit */
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void yd_cache_confirm_alloc_item(ydata_cache_t *cache, ydata_cache_item_t *item, oid_t oid)
|
||||
{
|
||||
if(!(item->attr & YDC_INVALIDATE)) return; /* some shit happens */
|
||||
|
||||
yd_cache_wrlock(cache);
|
||||
list_del(&item->listnode); /* delete from pending poll - guess, u can use API ugly and dirty */
|
||||
item->attr &= ~YDC_INVALIDATE; /* clear the invalidate bit */
|
||||
item->attr &= ~YDC_UNUSED; /* clear the use bit */
|
||||
yd_item_setoid(item, oid);
|
||||
usrtc_insert(&cache->idx_tree, &item->idxnode, (void *)&item->oid); /* now it will be in the splay tree of the active cached data */
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void *yd_cache_lookup(ydata_cache_t *cache, oid_t oid)
|
||||
{
|
||||
usrtc_node_t *node;
|
||||
ydata_cache_item_t *item;
|
||||
void *ret = NULL;
|
||||
|
||||
yd_cache_rdlock(cache);
|
||||
node = usrtc_lookup(&cache->idx_tree, &oid);
|
||||
if(node) {
|
||||
item = (ydata_cache_item_t *)usrtc_node_getdata(node);
|
||||
if(!(item->attr & YDC_INVALIDATE)) ret = yd_cache_ptrbyidx(cache, yd_item_idx(item));
|
||||
else if(item->attr & YDC_INVALIDATE) { /* invalidated item */
|
||||
yd_cache_unlock(cache); /* retake lock */
|
||||
yd_cache_wrlock(cache);
|
||||
usrtc_delete(&cache->idx_tree, &item->idxnode);
|
||||
if(item->attr & YDC_DIRTY) { list_del(&item->listnode); /* it was dirty - but invalidated, remove it */
|
||||
cache->dirties--;
|
||||
}
|
||||
item->attr = 0; /* clear attributes */
|
||||
item->attr |= YDC_UNUSED;
|
||||
list_add2tail(&cache->free_poll, &item->listnode);
|
||||
ret = NULL;
|
||||
}
|
||||
}
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
if(ret && *(uint32_t *)ret != YD_CACHE_SPACER_MAGIC ) { /* currupted - mark near elements invalidated ! */
|
||||
/* TODO: do it */
|
||||
}
|
||||
|
||||
if(ret) ret += sizeof(uint32_t);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline ydata_qitem_t *__quickitem_alloc(ydata_cache_item_t *zitem)
|
||||
{
|
||||
ydata_qitem_t *itm = malloc(sizeof(ydata_qitem_t));
|
||||
|
||||
if(itm) {
|
||||
list_init_node(&itm->node);
|
||||
itm->item = zitem;
|
||||
}
|
||||
|
||||
return itm;
|
||||
}
|
||||
|
||||
list_head_t *yd_cache_getrslist(ydata_cache_t *cache, uint8_t amount)
|
||||
{
|
||||
list_head_t *head = malloc(sizeof(list_head_t));
|
||||
usrtc_node_t *node;
|
||||
list_node_t *_i, *_si;
|
||||
ydata_qitem_t *itm;
|
||||
ydata_cache_item_t *zitem;
|
||||
int i;
|
||||
|
||||
if(!head) return NULL;
|
||||
if(!cache || !amount) goto __failcase; /* little bit of paranoic check */
|
||||
|
||||
yd_cache_wrlock(cache);
|
||||
for(i = 0, node = usrtc_last(&cache->idx_tree);
|
||||
i < amount;
|
||||
i++, node = usrtc_last(&cache->idx_tree)) {
|
||||
if(!node) break; /* pfff */
|
||||
zitem = (ydata_cache_item_t *)usrtc_node_getdata(node);
|
||||
/* create an quick entry */
|
||||
if(!(itm = __quickitem_alloc(zitem))) goto __failcase_hasent;
|
||||
|
||||
/* delete from the index tree */
|
||||
usrtc_delete(&cache->idx_tree, &zitem->idxnode);
|
||||
list_add2tail(head, &itm->node);
|
||||
}
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
return head;
|
||||
|
||||
__failcase_hasent:
|
||||
if(head) {
|
||||
list_for_each_safe(head, _i, _si) {
|
||||
itm = container_of(_i, ydata_qitem_t, node);
|
||||
zitem = itm->item;
|
||||
if(zitem->attr & YDC_INVALIDATE) { /* oops, invalidated item found ! */
|
||||
if(zitem->attr & YDC_DIRTY) {
|
||||
list_del(&zitem->listnode);
|
||||
cache->dirties--;
|
||||
}
|
||||
list_add2tail(&cache->free_poll, &zitem->listnode);
|
||||
zitem->attr = 0;
|
||||
zitem->attr |= YDC_UNUSED;
|
||||
} else /* return back */
|
||||
usrtc_insert(&cache->idx_tree, &zitem->idxnode, (void *)&zitem->oid);
|
||||
|
||||
list_del(&itm->node);
|
||||
free(itm);
|
||||
}
|
||||
yd_cache_unlock(cache);
|
||||
}
|
||||
|
||||
__failcase:
|
||||
if(head) free(head);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void yd_cache_qitems_pullback(ydata_cache_t *cache, list_head_t *list)
|
||||
{
|
||||
list_node_t *iter, *siter;
|
||||
ydata_qitem_t *itm;
|
||||
ydata_cache_item_t *zitem;
|
||||
|
||||
yd_cache_wrlock(cache);
|
||||
list_for_each_safe(list, iter, siter) {
|
||||
itm = container_of(iter, ydata_qitem_t, node);
|
||||
zitem = itm->item;
|
||||
if(zitem->attr & YDC_DIRTY) {
|
||||
list_del(&zitem->listnode);
|
||||
cache->dirties--;
|
||||
}
|
||||
zitem->attr = 0; /* reset flags */
|
||||
zitem->attr |= YDC_UNUSED;
|
||||
list_add2tail(&cache->free_poll, &zitem->listnode);
|
||||
|
||||
/* free it at all */
|
||||
list_del(&itm->node);
|
||||
free(itm);
|
||||
}
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
free(list);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void yd_cache_item_dirtyoid(ydata_cache_t *cache, oid_t oid)
|
||||
{
|
||||
usrtc_node_t *node;
|
||||
ydata_cache_item_t *zitem;
|
||||
|
||||
yd_cache_wrlock(cache);
|
||||
node = usrtc_lookup(&cache->idx_tree, &oid);
|
||||
if(node) {
|
||||
zitem = (ydata_cache_item_t *)usrtc_node_getdata(node);
|
||||
if(!(zitem->attr & YDC_DIRTY)) {
|
||||
list_add2tail(&cache->dirty_poll, &zitem->listnode);
|
||||
zitem->attr |= YDC_DIRTY;
|
||||
cache->dirties++;
|
||||
/* schedule sync thread, since threshold of dirty items occured */
|
||||
if(cache->dirties >= YDC_SYNCTHRESHOLD) pthread_mutex_unlock(&cache->dirtlock);
|
||||
}
|
||||
}
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void yd_cache_item_invalidateoid(ydata_cache_t *cache, oid_t oid)
|
||||
{
|
||||
usrtc_node_t *node;
|
||||
ydata_cache_item_t *zitem;
|
||||
|
||||
yd_cache_wrlock(cache);
|
||||
node = usrtc_lookup(&cache->idx_tree, &oid);
|
||||
if(node) {
|
||||
zitem = (ydata_cache_item_t *)usrtc_node_getdata(node);
|
||||
if(!(zitem->attr & YDC_INVALIDATE)) zitem->attr |= YDC_INVALIDATE;
|
||||
}
|
||||
yd_cache_unlock(cache);
|
||||
|
||||
return;
|
||||
}
|
@ -1,472 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
/*
|
||||
* 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 <ydaemon/dataobject.h>
|
||||
|
||||
static long __cmp_uint8(const void *a, const void *b)
|
||||
{
|
||||
return *(uint8_t *)a - *(uint8_t *)b;
|
||||
}
|
||||
|
||||
static long __cmp_cstr(const void *a, const void *b)
|
||||
{
|
||||
return strcmp((const char *)a, (const char *)b);
|
||||
}
|
||||
|
||||
dataobject_t *dotr_create(const char *name)
|
||||
{
|
||||
dataobject_t *dtr = malloc(sizeof(dataobject_t));
|
||||
|
||||
if(!dtr) return NULL;
|
||||
else memset(dtr, 0, sizeof(dataobject_t));
|
||||
|
||||
/* init name, indexes etc ... */
|
||||
strncpy(dtr->name, name, MAX_ITEM_NAME - sizeof(char));
|
||||
|
||||
list_init_head(&dtr->description);
|
||||
usrtc_init(&dtr->id_index, USRTC_REDBLACK, MAX_ITEMS, __cmp_uint8);
|
||||
usrtc_init(&dtr->name_index, USRTC_REDBLACK, MAX_ITEMS, __cmp_cstr);
|
||||
|
||||
return dtr;
|
||||
}
|
||||
|
||||
int dotr_set_item(dataobject_t *dotr, uint8_t type, uint64_t len,
|
||||
const char *name)
|
||||
{
|
||||
dataobject_item_t *ditem = malloc(sizeof(dataobject_item_t));
|
||||
char *indexes = malloc(2*sizeof(item_idx_t));
|
||||
item_idx_t *iidx, *nidx;
|
||||
|
||||
if(!ditem || !indexes) {
|
||||
if(ditem) free(ditem);
|
||||
if(indexes) free(indexes);
|
||||
return ENOMEM;
|
||||
} else {
|
||||
iidx = (item_idx_t *)indexes;
|
||||
nidx = (item_idx_t *)(indexes + sizeof(item_idx_t));
|
||||
}
|
||||
|
||||
/* init items */
|
||||
strncpy(ditem->name, name, MAX_ITEM_NAME - sizeof(char));
|
||||
ditem->id = usrtc_count(&dotr->id_index);
|
||||
ditem->type = type;
|
||||
ditem->len = len;
|
||||
list_init_node(&ditem->node);
|
||||
|
||||
iidx->key = &ditem->id;
|
||||
iidx->dtr = ditem;
|
||||
usrtc_node_init(&iidx->node, iidx);
|
||||
|
||||
nidx->key = ditem->name;
|
||||
nidx->dtr = ditem;
|
||||
usrtc_node_init(&nidx->node, nidx);
|
||||
|
||||
/* now insert all */
|
||||
list_add2tail(&dotr->description, &ditem->node);
|
||||
usrtc_insert(&dotr->id_index, &iidx->node, iidx->key);
|
||||
usrtc_insert(&dotr->name_index, &nidx->node, nidx->key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dotr_destroy(dataobject_t *dotr)
|
||||
{
|
||||
usrtc_t *tree = &dotr->id_index;
|
||||
usrtc_node_t *node = NULL;
|
||||
item_idx_t *idx;
|
||||
list_node_t *iter, *save;
|
||||
dataobject_item_t *ditem;
|
||||
|
||||
if(usrtc_count(tree)) { /* we can free only index, since it was allocated as one memory chunk */
|
||||
for(node = usrtc_first(tree); node != NULL; node = usrtc_first(tree)) {
|
||||
idx = (item_idx_t *)usrtc_node_getdata(node);
|
||||
usrtc_delete(tree, node);
|
||||
free(idx);
|
||||
}
|
||||
|
||||
/* free description */
|
||||
list_for_each_safe(&dotr->description, iter, save) {
|
||||
ditem = container_of(iter, dataobject_item_t, node);
|
||||
list_del(&ditem->node);
|
||||
free(ditem);
|
||||
}
|
||||
}
|
||||
|
||||
free(dotr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dotr_item_type(dataobject_t *obj, const char *name, uint64_t *len)
|
||||
{
|
||||
usrtc_node_t *node = usrtc_lookup(&obj->name_index, name);
|
||||
item_idx_t *idxnode;
|
||||
dataobject_item_t *dtr = NULL;
|
||||
|
||||
if(!node) { /* not found ! */
|
||||
__failed:
|
||||
*len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
idxnode = (item_idx_t *)usrtc_node_getdata(node);
|
||||
if(!idxnode) goto __failed;
|
||||
else dtr = idxnode->dtr;
|
||||
|
||||
if(!dtr) goto __failed;
|
||||
|
||||
*len = dtr->len;
|
||||
return dtr->type;
|
||||
}
|
||||
|
||||
char *dotr_item_nameptr(dataobject_t *obj, const char *name)
|
||||
{
|
||||
usrtc_node_t *node = usrtc_lookup(&obj->name_index, name);
|
||||
item_idx_t *idxnode;
|
||||
dataobject_item_t *dtr = NULL;
|
||||
|
||||
if(!node) /* not found ! */ return NULL;
|
||||
|
||||
idxnode = (item_idx_t *)usrtc_node_getdata(node);
|
||||
if(!idxnode) return NULL;
|
||||
else dtr = idxnode->dtr;
|
||||
|
||||
if(!dtr) return NULL;
|
||||
|
||||
return dtr->name;
|
||||
}
|
||||
|
||||
int dotr_item_nameidx(dataobject_t *obj, const char *name)
|
||||
{
|
||||
usrtc_node_t *node = usrtc_lookup(&obj->name_index, name);
|
||||
item_idx_t *idxnode;
|
||||
dataobject_item_t *dtr = NULL;
|
||||
|
||||
if(!node) /* not found ! */ return -1;
|
||||
|
||||
idxnode = (item_idx_t *)usrtc_node_getdata(node);
|
||||
if(!idxnode) return -1;
|
||||
else dtr = idxnode->dtr;
|
||||
|
||||
if(!dtr) return -1;
|
||||
|
||||
return dtr->id;
|
||||
}
|
||||
|
||||
static inline int __itemcmp(const dataobject_item_t *s1,
|
||||
const dataobject_item_t *s2)
|
||||
{
|
||||
int r = 0;
|
||||
if((r = strcmp(s1->name, s2->name))) return r;
|
||||
if((r = s1->len - s2->len)) return r;
|
||||
if((r = s1->type - s2->type)) return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dtocmp(const dataobject_t *src, const dataobject_t *dst)
|
||||
{
|
||||
int r = 0;
|
||||
list_node_t *iter, *siter;
|
||||
dataobject_item_t *ditem, *sitem;
|
||||
usrtc_node_t *unode;
|
||||
item_idx_t *iidx;
|
||||
|
||||
/* check name */
|
||||
if((r = strcmp(src->name, dst->name))) return r;
|
||||
/* check amount of items */
|
||||
if((r = usrtc_count((usrtc_t *)&src->id_index) - usrtc_count((usrtc_t *)&dst->id_index)))
|
||||
return r;
|
||||
|
||||
/* check items itself */
|
||||
list_for_each_safe(&src->description, iter, siter) {
|
||||
ditem = container_of(iter, dataobject_item_t, node);
|
||||
if(!(unode = usrtc_lookup((usrtc_t *)&dst->id_index, (const void *)&ditem->id)))
|
||||
return 100*ditem->id;
|
||||
|
||||
iidx = (item_idx_t *)usrtc_node_getdata(unode);
|
||||
sitem = iidx->dtr;
|
||||
|
||||
if((r = __itemcmp(ditem, sitem))) return r*ditem->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t dtolen(const dataobject_t *src)
|
||||
{
|
||||
size_t len = 0;
|
||||
list_node_t *iter, *siter;
|
||||
dataobject_item_t *ditem;
|
||||
|
||||
list_for_each_safe(&src->description, iter, siter) {
|
||||
ditem = container_of(iter, dataobject_item_t, node);
|
||||
len += ditem->len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
/*
|
||||
* 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 <ydaemon/dataobject.h>
|
||||
#include <ydaemon/cache.h>
|
||||
|
||||
int domx_init(domx_t *dt, dataobject_t *dodesc)
|
||||
{
|
||||
if(!dt || !dodesc) return EINVAL;
|
||||
|
||||
/* init first values */
|
||||
dt->dox = dodesc;
|
||||
dt->name = dodesc->name;
|
||||
dt->be = dt->cache = NULL;
|
||||
|
||||
/* init list for sntls lists */
|
||||
list_init_head(&dt->sxmp_channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int domx_set_be(domx_t *dt, void *be, const char *key)
|
||||
{
|
||||
struct be_ops *f = (struct be_ops *)be;
|
||||
domx_dsbe_t *dbe;
|
||||
|
||||
if(!dt) return EINVAL;
|
||||
if(!f || f->be_magic != BEMAGIC) return EINVAL;
|
||||
|
||||
if(!(dbe = malloc(sizeof(domx_dsbe_t)))) return ENOMEM;
|
||||
|
||||
dbe->domx = dt;
|
||||
dbe->priv = NULL;
|
||||
dbe->f = f;
|
||||
dt->be = dbe;
|
||||
|
||||
return dbe->f->init(dbe, key);
|
||||
}
|
||||
|
||||
int domx_set_cache(domx_t *dt, size_t size)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
/* paranoic check */
|
||||
if(!dt || !dt->dox) return EINVAL;
|
||||
|
||||
if(!(dt->cache = (void *)yd_cache_init(dt->dox, size)))
|
||||
r = errno;
|
||||
else r = yd_cache_start_thread(dt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int domx_set_sxmpchannel(domx_t *dt, const char *instance, int typeid, int access)
|
||||
{
|
||||
sxmp_ch_entry_t *sentry = NULL;
|
||||
|
||||
if(!dt || !instance) return EINVAL;
|
||||
|
||||
if(!(sentry = malloc(sizeof(sxmp_ch_entry_t)))) return ENOMEM;
|
||||
|
||||
/* init sntl channel entry */
|
||||
strncpy(sentry->instance, instance, 31);
|
||||
sentry->chtid = (uint16_t)typeid;
|
||||
sentry->filter = (ydm_access_filter_t)access;
|
||||
list_init_node(&sentry->node);
|
||||
|
||||
/* add this entry */
|
||||
list_add2tail(&dt->sxmp_channels, &sentry->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define __ITEMSTOFREED 32
|
||||
|
||||
int domx_get(domx_t *dt, uint64_t oid, void **refdata)
|
||||
{
|
||||
void *data;
|
||||
ydata_cache_item_t *itm;
|
||||
ydata_qitem_t *qitem;
|
||||
domx_dsbe_t *be;
|
||||
list_head_t *rsitemslist = NULL;
|
||||
list_node_t *iter, *siter;
|
||||
int r = 0;
|
||||
|
||||
/* paranoic check up */
|
||||
if(!dt || !dt->cache) return EINVAL;
|
||||
if(!(be = dt->be)) return EINVAL;
|
||||
|
||||
__retry: /* yep, that's here, because anybody can inject our data while we're trying to refresh cache */
|
||||
data = yd_cache_lookup((ydata_cache_t *)dt->cache, oid);
|
||||
|
||||
if(data) *refdata = data;
|
||||
else { /* cache miss occured */
|
||||
/* first allocate the required item within the cache */
|
||||
data = yd_cache_alloc_item((ydata_cache_t *)dt->cache, &itm);
|
||||
if(data) { /* we have a free entries ! */
|
||||
if((r = be->f->get(be, oid, data))) yd_cache_discard_alloc_item((ydata_cache_t *)dt->cache, itm);
|
||||
else {/* all is fine - confirm cache insertion */
|
||||
yd_cache_confirm_alloc_item((ydata_cache_t *)dt->cache, itm, oid);
|
||||
*refdata = data;
|
||||
}
|
||||
} else { /* we don't have free entries */
|
||||
if(!(rsitemslist = yd_cache_getrslist((ydata_cache_t *)dt->cache, __ITEMSTOFREED)))
|
||||
{ r = ENOMEM; goto __fini; }
|
||||
/* ok, now we're ready to do something - we have unplugged items clean it up then */
|
||||
list_for_each_safe(rsitemslist, iter, siter) {
|
||||
qitem = container_of(iter, ydata_qitem_t, node);
|
||||
itm = qitem->item;
|
||||
if(itm->attr & YDC_DIRTY) /* if dirty - sync, but we don't care result here - if corrupted - data is totally corrupteed*/
|
||||
be->f->set(be, itm->oid, (yd_cache_ptrbyidx((ydata_cache_t *)dt->cache, itm->idx)) + sizeof(uint32_t));
|
||||
}
|
||||
/* now we need to return there list back to the cache and retry */
|
||||
yd_cache_qitems_pullback((ydata_cache_t *)dt->cache, rsitemslist);
|
||||
goto __retry;
|
||||
}
|
||||
}
|
||||
|
||||
__fini:
|
||||
return r;
|
||||
}
|
||||
|
||||
int domx_set(domx_t *dt, uint64_t oid, const void *refdata)
|
||||
{
|
||||
domx_dsbe_t *be;
|
||||
void *data;
|
||||
ydata_cache_t *cc;
|
||||
int r = 0;
|
||||
|
||||
/* paranoic check up */
|
||||
if(!dt || !dt->cache) return EINVAL;
|
||||
if(!(be = dt->be)) return EINVAL;
|
||||
|
||||
cc = (ydata_cache_t *)dt->cache;
|
||||
|
||||
data = yd_cache_lookup(cc, oid);
|
||||
__again:
|
||||
if(data) { /* we have those object with this oid in cache */
|
||||
memcpy(data, refdata, cc->object_size); /* copy object data */
|
||||
yd_cache_item_dirtyoid(cc, oid); /* just point to the cache - dirty */
|
||||
} else { /* we're trying to set invalidated data */
|
||||
r = domx_get(dt, oid, &data);
|
||||
if(!r) goto __again;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int domx_remove(domx_t *dt, uint64_t oid)
|
||||
{
|
||||
domx_dsbe_t *be;
|
||||
void *data;
|
||||
ydata_cache_t *cc;
|
||||
|
||||
/* paranoic check up */
|
||||
if(!dt || !dt->cache) return EINVAL;
|
||||
if(!(be = dt->be)) return EINVAL;
|
||||
|
||||
cc = (ydata_cache_t *)dt->cache;
|
||||
|
||||
data = yd_cache_lookup(cc, oid);
|
||||
if(data) yd_cache_item_invalidateoid(cc, oid);
|
||||
|
||||
return be->f->remove(be, oid);
|
||||
}
|
||||
|
||||
int domx_creat(domx_t *dt, uint64_t *oid, const void *refdata)
|
||||
{
|
||||
domx_dsbe_t *be;
|
||||
oid_t r = 0;
|
||||
|
||||
/* paranoic check up */
|
||||
if(!dt || !dt->cache) return EINVAL;
|
||||
if(!(be = dt->be)) return EINVAL;
|
||||
|
||||
/* here we just create this one and nothing */
|
||||
r = be->f->creat(be, refdata);
|
||||
|
||||
if(!r) return errno;
|
||||
|
||||
*oid = r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
yd_idx_stream_t *domx_idxl_open(domx_t *dt, ydm_access_filter_t afilter,
|
||||
dataacc_pemctx_t *dacc, yd_filter_t *datafilter)
|
||||
{
|
||||
domx_dsbe_t *be;
|
||||
|
||||
/* paranoic check up */
|
||||
if(!dt || !dt->cache) {
|
||||
__einval:
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if(!(be = dt->be)) goto __einval;
|
||||
|
||||
return be->f->create_idx_stream(be, afilter, dacc, datafilter);
|
||||
}
|
||||
|
||||
void domx_idxl_close(domx_t *dt, yd_idx_stream_t *idxl)
|
||||
{
|
||||
domx_dsbe_t *be;
|
||||
|
||||
/* paranoic check up */
|
||||
if(!dt || !dt->cache) {
|
||||
__einval:
|
||||
errno = EINVAL;
|
||||
return;
|
||||
}
|
||||
if(!(be = dt->be) || !idxl) goto __einval;
|
||||
|
||||
be->f->destroy_idx_stream(idxl);
|
||||
}
|
||||
|
||||
yd_idx_stream_win_t *domx_idxl_read(domx_t *dt, yd_idx_stream_t *idxl)
|
||||
{
|
||||
domx_dsbe_t *be;
|
||||
|
||||
/* paranoic check up */
|
||||
if(!dt || !dt->cache) {
|
||||
__einval:
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if(!(be = dt->be) || !idxl) goto __einval;
|
||||
|
||||
return be->f->getportion_idx_stream(idxl);
|
||||
}
|
||||
|
@ -1,219 +0,0 @@
|
||||
/*
|
||||
* 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/>.";
|
||||
*
|
||||
*/
|
||||
|
||||
#define DMUX_USE 1
|
||||
#include <ydaemon/dataobject.h>
|
||||
|
||||
yd_filter_t *yd_filter_create(domx_t *refobj)
|
||||
{
|
||||
yd_filter_t *f = malloc(sizeof(yd_filter_t));
|
||||
|
||||
if(f) {
|
||||
f->domx = refobj;
|
||||
list_init_head(&f->filter);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void yd_filter_destroy(yd_filter_t *f)
|
||||
{
|
||||
list_head_t *lhead;
|
||||
list_node_t *iter, *siter, *liter, *lsiter;
|
||||
yd_filter_item_t *filter_item;
|
||||
yd_inlist_item_t *inl_item;
|
||||
dataobject_t *obj;
|
||||
uint64_t len;
|
||||
uint8_t type;
|
||||
|
||||
if(!f) return;
|
||||
else {
|
||||
lhead = &f->filter;
|
||||
obj = f->domx->dox;
|
||||
}
|
||||
|
||||
list_for_each_safe(lhead, iter, siter) {
|
||||
filter_item = container_of(iter, yd_filter_item_t, node);
|
||||
type = dotr_item_type(obj, filter_item->name, &len);
|
||||
if(type && len) {
|
||||
switch(filter_item->ftype) {
|
||||
case YDEQUAL:
|
||||
case YDNOTEQUAL:
|
||||
if(type == CSTR || type == TBLOB) free(filter_item->cstr);
|
||||
break;
|
||||
case YDINLIST:
|
||||
/* we must destroy the list */
|
||||
list_for_each_safe(filter_item->inlist, liter, lsiter) {
|
||||
inl_item = container_of(liter, yd_inlist_item_t, node);
|
||||
if(type == CSTR || type == TBLOB) free(inl_item->dta);
|
||||
list_del(&inl_item->node);
|
||||
free(inl_item);
|
||||
}
|
||||
free(filter_item->inlist);
|
||||
break;
|
||||
default: break; /* nothing to do */
|
||||
}
|
||||
}
|
||||
|
||||
/* free struct itself */
|
||||
list_del(&filter_item->node);
|
||||
free(filter_item);
|
||||
}
|
||||
|
||||
free(f);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static yd_filter_item_t *__alloc_init_fitem(filt_t ftype, char *name)
|
||||
{
|
||||
yd_filter_item_t *fitem = NULL;
|
||||
|
||||
if(name && (fitem = malloc(sizeof(yd_filter_item_t)))) {
|
||||
memset(fitem, 0, sizeof(yd_filter_item_t));
|
||||
fitem->name = name;
|
||||
fitem->ftype = ftype;
|
||||
list_init_node(&fitem->node);
|
||||
}
|
||||
|
||||
return fitem;
|
||||
}
|
||||
|
||||
int yd_filter_add_sf(yd_filter_t *f, const char *name, filt_t ftype,
|
||||
uint64_t vf, uint64_t vc)
|
||||
{
|
||||
yd_filter_item_t *fitem;
|
||||
dataobject_t *obj;
|
||||
uint64_t len;
|
||||
uint8_t type;
|
||||
|
||||
if(!f || !name) return EINVAL;
|
||||
|
||||
/* lookup for existing entry and check it */
|
||||
obj = f->domx->dox;
|
||||
type = dotr_item_type(obj, name, &len);
|
||||
if(!type && !len) return EINVAL;
|
||||
|
||||
/* check validity */
|
||||
if((type < CSTR) && (len > tltable[type].len)) return EINVAL; /* we cannot filter by array here */
|
||||
if(type > S64) return EINVAL; /* we're adding a simple filter rule */
|
||||
if(ftype == YDINLIST) return EINVAL; /* we're not working with that in this function */
|
||||
|
||||
fitem = __alloc_init_fitem(ftype, dotr_item_nameptr(obj, name));
|
||||
if(!fitem) return ENOMEM;
|
||||
|
||||
fitem->vf = vf;
|
||||
if(ftype == YDINLIST) fitem->vc = vc;
|
||||
|
||||
/* add this entry */
|
||||
list_add2tail(&f->filter, &fitem->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int yd_filter_add_str(yd_filter_t *f, const char *name, const char *value, int eq)
|
||||
{
|
||||
yd_filter_item_t *fitem;
|
||||
dataobject_t *obj;
|
||||
filt_t ftype;
|
||||
uint64_t len;
|
||||
uint8_t type;
|
||||
|
||||
if(!f || !name) return EINVAL;
|
||||
|
||||
/* lookup for existing entry and check it */
|
||||
obj = f->domx->dox;
|
||||
type = dotr_item_type(obj, name, &len);
|
||||
if(!type && !len) return EINVAL;
|
||||
|
||||
if(type != CSTR) return EINVAL; /* cannot do it, invalid */
|
||||
|
||||
if(!eq) ftype = YDNOTEQUAL;
|
||||
else ftype = YDEQUAL;
|
||||
|
||||
fitem = __alloc_init_fitem(ftype, dotr_item_nameptr(obj, name));
|
||||
if(!fitem) return ENOMEM;
|
||||
|
||||
if(!(fitem->cstr = strndup(value, len - sizeof(char)))) {
|
||||
free(fitem);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* add this entry */
|
||||
list_add2tail(&f->filter, &fitem->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int yd_filter_add_inlist(yd_filter_t *f, const char *name, int length, void **array)
|
||||
{
|
||||
yd_filter_item_t *fitem;
|
||||
yd_inlist_item_t *list_item;
|
||||
dataobject_t *obj;
|
||||
list_node_t *iter, *siter;
|
||||
uint64_t len;
|
||||
int i;
|
||||
uint8_t type;
|
||||
|
||||
if(!f || !name) return EINVAL;
|
||||
if(!length || !array) return EINVAL;
|
||||
|
||||
/* lookup for existing entry and check it */
|
||||
obj = f->domx->dox;
|
||||
type = dotr_item_type(obj, name, &len);
|
||||
if(!type && !len) return EINVAL;
|
||||
|
||||
fitem = __alloc_init_fitem(YDINLIST, dotr_item_nameptr(obj, name));
|
||||
if(!fitem) return ENOMEM;
|
||||
|
||||
if(!(fitem->inlist = malloc(sizeof(list_head_t)))) {
|
||||
__enomem:
|
||||
free(fitem);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* fill the list */
|
||||
for(i = 0; i < length; i++) {
|
||||
if(!(list_item = malloc(sizeof(yd_inlist_item_t)))) {
|
||||
__deep_enomem:
|
||||
list_for_each_safe(fitem->inlist, iter, siter) {
|
||||
list_item = container_of(iter, yd_inlist_item_t, node);
|
||||
if(type == CSTR || type == TBLOB) free(list_item->dta);
|
||||
list_del(&list_item->node);
|
||||
free(list_item);
|
||||
}
|
||||
/* free the list */
|
||||
free(fitem->inlist);
|
||||
goto __enomem;
|
||||
}
|
||||
if(type < CSTR) list_item->val = *(uint64_t *)array[i];
|
||||
else if(!(list_item->dta = strndup((const char *)array[i], len - sizeof(char)))) goto __deep_enomem;
|
||||
|
||||
list_init_node(&list_item->node);
|
||||
list_add2tail(fitem->inlist, &list_item->node);
|
||||
}
|
||||
|
||||
/* add this entry */
|
||||
list_add2tail(&f->filter, &fitem->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,184 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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 <ydaemon/dataobject.h>
|
||||
|
||||
yd_idx_stream_t *yd_index_stream_init(void)
|
||||
{
|
||||
yd_idx_stream_t *is = malloc(sizeof(yd_idx_stream_t));
|
||||
|
||||
if(!is) return NULL;
|
||||
else memset(is, 0, sizeof(yd_idx_stream_t));
|
||||
|
||||
list_init_head(&is->entries_wlist);
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
static inline void __empty_list(list_head_t *list)
|
||||
{
|
||||
list_node_t *iter, *siter;
|
||||
yd_wlist_node_t *wlistnode;
|
||||
|
||||
list_for_each_safe(list, iter, siter){
|
||||
wlistnode = container_of(iter, yd_wlist_node_t, node);
|
||||
list_del(&wlistnode->node);
|
||||
free(wlistnode);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void yd_index_stream_destroy(yd_idx_stream_t *is)
|
||||
{
|
||||
if(!is) return;
|
||||
else __empty_list(&is->entries_wlist);
|
||||
|
||||
free(is);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void yd_index_stream_emptylist(yd_idx_stream_t *is)
|
||||
{
|
||||
if(!is) return;
|
||||
else __empty_list(&is->entries_wlist);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
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}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -1,636 +0,0 @@
|
||||
/*
|
||||
* 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…
Reference in New Issue