Core: removed ydaemon, ydaemon is standalone now;
This commit is contained in:
		
							parent
							
								
									9b3ccae35b
								
							
						
					
					
						commit
						08b3807d09
					
				| @ -6,7 +6,7 @@ else | ||||
| EXAMPLES =  | ||||
| endif | ||||
| 
 | ||||
| SUBDIRS = include tdata sxt sexpr sxmp ydaemon tools man $(EXAMPLES) | ||||
| SUBDIRS = include tdata sxt sexpr sxmp tools man $(EXAMPLES) | ||||
| 
 | ||||
| libsxmpdocdir = ${prefix}/doc/libsxmp | ||||
| libsxmpdoc_DATA = \
 | ||||
|  | ||||
| @ -4,7 +4,6 @@ AC_INIT(libsxmp, m4_esyscmd([tr -d '\n' < VERSION.sxmp])) | ||||
| AC_SUBST([LIBSXT_VERSION], m4_esyscmd([tr -d '\n' < sxt/VERSION])) | ||||
| AC_SUBST([LIBTDATA_VERSION], m4_esyscmd([tr -d '\n' < tdata/VERSION])) | ||||
| AC_SUBST([LIBSEXPR_VERSION], m4_esyscmd([tr -d '\n' < sexpr/VERSION])) | ||||
| AC_SUBST([LIBYDAEMON_VERSION], m4_esyscmd([tr -d '\n' < ydaemon/VERSION])) | ||||
| 
 | ||||
| AC_CONFIG_HEADERS([config.h]) | ||||
| 
 | ||||
| @ -111,8 +110,6 @@ sexpr/Makefile | ||||
| sexpr/libsexpr.pc | ||||
| tdata/Makefile | ||||
| tdata/libtdata.pc | ||||
| ydaemon/Makefile | ||||
| ydaemon/libydaemon.pc | ||||
| include/Makefile | ||||
| man/Makefile | ||||
| tools/Makefile | ||||
|  | ||||
| @ -3,6 +3,5 @@ nobase_include_HEADERS = sxmp/sxmp.h sxmp/errno.h sxmp/limits.h sxmp/version.h \ | ||||
| 	sexpr/sexp_memory.h sexpr/sexp_ops.h sexpr/sexp_vis.h \
 | ||||
| 	tdata/bitwise.h tdata/idx_allocator.h tdata/macro.h tdata/tree.h \
 | ||||
| 	tdata/usrtc.h tdata/list.h tdata/ctrie.h \
 | ||||
| 	ydaemon/ydaemon.h ydaemon/cache.h ydaemon/dataobject.h \
 | ||||
| 	sxt/sxtkey.h sxt/lcrypt.h sxt/fe25519.h sxt/ge25519.h \
 | ||||
| 	sxt/sc25519.h | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										465
									
								
								ydaemon/cache.c
									
									
									
									
									
								
							
							
						
						
									
										465
									
								
								ydaemon/cache.c
									
									
									
									
									
								
							| @ -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; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										135
									
								
								ydaemon/daemon.c
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								ydaemon/daemon.c
									
									
									
									
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										226
									
								
								ydaemon/data.c
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								ydaemon/data.c
									
									
									
									
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										249
									
								
								ydaemon/domx.c
									
									
									
									
									
								
							
							
						
						
									
										249
									
								
								ydaemon/domx.c
									
									
									
									
									
								
							| @ -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); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										219
									
								
								ydaemon/filter.c
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								ydaemon/filter.c
									
									
									
									
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										241
									
								
								ydaemon/module.c
									
									
									
									
									
								
							
							
						
						
									
										241
									
								
								ydaemon/module.c
									
									
									
									
									
								
							| @ -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; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										636
									
								
								ydaemon/values.c
									
									
									
									
									
								
							
							
						
						
									
										636
									
								
								ydaemon/values.c
									
									
									
									
									
								
							| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user