diff --git a/src/include/66/graph.h b/src/include/66/graph.h index 393256c427673b9e8e2a49514b95a04489aab829..93069234b062ae84846c39aeb2acf5bda7502c07 100644 --- a/src/include/66/graph.h +++ b/src/include/66/graph.h @@ -25,10 +25,9 @@ #include <66/hash.h> extern void graph_build_tree(graph_t *g, struct resolve_hash_tree_s **htres, char const *base, resolve_tree_master_enum_t field) ; -extern void graph_build_service(graph_t *g, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint32_t flag) ; +extern void graph_build_service(graph_t *g, struct resolve_hash_s **hres, ssexec_t *info, uint32_t flag) ; extern int graph_compute_dependencies(graph_t *g, char const *vertex, char const *edge, uint8_t requiredby) ; -extern void graph_compute_visit(resolve_service_t *ares, unsigned int aresid, unsigned int *visit, unsigned int *list, graph_t *graph, unsigned int *nservice, uint8_t requiredby) ; - +extern void graph_compute_visit(struct resolve_hash_s hres, unsigned int *visit, unsigned int *list, graph_t *graph, unsigned int *nservice, uint8_t requiredby) ; extern int graph_build_service_bytree(graph_t *g, char const *tree, uint8_t what, uint8_t is_supervised) ; extern int graph_build_service_bytree_from_src(graph_t *g, char const *src, uint8_t what) ; diff --git a/src/include/66/hash.h b/src/include/66/hash.h new file mode 100644 index 0000000000000000000000000000000000000000..3fb3d326c34ff66d2726ec887535d3f233104b2f --- /dev/null +++ b/src/include/66/hash.h @@ -0,0 +1,1141 @@ +/* +Copyright (c) 2003-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SS_HASH_H +#define SS_HASH_H + +#define UTHASH_VERSION 2.3.0 + +#include <string.h> /* memcmp, memset, strlen */ +#include <stddef.h> /* ptrdiff_t */ +#include <stdlib.h> /* exit */ + +#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT +/* This codepath is provided for backward compatibility, but I plan to remove it. */ +#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead" +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT +#else +#include <stdint.h> /* uint8_t, uint32_t */ +#endif + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__MCST__) /* Elbrus C Compiler */ +#define DECLTYPE(x) (__typeof(x)) +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE(x) +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while (0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while (0) +#endif + +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_bzero +#define uthash_bzero(a,n) memset(a,'\0',n) +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif + +#ifndef HASH_FUNCTION +#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) +#endif + +#ifndef HASH_KEYCMP +#define HASH_KEYCMP(a,b,n) memcmp(a,b,n) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +#ifndef HASH_NONFATAL_OOM +#define HASH_NONFATAL_OOM 0 +#endif + +#if HASH_NONFATAL_OOM +/* malloc failures can be recovered from */ + +#ifndef uthash_nonfatal_oom +#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) +#define IF_HASH_NONFATAL_OOM(x) x + +#else +/* malloc failures result in lost memory, hash tables are unusable */ + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") +#define IF_HASH_NONFATAL_OOM(x) + +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) + +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ +} while (0) + +#define HASH_VALUE(keyptr,keylen,hashv) \ +do { \ + HASH_FUNCTION(keyptr, keylen, hashv); \ +} while (0) + +#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ + } \ + } \ +} while (0) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl,oomed) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh,head,oomed) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } else { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } \ + ) \ + } \ + } \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ +} while (0) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ +} while (0) + +#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ +} while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ +do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ +} while (0) + +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + do { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) + +#ifdef NO_DECLTYPE +#undef HASH_AKBI_INNER_LOOP +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + char *_hs_saved_head = (char*)(head); \ + do { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) +#endif + +#if HASH_NONFATAL_OOM + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + if (!(oomed)) { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + if (oomed) { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } else { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } else { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ +} while (0) + +#else + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ +} while (0) + +#endif + + +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ +} while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ +do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (const void*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ +} while (0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv,num_bkts,bkt) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ +} while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) + +#define HASH_DELETE_HH(hh,head,delptrhh) \ +do { \ + const struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ +} while (0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ +do { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ +} while (0) +#define HASH_ADD_STR(head,strfield,add) \ +do { \ + unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ +} while (0) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ +do { \ + unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ +} while (0) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#include <stdio.h> /* fprintf, stderr */ +#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head,where) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void*)_thh->hh_prev, (void*)_prev); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char*)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void*)_thh->prev, (void*)_prev); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head,where) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include <unistd.h> to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,hashv) \ +do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx + * (archive link: https://archive.is/Ivcan ) + */ +#define HASH_SAX(key,keylen,hashv) \ +do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char*)(key); \ + hashv = 0; \ + for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,hashv) \ +do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char*)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ +} while (0) + +#define HASH_OAT(key,keylen,hashv) \ +do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ +} while (0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,hashv) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned const char *_hj_key=(unsigned const char*)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ + case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ + case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ + default: ; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ +} while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,hashv) \ +do { \ + unsigned const char *_sfh_key=(unsigned const char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + break; \ + default: ; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ +} while (0) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ +do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ +} while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ +do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ + && !(addhh)->tbl->noexpand) { \ + HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + HASH_DEL_IN_BKT(head,addhh); \ + } \ + ) \ + } \ +} while (0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(head,delhh) \ +do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ +} while (0) + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + if (!_he_new_buckets) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero(_he_new_buckets, \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ + _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ + ((tbl)->ineff_expands+1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ +} while (0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ + )) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail != NULL ) { \ + _hs_tail->next = ((_hs_e != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = ((_hs_tail != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if ((src) != NULL) { \ + for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ + _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + } \ + ) \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + } \ + ) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if ((head) != NULL) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ +} while (0) + +#define HASH_OVERHEAD(hh,head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + const void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + + +#endif diff --git a/src/include/66/module.h b/src/include/66/module.h index 1f9c7ced72696e457c93a79107464f7995038bcc..bc0e16224be2074a54d824838507fa80dbd5dbaf 100644 --- a/src/include/66/module.h +++ b/src/include/66/module.h @@ -35,7 +35,7 @@ #define SS_MODULE_REQUIREDBY "/requiredby" #define SS_MODULE_REQUIREDBY_LEN (sizeof SS_MODULE_REQUIREDBY - 1) -extern void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force) ; +extern void parse_module(resolve_service_t *res, struct resolve_hash_s **hres, ssexec_t *info, uint8_t force) ; extern void parse_module_check_dir(char const *src,char const *dir) ; extern void parse_module_check_name(char const *src, char const *name) ; diff --git a/src/include/66/parse.h b/src/include/66/parse.h index 83b0e8371151358f782ed2c542bf85149ae4e63a..5022e928d4d954e339f1517496214beeed4f09bd 100644 --- a/src/include/66/parse.h +++ b/src/include/66/parse.h @@ -47,9 +47,10 @@ extern void parse_cleanup(resolve_service_t *res, char const *tmpdir, uint8_t fo /** main */ extern void start_parser(char const *sv, ssexec_t *info, uint8_t disable_module, char const *directory_forced) ; -extern void parse_service(char const *sv, ssexec_t *info, uint8_t force, uint8_t conf) ; -extern int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) ; -extern int parse_interdependences(char const *service, char const *list, unsigned int listlen, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) ; +extern void parse_service(struct resolve_hash_s **href, char const *sv, ssexec_t *info, uint8_t force, uint8_t conf) ; +extern int parse_frontend(char const *sv, struct resolve_hash_s **hres, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) ; +extern int parse_interdependences(char const *service, char const *list, unsigned int listlen, struct resolve_hash_s **hres, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) ; +extern void parse_append_logger(struct resolve_hash_s **hres, resolve_service_t *res, ssexec_t *info) ; /** split */ extern int parse_section(stralloc *secname, char const *str, size_t *pos) ; @@ -74,13 +75,19 @@ extern int parse_clean_list(stralloc *sa, char const *str) ; extern int parse_clean_line(char *str) ; extern int parse_mandatory(resolve_service_t *res) ; extern void parse_error(int ierr, int idsec, int idkey) ; -extern void parse_rename_interdependences(resolve_service_t *res, char const *prefix, resolve_service_t *ares, unsigned int *areslen) ; +extern void parse_rename_interdependences(resolve_service_t *res, char const *prefix, struct resolve_hash_s **hres, ssexec_t *info) ; extern void parse_db_migrate(resolve_service_t *res, ssexec_t *info) ; /** module */ -extern void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force) ; +extern void parse_module(resolve_service_t *res, struct resolve_hash_s **hres, ssexec_t *info, uint8_t force) ; /** resolve */ -extern void parse_compute_resolve(unsigned int idx, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info) ; +extern void parse_compute_resolve(resolve_service_t *res, ssexec_t *info) ; +extern uint32_t compute_src_servicedir(resolve_wrapper_t_ref wres, ssexec_t *info) ; +extern uint32_t compute_live_servicedir(resolve_wrapper_t_ref wres, ssexec_t *info) ; +extern uint32_t compute_status(resolve_wrapper_t_ref wres, ssexec_t *info) ; +extern uint32_t compute_scan_dir(resolve_wrapper_t_ref wres, ssexec_t *info) ; +extern uint32_t compute_state_dir(resolve_wrapper_t_ref wres, ssexec_t *info, char const *folder) ; +extern uint32_t compute_pipe_service(resolve_wrapper_t_ref wres, ssexec_t *info, char const *name) ; #endif diff --git a/src/include/66/sanitize.h b/src/include/66/sanitize.h index d5cd05ec3615f28abfb6b3be94eb655091fe815c..47d14c6df7643e2b8dba9b3bf061b31c4e182910 100644 --- a/src/include/66/sanitize.h +++ b/src/include/66/sanitize.h @@ -27,7 +27,7 @@ extern void sanitize_source(char const *name, ssexec_t *info, uint32_t flag) ; extern int sanitize_fdholder(resolve_service_t *res, ss_state_t *sta, uint32_t flag, uint8_t init) ; extern int sanitize_livestate(resolve_service_t *res, ss_state_t *sta) ; extern int sanitize_scandir(resolve_service_t *res, ss_state_t *sta) ; -extern void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_service_t *ares, unsigned int areslen) ; +extern void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, struct resolve_hash_s **hres) ; extern void sanitize_graph(ssexec_t *info) ; /** @Return 0 the service is already written * @Return 1 the service will be overwritten diff --git a/src/include/66/service.h b/src/include/66/service.h index 81c42137bb652f3bc0a121c4d7f1b9de960edb68..3ff38f5b97833ba0ee3d8db62220acb07d745583 100644 --- a/src/include/66/service.h +++ b/src/include/66/service.h @@ -25,6 +25,7 @@ #include <66/ssexec.h> #include <66/resolve.h> +#include <66/hash.h> typedef struct resolve_service_addon_path_s resolve_service_addon_path_t, *resolve_service_addon_path_t_ref ; struct resolve_service_addon_path_s @@ -302,6 +303,15 @@ enum resolve_service_enum_e } ; +struct resolve_hash_s { + char name[SS_MAX_SERVICE_NAME + 1] ; // name as key + uint8_t visit ; + resolve_service_t res ; + UT_hash_handle hh ; + +} ; +#define RESOLVE_HASH_ZERO { 0, 0, RESOLVE_SERVICE_ZERO, NULL } + extern resolve_field_table_t resolve_service_field_table[] ; extern int service_cmp_basedir(char const *dir) ; @@ -310,8 +320,6 @@ extern int service_frontend_path(stralloc *sasrc,char const *sv, uid_t owner,cha extern int service_frontend_src(stralloc *sasrc, char const *name, char const *src, char const **exclude) ; extern int service_is_g(char const *name, uint32_t flag) ; extern int service_get_treename(char *atree, char const *name, uint32_t flag) ; -extern void service_resolve_array_free(resolve_service_t *ares, unsigned int areslen) ; -extern int service_resolve_array_search(resolve_service_t *ares, unsigned int areslen, char const *name) ; extern int service_resolve_copy(resolve_service_t *dst, resolve_service_t *res) ; extern int service_resolve_get_field_tosa(stralloc *sa, resolve_service_t *res, resolve_service_enum_t field) ; extern int service_resolve_modify_field(resolve_service_t *res, resolve_service_enum_t field, char const *data) ; @@ -319,7 +327,7 @@ extern int service_resolve_read_cdb(cdb *c, resolve_service_t *res) ; extern void service_resolve_write(resolve_service_t *res) ; extern void service_resolve_write_remote(resolve_service_t *res, char const *dst, uint8_t force) ; extern int service_resolve_write_cdb(cdbmaker *c, resolve_service_t *sres) ; -extern void service_enable_disable(graph_t *g, unsigned int idx, resolve_service_t *ares, unsigned int areslen, uint8_t action, unsigned int *visit, uint8_t propagate, ssexec_t *info) ; +extern void service_enable_disable(graph_t *g, struct resolve_hash_s *hash, struct resolve_hash_s **hres, uint8_t action, uint8_t propagate, ssexec_t *info) ; extern void service_switch_tree(resolve_service_t *res, char const *base, char const *totreename, ssexec_t *info) ; extern void service_db_migrate(resolve_service_t *old, resolve_service_t *new, char const *base, uint8_t requiredby) ; /* avoid circular dependencies by prototyping the ss_state_t instead @@ -327,9 +335,14 @@ extern void service_db_migrate(resolve_service_t *old, resolve_service_t *new, c typedef struct ss_state_s ss_state_t, *ss_state_t_ref ; /** Graph */ -extern void service_graph_g(char const *slist, size_t slen, graph_t *graph, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint32_t flag) ; -extern void service_graph_collect(graph_t *g, char const *alist, size_t alen, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint32_t flag) ; -extern void service_graph_build(graph_t *g, resolve_service_t *ares, unsigned int areslen, uint32_t flag) ; - +extern void service_graph_g(char const *slist, size_t slen, graph_t *graph, struct resolve_hash_s **hres, ssexec_t *info, uint32_t flag) ; +extern void service_graph_collect(graph_t *g, char const *alist, size_t alen, struct resolve_hash_s **hres, ssexec_t *info, uint32_t flag) ; +extern void service_graph_build(graph_t *g, struct resolve_hash_s **hres, uint32_t flag) ; + +/** Hash */ +extern int hash_add(struct resolve_hash_s **hres, char const *name, resolve_service_t res) ; +extern struct resolve_hash_s *hash_search(struct resolve_hash_s **hres, char const *name) ; +extern int hash_count(struct resolve_hash_s **hres) ; +extern void hash_free(struct resolve_hash_s **hres) ; #endif diff --git a/src/include/66/svc.h b/src/include/66/svc.h index d378f0452a24e491efe3f0e650386dc8c51061ed..33e9bb1321eafe4f532d18fb761130e9048bb1fa 100644 --- a/src/include/66/svc.h +++ b/src/include/66/svc.h @@ -40,7 +40,7 @@ struct pidservice_s { int pipe[2] ; pid_t pid ; - int aresid ; // id at array ares + resolve_service_t *res ; // resolve of service through hash unsigned int vertex ; // id at graph_hash_t struct uint8_t state ; int nedge ; @@ -54,7 +54,7 @@ struct pidservice_s #define PIDSERVICE_ZERO { \ .pipe[0] = -1, \ .pipe[1] = -1, \ - .aresid = -1, \ + .res = NULL, \ .vertex = -1, \ .state = 0, \ .nedge = 0, \ @@ -63,13 +63,13 @@ struct pidservice_s .notif = { 0 } \ } -extern void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apids, graph_t *g, resolve_service_t *ares, unsigned int areslen, ssexec_t *info, uint8_t requiredby, uint32_t flag) ; -extern int svc_launch(pidservice_t *apids, unsigned int napid, uint8_t what, graph_t *graph, resolve_service_t *ares, unsigned int areslen, ssexec_t *info, char const *rise, uint8_t rise_opt, uint8_t msg, char const *signal, uint8_t propagate) ; -extern int svc_compute_ns(resolve_service_t *ares, unsigned int areslen, unsigned int aresid, uint8_t what, ssexec_t *info, char const *updown, uint8_t opt_updown, uint8_t reloadmsg,char const *data, uint8_t propagate, pidservice_t *apids, unsigned int napids) ; +extern void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apids, graph_t *g, struct resolve_hash_s **hres, ssexec_t *info, uint8_t requiredby, uint32_t flag) ; +extern int svc_launch(pidservice_t *apids, unsigned int napid, uint8_t what, graph_t *graph, struct resolve_hash_s **hres, ssexec_t *info, char const *rise, uint8_t rise_opt, uint8_t msg, char const *signal, uint8_t propagate) ; +extern int svc_compute_ns(resolve_service_t *res, uint8_t what, ssexec_t *info, char const *updown, uint8_t opt_updown, uint8_t reloadmsg,char const *data, uint8_t propagate, pidservice_t *apids, unsigned int napids) ; extern int svc_scandir_ok (char const *dir) ; extern int svc_scandir_send(char const *scandir,char const *signal) ; extern int svc_send_wait(char const *const *list, unsigned int nservice, char **sig, unsigned int siglen, ssexec_t *info) ; -extern void svc_unsupervise(unsigned int *alist, unsigned int alen, graph_t *g, resolve_service_t *ares, unsigned int areslen, ssexec_t *info) ; +extern void svc_unsupervise(unsigned int *alist, unsigned int alen, graph_t *g, struct resolve_hash_s **hres, ssexec_t *info) ; extern void svc_send_fdholder(char const *socket, char const *signal) ; #endif diff --git a/src/lib66/exec/ssexec_disable.c b/src/lib66/exec/ssexec_disable.c index a1cbbfc9c8bb132303088bd16651aa69dea7c986..5a57cfe3802bd7e4ccd9fae246f3d3f11ec1590d 100644 --- a/src/lib66/exec/ssexec_disable.c +++ b/src/lib66/exec/ssexec_disable.c @@ -18,10 +18,8 @@ #include <oblibs/log.h> #include <oblibs/types.h> #include <oblibs/string.h> -#include <oblibs/sastr.h> #include <skalibs/sgetopt.h> -#include <skalibs/stralloc.h> #include <66/constants.h> #include <66/ssexec.h> @@ -40,15 +38,12 @@ int ssexec_disable(int argc, char const *const *argv, ssexec_t *info) int n = 0, e = 1 ; size_t pos = 0 ; graph_t graph = GRAPH_ZERO ; - stralloc sa = STRALLOC_ZERO ; + struct resolve_hash_s *hres = NULL ; + struct resolve_hash_s tostop[argc] ; - unsigned int areslen = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; - unsigned int visit[SS_MAX_SERVICE + 1] ; + memset(tostop, 0, sizeof(struct resolve_hash_s) * argc) ; - memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; - { subgetopt l = SUBGETOPT_ZERO ; @@ -95,27 +90,28 @@ int ssexec_disable(int argc, char const *const *argv, ssexec_t *info) log_usage(info->usage, "\n", info->help) ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- try to parse it first") ; for (; n < argc ; n++) { - int aresid = service_resolve_array_search(ares, areslen, argv[n]) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(&hres, argv[n]) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", argv[n], " not available -- did you parse it?") ; - service_enable_disable(&graph, aresid, ares, areslen, 0, visit, propagate, info) ; + service_enable_disable(&graph, hash, &hres, 0, propagate, info) ; - if (!sastr_add_string(&sa, argv[n])) - log_dieu(LOG_EXIT_SYS, "add string") ; + tostop[n] = *hash ; } - if (stop && sa.len) { + graph_free_all(&graph) ; + e = 0 ; + + if (stop && n) { - size_t len = sastr_nelement(&sa) ; - int nargc = 3 + len ; + int nargc = 3 + n ; char const *prog = PROG ; char const *newargv[nargc] ; unsigned int m = 0 ; @@ -128,8 +124,8 @@ int ssexec_disable(int argc, char const *const *argv, ssexec_t *info) newargv[m++] = "stop" ; newargv[m++] = "-u" ; - FOREACH_SASTR(&sa, pos) - newargv[m++] = sa.s + pos ; + for (; pos < n ; pos++) + newargv[m++] = tostop[pos].name ; newargv[m] = 0 ; PROG = "stop" ; @@ -138,15 +134,9 @@ int ssexec_disable(int argc, char const *const *argv, ssexec_t *info) info->help = help ; info->usage = usage ; - - goto end ; } - e = 0 ; - end: - stralloc_free(&sa) ; - service_resolve_array_free(ares, areslen) ; - graph_free_all(&graph) ; + hash_free(&hres) ; return e ; } diff --git a/src/lib66/exec/ssexec_enable.c b/src/lib66/exec/ssexec_enable.c index 837ba083a2604af5f30e122e1c421944f18e4402..9fda2a90365e8ec908228adfbff4d62869f1b87a 100644 --- a/src/lib66/exec/ssexec_enable.c +++ b/src/lib66/exec/ssexec_enable.c @@ -16,7 +16,6 @@ #include <oblibs/log.h> #include <oblibs/types.h> // FLAGS -#include <oblibs/stack.h> #include <skalibs/sgetopt.h> @@ -37,14 +36,12 @@ int ssexec_enable(int argc, char const *const *argv, ssexec_t *info) int n = 0, e = 1 ; size_t pos = 0 ; graph_t graph = GRAPH_ZERO ; + struct resolve_hash_s *hres = NULL ; + struct resolve_hash_s tostart[argc] ; - unsigned int areslen = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; - unsigned int visit[SS_MAX_SERVICE + 1] ; + memset(tostart, 0, sizeof(struct resolve_hash_s) * argc) ; - memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; - { subgetopt l = SUBGETOPT_ZERO ; @@ -80,52 +77,46 @@ int ssexec_enable(int argc, char const *const *argv, ssexec_t *info) if (argc < 1) log_usage(info->usage, "\n", info->help) ; - _init_stack_(stk, argc * SS_MAX_TREENAME) ; - for(; n < argc ; n++) sanitize_source(argv[n], info, flag) ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- please make a bug report") ; for (n = 0 ; n < argc ; n++) { - int aresid = service_resolve_array_search(ares, areslen, argv[n]) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(&hres, argv[n]) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", argv[n], " not available -- did you parse it?") ; - service_enable_disable(&graph, aresid, ares, areslen, 1, visit, propagate, info) ; + service_enable_disable(&graph, hash, &hres, 1, propagate, info) ; if (info->opt_tree) { - service_switch_tree(&ares[aresid], info->base.s, info->treename.s, info) ; + service_switch_tree(&hash->res, info->base.s, info->treename.s, info) ; - if (ares[aresid].logger.want && ares[aresid].type == TYPE_CLASSIC) { + if (hash->res.logger.want && hash->res.type == TYPE_CLASSIC) { - int logid = service_resolve_array_search(ares, areslen, ares[aresid].sa.s + ares[aresid].logger.name) ; - if (logid < 0) - log_die(LOG_EXIT_USER, "service: ", ares[aresid].sa.s + ares[aresid].logger.name, " not available -- please make a bug report") ; + struct resolve_hash_s *log = hash_search(&hres, hash->res.sa.s + hash->res.logger.name) ; + if (log == NULL) + log_die(LOG_EXIT_USER, "service: ", hash->res.sa.s + hash->res.logger.name, " not available -- please make a bug report") ; - service_switch_tree(&ares[logid], info->base.s, info->treename.s, info) ; + service_switch_tree(&log->res, info->base.s, info->treename.s, info) ; } } - if (!stack_add_g(&stk, argv[n])) - log_dieu(LOG_EXIT_SYS, "add string") ; + tostart[n] = *hash ; } - service_resolve_array_free(ares, areslen) ; graph_free_all(&graph) ; - e = 0 ; - if (start && stk.len) { + if (start && n) { - size_t len = stack_count_element(&stk) ; - int nargc = 2 + len ; + int nargc = 2 + n ; char const *prog = PROG ; char const *newargv[nargc] ; unsigned int m = 0 ; @@ -137,8 +128,8 @@ int ssexec_enable(int argc, char const *const *argv, ssexec_t *info) info->usage = usage_start ; newargv[m++] = "start" ; - FOREACH_STK(&stk, pos) - newargv[m++] = stk.s + pos ; + for (; pos < n ; pos++) + newargv[m++] = tostart[pos].name ; newargv[m] = 0 ; PROG = "start" ; @@ -149,5 +140,7 @@ int ssexec_enable(int argc, char const *const *argv, ssexec_t *info) info->usage = usage ; } + hash_free(&hres) ; + return e ; } diff --git a/src/lib66/exec/ssexec_parse.c b/src/lib66/exec/ssexec_parse.c index 316268e9d3ad3f73427cf6b7a9aa4384186d4d4b..b5d5311b246dc5f4eaa53b79cfc6312b46a8e034 100644 --- a/src/lib66/exec/ssexec_parse.c +++ b/src/lib66/exec/ssexec_parse.c @@ -113,13 +113,15 @@ int ssexec_parse(int argc, char const *const *argv, ssexec_t *info) * service can be a directory name. In this case * we parse all services inside. */ size_t pos = 0 ; + struct resolve_hash_s *hres = NULL ; FOREACH_SASTR(&sa, pos) - parse_service(sa.s + pos, info, force, conf) ; - } + parse_service(&hres, sa.s + pos, info, force, conf) ; - sanitize_graph(info) ; + hash_free(&hres) ; + } stralloc_free(&sa) ; + sanitize_graph(info) ; return 0 ; } diff --git a/src/lib66/exec/ssexec_reconfigure.c b/src/lib66/exec/ssexec_reconfigure.c index dee2e491a682f70ba6f2114955ffdf4e3a306c2d..2cd26764402e217ea528e5a311f6d5cc5c6049f6 100644 --- a/src/lib66/exec/ssexec_reconfigure.c +++ b/src/lib66/exec/ssexec_reconfigure.c @@ -17,7 +17,6 @@ #include <oblibs/log.h> #include <oblibs/types.h> #include <oblibs/graph.h> -#include <oblibs/stack.h> #include <oblibs/string.h> #include <skalibs/sgetopt.h> @@ -32,7 +31,6 @@ #include <66/service.h> #include <66/constants.h> #include <66/tree.h> -#include <skalibs/djbunix.h> int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) { @@ -42,17 +40,17 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) uint32_t flag = 0 ; uint8_t siglen = 0, issupervised = 0 ; graph_t graph = GRAPH_ZERO ; - - unsigned int areslen = 0, list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], tostate[SS_MAX_SERVICE + 1], ntostate = 0, nservice = 0, n = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; + resolve_service_t_ref pres = 0 ; + struct resolve_hash_s tostate[argc] ; + struct resolve_hash_s toenable[argc] ; + unsigned int list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], ntostate = 0, ntoenable = 0, nservice = 0, n = 0 ; ss_state_t sta = STATE_ZERO ; - resolve_service_t res = RESOLVE_SERVICE_ZERO ; - resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ; - _init_stack_(stk, argc * SS_MAX_SERVICE_NAME) ; memset(list, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; - memset(tostate, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; + memset(tostate, 0, argc * sizeof(struct resolve_hash_s)) ; + memset(toenable, 0, argc * sizeof(struct resolve_hash_s)) ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_TOPARSE|STATE_FLAGS_WANTUP) ; { @@ -87,38 +85,38 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) log_usage(info->usage, "\n", info->help) ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- have you already parsed a service?") ; for (; n < argc ; n++) { - int aresid = service_resolve_array_search(ares, areslen, argv[n]) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(&hres, argv[n]) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", argv[n], " not available -- did you parse it?") ; - char status[strlen(ares[aresid].sa.s + ares[aresid].path.servicedir) + SS_STATE_LEN + 1] ; + pres = &hash->res ; + char status[strlen(pres->sa.s + pres->path.servicedir) + SS_STATE_LEN + 1] ; - auto_strings(status, ares[aresid].sa.s + ares[aresid].path.servicedir, SS_STATE) ; + auto_strings(status, pres->sa.s + pres->path.servicedir, SS_STATE) ; - if (!state_read(&sta, &ares[aresid])) + if (!state_read(&sta, pres)) log_dieu(LOG_EXIT_SYS, "read state file of: ", argv[n]) ; sta.toparse = STATE_FLAGS_TRUE ; - if (!state_write(&sta, &ares[aresid])) + if (!state_write(&sta, pres)) log_dieusys(LOG_EXIT_SYS, "write status file of: ", argv[n]) ; /** need to reverse the previous state change to * for current live service.*/ - tostate[ntostate++] = aresid ; + tostate[ntostate++] = *hash ; issupervised = sta.issupervised == STATE_FLAGS_TRUE ? 1 : 0 ; - if (ares[aresid].enabled && !ares[aresid].inns) - if (!stack_add_g(&stk, argv[n])) - log_dieu(LOG_EXIT_SYS, "add string") ; + if (pres->enabled && !pres->inns) + toenable[ntoenable++] = *hash ; if (!issupervised) { /* only force to parse it again */ @@ -131,7 +129,7 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) /** services of group boot cannot be restarted, the changes will appear only at * next reboot.*/ - r = tree_ongroups(ares[aresid].sa.s + ares[aresid].path.home, ares[aresid].sa.s + ares[aresid].treename, TREE_GROUPS_BOOT) ; + r = tree_ongroups(pres->sa.s + pres->path.home, pres->sa.s + pres->treename, TREE_GROUPS_BOOT) ; if (r < 0) log_dieu(LOG_EXIT_SYS, "get groups of service: ", argv[n]) ; @@ -139,7 +137,7 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) if (r) continue ; - graph_compute_visit(ares, aresid, visit, list, &graph, &nservice, 1) ; + graph_compute_visit(*hash, visit, list, &graph, &nservice, 1) ; } } @@ -208,12 +206,12 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) /** live of the service still exist. * Reverse to the previous state of the toparse flag. */ - if (state_read_remote(&sta, ares[tostate[n]].sa.s + ares[tostate[n]].live.statedir)) { + if (state_read_remote(&sta, tostate[n].res.sa.s + tostate[n].res.live.statedir)) { sta.toparse = STATE_FLAGS_FALSE ; - if (!state_write_remote(&sta, ares[tostate[n]].sa.s + ares[tostate[n]].live.statedir)) - log_warnusys("write status file of: ", ares[tostate[n]].sa.s + ares[tostate[n]].live.statedir) ; + if (!state_write_remote(&sta, tostate[n].res.sa.s + tostate[n].res.live.statedir)) + log_warnusys("write status file of: ", tostate[n].res.sa.s + tostate[n].res.live.statedir) ; } } @@ -251,11 +249,11 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) info->usage = usage ; } - if (stk.len) { + if (ntoenable) { /** enable again the service if it was enabled */ unsigned int m = 0 ; - int nargc = 2 + stk.count ; + int nargc = 2 + ntoenable ; char const *prog = PROG ; char const *newargv[nargc] ; @@ -268,10 +266,10 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) newargv[m++] = "enable" ; n = 0 ; - FOREACH_STK(&stk, n) { + for (; n < ntoenable ; n++) { - char *name = stk.s + n ; - if (get_rstrlen_until(name,SS_LOG_SUFFIX) < 0) + char *name = toenable[n].name ; + if (get_rstrlen_until(name,SS_LOG_SUFFIX) < 0) newargv[m++] = name ; } @@ -286,10 +284,8 @@ int ssexec_reconfigure(int argc, char const *const *argv, ssexec_t *info) } freed: - resolve_free(wres) ; - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; graph_free_all(&graph) ; return e ; - } diff --git a/src/lib66/exec/ssexec_reload.c b/src/lib66/exec/ssexec_reload.c index bda2d1ac2bf9b182da4367ac86cf5170f86ae423..3ebfbb1d2127b4790fcd1d0bd4335483426bb20b 100644 --- a/src/lib66/exec/ssexec_reload.c +++ b/src/lib66/exec/ssexec_reload.c @@ -37,9 +37,8 @@ int ssexec_reload(int argc, char const *const *argv, ssexec_t *info) uint32_t flag = 0 ; uint8_t siglen = 2 ; graph_t graph = GRAPH_ZERO ; - - unsigned int areslen = 0, m = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; + unsigned int m = 0 ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; @@ -105,20 +104,20 @@ int ssexec_reload(int argc, char const *const *argv, ssexec_t *info) } /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- please make a bug report") ; for (n = 0 ; n < argc ; n++) { - int aresid = service_resolve_array_search(ares, areslen, argv[n]) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(&hres, argv[n]) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", *argv, " not available -- did you pars it?") ; - if (ares[aresid].type == TYPE_ONESHOT) { + if (hash->res.type == TYPE_ONESHOT) { nargc++ ; - nargv[m++] = ares[aresid].sa.s + ares[aresid].name ; + nargv[m++] = hash->res.sa.s + hash->res.name ; } } @@ -171,7 +170,7 @@ int ssexec_reload(int argc, char const *const *argv, ssexec_t *info) } err: - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; graph_free_all(&graph) ; return r ; diff --git a/src/lib66/exec/ssexec_remove.c b/src/lib66/exec/ssexec_remove.c index d84de2cebf24b4d55b7156ca1286c1ad4ff897d4..27fa39919de97f43c3ecfc9360c117acc5f57a23 100644 --- a/src/lib66/exec/ssexec_remove.c +++ b/src/lib66/exec/ssexec_remove.c @@ -38,6 +38,7 @@ #include <66/constants.h> #include <66/svc.h> #include <66/utils.h> +#include <66/hash.h> static void auto_remove(char const *path) { @@ -46,7 +47,7 @@ static void auto_remove(char const *path) log_dieusys(LOG_EXIT_SYS, "remove directory: ", path) ; } -static void remove_deps(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, stralloc *sa, ssexec_t *info) +static void remove_deps(resolve_service_t *res, struct resolve_hash_s **hres, stralloc *sa, ssexec_t *info) { if (!res->dependencies.nrequiredby) @@ -82,10 +83,12 @@ static void remove_deps(resolve_service_t *res, resolve_service_t *ares, unsigne if (!sastr_add_string(sa, stk.s + pos)) log_dieusys(LOG_EXIT_SYS, "add service: ", stk.s + pos, " to selection") ; - ares[(*areslen)++] = dres ; + log_trace("add service: ", stk.s + pos, " to the service selection") ; + if (!hash_add(hres, stk.s + pos, dres)) + log_dieu(LOG_EXIT_SYS, "append service selection with: ", stk.s + pos) ; if (dres.dependencies.nrequiredby) - remove_deps(&dres, ares, areslen, sa, info) ; + remove_deps(&dres, hres, sa, info) ; } free(wres) ; @@ -109,9 +112,10 @@ static void remove_service(resolve_service_t *res, ssexec_t *info) resolve_wrapper_t_ref lwres = resolve_set_struct(DATA_SERVICE, &lres) ; r = resolve_read_g(lwres, info->base.s, res->sa.s + res->logger.name) ; - if (r <= 0) - log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", res->sa.s + res->logger.name) ; - + if (r <= 0) { + log_warnusys("read resolve file of: ", res->sa.s + res->logger.name, " -- ignoring it") ; + goto end ; + } auto_remove(lres.sa.s + lres.path.servicedir) ; auto_remove(lres.sa.s + lres.logger.destination) ; @@ -130,7 +134,7 @@ static void remove_service(resolve_service_t *res, ssexec_t *info) resolve_free(lwres) ; } - + end: auto_strings(sym, res->sa.s + res->path.home, SS_SYSTEM, SS_RESOLVE, SS_SERVICE, "/", res->sa.s + res->name) ; log_trace("remove symlink: ", sym) ; @@ -150,10 +154,10 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) size_t pos = 0 ; uint32_t flag = 0 ; uint8_t siglen = 0 ; - unsigned int areslen = 0 ; ss_state_t ste = STATE_ZERO ; stralloc sa = STRALLOC_ZERO ; resolve_wrapper_t_ref wres = 0 ; + struct resolve_hash_s *hres = NULL, *c, *tmp ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_ISSUPERVISED|STATE_FLAGS_TOUNSUPERVISE|STATE_FLAGS_WANTDOWN) ; @@ -189,9 +193,6 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) if (argc < 1) log_usage(info->usage, "\n", info->help) ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; - memset(ares, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; - for(; pos < argc ; pos++) { resolve_service_t res = RESOLVE_SERVICE_ZERO ; @@ -220,10 +221,12 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) log_dieusys(LOG_EXIT_SYS, "add service: ", argv[pos], " to selection") ; } - ares[areslen++] = res ; + log_trace("add service: ", argv[pos], " to the service selection") ; + if (!hash_add(&hres, argv[pos], res)) + log_dieu(LOG_EXIT_SYS, "append service selection with: ", argv[pos]) ; if (!siglen) - remove_deps(&res, ares, &areslen, &sa, info) ; + remove_deps(&res, &hres, &sa, info) ; } r = svc_scandir_ok(info->scandir.s) ; @@ -263,18 +266,18 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) info->usage = usage ; } - for (pos = 0 ; pos < areslen ; pos++) { + HASH_ITER(hh, hres, c, tmp) { - remove_service(&ares[pos], info) ; + remove_service(&c->res, info) ; - if (ares[pos].type == TYPE_MODULE) { + if (c->res.type == TYPE_MODULE) { - if (ares[pos].dependencies.ncontents) { + if (c->res.dependencies.ncontents) { size_t pos = 0 ; resolve_service_t mres = RESOLVE_SERVICE_ZERO ; resolve_wrapper_t_ref mwres = resolve_set_struct(DATA_SERVICE, &mres) ; - _init_stack_(stk, strlen(ares[pos].sa.s + ares[pos].dependencies.contents)) ; + _init_stack_(stk, strlen(c->res.sa.s + c->res.dependencies.contents)) ; if (!stack_clean_string_g(&stk, c->res.sa.s + c->res.dependencies.contents)) log_dieu(LOG_EXIT_SYS, "convert string") ; @@ -282,8 +285,10 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) FOREACH_STK(&stk, pos) { r = resolve_read_g(mwres, info->base.s, stk.s + pos) ; - if (r <= 0) - log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", stk.s + pos) ; + if (r <= 0) { + log_warnusys("read resolve file of: ", stk.s + pos) ; + continue ; + } remove_service(&mres, info) ; } @@ -296,7 +301,7 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) if (!info->owner) { - auto_strings(dir, SS_SERVICE_ADMDIR, ares[pos].sa.s + ares[pos].name) ; + auto_strings(dir, SS_SERVICE_ADMDIR, c->res.sa.s + c->res.name) ; } else { @@ -305,7 +310,7 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) size_t dirlen = strlen(dir) ; - auto_strings(dir + dirlen, SS_SERVICE_USERDIR, ares[pos].sa.s + ares[pos].name) ; + auto_strings(dir + dirlen, SS_SERVICE_USERDIR, c->res.sa.s + c->res.name) ; } auto_remove(dir) ; @@ -313,7 +318,7 @@ int ssexec_remove(int argc, char const *const *argv, ssexec_t *info) } stralloc_free(&sa) ; - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; free(wres) ; return 0 ; diff --git a/src/lib66/exec/ssexec_restart.c b/src/lib66/exec/ssexec_restart.c index 8f4ec70e3cbf9d0a418eb8becd533175b9374617..9dab2753c35a110feb7f2734aeac607cf8d42a07 100644 --- a/src/lib66/exec/ssexec_restart.c +++ b/src/lib66/exec/ssexec_restart.c @@ -38,9 +38,7 @@ int ssexec_restart(int argc, char const *const *argv, ssexec_t *info) uint32_t flag = 0 ; uint8_t siglen = 3 ; graph_t graph = GRAPH_ZERO ; - - unsigned int areslen = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; ss_state_t sta = STATE_ZERO ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_TORESTART|STATE_FLAGS_WANTUP) ; @@ -81,18 +79,18 @@ int ssexec_restart(int argc, char const *const *argv, ssexec_t *info) log_diesys(LOG_EXIT_SYS,"scandir: ", info->scandir.s, " is not running") ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- have you already parsed a service?") ; for (n = 0 ; n < argc ; n++) { - int aresid = service_resolve_array_search(ares, areslen, argv[n]) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(&hres, argv[n]) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", *argv, " not available -- did you parse it?") ; - if (!state_read(&sta, &ares[aresid])) + if (!state_read(&sta, &hash->res)) log_dieu(LOG_EXIT_SYS, "read state file of: ", argv[n]) ; if (sta.issupervised == STATE_FLAGS_FALSE) @@ -117,7 +115,7 @@ int ssexec_restart(int argc, char const *const *argv, ssexec_t *info) r = svc_send_wait(argv, argc, sig, siglen, info) ; - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; graph_free_all(&graph) ; return r ; diff --git a/src/lib66/exec/ssexec_signal.c b/src/lib66/exec/ssexec_signal.c index a43c0eb673924ab6bac6e9b25ba02da96432e88e..ae11fb42ed2d023f41eecb6c149971a4ddad4f74 100644 --- a/src/lib66/exec/ssexec_signal.c +++ b/src/lib66/exec/ssexec_signal.c @@ -54,17 +54,14 @@ int ssexec_signal(int argc, char const *const *argv, ssexec_t *info) int r ; uint8_t what = 1, requiredby = 0, propagate = 1 ; graph_t graph = GRAPH_ZERO ; - unsigned int napid = 0 ; - char updown[4] = "-w \0" ; uint8_t opt_updown = 0 ; char data[DATASIZE + 1] = "-" ; unsigned int datalen = 1 ; uint8_t reloadmsg = 0 ; - - unsigned int areslen = 0, list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1] ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; + unsigned int list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1] ; /* * STATE_FLAGS_TOPROPAGATE = 0 @@ -175,20 +172,21 @@ int ssexec_signal(int argc, char const *const *argv, ssexec_t *info) log_diesys(LOG_EXIT_SYS,"scandir: ", info->scandir.s," is not running") ; /** build the graph of the entire system.*/ - graph_build_service(&graph, ares, &areslen, info, gflag) ; + graph_build_service(&graph, &hres, info, gflag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not supervised -- initiate its first") ; for (; *argv ; argv++) { - int aresid = service_resolve_array_search(ares, areslen, *argv) ; + + struct resolve_hash_s *hash = hash_search(&hres, *argv) ; /** The service may not be supervised, for example serviceB depends on * serviceA and serviceB was unsupervised by the user. So it will be ignored * by the function graph_build_service. In this case, the service does not * exist at array. * * At stop process, just ignore it as it already down anyway */ - if (aresid < 0) { + if (hash == NULL) { if (what && data[1] != 'r' || data[1] != 'h') { log_warn("service: ", *argv, " is already stopped or unsupervised -- ignoring it") ; continue ; @@ -196,17 +194,17 @@ int ssexec_signal(int argc, char const *const *argv, ssexec_t *info) log_die(LOG_EXIT_USER, "service: ", *argv, " not available -- did you parse it?") ; } } - graph_compute_visit(ares, aresid, visit, list, &graph, &napid, requiredby) ; + graph_compute_visit(*hash, visit, list, &graph, &napid, requiredby) ; } pidservice_t apids[napid] ; - svc_init_array(list, napid, apids, &graph, ares, areslen, info, requiredby, gflag) ; + svc_init_array(list, napid, apids, &graph, &hres, info, requiredby, gflag) ; - r = svc_launch(apids, napid, what, &graph, ares, areslen, info, updown, opt_updown, reloadmsg, data, propagate) ; + r = svc_launch(apids, napid, what, &graph, &hres, info, updown, opt_updown, reloadmsg, data, propagate) ; graph_free_all(&graph) ; - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; return r ; } diff --git a/src/lib66/exec/ssexec_start.c b/src/lib66/exec/ssexec_start.c index 2f8ebe385356eedc02f0d6e8e58699f6c4bbd683..0b3249ec57dc2ec2a0aacf06b124e8ef9ada3534 100644 --- a/src/lib66/exec/ssexec_start.c +++ b/src/lib66/exec/ssexec_start.c @@ -20,6 +20,7 @@ #include <oblibs/sastr.h> #include <skalibs/sgetopt.h> +#include <skalibs/genalloc.h> #include <66/ssexec.h> #include <66/config.h> @@ -29,18 +30,19 @@ #include <66/sanitize.h> #include <66/service.h> #include <66/enum.h> +#include <66/hash.h> int ssexec_start(int argc, char const *const *argv, ssexec_t *info) { log_flow() ; + int n = 0 ; uint32_t flag = 0 ; graph_t graph = GRAPH_ZERO ; uint8_t siglen = 3 ; + unsigned int list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], nservice = 0 ; - int n = 0 ; - unsigned int areslen = 0, list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], nservice = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; memset(list, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; @@ -90,25 +92,24 @@ int ssexec_start(int argc, char const *const *argv, ssexec_t *info) sanitize_source(argv[n], info, flag) ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- please make a bug report") ; for (n = 0 ; n < argc ; n++) { - int aresid = service_resolve_array_search(ares, areslen, argv[n]) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(&hres, argv[n]) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", argv[n], " not available -- did you parse it?") ; - graph_compute_visit(ares, aresid, visit, list, &graph, &nservice, 0) ; + graph_compute_visit(*hash, visit, list, &graph, &nservice, 0) ; } /** initiate services at the corresponding scandir */ - sanitize_init(list, nservice, &graph, ares, areslen) ; - - service_resolve_array_free(ares, areslen) ; + sanitize_init(list, nservice, &graph, &hres) ; + hash_free(&hres) ; graph_free_all(&graph) ; char *sig[siglen] ; diff --git a/src/lib66/exec/ssexec_status.c b/src/lib66/exec/ssexec_status.c index 18cf4c37bd9c05ead69702e9550f841eeed0055c..f9d02ce31458377ba1ef05a1068ad3d632f9f752 100644 --- a/src/lib66/exec/ssexec_status.c +++ b/src/lib66/exec/ssexec_status.c @@ -322,16 +322,13 @@ static void info_display_requiredby(char const *field, resolve_service_t *res) size_t padding = 1 ; int r ; graph_t graph = GRAPH_ZERO ; - - unsigned int areslen = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; - + struct resolve_hash_s *hres = NULL ; stralloc deps = STRALLOC_ZERO ; if (NOFIELD) padding = info_display_field_name(field) ; else { field = 0 ; padding = 0 ; } - graph_build_service(&graph, ares, &areslen, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; + graph_build_service(&graph, &hres, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- please make a bug report") ; @@ -391,6 +388,7 @@ static void info_display_requiredby(char const *field, resolve_service_t *res) } freed: graph_free_all(&graph) ; + hash_free(&hres) ; stralloc_free(&deps) ; } @@ -399,16 +397,14 @@ static void info_display_deps(char const *field, resolve_service_t *res) int r ; size_t padding = 1 ; graph_t graph = GRAPH_ZERO ; - - unsigned int areslen = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; stralloc deps = STRALLOC_ZERO ; if (NOFIELD) padding = info_display_field_name(field) ; else { field = 0 ; padding = 0 ; } - graph_build_service(&graph, ares, &areslen, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; + graph_build_service(&graph, &hres, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- please make a bug report") ; @@ -468,6 +464,7 @@ static void info_display_deps(char const *field, resolve_service_t *res) freed: graph_free_all(&graph) ; + hash_free(&hres) ; stralloc_free(&deps) ; } @@ -504,9 +501,7 @@ static void info_display_contents(char const *field, resolve_service_t *res) size_t padding = 1 ; graph_t graph = GRAPH_ZERO ; stralloc sa = STRALLOC_ZERO ; - - unsigned int areslen = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; if (NOFIELD) padding = info_display_field_name(field) ; else { field = 0 ; padding = 0 ; } @@ -517,7 +512,7 @@ static void info_display_contents(char const *field, resolve_service_t *res) if (!sastr_clean_string(&sa, res->sa.s + res->dependencies.contents)) log_dieu(LOG_EXIT_SYS, "clean string") ; - service_graph_g(sa.s, sa.len, &graph, ares, &areslen, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; + service_graph_g(sa.s, sa.len, &graph, &hres, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- please make a bug report") ; @@ -564,7 +559,7 @@ static void info_display_contents(char const *field, resolve_service_t *res) freed: graph_free_all(&graph) ; - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; stralloc_free(&sa) ; } diff --git a/src/lib66/exec/ssexec_stop.c b/src/lib66/exec/ssexec_stop.c index f49100ea7445c53132eef00e54a98508dcf1215f..b3bacc395901a413f3ecf26ec154270f6e1db1e0 100644 --- a/src/lib66/exec/ssexec_stop.c +++ b/src/lib66/exec/ssexec_stop.c @@ -41,9 +41,8 @@ int ssexec_stop(int argc, char const *const *argv, ssexec_t *info) graph_t graph = GRAPH_ZERO ; uint8_t siglen = 3 ; int e = 0 ; - - unsigned int areslen = 0, list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], nservice = 0, pos = 0, idx = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; + unsigned int list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], nservice = 0, pos = 0, idx = 0 ; memset(list, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; @@ -99,25 +98,24 @@ int ssexec_stop(int argc, char const *const *argv, ssexec_t *info) log_diesys(LOG_EXIT_SYS,"scandir: ", info->scandir.s," is not running") ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- did you start it first?") ; for (; pos < argc ; pos++) { - int aresid = service_resolve_array_search(ares, areslen, argv[pos]) ; - /** The service may not be supervised, so it will be ignored by the * function graph_build_service. In this case, the service does not * exist at array. * * This the stop process, just ignore it as it already down anyway */ - if (aresid < 0) { + struct resolve_hash_s *hash = hash_search(&hres, argv[pos]) ; + if (hash == NULL) { log_warn("service: ", argv[pos], " is already stopped or unsupervised -- ignoring it") ; continue ; } - graph_compute_visit(ares, aresid, visit, list, &graph, &nservice, 1) ; + graph_compute_visit(*hash, visit, list, &graph, &nservice, 1) ; } char *sig[siglen] ; @@ -155,17 +153,17 @@ int ssexec_stop(int argc, char const *const *argv, ssexec_t *info) fvisit[idx] = 1 ; } - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(&hres, name) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", name, " not available -- please make a bug report") ; /** the logger need to be stopped in case of unsupervise request */ if (FLAGS_ISSET(flag, STATE_FLAGS_TOUNSUPERVISE)) { - if (get_rstrlen_until(name, SS_LOG_SUFFIX) < 0 && ares[aresid].logger.want) { + if (get_rstrlen_until(name, SS_LOG_SUFFIX) < 0 && hash->res.logger.want) { - nargv[nargc++] = ares[aresid].sa.s + ares[aresid].logger.name ; - idx = graph_hash_vertex_get_id(&graph, ares[aresid].sa.s + ares[aresid].logger.name) ; + nargv[nargc++] = hash->res.sa.s + hash->res.logger.name ; + idx = graph_hash_vertex_get_id(&graph, hash->res.sa.s + hash->res.logger.name) ; if (!fvisit[idx]) { flist[fnservice++] = idx ; fvisit[idx] = 1 ; @@ -179,9 +177,9 @@ int ssexec_stop(int argc, char const *const *argv, ssexec_t *info) e = svc_send_wait(nargv, nargc, sig, siglen, info) ; if (FLAGS_ISSET(flag, STATE_FLAGS_TOUNSUPERVISE)) - svc_unsupervise(flist, fnservice, &graph, ares, areslen, info) ; + svc_unsupervise(flist, fnservice, &graph, &hres, info) ; - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; graph_free_all(&graph) ; return e ; diff --git a/src/lib66/exec/ssexec_tree_init.c b/src/lib66/exec/ssexec_tree_init.c index fd18baaa92ec24fa8f27635d29fa1995a5b4fef0..8fd125f15b398a6a756870220cb1c8b57586be40 100644 --- a/src/lib66/exec/ssexec_tree_init.c +++ b/src/lib66/exec/ssexec_tree_init.c @@ -40,9 +40,8 @@ static void doit(stralloc *sa, ssexec_t *info, uint8_t earlier) uint32_t flag = 0 ; graph_t graph = GRAPH_ZERO ; - - unsigned int areslen = 0, list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], nservice = 0, n = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL ; + unsigned int list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1], nservice = 0, n = 0 ; memset(list, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; @@ -52,15 +51,16 @@ static void doit(stralloc *sa, ssexec_t *info, uint8_t earlier) FLAGS_SET(flag, STATE_FLAGS_ISEARLIER) ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not available -- have you already parsed a service?") ; FOREACH_SASTR(sa, n) { - int aresid = service_resolve_array_search(ares, areslen, sa->s + n) ; - if (aresid < 0) { + struct resolve_hash_s *hash ; + hash = hash_search(&hres, sa->s + n) ; + if (hash == NULL) { if (earlier) { log_trace("ignoring none earlier service: ", sa->s + n) ; @@ -77,7 +77,7 @@ static void doit(stralloc *sa, ssexec_t *info, uint8_t earlier) if (earlier) { - if (ares[aresid].earlier) { + if (hash->res.earlier) { list[nservice++] = idx ; visit[idx] = 1 ; @@ -85,14 +85,14 @@ static void doit(stralloc *sa, ssexec_t *info, uint8_t earlier) } else { - if (ares[aresid].enabled) { + if (hash->res.enabled) { list[nservice++] = idx ; visit[idx] = 1 ; } else { - log_trace("ignoring not enabled service: ", ares[aresid].sa.s + ares[aresid].name) ; + log_trace("ignoring not enabled service: ", hash->res.sa.s + hash->res.name) ; } } @@ -109,13 +109,14 @@ static void doit(stralloc *sa, ssexec_t *info, uint8_t earlier) char *name = graph.data.s + genalloc_s(graph_hash_t,&graph.hash)[l[pos]].vertex ; - aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) + struct resolve_hash_s *h ; + h = hash_search(&hres, name) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", name, " not available -- did you parse it?") ; if (earlier) { - if (ares[aresid].earlier) { + if (h->res.earlier) { list[nservice++] = l[pos] ; visit[l[pos]] = 1 ; @@ -123,7 +124,7 @@ static void doit(stralloc *sa, ssexec_t *info, uint8_t earlier) } else { - if (ares[aresid].enabled) { + if (h->res.enabled) { list[nservice++] = l[pos] ; visit[l[pos]] = 1 ; @@ -134,9 +135,9 @@ static void doit(stralloc *sa, ssexec_t *info, uint8_t earlier) } } - sanitize_init(list, nservice, &graph, ares, areslen) ; + sanitize_init(list, nservice, &graph, &hres) ; - service_resolve_array_free(ares, areslen) ; + hash_free(&hres) ; graph_free_all(&graph) ; } diff --git a/src/lib66/exec/ssexec_tree_signal.c b/src/lib66/exec/ssexec_tree_signal.c index d982fe380d464b755f6fdf202424b41c2e1fa214..33f753f961af69ca328d1fe6a506002cf9125e0a 100644 --- a/src/lib66/exec/ssexec_tree_signal.c +++ b/src/lib66/exec/ssexec_tree_signal.c @@ -643,10 +643,6 @@ static int async_deps(struct resolve_hash_tree_s **htres, pidtree_t *apidt, unsi if (!visit[pos]) { - id = pidtree_get_id(apidt, id) ; - if (id < 0) - log_dieu(LOG_EXIT_SYS, "get apidtree id -- please make a bug report") ; - id = check_action(apidt, id, c, what) ; if (id < 0) log_die(LOG_EXIT_SYS, "tree dependency: ", apidt[id].tres->sa.s + apidt[id].tres->name, " of: ", apidt[id].tres->sa.s + apidt[id].tres->name," crashed") ; diff --git a/src/lib66/exec/ssexec_tree_status.c b/src/lib66/exec/ssexec_tree_status.c index 7689c9ccee6192cfd87f377286d92814eddd718c..e21647681dcfa9078e88c6575fca562f46bd6ff0 100644 --- a/src/lib66/exec/ssexec_tree_status.c +++ b/src/lib66/exec/ssexec_tree_status.c @@ -370,7 +370,7 @@ static void info_display_contents(char const *field, char const *treename) if (!sa.len) goto empty ; - service_graph_g_hash(sa.s, sa.len, &graph, &hres, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; + service_graph_g(sa.s, sa.len, &graph, &hres, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; if (!HASH_COUNT(hres)) goto empty ; diff --git a/src/lib66/graph/graph_build_service.c b/src/lib66/graph/graph_build_service.c index fe2a0249f10e7f42cc62b9e6f026531679321f7c..fceacb3ea4baf9517891ac71e07a12d4b3619c88 100644 --- a/src/lib66/graph/graph_build_service.c +++ b/src/lib66/graph/graph_build_service.c @@ -27,8 +27,9 @@ #include <66/graph.h> #include <66/state.h> #include <66/config.h> +#include <66/hash.h> -void graph_build_service(graph_t *graph, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint32_t flag) +void graph_build_service(graph_t *graph, struct resolve_hash_s **hres, ssexec_t *info, uint32_t flag) { log_flow() ; @@ -41,9 +42,7 @@ void graph_build_service(graph_t *graph, resolve_service_t *ares, unsigned int * if (!sastr_dir_get_recursive(&sa, solve, exclude, S_IFLNK, 0)) log_dieu(LOG_EXIT_SYS, "get resolve files") ; - memset(ares, 0, (SS_MAX_SERVICE + 1) * sizeof(resolve_service_t)) ; - - service_graph_g(sa.s, sa.len, graph, ares, areslen, info, flag) ; + service_graph_g(sa.s, sa.len, graph, hres, info, flag) ; stralloc_free(&sa) ; } diff --git a/src/lib66/graph/graph_build_tree.c b/src/lib66/graph/graph_build_tree.c index b1b5fd26cbc828bcaed7cfeda220efd693ced868..0ca246c2b9292428f3a35fe7a8eb46adbe6eea14 100644 --- a/src/lib66/graph/graph_build_tree.c +++ b/src/lib66/graph/graph_build_tree.c @@ -78,6 +78,5 @@ void graph_build_tree(graph_t *g, struct resolve_hash_tree_s **htres, char const if (!graph_matrix_sort(g)) log_dieu(LOG_EXIT_SYS, "sort the graph") ; - resolve_free(wres) ; stralloc_free(&sa) ; } diff --git a/src/lib66/graph/graph_compute_visit.c b/src/lib66/graph/graph_compute_visit.c index 27eab5cb58dc8b71dd11c23dbbcb5ae9c5762f3f..84b9ac7a98e70855a825855959847dd1329f8170 100644 --- a/src/lib66/graph/graph_compute_visit.c +++ b/src/lib66/graph/graph_compute_visit.c @@ -21,13 +21,13 @@ #include <66/service.h> #include <66/enum.h> -void graph_compute_visit(resolve_service_t *ares, unsigned int aresid, unsigned int *visit, unsigned int *list, graph_t *graph, unsigned int *nservice, uint8_t requiredby) +void graph_compute_visit(struct resolve_hash_s hash, unsigned int *visit, unsigned int *list, graph_t *graph, unsigned int *nservice, uint8_t requiredby) { log_flow() ; unsigned int l[graph->mlen], c = 0, pos = 0, idx = 0 ; - idx = graph_hash_vertex_get_id(graph, ares[aresid].sa.s + ares[aresid].name) ; + idx = graph_hash_vertex_get_id(graph, hash.res.sa.s + hash.res.name) ; if (!visit[idx]) { list[(*nservice)++] = idx ; @@ -35,7 +35,7 @@ void graph_compute_visit(resolve_service_t *ares, unsigned int aresid, unsigned } /** find dependencies of the service from the graph, do it recursively */ - c = graph_matrix_get_edge_g_list(l, graph, ares[aresid].sa.s + ares[aresid].name, requiredby, 1) ; + c = graph_matrix_get_edge_g_list(l, graph, hash.res.sa.s + hash.res.name, requiredby, 1) ; /** append to the list to deal with */ for (pos = 0 ; pos < c ; pos++) { diff --git a/src/lib66/module/parse_module.c b/src/lib66/module/parse_module.c index 0b168220db5ecc85d5933cbfad54357613aa1be1..8431a3032a317b19943151e2364b7c83fbfd6810 100644 --- a/src/lib66/module/parse_module.c +++ b/src/lib66/module/parse_module.c @@ -39,7 +39,7 @@ #include <66/sanitize.h> #include <66/state.h> -static void parse_module_dependencies(stralloc *list, resolve_service_t *res, uint8_t requiredby, resolve_service_t *ares, unsigned int *areslen, uint8_t force, uint8_t conf, ssexec_t *info) +static void parse_module_dependencies(stralloc *list, resolve_service_t *res, uint8_t requiredby, struct resolve_hash_s **hres, uint8_t force, uint8_t conf, ssexec_t *info) { log_flow() ; @@ -79,7 +79,7 @@ static void parse_module_dependencies(stralloc *list, resolve_service_t *res, ui (*nfield)++ ; - parse_frontend(sa.s, ares, areslen, info, force, conf, 0, fname, 0, 0) ; + parse_frontend(sa.s, hres, info, force, conf, 0, fname, 0, 0) ; } @@ -142,7 +142,7 @@ static void parse_module_regex(resolve_service_t *res, char *copy, size_t copyle regex_configure(res, info, copy, name) ; } -void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force) +void parse_module(resolve_service_t *res, struct resolve_hash_s **hres, ssexec_t *info, uint8_t force) { log_flow() ; @@ -236,12 +236,12 @@ void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int auto_strings(copy + copylen, SS_MODULE_ACTIVATED SS_MODULE_DEPENDS) ; get_list(&list, copy, name, S_IFREG, exclude) ; - parse_module_dependencies(&list, res, 0, ares, areslen, force, conf, info) ; + parse_module_dependencies(&list, res, 0, hres, force, conf, info) ; auto_strings(copy + copylen, SS_MODULE_ACTIVATED SS_MODULE_REQUIREDBY) ; get_list(&list, copy, name, S_IFREG, exclude) ; - parse_module_dependencies(&list, res, 1, ares, areslen, force, conf, info) ; + parse_module_dependencies(&list, res, 1, hres, force, conf, info) ; } auto_strings(copy + copylen, SS_MODULE_ACTIVATED) ; @@ -307,7 +307,7 @@ void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int if (!auto_stra(&info->treename, res->sa.s + res->treename)) log_die_nomem("stralloc") ; - parse_frontend(list.s, ares, areslen, info, force, conf, copy, fname, name, res->intree ? res->sa.s + res->intree : 0) ; + parse_frontend(list.s, hres, info, force, conf, copy, fname, name, res->intree ? res->sa.s + res->intree : 0) ; info->opt_tree = opt_tree ; } @@ -316,7 +316,7 @@ void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int /** append the module name at each inner depends/requiredby dependencies service name * and define contents field.*/ - parse_rename_interdependences(res, name, ares, areslen) ; + parse_rename_interdependences(res, name, hres, info) ; /** Remove the module name from requiredby field * of the dependencies if the service disappears with the diff --git a/src/lib66/parse/deps-lib/deps b/src/lib66/parse/deps-lib/deps index d9041bc0c7a9105f7f7087f791cd6e995c846a6a..b72e0338da31808ca4e91a8598db1fa48cb6e23d 100644 --- a/src/lib66/parse/deps-lib/deps +++ b/src/lib66/parse/deps-lib/deps @@ -1,3 +1,4 @@ +parse_append_logger.o parse_clean_line.o parse_clean_list.o parse_clean_quotes.o diff --git a/src/lib66/parse/parse_append_logger.c b/src/lib66/parse/parse_append_logger.c new file mode 100644 index 0000000000000000000000000000000000000000..c44e34d5106d53cb03bab2b08dccb8d2ea24c531 --- /dev/null +++ b/src/lib66/parse/parse_append_logger.c @@ -0,0 +1,300 @@ +/* + * parse_append_logger.c + * + * Copyright (c) 2018-2023 Eric Vidal <eric@obarun.org> + * + * All rights reserved. + * + * This file is part of Obarun. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution. + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file./ + */ + +#include <string.h> + +#include <oblibs/string.h> +#include <oblibs/log.h> + +#include <66/resolve.h> +#include <66/service.h> +#include <66/enum.h> +#include <66/constants.h> +#include <66/config.h> +#include <66/utils.h> +#include <66/config.h> +#include <66/parse.h> + +#include <s6/config.h> + +#ifndef FAKELEN +#define FAKELEN strlen(run) +#endif + +static uint32_t compute_log_dir(resolve_wrapper_t_ref wres, resolve_service_t *res) +{ + log_flow() ; + + size_t namelen = strlen(res->sa.s + res->name) ; + size_t syslen = res->owner ? strlen(res->sa.s + res->path.home) + strlen(SS_LOGGER_USERDIR) : strlen(SS_LOGGER_SYSDIR) ; + size_t dstlen = res->logger.destination ? strlen(res->sa.s + res->logger.destination) : strlen(SS_LOGGER_SYSDIR) ; + + char dstlog[syslen + dstlen + namelen + 1] ; + + if (!res->logger.destination) { + + if (res->owner) { + + char home[syslen + 1 + strlen(SS_LOGGER_USERDIR) + 1] ; + + if (!set_ownerhome_stack(home)) + log_dieusys(LOG_EXIT_SYS,"set home directory") ; + + auto_strings(dstlog, home, SS_LOGGER_USERDIR, res->sa.s + res->name) ; + + } else + auto_strings(dstlog, SS_LOGGER_SYSDIR, res->sa.s + res->name) ; + + } else { + + auto_strings(dstlog, res->sa.s + res->logger.destination) ; + } + + return resolve_add_string(wres, dstlog) ; +} + + +static void compute_log_script(resolve_service_t *res, resolve_service_t *log) +{ + + log_flow() ; + + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, log) ; + + int build = !strcmp(res->sa.s + res->logger.execute.run.build, "custom") ? BUILD_CUSTOM : BUILD_AUTO ; + + char *pmax = 0 ; + char *pback = 0 ; + char max[UINT32_FMT] ; + char back[UINT32_FMT] ; + char *timestamp = 0 ; + int itimestamp = SS_LOGGER_TIMESTAMP ; + char *logrunner = res->logger.execute.run.runas ? res->sa.s + res->logger.execute.run.runas : SS_LOGGER_RUNNER ; + + log->execute.run.runas = resolve_add_string(wres, logrunner) ; + + /** timestamp */ + if (res->logger.timestamp != 3) + timestamp = res->logger.timestamp == TIME_NONE ? "" : res->logger.timestamp == TIME_ISO ? "T" : "t" ; + else + timestamp = itimestamp == TIME_NONE ? "" : itimestamp == TIME_ISO ? "T" : "t" ; + + /** backup */ + if (res->logger.backup) { + + back[uint32_fmt(back,res->logger.backup)] = 0 ; + pback = back ; + + } + + /** file size */ + if (res->logger.maxsize) { + + max[uint32_fmt(max,res->logger.maxsize)] = 0 ; + pmax = max ; + + } + + char *shebang = "#!" SS_EXECLINE_SHEBANGPREFIX "execlineb -P\n" ; + + { + /** run scripts */ + char run[SS_MAX_PATH_LEN + 1] ; + + auto_strings(run, \ + shebang, \ + "s6-fdholder-retrieve ", \ + res->sa.s + res->live.fdholderdir, "/s ", \ + "\"" SS_FDHOLDER_PIPENAME "r-", \ + res->sa.s + res->logger.name, "\"\n", \ + "./run.user\n") ; + + log->execute.run.run = resolve_add_string(wres, run) ; + + } + + { + if (!build) { + /** run.user script */ + char run[SS_MAX_PATH_LEN + 1] ; + + auto_strings(run, shebang) ; + + auto_strings(run + FAKELEN, "fdmove -c 2 1\n") ; + + /** runas */ + if (!res->owner) + auto_strings(run + FAKELEN, S6_BINPREFIX "s6-setuidgid ", logrunner, "\n") ; + + auto_strings(run + FAKELEN, "s6-log ") ; + + if (SS_LOGGER_NOTIFY) + auto_strings(run + FAKELEN, "-d3 ") ; + + auto_strings(run + FAKELEN, "n", pback, " ") ; + + if (res->logger.timestamp < TIME_NONE) + auto_strings(run + FAKELEN, timestamp, " ") ; + + auto_strings(run + FAKELEN, "s", pmax, " ", res->sa.s + res->logger.destination, "\n") ; + + log->execute.run.run_user = resolve_add_string(wres, run) ; + + } else { + + if (res->logger.execute.run.shebang) + log_warn("@shebang field is deprecated -- please define it at start of your @execute field instead") ; + + char *shebang = res->logger.execute.run.shebang ? res->sa.s + res->logger.execute.run.shebang : "#!" SS_EXECLINE_SHEBANGPREFIX "execlineb -P\n" ; + size_t shebanglen = strlen(shebang) ; + + char run[shebanglen + strlen(res->sa.s + res->logger.execute.run.run_user) + 2] ; + auto_strings(run, shebang, res->sa.s + res->logger.execute.run.run_user, "\n") ; + + log->execute.run.run_user = resolve_add_string(wres, run) ; + } + } + + free(wres) ; +} + +static void compute_logger(resolve_service_t *res, resolve_service_t *log, ssexec_t *info) +{ + log_flow() ; + + if (!res->logger.name) + return ; + + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, log) ; + + resolve_init(wres) ; + + char *str = res->sa.s ; + size_t namelen = strlen(str + res->logger.name) ; + char name[namelen + 1] ; + char description[namelen + 7 + 1] ; + + auto_strings(name, str + res->logger.name) ; + + auto_strings(description, str + res->name, " logger") ; + + log->name = resolve_add_string(wres, name) ; + log->description = resolve_add_string(wres, description) ; + log->version = resolve_add_string(wres, str + res->version) ; + log->type = res->type ; + log->notify = 3 ; + log->maxdeath = res->maxdeath ; + log->earlier = res->earlier ; + if (res->intree) + log->intree = resolve_add_string(wres, str + res->intree) ; + + log->ownerstr = resolve_add_string(wres, str + res->ownerstr) ; + log->owner = res->owner ; + log->treename = resolve_add_string(wres, str + res->treename) ; + log->user = resolve_add_string(wres, str + res->user) ; + if (res->inns) + log->inns = resolve_add_string(wres, str + res->inns) ; + + log->path.home = resolve_add_string(wres, str + res->path.home) ; + log->path.frontend = resolve_add_string(wres, str + res->path.frontend) ; + log->path.servicedir = compute_src_servicedir(wres, info) ; + log->dependencies.requiredby = resolve_add_string(wres, str + res->name) ; + log->dependencies.nrequiredby = 1 ; + + log->execute.run.build = resolve_add_string(wres, str + res->logger.execute.run.build) ; + log->execute.run.shebang = res->logger.execute.run.shebang ? resolve_add_string(wres, str + res->logger.execute.run.shebang) : 0 ; + log->execute.run.runas = resolve_add_string(wres, str + res->logger.execute.run.runas) ; + log->execute.timeout.kill = res->logger.execute.timeout.kill ; + log->execute.timeout.finish = res->logger.execute.timeout.finish ; + log->execute.down = res->logger.execute.down ; + log->execute.downsignal = res->logger.execute.downsignal ; + + log->live.livedir = resolve_add_string(wres, info->live.s) ; + log->live.status = compute_status(wres, info) ; + log->live.servicedir = compute_live_servicedir(wres, info) ; + log->live.scandir = compute_scan_dir(wres, info) ; + log->live.statedir = compute_state_dir(wres, info, SS_STATE + 1) ; + log->live.eventdir = compute_state_dir(wres, info, SS_EVENTDIR + 1) ; + log->live.notifdir = compute_state_dir(wres, info, "notif") ; + log->live.supervisedir = compute_state_dir(wres, info, SS_SUPERVISEDIR + 1) ; + log->live.fdholderdir = compute_pipe_service(wres, info, SS_FDHOLDER) ; + log->live.oneshotddir = compute_pipe_service(wres, info, SS_ONESHOTD) ; + + log->logger.destination = resolve_add_string(wres, str + res->logger.destination) ; + log->logger.backup = res->logger.backup ; + log->logger.maxsize = res->logger.maxsize ; + log->logger.timestamp = res->logger.timestamp ; + log->logger.want = 0 ; + + // oneshot do not use fdholder daemon + if (res->type == TYPE_CLASSIC) + compute_log_script(res, log) ; + + free(wres) ; + +} + +void parse_append_logger(struct resolve_hash_s **hres, resolve_service_t *res, ssexec_t *info) +{ + log_flow() ; + + char *name = res->sa.s + res->name ; + struct resolve_hash_s *hash ; + resolve_service_t lres = RESOLVE_SERVICE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; + size_t namelen = strlen(name) ; + char logname[namelen + SS_LOG_SUFFIX_LEN + 1] ; + + auto_strings(logname, name, SS_LOG_SUFFIX) ; + + res->logger.name = resolve_add_string(wres, logname) ; + + res->logger.destination = compute_log_dir(wres, res) ; + + res->logger.execute.run.runas = res->logger.execute.run.runas ? resolve_add_string(wres, res->sa.s + res->logger.execute.run.runas) : resolve_add_string(wres, SS_LOGGER_RUNNER) ; + + hash = hash_search(hres, logname) ; + if (hash == NULL && res->type == TYPE_CLASSIC) { + /** the logger is not a service with oneshot type */ + + if (res->dependencies.ndepends) { + + char buf[strlen(res->sa.s + res->dependencies.depends) + 1 + strlen(res->sa.s + res->logger.name) + 1] ; + auto_strings(buf, res->sa.s + res->dependencies.depends, " ", res->sa.s + res->logger.name) ; + + res->dependencies.depends = resolve_add_string(wres, buf) ; + + } else { + + res->dependencies.depends = resolve_add_string(wres, res->sa.s + res->logger.name) ; + } + + res->dependencies.ndepends++ ; + + compute_logger(res, &lres, info) ; + + /** sanitize_init use this field */ + res->logger.execute.run.run = resolve_add_string(wres, lres.sa.s + lres.execute.run.run) ; + res->logger.execute.run.run_user = resolve_add_string(wres, lres.sa.s + lres.execute.run.run_user) ; + + if (hash_count(hres) > SS_MAX_SERVICE) + log_die(LOG_EXIT_SYS, "too many services to parse -- compile again 66 changing the --max-service options") ; + + log_trace("add service: ", logname, " to the service selection") ; + if (!hash_add(hres, logname, lres)) + log_dieu(LOG_EXIT_SYS, "append service selection with: ", logname) ; + } + + free(wres) ; +} \ No newline at end of file diff --git a/src/lib66/parse/parse_compute_resolve.c b/src/lib66/parse/parse_compute_resolve.c index 195ec77878572ea084a0ddb84b305afc6db9ca29..df7d1ee23c765888746dfe9b000b2ccd955f4597 100644 --- a/src/lib66/parse/parse_compute_resolve.c +++ b/src/lib66/parse/parse_compute_resolve.c @@ -37,7 +37,7 @@ #define FAKELEN strlen(run) #endif -static uint32_t compute_src_servicedir(resolve_wrapper_t_ref wres, ssexec_t *info) +uint32_t compute_src_servicedir(resolve_wrapper_t_ref wres, ssexec_t *info) { log_flow() ; @@ -52,7 +52,7 @@ static uint32_t compute_src_servicedir(resolve_wrapper_t_ref wres, ssexec_t *inf return resolve_add_string(wres, dir) ; } -static uint32_t compute_live_servicedir(resolve_wrapper_t_ref wres, ssexec_t *info) +uint32_t compute_live_servicedir(resolve_wrapper_t_ref wres, ssexec_t *info) { log_flow() ; @@ -68,7 +68,7 @@ static uint32_t compute_live_servicedir(resolve_wrapper_t_ref wres, ssexec_t *in } -static uint32_t compute_status(resolve_wrapper_t_ref wres, ssexec_t *info) +uint32_t compute_status(resolve_wrapper_t_ref wres, ssexec_t *info) { log_flow() ; @@ -84,7 +84,7 @@ static uint32_t compute_status(resolve_wrapper_t_ref wres, ssexec_t *info) } -static uint32_t compute_scan_dir(resolve_wrapper_t_ref wres, ssexec_t *info) +uint32_t compute_scan_dir(resolve_wrapper_t_ref wres, ssexec_t *info) { log_flow() ; @@ -99,7 +99,7 @@ static uint32_t compute_scan_dir(resolve_wrapper_t_ref wres, ssexec_t *info) return resolve_add_string(wres, dir) ; } -static uint32_t compute_state_dir(resolve_wrapper_t_ref wres, ssexec_t *info, char const *folder) +uint32_t compute_state_dir(resolve_wrapper_t_ref wres, ssexec_t *info, char const *folder) { log_flow() ; @@ -115,7 +115,7 @@ static uint32_t compute_state_dir(resolve_wrapper_t_ref wres, ssexec_t *info, ch return resolve_add_string(wres, dir) ; } -static uint32_t compute_pipe_service(resolve_wrapper_t_ref wres, ssexec_t *info, char const *service, char const *name) +uint32_t compute_pipe_service(resolve_wrapper_t_ref wres, ssexec_t *info, char const *name) { log_flow() ; @@ -128,39 +128,6 @@ static uint32_t compute_pipe_service(resolve_wrapper_t_ref wres, ssexec_t *info, } -static uint32_t compute_log_dir(resolve_wrapper_t_ref wres, resolve_service_t *res) -{ - log_flow() ; - - size_t namelen = strlen(res->sa.s + res->name) ; - size_t syslen = res->owner ? strlen(res->sa.s + res->path.home) + strlen(SS_LOGGER_USERDIR) : strlen(SS_LOGGER_SYSDIR) ; - size_t dstlen = res->logger.destination ? strlen(res->sa.s + res->logger.destination) : strlen(SS_LOGGER_SYSDIR) ; - - char dstlog[syslen + dstlen + namelen + 1] ; - - if (!res->logger.destination) { - - if (res->owner) { - - char home[SS_MAX_PATH_LEN + 1 + strlen(SS_LOGGER_USERDIR) + 1] ; - - if (!set_ownerhome_stack(home)) - log_dieusys(LOG_EXIT_SYS,"set home directory") ; - - auto_strings(dstlog, home, SS_LOGGER_USERDIR, res->sa.s + res->name) ; - - } else - - auto_strings(dstlog, SS_LOGGER_SYSDIR, res->sa.s + res->name) ; - - } else { - - auto_strings(dstlog, res->sa.s + res->logger.destination) ; - } - - return resolve_add_string(wres, dstlog) ; -} - /** * @!runorfinish -> finish, @runorfinish -> run * */ @@ -170,9 +137,8 @@ static void compute_wrapper_scripts(resolve_service_t *res, resolve_service_addo resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; char *shebang = "#!" SS_EXECLINE_SHEBANGPREFIX "execlineb -" ; - size_t shebanglen = strlen(shebang) ; - char run[shebanglen + strlen(res->sa.s + res->live.fdholderdir) + SS_FDHOLDER_PIPENAME_LEN + strlen(res->sa.s + res->name) + SS_LOG_SUFFIX_LEN + strlen(S6_BINPREFIX) + (SS_MAX_PATH*2) + SS_MAX_PATH + strlen(file) + 132 + 1] ; + char run[SS_MAX_PATH_LEN + 1] ; auto_strings(run, shebang, !runorfinish ? (res->type != TYPE_ONESHOT ? "S0\n" : "P\n") : "P\n") ; @@ -196,7 +162,7 @@ static void compute_wrapper_scripts(resolve_service_t *res, resolve_service_addo } /** - * @!runorfinish -> finish, @runofinish -> run + * @!runorfinish -> finish.user, @runofinish -> run.user * */ static void compute_wrapper_scripts_user(resolve_service_t *res, resolve_service_addon_scripts_t *scripts, uint8_t runorfinish) { @@ -251,209 +217,10 @@ static void compute_wrapper_scripts_user(resolve_service_t *res, resolve_service free(wres) ; } -static void compute_log_script(resolve_service_t *res) -{ - - log_flow() ; - - resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; - - int build = !strcmp(res->sa.s + res->logger.execute.run.build, "custom") ? BUILD_CUSTOM : BUILD_AUTO ; - - char *pmax = 0 ; - char *pback = 0 ; - char max[UINT32_FMT] ; - char back[UINT32_FMT] ; - char *timestamp = 0 ; - int itimestamp = SS_LOGGER_TIMESTAMP ; - char *logrunner = res->logger.execute.run.runas ? res->sa.s + res->logger.execute.run.runas : SS_LOGGER_RUNNER ; - - res->logger.execute.run.runas = resolve_add_string(wres, logrunner) ; - - /** timestamp */ - if (res->logger.timestamp != 3) - timestamp = res->logger.timestamp == TIME_NONE ? "" : res->logger.timestamp == TIME_ISO ? "T" : "t" ; - else - timestamp = itimestamp == TIME_NONE ? "" : itimestamp == TIME_ISO ? "T" : "t" ; - - /** backup */ - if (res->logger.backup) { - - back[uint32_fmt(back,res->logger.backup)] = 0 ; - pback = back ; - - } - - /** file size */ - if (res->logger.maxsize) { - - max[uint32_fmt(max,res->logger.maxsize)] = 0 ; - pmax = max ; - - } - - char *shebang = "#!" SS_EXECLINE_SHEBANGPREFIX "execlineb -P\n" ; - size_t shebanglen = strlen(shebang) ; - - { - /** run scripts */ - char run[strlen(shebang) + strlen(res->sa.s + res->live.fdholderdir) + SS_FDHOLDER_PIPENAME_LEN + strlen(res->sa.s + res->logger.name) + strlen(logrunner) + strlen(S6_BINPREFIX) + strlen(res->sa.s + res->logger.execute.run.runas) + 67 + 1] ; - - auto_strings(run, \ - shebang, \ - "s6-fdholder-retrieve ", \ - res->sa.s + res->live.fdholderdir, "/s ", \ - "\"" SS_FDHOLDER_PIPENAME "r-", \ - res->sa.s + res->logger.name, "\"\n") ; - - auto_strings(run + FAKELEN, "./run.user\n") ; - - res->logger.execute.run.run = resolve_add_string(wres, run) ; - - } - - { - if (!build) { - /** run.user script */ - char run[shebanglen + strlen(pback) + strlen(timestamp) + strlen(pmax) + strlen(res->sa.s + res->logger.destination) + 17 + 1] ; - - auto_strings(run, shebang) ; - - auto_strings(run + FAKELEN, "fdmove -c 2 1\n") ; - - /** runas */ - if (!res->owner) - auto_strings(run + FAKELEN, S6_BINPREFIX "s6-setuidgid ", logrunner, "\n") ; - - - auto_strings(run + FAKELEN, "s6-log ") ; - - if (SS_LOGGER_NOTIFY) - auto_strings(run + FAKELEN, "-d3 ") ; - - auto_strings(run + FAKELEN, "n", pback, " ") ; - - if (res->logger.timestamp < TIME_NONE) - auto_strings(run + FAKELEN, timestamp, " ") ; - - auto_strings(run + FAKELEN, "s", pmax, " ", res->sa.s + res->logger.destination, "\n") ; - - res->logger.execute.run.run_user = resolve_add_string(wres, run) ; - - } else { - - if (res->logger.execute.run.shebang) - log_warn("@shebang field is deprecated -- please define it at start of your @execute field instead") ; - - char *shebang = res->logger.execute.run.shebang ? res->sa.s + res->logger.execute.run.shebang : "#!" SS_EXECLINE_SHEBANGPREFIX "execlineb -P\n" ; - size_t shebanglen = strlen(shebang) ; - - char run[shebanglen + strlen(res->sa.s + res->logger.execute.run.run_user) + 2] ; - auto_strings(run, shebang, res->sa.s + res->logger.execute.run.run_user, "\n") ; - - res->logger.execute.run.run_user = resolve_add_string(wres, run) ; - } - } - - free(wres) ; -} - -static void compute_log(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info) +void parse_compute_resolve(resolve_service_t *res, ssexec_t *info) { log_flow() ; - if (!res->logger.name) - return ; - - resolve_service_t lres = RESOLVE_SERVICE_ZERO ; - resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &lres) ; - - resolve_init(wres) ; - - char *str = res->sa.s ; - size_t namelen = strlen(str + res->logger.name) ; - char name[namelen + 1] ; - char description[namelen + 7 + 1] ; - - auto_strings(name, str + res->logger.name) ; - - auto_strings(description, str + res->name, " logger") ; - - lres.name = resolve_add_string(wres, name) ; - lres.description = resolve_add_string(wres, description) ; - lres.version = resolve_add_string(wres, str + res->version) ; - lres.type = res->type ; - lres.notify = 3 ; - lres.maxdeath = res->maxdeath ; - lres.earlier = res->earlier ; - if (res->intree) - lres.intree = resolve_add_string(wres, str + res->intree) ; - - lres.ownerstr = resolve_add_string(wres, str + res->ownerstr) ; - lres.owner = res->owner ; - lres.treename = resolve_add_string(wres, str + res->treename) ; - lres.user = resolve_add_string(wres, str + res->user) ; - if (res->inns) - lres.inns = resolve_add_string(wres, str + res->inns) ; - - lres.path.home = resolve_add_string(wres, str + res->path.home) ; - lres.path.frontend = resolve_add_string(wres, str + res->path.frontend) ; - lres.path.servicedir = compute_src_servicedir(wres, info) ; - - lres.dependencies.requiredby = resolve_add_string(wres, str + res->name) ; - lres.dependencies.nrequiredby = 1 ; - - lres.execute.run.build = resolve_add_string(wres, str + res->logger.execute.run.build) ; - lres.execute.run.shebang = res->logger.execute.run.shebang ? resolve_add_string(wres, str + res->logger.execute.run.shebang) : 0 ; - lres.execute.run.runas = res->logger.execute.run.runas ? resolve_add_string(wres, str + res->logger.execute.run.runas) : resolve_add_string(wres, SS_LOGGER_RUNNER) ; - lres.execute.timeout.kill = res->logger.execute.timeout.kill ; - lres.execute.timeout.finish = res->logger.execute.timeout.finish ; - lres.execute.down = res->logger.execute.down ; - lres.execute.downsignal = res->logger.execute.downsignal ; - - lres.live.livedir = resolve_add_string(wres, info->live.s) ; - lres.live.status = compute_status(wres, info) ; - lres.live.servicedir = compute_live_servicedir(wres, info) ; - lres.live.scandir = compute_scan_dir(wres, info) ; - lres.live.statedir = compute_state_dir(wres, info, SS_STATE + 1) ; - lres.live.eventdir = compute_state_dir(wres, info, SS_EVENTDIR + 1) ; - lres.live.notifdir = compute_state_dir(wres, info, "notif") ; - lres.live.supervisedir = compute_state_dir(wres, info, SS_SUPERVISEDIR + 1) ; - lres.live.fdholderdir = compute_pipe_service(wres, info, name, SS_FDHOLDER) ; - lres.live.oneshotddir = compute_pipe_service(wres, info, name, SS_ONESHOTD) ; - - lres.logger.destination = resolve_add_string(wres, str + res->logger.destination) ; - lres.logger.backup = res->logger.backup ; - lres.logger.maxsize = res->logger.maxsize ; - lres.logger.timestamp = res->logger.timestamp ; - lres.logger.want = 0 ; - - // oneshot do not use fdholder daemon - if (res->type == TYPE_CLASSIC) { - - compute_log_script(res) ; - lres.execute.run.run = resolve_add_string(wres, res->sa.s + res->logger.execute.run.run) ; - lres.execute.run.run_user = resolve_add_string(wres, res->sa.s + res->logger.execute.run.run_user) ; - lres.execute.run.runas = resolve_add_string(wres, res->sa.s + res->logger.execute.run.runas) ; - } - - if (service_resolve_array_search(ares, *areslen, name) < 0) { - - log_trace("add service ", name, " to the selection") ; - if (*areslen > SS_MAX_SERVICE) - log_die(LOG_EXIT_SYS, "too many services to parse -- compile again 66 changing the --max-service options") ; - - ares[(*areslen)++] = lres ; - } - - free(wres) ; -} - -void parse_compute_resolve(unsigned int idx, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info) -{ - log_flow() ; - - resolve_service_t_ref res = &ares[idx] ; resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; char name[strlen(res->sa.s + res->name) + 1] ; @@ -486,43 +253,10 @@ void parse_compute_resolve(unsigned int idx, resolve_service_t *ares, unsigned i res->live.supervisedir = compute_state_dir(wres, info, SS_SUPERVISEDIR + 1) ; /* fdholder */ - res->live.fdholderdir = compute_pipe_service(wres, info, name, SS_FDHOLDER) ; + res->live.fdholderdir = compute_pipe_service(wres, info, SS_FDHOLDER) ; /* oneshotd */ - res->live.oneshotddir = compute_pipe_service(wres, info, name, SS_ONESHOTD) ; - - if (res->logger.want && (res->type == TYPE_CLASSIC || res->type == TYPE_ONESHOT)) { - - size_t namelen = strlen(name) ; - - char logname[namelen + SS_LOG_SUFFIX_LEN + 1] ; - - auto_strings(logname, name, SS_LOG_SUFFIX) ; - - res->logger.name = resolve_add_string(wres, logname) ; - - res->logger.destination = compute_log_dir(wres, res) ; - - if (res->type == TYPE_CLASSIC) { - - /** the logger is not a service with oneshot type */ - if (res->dependencies.ndepends) { - - char buf[strlen(res->sa.s + res->dependencies.depends) + 1 + strlen(res->sa.s + res->logger.name) + 1] ; - auto_strings(buf, res->sa.s + res->dependencies.depends, " ", res->sa.s + res->logger.name) ; - - res->dependencies.depends = resolve_add_string(wres, buf) ; - - } else { - - res->dependencies.depends = resolve_add_string(wres, res->sa.s + res->logger.name) ; - } - - res->dependencies.ndepends++ ; - - compute_log(res, ares, areslen, info) ; - } - } + res->live.oneshotddir = compute_pipe_service(wres, info, SS_ONESHOTD) ; if (res->type == TYPE_ONESHOT || res->type == TYPE_CLASSIC) { diff --git a/src/lib66/parse/parse_frontend.c b/src/lib66/parse/parse_frontend.c index 02dc6ba59d44587b0a9761393466c8ee1850731e..80c7c7aaa736595187d2c2bff22d2fba348e9c7f 100644 --- a/src/lib66/parse/parse_frontend.c +++ b/src/lib66/parse/parse_frontend.c @@ -86,7 +86,7 @@ static void parse_service_instance(stralloc *frontend, char const *svsrc, char c * @Die on fail * @Return 1 on success * @Return 2 -> already parsed */ -int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) +int parse_frontend(char const *sv, struct resolve_hash_s **hres, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) { log_flow() ; @@ -95,6 +95,7 @@ int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *aresle size_t svlen = strlen(sv) ; char svname[svlen + 1], svsrc[svlen + 1] ; stralloc sa = STRALLOC_ZERO ; + struct resolve_hash_s *hash ; if (!ob_basename(svname, sv)) log_dieu(LOG_EXIT_SYS, "get basename of: ", sv) ; @@ -104,18 +105,21 @@ int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *aresle if (inns) { - if (service_resolve_array_search(ares, *areslen, svname) >= 0) + hash = hash_search(hres, svname) ; + if (hash != NULL) log_warn_return(2, "ignoring: ", svname, " service -- already appended to the selection") ; char n[strlen(inns) + 1 + strlen(svname) + 1] ; auto_strings(n, inns, ":", svname) ; - if (service_resolve_array_search(ares, *areslen, n) >= 0) + hash = hash_search(hres, n) ; + if (hash != NULL) log_warn_return(2, "ignoring: ", n, " service -- already appended to the selection") ; } else { - if (service_resolve_array_search(ares, *areslen, svname) >= 0) + hash = hash_search(hres, svname) ; + if (hash != NULL) log_warn_return(2, "ignoring: ", svname, " service -- already appended to the selection") ; } @@ -262,19 +266,28 @@ int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *aresle /** parse interdependences if the service was never parsed */ if (isparsed == STATE_FLAGS_FALSE) { - if (!parse_interdependences(svname, res.sa.s + res.dependencies.depends, res.dependencies.ndepends, ares, areslen, info, force, conf, forced_directory, main, inns, intree)) + if (!parse_interdependences(svname, res.sa.s + res.dependencies.depends, res.dependencies.ndepends, hres, info, force, conf, forced_directory, main, inns, intree)) log_dieu(LOG_EXIT_SYS, "parse dependencies of service: ", svname) ; } if (res.type == TYPE_MODULE) - parse_module(&res, ares, areslen, info, force) ; + parse_module(&res, hres, info, force) ; - if (service_resolve_array_search(ares, *areslen, res.sa.s + res.name) < 0) { + parse_compute_resolve(&res, info) ; - log_trace("add service ", res.sa.s + res.name, " to the selection") ; - if (*areslen > SS_MAX_SERVICE) + if (res.logger.want && res.type != TYPE_MODULE && !res.inns) + parse_append_logger(hres, &res, info) ; + + hash = hash_search(hres, res.sa.s + res.name) ; + if (hash == NULL) { + + if (hash_count(hres) > SS_MAX_SERVICE) log_die(LOG_EXIT_SYS, "too many services to parse -- compile again 66 changing the --max-service options") ; - ares[(*areslen)++] = res ; + + log_trace("add service: ", res.sa.s + res.name, " to the service selection") ; + char *name = res.sa.s + res.name ; // hash_add + log_dieu doesn't accept res.sa.s + res.name + if (!hash_add(hres, name, res)) + log_dieu(LOG_EXIT_SYS, "append service selection with: ", name) ; } stralloc_free(&sa) ; diff --git a/src/lib66/parse/parse_interdependences.c b/src/lib66/parse/parse_interdependences.c index 5e70e87adf68edf5138b465c76cfa289754a44cc..417a408580d53d420db24ce4ecfc13f1eb4d664f 100644 --- a/src/lib66/parse/parse_interdependences.c +++ b/src/lib66/parse/parse_interdependences.c @@ -30,7 +30,7 @@ #include <66/instance.h> #include <66/module.h> -int parse_interdependences(char const *service, char const *list, unsigned int listlen, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) +int parse_interdependences(char const *service, char const *list, unsigned int listlen, struct resolve_hash_s **hres, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory, char const *main, char const *inns, char const *intree) { log_flow() ; @@ -89,7 +89,7 @@ int parse_interdependences(char const *service, char const *list, unsigned int l * forced_directory == 0 means that the service * comes from an external directory of the module. * In this case don't associated it at the module. */ - parse_frontend(sa.s, ares, areslen, info, force, conf, forced_directory, main, !forced_directory ? 0 : inns, !forced_directory ? 0 : intree) ; + parse_frontend(sa.s, hres, info, force, conf, forced_directory, main, !forced_directory ? 0 : inns, !forced_directory ? 0 : intree) ; } } else diff --git a/src/lib66/parse/parse_rename_interdependences.c b/src/lib66/parse/parse_rename_interdependences.c index a150b8cedbf986c975a243378988710c60353d51..56a09dc601167fe1f026efc479c75020c4da4809 100644 --- a/src/lib66/parse/parse_rename_interdependences.c +++ b/src/lib66/parse/parse_rename_interdependences.c @@ -27,124 +27,123 @@ #include <66/resolve.h> #include <66/enum.h> #include <66/constants.h> +#include <66/hash.h> -static void parse_prefix(char *result, stack *stk, resolve_service_t *ares, unsigned int areslen, char const *prefix) +static void parse_prefix(char *result, stack *stk, struct resolve_hash_s **hres, char const *prefix) { log_flow() ; - int aresid = -1 ; size_t pos = 0, mlen = strlen(prefix) ; + struct resolve_hash_s *hash ; FOREACH_STK(stk, pos) { - aresid = service_resolve_array_search(ares, areslen, stk->s + pos) ; + hash = hash_search(hres, stk->s + pos) ; + if (hash == NULL) { - if (aresid < 0) { /** try with the name of the prefix as prefix */ char tmp[mlen + 1 + strlen(stk->s + pos) + 1] ; auto_strings(tmp, prefix, ":", stk->s + pos) ; - aresid = service_resolve_array_search(ares, areslen, tmp) ; - if (aresid < 0) + hash = hash_search(hres, tmp) ; + if (hash == NULL) log_die(LOG_EXIT_USER, "service: ", stk->s + pos, " not available -- please make a bug report") ; } /** check if the dependencies is a external one. In this - * case, the service is not considered as part of the prefix */ - if (ares[aresid].inns && (!strcmp(ares[aresid].sa.s + ares[aresid].inns, prefix))) + * case, the service is not considered as part of the ns */ + if (hash->res.inns && (!strcmp(hash->res.sa.s + hash->res.inns, prefix)) && str_start_with(hash->res.sa.s + hash->res.name, prefix)) auto_strings(result + strlen(result), prefix, ":", stk->s + pos, " ") ; else - auto_strings(result + strlen(result), stk->s + pos, " ") ; + auto_strings(result + strlen(result), hash->res.sa.s + hash->res.name, " ") ; } result[strlen(result) - 1] = 0 ; } -static void parse_prefix_name(unsigned int idx, resolve_service_t *ares, unsigned int areslen, char const *prefix) +static void parse_prefix_name(resolve_service_t *res, struct resolve_hash_s **hres, char const *prefix) { log_flow() ; size_t mlen = strlen(prefix) ; - resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &ares[idx]) ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; - if (ares[idx].dependencies.ndepends) { + if (res->dependencies.ndepends) { - size_t depslen = strlen(ares[idx].sa.s + ares[idx].dependencies.depends) ; + size_t depslen = strlen(res->sa.s + res->dependencies.depends) ; _init_stack_(stk, depslen + 1) ; if (!stack_clean_string(&stk, res->sa.s + res->dependencies.depends, depslen)) log_dieusys(LOG_EXIT_SYS, "convert string to stack") ; - size_t len = (mlen + 1 + SS_MAX_TREENAME + 2) * ares[idx].dependencies.ndepends ; + size_t len = (mlen + 1 + SS_MAX_TREENAME + 2) * res->dependencies.ndepends ; char n[len] ; memset(n, 0, len * sizeof(char)); ; - parse_prefix(n, &stk, ares, areslen, prefix) ; + parse_prefix(n, &stk, hres, prefix) ; - ares[idx].dependencies.depends = resolve_add_string(wres, n) ; + res->dependencies.depends = resolve_add_string(wres, n) ; } - if (ares[idx].dependencies.nrequiredby) { + if (res->dependencies.nrequiredby) { - size_t depslen = strlen(ares[idx].sa.s + ares[idx].dependencies.requiredby) ; + size_t depslen = strlen(res->sa.s + res->dependencies.requiredby) ; _init_stack_(stk, depslen + 1) ; if (!stack_clean_string(&stk, res->sa.s + res->dependencies.requiredby, depslen)) log_dieusys(LOG_EXIT_SYS, "convert string to stack") ; - size_t len = (mlen + 1 + SS_MAX_TREENAME + 2) * ares[idx].dependencies.nrequiredby ; + size_t len = (mlen + 1 + SS_MAX_TREENAME + 2) * res->dependencies.nrequiredby ; char n[len] ; memset(n, 0, len * sizeof(char)) ; - parse_prefix(n, &stk, ares, areslen, prefix) ; + parse_prefix(n, &stk, hres, prefix) ; - ares[idx].dependencies.requiredby = resolve_add_string(wres, n) ; + res->dependencies.requiredby = resolve_add_string(wres, n) ; } free(wres) ; } -void parse_rename_interdependences(resolve_service_t *res, char const *prefix, resolve_service_t *ares, unsigned int *areslen) +void parse_rename_interdependences(resolve_service_t *res, char const *prefix, struct resolve_hash_s **hres, ssexec_t *info) { log_flow() ; - unsigned int aresid = 0 ; - size_t plen = strlen(prefix) ; - unsigned int visit[SS_MAX_SERVICE + 1] ; - resolve_wrapper_t_ref awres = 0 ; + struct resolve_hash_s *c, *tmp ; stralloc sa = STRALLOC_ZERO ; resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; - memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; - - for (; aresid < *areslen ; aresid++) { + HASH_ITER(hh, *hres, c, tmp) { - if (!strcmp(ares[aresid].sa.s + ares[aresid].inns, prefix)) { + if (!strcmp(c->res.sa.s + c->res.inns, prefix)) { - if (ares[aresid].dependencies.ndepends || ares[aresid].dependencies.nrequiredby) - parse_prefix_name(aresid, ares, *areslen, prefix) ; + if (c->res.dependencies.ndepends || c->res.dependencies.nrequiredby) + parse_prefix_name(&c->res, hres, prefix) ; - if (ares[aresid].logger.want && ares[aresid].type == TYPE_CLASSIC) { + if (c->res.logger.want && (c->res.type == TYPE_CLASSIC || c->res.type == TYPE_ONESHOT)) { - char n[strlen(ares[aresid].sa.s + ares[aresid].name) + SS_LOG_SUFFIX_LEN + 1] ; + size_t namelen = strlen(c->res.sa.s + c->res.name) ; + char logname[namelen + SS_LOG_SUFFIX_LEN + 1] ; - auto_strings(n, ares[aresid].sa.s + ares[aresid].name, SS_LOG_SUFFIX) ; + auto_strings(logname, c->res.sa.s + c->res.name, SS_LOG_SUFFIX) ; - if (!sastr_add_string(&sa, n)) - log_die_nomem("stralloc") ; - } + parse_append_logger(hres, &c->res, info) ; - char tmp[plen + 1 + strlen(ares[aresid].sa.s + ares[aresid].name) + 1] ; + if (c->res.type == TYPE_CLASSIC) { + if (!sastr_add_string(&sa, logname)) + log_die_nomem("stralloc") ; + } - auto_strings(tmp, prefix, ":", ares[aresid].sa.s + ares[aresid].name) ; + } - if (!sastr_add_string(&sa, ares[aresid].sa.s + ares[aresid].name)) - log_die_nomem("stralloc") ; + if (sastr_cmp(&sa, c->res.sa.s + c->res.name) < 0 ) + if (!sastr_add_string(&sa, c->res.sa.s + c->res.name)) + log_die_nomem("stralloc") ; } } @@ -152,5 +151,4 @@ void parse_rename_interdependences(resolve_service_t *res, char const *prefix, r stralloc_free(&sa) ; free(wres) ; - free(awres) ; } diff --git a/src/lib66/parse/parse_service.c b/src/lib66/parse/parse_service.c index 195cb1d000ad1c9595274bf5d57f4f999dd8e63c..d7957836f6d784dedde40a3b098aec64739c3f53 100644 --- a/src/lib66/parse/parse_service.c +++ b/src/lib66/parse/parse_service.c @@ -38,6 +38,7 @@ #include <66/graph.h> #include <66/sanitize.h> #include <66/symlink.h> +#include <66/hash.h> parse_mill_t MILL_GET_SECTION_NAME = \ { \ @@ -163,77 +164,69 @@ static void parse_write_state(resolve_service_t *res, char const *dst, uint8_t f } } -void parse_service(char const *sv, ssexec_t *info, uint8_t force, uint8_t conf) +void parse_service(struct resolve_hash_s **hres, char const *sv, ssexec_t *info, uint8_t force, uint8_t conf) { log_flow(); int r ; - unsigned int areslen = 0, count = 0, pos = 0 ; uint8_t rforce = 0 ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; stralloc sa = STRALLOC_ZERO ; + struct resolve_hash_s *c, *tmp ; char main[strlen(sv) + 1] ; if (!ob_basename(main, sv)) log_dieu(LOG_EXIT_SYS, "get basename of: ", sv) ; - r = parse_frontend(sv, ares, &areslen, info, force, conf, 0, main, 0, 0) ; + r = parse_frontend(sv, hres, info, force, conf, 0, main, 0, 0) ; if (r == 2) /** already parsed */ return ; - /** parse_compute_resolve add the logger - * to the ares array */ - count = areslen ; - for (; pos < count ; pos++) - parse_compute_resolve(pos, ares, &areslen, info) ; - - for (pos = 0 ; pos < areslen ; pos++) { + HASH_ITER(hh, *hres, c, tmp) { sa.len = 0 ; /** be paranoid */ rforce = 0 ; - size_t namelen = strlen(ares[pos].sa.s + ares[pos].name), homelen = strlen(ares[pos].sa.s + ares[pos].path.home) ; + size_t namelen = strlen(c->res.sa.s + c->res.name), homelen = strlen(c->res.sa.s + c->res.path.home) ; char servicedir[homelen + SS_SYSTEM_LEN + SS_SERVICE_LEN + SS_SVC_LEN + 1 + namelen + 1] ; - auto_strings(servicedir, ares[pos].sa.s + ares[pos].path.home, SS_SYSTEM, SS_SERVICE, SS_SVC, "/", ares[pos].sa.s + ares[pos].name) ; + auto_strings(servicedir, c->res.sa.s + c->res.path.home, SS_SYSTEM, SS_SERVICE, SS_SVC, "/", c->res.sa.s + c->res.name) ; - if (sanitize_write(&ares[pos], force)) + if (sanitize_write(&c->res, force)) rforce = 1 ; - if (!auto_stra(&sa, "/tmp/", ares[pos].sa.s + ares[pos].name, ":XXXXXX")) + if (!auto_stra(&sa, "/tmp/", c->res.sa.s + c->res.name, ":XXXXXX")) log_die_nomem("stralloc") ; if (!mkdtemp(sa.s)) log_dieusys(LOG_EXIT_SYS, "create temporary directory") ; - write_services(&ares[pos], sa.s, rforce) ; + write_services(&c->res, sa.s, rforce) ; - parse_write_state(&ares[pos], sa.s, rforce) ; + parse_write_state(&c->res, sa.s, rforce) ; - service_resolve_write_remote(&ares[pos], sa.s, rforce) ; + service_resolve_write_remote(&c->res, sa.s, rforce) ; - parse_copy_to_source(servicedir, sa.s, &ares[pos], rforce) ; + parse_copy_to_source(servicedir, sa.s, &c->res, rforce) ; /** do not die here, just warn the user */ log_trace("remove temporary directory: ", sa.s) ; if (!dir_rm_rf(sa.s)) log_warnu("remove temporary directory: ", sa.s) ; - tree_service_add(ares[pos].sa.s + ares[pos].treename, ares[pos].sa.s + ares[pos].name, info) ; + tree_service_add(c->res.sa.s + c->res.treename, c->res.sa.s + c->res.name, info) ; - if (!symlink_make(&ares[pos])) + if (!symlink_make(&c->res)) log_dieusys(LOG_EXIT_SYS, "make service symlink") ; /** symlink may exist already, be sure to point to the correct location */ - if (!symlink_switch(&ares[pos], SYMLINK_SOURCE)) + if (!symlink_switch(&c->res, SYMLINK_SOURCE)) log_dieusys(LOG_EXIT_SYS, "sanitize_symlink") ; - log_info("Parsed successfully: ", ares[pos].sa.s + ares[pos].name, " at tree: ", ares[pos].sa.s + ares[pos].treename) ; + log_info("Parsed successfully: ", c->res.sa.s + c->res.name, " at tree: ", c->res.sa.s + c->res.treename) ; } - service_resolve_array_free(ares, areslen) ; stralloc_free(&sa) ; } diff --git a/src/lib66/sanitize/sanitize_graph.c b/src/lib66/sanitize/sanitize_graph.c index 67f6bb8eba4ff0577be264a174bfe6e93aef5425..2e6b5f3caab9d9ac2ab27f69f0eb0c0a40f10e43 100644 --- a/src/lib66/sanitize/sanitize_graph.c +++ b/src/lib66/sanitize/sanitize_graph.c @@ -30,6 +30,7 @@ #include <66/graph.h> #include <66/constants.h> #include <66/enum.h> +#include <66/hash.h> /** rewrite depends/requiredby of each service * found on the system */ @@ -37,53 +38,53 @@ void sanitize_graph(ssexec_t *info) { log_flow() ; - int n = 0 ; uint32_t flag = 0 ; - unsigned int areslen = 0 ; stralloc sa = STRALLOC_ZERO ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hres = NULL, *c, *tmp ; graph_t graph = GRAPH_ZERO ; + resolve_wrapper_t_ref wres = 0 ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_TOPARSE|STATE_FLAGS_WANTUP|STATE_FLAGS_WANTDOWN) ; + log_trace("sanitize system graph") ; /** build the graph of the entire system */ - graph_build_service(&graph, ares, &areslen, info, flag) ; + graph_build_service(&graph, &hres, info, flag) ; - for (; n < areslen ; n++) { + HASH_ITER(hh, hres, c, tmp) { sa.len = 0 ; - resolve_service_t_ref res = &ares[n] ; - resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; - char *name = res->sa.s + res->name ; + wres = resolve_set_struct(DATA_SERVICE, &c->res) ; + + char *name = c->res.sa.s + c->res.name ; if (graph_matrix_get_edge_g_sa(&sa, &graph, name, 0, 0) < 0) log_dieu(LOG_EXIT_SYS, "get dependencies of service: ", name) ; - res->dependencies.ndepends = 0 ; - res->dependencies.depends = 0 ; + c->res.dependencies.ndepends = 0 ; + c->res.dependencies.depends = 0 ; if (sa.len) - res->dependencies.depends = parse_compute_list(wres, &sa, &res->dependencies.ndepends, 0) ; + c->res.dependencies.depends = parse_compute_list(wres, &sa, &c->res.dependencies.ndepends, 0) ; sa.len = 0 ; if (graph_matrix_get_edge_g_sa(&sa, &graph, name, 1, 0) < 0) log_dieu(LOG_EXIT_SYS, "get requiredby of service: ", name) ; - res->dependencies.nrequiredby = 0 ; - res->dependencies.requiredby = 0 ; + c->res.dependencies.nrequiredby = 0 ; + c->res.dependencies.requiredby = 0 ; if (sa.len) - res->dependencies.requiredby = parse_compute_list(wres, &sa, &res->dependencies.nrequiredby, 0) ; + c->res.dependencies.requiredby = parse_compute_list(wres, &sa, &c->res.dependencies.nrequiredby, 0) ; if (!resolve_write_g(wres, info->base.s, name)) log_dieu(LOG_EXIT_SYS, "write resolve file of service: ", name) ; - free(wres) ; + resolve_free(wres) ; } - service_resolve_array_free(ares, areslen) ; - graph_free_all(&graph) ; stralloc_free(&sa) ; + hash_free(&hres) ; + graph_free_all(&graph) ; } diff --git a/src/lib66/sanitize/sanitize_init.c b/src/lib66/sanitize/sanitize_init.c index bc52362b7cb7fed22875024966a91886fa14c43b..ad93ec2a6cb9344a329d86a82b3c4353e514057e 100644 --- a/src/lib66/sanitize/sanitize_init.c +++ b/src/lib66/sanitize/sanitize_init.c @@ -42,105 +42,109 @@ #include <66/sanitize.h> #include <66/symlink.h> -static unsigned int toclean[SS_MAX_SERVICE + 1] ; - -void cleanup(resolve_service_t *ares, unsigned int areslen) +void cleanup(struct resolve_hash_s *hash, unsigned int alen) { unsigned int pos = 0 ; int e = errno ; ss_state_t sta = STATE_ZERO ; + resolve_service_t_ref pres = 0 ; - for (; pos < areslen ; pos++) { + for (; pos < alen ; pos++) { - if (toclean[pos]) { + pres = &hash[pos].res ; - if (!sanitize_fdholder(&ares[pos], &sta, STATE_FLAGS_FALSE, 0)) - log_warnusys("sanitize fdholder directory: ", ares[pos].sa.s + ares[pos].live.fdholderdir); + if (!sanitize_fdholder(pres, &sta, STATE_FLAGS_FALSE, 0)) + log_warnusys("sanitize fdholder directory: ", pres->sa.s + pres->live.fdholderdir); - log_trace("remove directory: ", ares[pos].sa.s + ares[pos].live.servicedir) ; - if (!dir_rm_rf(ares[pos].sa.s + ares[pos].live.servicedir)) - log_warnusys("remove live directory: ", ares[pos].sa.s + ares[pos].live.servicedir) ; + log_trace("remove directory: ", pres->sa.s + pres->live.servicedir) ; + if (!dir_rm_rf(pres->sa.s + pres->live.servicedir)) + log_warnusys("remove live directory: ", pres->sa.s + pres->live.servicedir) ; + + log_trace("remove symlink: ", pres->sa.s + pres->live.scandir) ; + unlink(pres->sa.s + pres->live.scandir) ; - log_trace("remove symlink: ", ares[pos].sa.s + ares[pos].live.scandir) ; - unlink(ares[pos].sa.s + ares[pos].live.scandir) ; - } } errno = e ; } -void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_service_t *ares, unsigned int areslen) +void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, struct resolve_hash_s **hres) { log_flow() ; + /* nothing to do */ + if (!alen) + return ; + ftrigr_t fifo = FTRIGR_ZERO ; uint32_t earlier ; gid_t gid = getgid() ; int is_supervised = 0 ; - unsigned int pos = 0, nsv = 0 ; - unsigned int real[alen], msg[areslen] ; + unsigned int pos = 0, nsv = 0, msg[alen] ; ss_state_t sta = STATE_ZERO ; + resolve_service_t_ref pres = 0 ; + struct resolve_hash_s toclean[alen] ; + struct resolve_hash_s real[alen] ; + unsigned int ntoclean = 0 ; - memset(msg, 0, areslen * sizeof(unsigned int)) ; - memset(toclean, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; - - /* nothing to do */ - if (!alen) - return ; + memset(msg, 0, alen * sizeof(unsigned int)) ; + memset(toclean, 0, alen * sizeof(struct resolve_hash_s)) ; + memset(real, 0, alen * sizeof(struct resolve_hash_s)) ; for (; pos < alen ; pos++) { char *name = g->data.s + genalloc_s(graph_hash_t,&g->hash)[alist[pos]].vertex ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) + struct resolve_hash_s *hash = hash_search(hres,name) ; + if (hash == NULL) log_dieu(LOG_EXIT_SYS,"find ares id -- please make a bug reports") ; - toclean[aresid] = 1 ; - earlier = ares[aresid].earlier ; - char *scandir = ares[aresid].sa.s + ares[aresid].live.scandir ; + pres = &hash->res ; + + toclean[ntoclean++] = *hash ; + earlier = pres->earlier ; + char *scandir = pres->sa.s + pres->live.scandir ; size_t scandirlen = strlen(scandir) ; - int r = state_read(&sta, &ares[aresid]) ; + int r = state_read(&sta, pres) ; if (!r) log_dieu(LOG_EXIT_SYS, "read state file of: ", name, " -- please make a bug reports") ; - if (!sanitize_livestate(&ares[aresid], &sta)) { - cleanup(ares, areslen) ; - log_dieu(LOG_EXIT_SYS, "sanitize state directory: ", ares[aresid].sa.s + ares[aresid].name) ; + if (!sanitize_livestate(pres, &sta)) { + cleanup(toclean, ntoclean) ; + log_dieu(LOG_EXIT_SYS, "sanitize state directory: ", pres->sa.s + pres->name) ; } /** * Module type are not a daemons. We don't need to supervise it. * Special case for Oneshot, we only deal with the scandir symlink. */ - if (ares[aresid].type == TYPE_MODULE) + if (pres->type == TYPE_MODULE) continue ; is_supervised = access(scandir, F_OK) ; if (!earlier && !is_supervised) { log_trace(name," already initialized -- ignore it") ; - msg[aresid] = 1 ; + msg[pos] = 1 ; continue ; } if (is_supervised == -1) { - if (!sanitize_scandir(&ares[aresid], &sta)) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "sanitize_scandir directory: ", ares[aresid].sa.s + ares[aresid].live.scandir) ; + if (!sanitize_scandir(pres, &sta)) { + cleanup(toclean, pos) ; + log_dieusys(LOG_EXIT_SYS, "sanitize_scandir directory: ", pres->sa.s + pres->live.scandir) ; } - if (ares[aresid].type == TYPE_ONESHOT) { + if (pres->type == TYPE_ONESHOT) { - if (!state_write(&sta, &ares[aresid])) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "write status file of: ", ares[aresid].sa.s + ares[aresid].name) ; + if (!state_write(&sta, pres)) { + cleanup(toclean, pos) ; + log_dieusys(LOG_EXIT_SYS, "write status file of: ", pres->sa.s + pres->name) ; } continue ; } - } /* down file */ @@ -151,7 +155,7 @@ void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_s log_trace("create file: ", downfile) ; int fd = open_trunc(downfile) ; if (fd < 0) { - cleanup(ares, areslen) ; + cleanup(toclean, pos) ; log_dieusys(LOG_EXIT_SYS, "create file: ", downfile) ; } fd_close(fd) ; @@ -159,24 +163,24 @@ void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_s if (!earlier && is_supervised) { - if (!sanitize_fdholder(&ares[aresid], &sta, STATE_FLAGS_TRUE, 1)) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "sanitize fdholder directory: ", ares[aresid].sa.s + ares[aresid].live.fdholderdir) ; + if (!sanitize_fdholder(pres, &sta, STATE_FLAGS_TRUE, 1)) { + cleanup(toclean, pos) ; + log_dieusys(LOG_EXIT_SYS, "sanitize fdholder directory: ", pres->sa.s + pres->live.fdholderdir) ; } - log_trace("create fifo: ", ares[aresid].sa.s + ares[aresid].live.eventdir) ; - if (!ftrigw_fifodir_make(ares[aresid].sa.s + ares[aresid].live.eventdir, gid, 0)) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "create fifo: ", ares[aresid].sa.s + ares[aresid].live.eventdir) ; + log_trace("create fifo: ", pres->sa.s + pres->live.eventdir) ; + if (!ftrigw_fifodir_make(pres->sa.s + pres->live.eventdir, gid, 0)) { + cleanup(toclean, pos) ; + log_dieusys(LOG_EXIT_SYS, "create fifo: ", pres->sa.s + pres->live.eventdir) ; } } - if (!state_write(&sta, &ares[aresid])) { - cleanup(ares, areslen) ; + if (!state_write(&sta, pres)) { + cleanup(toclean, pos) ; log_dieu(LOG_EXIT_SYS, "write state file of: ", name) ; } - real[nsv++] = (unsigned int)aresid ; + real[nsv++] = *hash ; } /** @@ -198,24 +202,24 @@ void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_s tain_addsec(&deadline, &STAMP, 3) ; if (!ftrigr_startf_g(&fifo, &deadline)) { - cleanup(ares, areslen) ; + cleanup(toclean, ntoclean) ; log_dieusys(LOG_EXIT_SYS, "ftrigr") ; } for (pos = 0 ; pos < nsv ; pos++) { - if (ares[real[pos]].type == TYPE_CLASSIC && !ares[real[pos]].earlier) { + if (real[pos].res.type == TYPE_CLASSIC && !real[pos].res.earlier) { fake = pos ; - char *sa = ares[real[pos]].sa.s ; - char *eventdir = sa + ares[real[pos]].live.eventdir ; + char *sa = real[pos].res.sa.s ; + char *eventdir = sa + real[pos].res.live.eventdir ; log_trace("subcribe to fifo: ", eventdir) ; /** unsubscribe automatically, options is 0 */ ids[nids] = ftrigr_subscribe_g(&fifo, eventdir, "s", 0, &deadline) ; if (!ids[nids++]) { - cleanup(ares, areslen) ; + cleanup(toclean, ntoclean) ; log_dieusys(LOG_EXIT_SYS, "subcribe to fifo: ", eventdir) ; } } @@ -225,14 +229,14 @@ void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_s state_set_flag(&sta, STATE_FLAGS_TORELOAD, STATE_FLAGS_TRUE) ; - if (!sanitize_scandir(&ares[real[fake]], &sta)) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "sanitize scandir directory: ", ares[real[fake]].sa.s + ares[real[fake]].live.scandir) ; + if (!sanitize_scandir(&real[fake].res, &sta)) { + cleanup(toclean, ntoclean) ; + log_dieusys(LOG_EXIT_SYS, "sanitize scandir directory: ", real[fake].res.sa.s + real[fake].res.live.scandir) ; } log_trace("waiting for events on fifo...") ; if (ftrigr_wait_and_g(&fifo, ids, nids, &deadline) < 0) { - cleanup(ares, areslen) ; + cleanup(toclean, ntoclean) ; log_dieusys(LOG_EXIT_SYS, "wait for events") ; } } @@ -249,55 +253,56 @@ void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_s ss_state_t sta = STATE_ZERO ; char *name = g->data.s + genalloc_s(graph_hash_t,&g->hash)[alist[pos]].vertex ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) { - cleanup(ares, areslen) ; - log_dieu(LOG_EXIT_SYS, "find ares id of: ", name, " -- please make a bug reports") ; + + struct resolve_hash_s *hash = hash_search(hres, name) ; + if (hash == NULL) { + cleanup(toclean, ntoclean) ; + log_dieu(LOG_EXIT_SYS, "find hash id of: ", name, " -- please make a bug reports") ; } - char *sa = ares[aresid].sa.s ; + pres = &hash->res ; + char *sa = pres->sa.s ; - if (!state_read(&sta, &ares[aresid])) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "read status file of: ", sa + ares[aresid].name) ; + if (!state_read(&sta, pres)) { + cleanup(toclean, ntoclean) ; + log_dieusys(LOG_EXIT_SYS, "read status file of: ", sa + pres->name) ; } - if (ares[aresid].type == TYPE_CLASSIC) { + if (pres->type == TYPE_CLASSIC) { if (!earlier) { - log_trace("clean event directory: ", sa + ares[aresid].live.eventdir) ; - if (!ftrigw_clean(sa + ares[aresid].live.eventdir)) - log_warnu("clean event directory: ", sa + ares[aresid].live.eventdir) ; + log_trace("clean event directory: ", sa + pres->live.eventdir) ; + if (!ftrigw_clean(sa + pres->live.eventdir)) + log_warnu("clean event directory: ", sa + pres->live.eventdir) ; } } - if (ares[aresid].type == TYPE_CLASSIC || ares[aresid].type == TYPE_ONESHOT) { - - if (ares[aresid].logger.want) { - /** Creation of the logger destination. This is made here to avoid - * issues on tmpfs logger directory destination */ - uid_t log_uid ; - gid_t log_gid ; - char *logrunner = ares[aresid].logger.execute.run.runas ? ares[aresid].sa.s + ares[aresid].logger.execute.run.runas : SS_LOGGER_RUNNER ; - char *dst = ares[aresid].sa.s + ares[aresid].logger.destination ; - - if (!youruid(&log_uid, logrunner) || !yourgid(&log_gid, log_uid)) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "get uid and gid of: ", logrunner) ; - } - log_trace("create directory: ", dst) ; - if (!dir_create_parent(dst, 0755)) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "create directory: ", ares[aresid].sa.s + ares[aresid].logger.destination) ; - } + if ((pres->type == TYPE_CLASSIC || pres->type == TYPE_ONESHOT) && pres->logger.want) { + + /** Creation of the logger destination. This is made here to avoid + * issues on tmpfs logger directory destination */ + uid_t log_uid ; + gid_t log_gid ; + char *logrunner = pres->sa.s + pres->logger.execute.run.runas ; + char *dst = pres->sa.s + pres->logger.destination ; + + if (!youruid(&log_uid, logrunner) || !yourgid(&log_gid, log_uid)) { + cleanup(toclean, ntoclean) ; + log_dieusys(LOG_EXIT_SYS, "get uid and gid of: ", logrunner) ; + } + + log_trace("create directory: ", dst) ; + if (!dir_create_parent(dst, 0755)) { + cleanup(toclean, ntoclean) ; + log_dieusys(LOG_EXIT_SYS, "create directory: ", dst) ; + } - if (!ares[aresid].owner && (strcmp(ares[aresid].sa.s + ares[aresid].logger.execute.run.build, "custom"))) { + if (!pres->owner && (strcmp(pres->sa.s + pres->logger.execute.run.build, "custom"))) { - if (chown(dst, log_uid, log_gid) == -1) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "chown: ", dst) ; - } + if (chown(dst, log_uid, log_gid) == -1) { + cleanup(toclean, ntoclean) ; + log_dieusys(LOG_EXIT_SYS, "chown: ", dst) ; } } } @@ -306,12 +311,12 @@ void sanitize_init(unsigned int *alist, unsigned int alen, graph_t *g, resolve_s state_set_flag(&sta, STATE_FLAGS_TOINIT, STATE_FLAGS_FALSE) ; state_set_flag(&sta, STATE_FLAGS_ISSUPERVISED, STATE_FLAGS_TRUE) ; - if (!state_write(&sta, &ares[aresid])) { - cleanup(ares, areslen) ; - log_dieusys(LOG_EXIT_SYS, "write status file of: ", sa + ares[aresid].name) ; + if (!state_write(&sta, pres)) { + cleanup(toclean, ntoclean) ; + log_dieusys(LOG_EXIT_SYS, "write status file of: ", sa + pres->name) ; } - if (!msg[aresid]) + if (!msg[pos]) log_info("Initialized successfully: ", name) ; } } diff --git a/src/lib66/service/deps-lib/deps b/src/lib66/service/deps-lib/deps index 6df5dced719c4209b6f856c54c5e4cfd99ae53a1..d12958fd884fff7adc49b0fba8e892548380c732 100644 --- a/src/lib66/service/deps-lib/deps +++ b/src/lib66/service/deps-lib/deps @@ -7,9 +7,8 @@ service_frontend_src.o service_graph_build.o service_graph_collect.o service_graph_g.o +service_hash.o service_is_g.o -service_resolve_array_free.o -service_resolve_array_search.o service_resolve_copy.o service_resolve_get_field_tosa.o service_resolve_modify_field.o diff --git a/src/lib66/service/service_enable_disable.c b/src/lib66/service/service_enable_disable.c index 94ab869558a8d267b43a9ed1a7a3a87ee49d01f6..61965ffcc619a06c5e7979d5039c54af9e544b8c 100644 --- a/src/lib66/service/service_enable_disable.c +++ b/src/lib66/service/service_enable_disable.c @@ -17,6 +17,7 @@ #include <oblibs/log.h> #include <oblibs/graph.h> +#include <oblibs/stack.h> #include <oblibs/sastr.h> #include <skalibs/stralloc.h> @@ -27,13 +28,13 @@ #include <66/enum.h> #include <66/ssexec.h> -static void service_enable_disable_deps(graph_t *g, unsigned int idx, resolve_service_t *ares, unsigned int areslen, uint8_t action, unsigned int *visit, uint8_t propagate, ssexec_t *info) +static void service_enable_disable_deps(graph_t *g, struct resolve_hash_s *hash, struct resolve_hash_s **hres, uint8_t action, uint8_t propagate, ssexec_t *info) { log_flow() ; size_t pos = 0 ; stralloc sa = STRALLOC_ZERO ; - resolve_service_t_ref res = &ares[idx] ; + resolve_service_t_ref res = &hash->res ; if (graph_matrix_get_edge_g_sa(&sa, g, res->sa.s + res->name, action ? 0 : 1, 0) < 0) log_dieu(LOG_EXIT_SYS, "get ", action ? "dependencies" : "required by" ," of: ", res->sa.s + res->name) ; @@ -43,12 +44,15 @@ static void service_enable_disable_deps(graph_t *g, unsigned int idx, resolve_se FOREACH_SASTR(&sa, pos) { char *name = sa.s + pos ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) + + struct resolve_hash_s *h = hash_search(hres, name) ; + if (h == NULL) log_die(LOG_EXIT_USER, "service: ", name, " not available -- did you parse it?") ; - if (!visit[aresid]) - service_enable_disable(g, aresid, ares, areslen, action, visit, propagate, info) ; + if (!h->visit) { + service_enable_disable(g, h, hres, action, propagate, info) ; + h->visit = 1 ; + } } } @@ -57,27 +61,29 @@ static void service_enable_disable_deps(graph_t *g, unsigned int idx, resolve_se /** @action -> 0 disable * @action -> 1 enable */ -void service_enable_disable(graph_t *g, unsigned int idx, resolve_service_t *ares, unsigned int areslen, uint8_t action, unsigned int *visit, uint8_t propagate, ssexec_t *info) +void service_enable_disable(graph_t *g, struct resolve_hash_s *hash, struct resolve_hash_s **hres, uint8_t action, uint8_t propagate, ssexec_t *info) { log_flow() ; - if (!visit[idx]) { + if (!hash->visit) { - resolve_service_t_ref res = &ares[idx] ; + resolve_service_t_ref res = &hash->res ; resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ; + char const *treename = res->sa.s + (res->intree ? res->intree : res->treename) ; /** resolve file may already exist. Be sure to add it to the contents field of the tree.*/ if (action) - tree_service_add(res->sa.s + (res->intree ? res->intree : res->treename), res->sa.s + res->name, info) ; + tree_service_add(treename, res->sa.s + res->name, info) ; - if (!service_resolve_modify_field(res, E_RESOLVE_SERVICE_ENABLED, !action ? "0" : "1")) - log_dieu(LOG_EXIT_SYS, "modify resolve file of: ", res->sa.s + res->name) ; + res->enabled = action ; if (!resolve_write_g(wres, res->sa.s + res->path.home, res->sa.s + res->name)) log_dieu(LOG_EXIT_SYS, "write resolve file of: ", res->sa.s + res->name) ; if (propagate) - service_enable_disable_deps(g, idx, ares, areslen, action, visit, propagate, info) ; + service_enable_disable_deps(g, hash, hres, action, propagate, info) ; + + free(wres) ; /** the logger must be disabled to avoid to start it * with the 66 tree start <tree> command */ @@ -85,26 +91,27 @@ void service_enable_disable(graph_t *g, unsigned int idx, resolve_service_t *are char *name = res->sa.s + res->logger.name ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) + struct resolve_hash_s *h = hash_search(hres, name) ; + if (h == NULL) log_die(LOG_EXIT_USER, "service: ", name, " not available -- did you parse it?") ; - if (!visit[aresid]) { + if (!h->visit) { - wres = resolve_set_struct(DATA_SERVICE, &ares[aresid]) ; + wres = resolve_set_struct(DATA_SERVICE, &h->res) ; if (action) - tree_service_add(ares[aresid].sa.s + (ares[aresid].intree ? ares[aresid].intree : ares[aresid].treename), ares[aresid].sa.s + ares[aresid].name, info) ; + tree_service_add(treename, h->res.sa.s + h->res.name, info) ; - if (!service_resolve_modify_field(&ares[aresid], E_RESOLVE_SERVICE_ENABLED, !action ? "0" : "1")) - log_dieu(LOG_EXIT_SYS, "modify resolve file of: ", ares[aresid].sa.s + ares[aresid].name) ; + h->res.enabled = action ; - if (!resolve_write_g(wres, ares[aresid].sa.s + ares[aresid].path.home, ares[aresid].sa.s + ares[aresid].name)) - log_dieu(LOG_EXIT_SYS, "write resolve file of: ", ares[aresid].sa.s + ares[aresid].name) ; + if (!resolve_write_g(wres, h->res.sa.s + h->res.path.home, h->res.sa.s + h->res.name)) + log_dieu(LOG_EXIT_SYS, "write resolve file of: ", h->res.sa.s + h->res.name) ; - log_info("Disabled successfully service: ", name) ; + log_info("Disabled successfully: ", name) ; - visit[aresid] = 1 ; + h->visit = 1 ; + + resolve_free(wres) ; } } @@ -121,36 +128,37 @@ void service_enable_disable(graph_t *g, unsigned int idx, resolve_service_t *are FOREACH_STK(&stk, pos) { char *name = stk.s + pos ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) + + struct resolve_hash_s *h = hash_search(hres, name) ; + if (h == NULL) log_die(LOG_EXIT_USER, "service: ", name, " not available -- did you parse it?") ; - if (!visit[aresid]) { + if (!h->visit) { - wres = resolve_set_struct(DATA_SERVICE, &ares[aresid]) ; + wres = resolve_set_struct(DATA_SERVICE, &h->res) ; if (action) - tree_service_add(ares[aresid].sa.s + (ares[aresid].intree ? ares[aresid].intree : ares[aresid].treename), ares[aresid].sa.s + ares[aresid].name, info) ; + tree_service_add(treename, h->res.sa.s + h->res.name, info) ; - if (!service_resolve_modify_field(&ares[aresid], E_RESOLVE_SERVICE_ENABLED, !action ? "0" : "1")) - log_dieu(LOG_EXIT_SYS, "modify resolve file of: ", ares[aresid].sa.s + ares[aresid].name) ; + h->res.enabled = action ; - if (!resolve_write_g(wres, ares[aresid].sa.s + ares[aresid].path.home, ares[aresid].sa.s + ares[aresid].name)) - log_dieu(LOG_EXIT_SYS, "write resolve file of: ", ares[aresid].sa.s + ares[aresid].name) ; + if (!resolve_write_g(wres, h->res.sa.s + h->res.path.home, h->res.sa.s + h->res.name)) + log_dieu(LOG_EXIT_SYS, "write resolve file of: ", h->res.sa.s + h->res.name) ; - service_enable_disable_deps(g, aresid, ares, areslen, action, visit, propagate, info) ; + service_enable_disable_deps(g, h, hres, action, propagate, info) ; - visit[aresid] = 1 ; + h->visit = 1 ; - log_info(!action ? "Disabled" : "Enabled"," successfully service: ", ares[aresid].sa.s + ares[aresid].name) ; + log_info(!action ? "Disabled" : "Enabled"," successfully service: ", h->res.sa.s + h->res.name) ; + + resolve_free(wres) ; } } } } - free(wres) ; - visit[idx] = 1 ; + hash->visit = 1 ; - log_info(!action ? "Disabled" : "Enabled"," successfully service: ", ares[idx].sa.s + ares[idx].name) ; + log_info(!action ? "Disabled" : "Enabled"," successfully: ", hash->res.sa.s + hash->res.name) ; } } diff --git a/src/lib66/service/service_graph_build.c b/src/lib66/service/service_graph_build.c index 09f2dc0ecec6ae9566e8ea52ef349deccc71602b..0a4d8fb92678e3a221354860309b31ed7334b735 100644 --- a/src/lib66/service/service_graph_build.c +++ b/src/lib66/service/service_graph_build.c @@ -23,8 +23,9 @@ #include <66/service.h> #include <66/graph.h> #include <66/state.h> +#include <66/hash.h> -static void issupervised(char *store, resolve_service_t *ares, unsigned int areslen, char const *str) +static void issupervised(char *store, struct resolve_hash_s **hres, char const *str) { size_t pos = 0, len = strlen(str) ; ss_state_t ste = STATE_ZERO ; @@ -39,16 +40,16 @@ static void issupervised(char *store, resolve_service_t *ares, unsigned int ares char *name = stk.s + pos ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) { + struct resolve_hash_s *hash = hash_search(hres, name) ; + if (hash == NULL) { log_warn("service: ", name, " not available -- ignore it") ; continue ; } - if (!state_check(&ares[aresid])) + if (!state_check(&hash->res)) continue ; - if (!state_read(&ste, &ares[aresid])) + if (!state_read(&ste, &hash->res)) continue ; if (ste.issupervised == STATE_FLAGS_TRUE) @@ -60,23 +61,23 @@ static void issupervised(char *store, resolve_service_t *ares, unsigned int ares store[strlen(store) - 1] = 0 ; } -void service_graph_build(graph_t *g, resolve_service_t *ares, unsigned int areslen, uint32_t flag) +void service_graph_build(graph_t *g, struct resolve_hash_s **hres, uint32_t flag) { log_flow() ; - unsigned int pos = 0 ; ss_state_t ste = STATE_ZERO ; resolve_service_t_ref pres = 0 ; + struct resolve_hash_s *c, *tmp ; - for (; pos < areslen ; pos++) { + HASH_ITER(hh, *hres, c, tmp) { - pres = &ares[pos] ; + pres = &c->res ; char *service = pres->sa.s + pres->name ; - if (!state_check(&ares[pos])) + if (!state_check(pres)) continue ; - if (!state_read(&ste, &ares[pos])) + if (!state_read(&ste, pres)) continue ; if (ste.issupervised == STATE_FLAGS_FALSE && FLAGS_ISSET(flag, STATE_FLAGS_ISSUPERVISED)) { @@ -95,7 +96,7 @@ void service_graph_build(graph_t *g, resolve_service_t *ares, unsigned int aresl if (FLAGS_ISSET(flag, STATE_FLAGS_ISSUPERVISED)) { - issupervised(store, ares, areslen, pres->sa.s + pres->dependencies.depends) ; + issupervised(store, hres, pres->sa.s + pres->dependencies.depends) ; } else { @@ -114,7 +115,7 @@ void service_graph_build(graph_t *g, resolve_service_t *ares, unsigned int aresl if (FLAGS_ISSET(flag, STATE_FLAGS_ISSUPERVISED)) { - issupervised(store, ares, areslen, pres->sa.s + pres->dependencies.requiredby) ; + issupervised(store, hres, pres->sa.s + pres->dependencies.requiredby) ; } else { diff --git a/src/lib66/service/service_graph_collect.c b/src/lib66/service/service_graph_collect.c index b885e84c0db986730ca714bf2ee4a431e7cde670..99fcb3e64db79055d040aa1ef11377e8530623c7 100644 --- a/src/lib66/service/service_graph_collect.c +++ b/src/lib66/service/service_graph_collect.c @@ -27,12 +27,13 @@ #include <66/state.h> #include <66/graph.h> #include <66/enum.h> +#include <66/hash.h> /** list all services of the system dependending of the flag passed. * STATE_FLAGS_TOPARSE -> call sanitize_source * STATE_FLAGS_TOPROPAGATE -> it build with the dependencies/requiredby services. * STATE_FLAGS_ISSUPERVISED -> only keep already supervised service*/ -void service_graph_collect(graph_t *g, char const *slist, size_t slen, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint32_t flag) +void service_graph_collect(graph_t *g, char const *slist, size_t slen, struct resolve_hash_s **hres, ssexec_t *info, uint32_t flag) { log_flow () ; @@ -45,13 +46,11 @@ void service_graph_collect(graph_t *g, char const *slist, size_t slen, resolve_s for (; pos < slen ; pos += strlen(slist + pos) + 1) { char const *name = slist + pos ; + struct resolve_hash_s *hash = hash_search(hres, name) ; - if (service_resolve_array_search(ares, (*areslen), name) < 0) { + if (hash == NULL) { resolve_service_t res = RESOLVE_SERVICE_ZERO ; - /** need to make a copy of the resolve due of the freed - * of the wres struct at the end of the process */ - resolve_service_t cp = RESOLVE_SERVICE_ZERO ; wres = resolve_set_struct(DATA_SERVICE, &res) ; /** double pass with resolve_read. @@ -90,10 +89,9 @@ void service_graph_collect(graph_t *g, char const *slist, size_t slen, resolve_s if (res.earlier) { - if (!service_resolve_copy(&cp, &res)) - log_dieu(LOG_EXIT_SYS, "copy resolve file of: ", name, " -- please make a bug report") ; - - ares[(*areslen)++] = cp ; + log_trace("add service: ", name, " to the graph selection") ; + if (!hash_add(hres, name, res)) + log_dieu(LOG_EXIT_SYS, "append graph selection with: ", name) ; continue ; } resolve_free(wres) ; @@ -104,10 +102,9 @@ void service_graph_collect(graph_t *g, char const *slist, size_t slen, resolve_s if (ste.issupervised == STATE_FLAGS_TRUE) { - if (!service_resolve_copy(&cp, &res)) - log_dieu(LOG_EXIT_SYS, "copy resolve file of: ", name, " -- please make a bug report") ; - - ares[(*areslen)++] = cp ; + log_trace("add service: ", name, " to the graph selection") ; + if (!hash_add(hres, name, res)) + log_dieu(LOG_EXIT_SYS, "append graph selection with: ", name) ; } else { resolve_free(wres) ; @@ -116,10 +113,9 @@ void service_graph_collect(graph_t *g, char const *slist, size_t slen, resolve_s } else { - if (!service_resolve_copy(&cp, &res)) - log_dieu(LOG_EXIT_SYS, "copy resolve file of: ", name, " -- please make a bug report") ; - - ares[(*areslen)++] = cp ; + log_trace("add service: ", name, " to the graph selection") ; + if (!hash_add(hres, name, res)) + log_dieu(LOG_EXIT_SYS, "append graph selection with: ", name) ; } if (FLAGS_ISSET(flag, STATE_FLAGS_TOPROPAGATE)) { @@ -132,7 +128,7 @@ void service_graph_collect(graph_t *g, char const *slist, size_t slen, resolve_s if (!stack_clean_string(&stk, res.sa.s + res.dependencies.depends, len)) log_dieusys(LOG_EXIT_SYS, "clean string") ; - service_graph_collect(g, stk.s, stk.len, ares, areslen, info, flag) ; + service_graph_collect(g, stk.s, stk.len, hres, info, flag) ; } @@ -144,11 +140,12 @@ void service_graph_collect(graph_t *g, char const *slist, size_t slen, resolve_s if (!stack_clean_string(&stk, res.sa.s + res.dependencies.requiredby, len)) log_dieusys(LOG_EXIT_SYS, "clean string") ; - service_graph_collect(g, stk.s, stk.len, ares, areslen, info, flag) ; + service_graph_collect(g, stk.s, stk.len, hres, info, flag) ; } } - resolve_free(wres) ; + + free(wres) ; } } } diff --git a/src/lib66/service/service_graph_g.c b/src/lib66/service/service_graph_g.c index 7d806ccda27780cd4f335611191e4f46fe9a9aef..ac3f1ac6250125eb0e89347b9360307c2ed9249c 100644 --- a/src/lib66/service/service_graph_g.c +++ b/src/lib66/service/service_graph_g.c @@ -25,6 +25,7 @@ #include <66/ssexec.h> #include <66/state.h> #include <66/enum.h> +#include <66/hash.h> static void debug_flag(uint32_t flag) { @@ -73,19 +74,19 @@ static void debug_flag(uint32_t flag) log_trace("requested flags to build the graph: ", req) ; } -void service_graph_g(char const *slist, size_t slen, graph_t *graph, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint32_t flag) +void service_graph_g(char const *slist, size_t slen, graph_t *graph, struct resolve_hash_s **hres, ssexec_t *info, uint32_t flag) { log_flow() ; debug_flag(flag) ; - service_graph_collect(graph, slist, slen, ares, areslen, info, flag) ; + service_graph_collect(graph, slist, slen, hres, info, flag) ; - if (!*areslen) { + if (!HASH_COUNT(*hres)) { /* avoid empty string */ log_warn("no services matching the requirements at tree: ", info->treename.s) ; return ; } - service_graph_build(graph, ares, (*areslen), flag) ; + service_graph_build(graph, hres, flag) ; } diff --git a/src/lib66/service/service_hash.c b/src/lib66/service/service_hash.c new file mode 100644 index 0000000000000000000000000000000000000000..26d314e1476a2970b2d0d56802f8a04013ac377c --- /dev/null +++ b/src/lib66/service/service_hash.c @@ -0,0 +1,70 @@ +/* + * service_hash.c + * + * Copyright (c) 2018-2023 Eric Vidal <eric@obarun.org> + * + * All rights reserved. + * + * This file is part of Obarun. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution. + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file./ + */ + +#include <stddef.h> +#include <stdlib.h> + +#include <oblibs/log.h> +#include <oblibs/string.h> + +#include <66/service.h> +#include <66/hash.h> + +#include <66/resolve.h> + +int hash_add(struct resolve_hash_s **hash, char const *name, resolve_service_t res) +{ + log_flow() ; + + struct resolve_hash_s *s ; + s = (struct resolve_hash_s *)malloc(sizeof(*s)); + if (s == NULL) + return 0 ; + + memset(s, 0, sizeof(*s)) ; + s->visit = 0 ; + auto_strings(s->name, name) ; + s->res = res ; + HASH_ADD_STR(*hash, name, s) ; + + return 1 ; +} + +struct resolve_hash_s *hash_search(struct resolve_hash_s **hash, char const *name) +{ + log_flow() ; + + struct resolve_hash_s *s ; + HASH_FIND_STR(*hash, name, s) ; + return s ; + +} + +int hash_count(struct resolve_hash_s **hash) +{ + return HASH_COUNT(*hash) ; +} + +void hash_free(struct resolve_hash_s **hash) +{ + log_flow() ; + + struct resolve_hash_s *c, *tmp ; + + HASH_ITER(hh, *hash, c, tmp) { + stralloc_free(&c->res.sa) ; + HASH_DEL(*hash, c) ; + free(c) ; + } +} diff --git a/src/lib66/service/service_resolve_array_free.c b/src/lib66/service/service_resolve_array_free.c deleted file mode 100644 index 9688b39d26e22021fe69f5f254cf0c314a933b51..0000000000000000000000000000000000000000 --- a/src/lib66/service/service_resolve_array_free.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * service_resolve_array_free.c - * - * Copyright (c) 2018-2023 Eric Vidal <eric@obarun.org> - * - * All rights reserved. - * - * This file is part of Obarun. It is subject to the license terms in - * the LICENSE file found in the top-level directory of this - * distribution. - * This file may not be copied, modified, propagated, or distributed - * except according to the terms contained in the LICENSE file./ - */ - -#include <skalibs/stralloc.h> - -#include <66/service.h> - -void service_resolve_array_free(resolve_service_t *ares, unsigned int areslen) -{ - - unsigned int pos = 0 ; - for (; pos < areslen ; pos++) - stralloc_free(&ares[pos].sa) ; -} - diff --git a/src/lib66/service/service_resolve_array_search.c b/src/lib66/service/service_resolve_array_search.c deleted file mode 100644 index 1872aba40f194306979789495b642df788c8e996..0000000000000000000000000000000000000000 --- a/src/lib66/service/service_resolve_array_search.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * service_resolve_array_search.c - * - * Copyright (c) 2018-2023 Eric Vidal <eric@obarun.org> - * - * All rights reserved. - * - * This file is part of Obarun. It is subject to the license terms in - * the LICENSE file found in the top-level directory of this - * distribution. - * This file may not be copied, modified, propagated, or distributed - * except according to the terms contained in the LICENSE file./ - */ - -#include <string.h> -#include <oblibs/log.h> -#include <66/service.h> - -int service_resolve_array_search(resolve_service_t *ares, unsigned int areslen, char const *name) -{ - log_flow() ; - - unsigned int pos = 0 ; - - for (; pos < areslen ; pos++) { - - char const *n = ares[pos].sa.s + ares[pos].name ; - if (!strcmp(name, n)) - return pos ; - } - - return -1 ; -} - diff --git a/src/lib66/svc/svc_compute_ns.c b/src/lib66/svc/svc_compute_ns.c index 266d3e3cfff8c3bd2022ff3609e713486f7012fe..b417f6bbff0680d5472335eb68ae411f361d5d0b 100644 --- a/src/lib66/svc/svc_compute_ns.c +++ b/src/lib66/svc/svc_compute_ns.c @@ -28,7 +28,7 @@ #include <66/sanitize.h> /** sares -> services ares */ -int svc_compute_ns(resolve_service_t *sares, unsigned int sareslen, unsigned int saresid, uint8_t what, ssexec_t *info, char const *updown, uint8_t opt_updown, uint8_t reloadmsg,char const *data, uint8_t propagate, pidservice_t *handled, unsigned int nhandled) +int svc_compute_ns(resolve_service_t *res, uint8_t what, ssexec_t *info, char const *updown, uint8_t opt_updown, uint8_t reloadmsg,char const *data, uint8_t propagate, pidservice_t *handled, unsigned int nhandled) { log_flow() ; @@ -39,12 +39,11 @@ int svc_compute_ns(resolve_service_t *sares, unsigned int sareslen, unsigned int _init_stack_(stk, SS_MAX_SERVICE * SS_MAX_SERVICE_NAME) ; unsigned int napid = 0 ; - unsigned int areslen = 0, list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1] ; - resolve_service_t ares[SS_MAX_SERVICE + 1] ; + unsigned int list[SS_MAX_SERVICE + 1], visit[SS_MAX_SERVICE + 1] ; + struct resolve_hash_s *hash = NULL ; memset(list, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; memset(visit, 0, (SS_MAX_SERVICE + 1) * sizeof(unsigned int)) ; - memset(ares, 0, (SS_MAX_SERVICE + 1) * sizeof(resolve_service_t)) ; uint32_t gflag = STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP ; if (!propagate) @@ -56,18 +55,18 @@ int svc_compute_ns(resolve_service_t *sares, unsigned int sareslen, unsigned int FLAGS_CLEAR(gflag, STATE_FLAGS_WANTUP) ; } - if (sares[saresid].dependencies.ncontents) { + if (res->dependencies.ncontents) { if (!stack_clean_string_g(&stk, res->sa.s + res->dependencies.contents)) log_dieu(LOG_EXIT_SYS, "clean string") ; } else { - log_warn("empty ns: ", sares[saresid].sa.s + sares[saresid].name) ; + log_warn("empty ns: ", res->sa.s + res->name) ; return 0 ; } /** build the graph of the ns */ - service_graph_g(stk.s, stk.len, &graph, ares, &areslen, info, gflag) ; + service_graph_g(stk.s, stk.len, &graph, &hash, info, gflag) ; if (!graph.mlen) log_die(LOG_EXIT_USER, "services selection is not supervised -- initiate its first") ; @@ -76,28 +75,28 @@ int svc_compute_ns(resolve_service_t *sares, unsigned int sareslen, unsigned int char const *name = stk.s + pos ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) + struct resolve_hash_s *h = hash_search(&hash, name) ; + if (h == NULL) log_die(LOG_EXIT_USER, "service: ", name, " not available -- did you parse it?") ; - if (ares[aresid].earlier) { - log_warn("ignoring ealier service: ", ares[aresid].sa.s + ares[aresid].name) ; + if (h->res.earlier) { + log_warn("ignoring ealier service: ", h->res.sa.s + h->res.name) ; continue ; } - graph_compute_visit(ares, aresid, visit, list, &graph, &napid, requiredby) ; + graph_compute_visit(*h, visit, list, &graph, &napid, requiredby) ; } if (!what) - sanitize_init(list, napid, &graph, ares, areslen) ; + sanitize_init(list, napid, &graph, &hash) ; pidservice_t apids[napid] ; - svc_init_array(list, napid, apids, &graph, ares, areslen, info, requiredby, gflag) ; + svc_init_array(list, napid, apids, &graph, &hash, info, requiredby, gflag) ; - r = svc_launch(apids, napid, what, &graph, ares, areslen, info, updown, opt_updown, reloadmsg, data, propagate) ; + r = svc_launch(apids, napid, what, &graph, &hash, info, updown, opt_updown, reloadmsg, data, propagate) ; + hash_free(&hash) ; graph_free_all(&graph) ; - service_resolve_array_free(ares, areslen) ; return r ; } diff --git a/src/lib66/svc/svc_init_array.c b/src/lib66/svc/svc_init_array.c index da7288f7671ae50b7002b718fbd3284b0159f110..c735caad74d7dd987574130d6eab1cc4426a13ef 100644 --- a/src/lib66/svc/svc_init_array.c +++ b/src/lib66/svc/svc_init_array.c @@ -42,7 +42,7 @@ static pidservice_t pidservice_init(unsigned int len) return pids ; } -void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apids, graph_t *g, resolve_service_t *ares, unsigned int areslen, ssexec_t *info, uint8_t requiredby, uint32_t flag) +void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apids, graph_t *g, struct resolve_hash_s **hres, ssexec_t *info, uint8_t requiredby, uint32_t flag) { log_flow() ; @@ -55,20 +55,20 @@ void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apid char *name = g->data.s + genalloc_s(graph_hash_t,&g->hash)[list[pos]].vertex ; - pids.aresid = service_resolve_array_search(ares, areslen, name) ; - - if (pids.aresid < 0) - log_dieu(LOG_EXIT_SYS,"find ares id of: ", name, " -- please make a bug reports") ; + struct resolve_hash_s *hash = hash_search(hres, name) ; + if (hash == NULL) + log_dieu(LOG_EXIT_SYS,"find hash id of: ", name, " -- please make a bug reports") ; + pids.res = &hash->res ; if (FLAGS_ISSET(flag, STATE_FLAGS_TOPROPAGATE)) { - pids.nedge = graph_matrix_get_edge_g_sorted_list(pids.edge, g, name, requiredby, 1) ; + pids.nedge = graph_matrix_get_edge_g_sorted_list(pids.edge, g, name, requiredby, 0) ; if (pids.nedge < 0) log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of service: ", name) ; - pids.nnotif = graph_matrix_get_edge_g_sorted_list(pids.notif, g, name, !requiredby, 1) ; + pids.nnotif = graph_matrix_get_edge_g_sorted_list(pids.notif, g, name, !requiredby, 0) ; if (pids.nnotif < 0) log_dieu(LOG_EXIT_SYS,"get sorted ", !requiredby ? "required by" : "dependency", " list of service: ", name) ; @@ -79,11 +79,11 @@ void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apid if (pids.vertex < 0) log_dieu(LOG_EXIT_SYS, "get vertex id -- please make a bug report") ; - if (ares[pids.aresid].type != TYPE_CLASSIC) { + if (pids.res->type != TYPE_CLASSIC) { ss_state_t sta = STATE_ZERO ; - if (!state_read(&sta, &ares[pids.aresid])) + if (!state_read(&sta, pids.res)) log_dieusys(LOG_EXIT_SYS, "read state file of: ", name) ; if (sta.isup == STATE_FLAGS_TRUE) @@ -95,7 +95,7 @@ void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apid s6_svstatus_t status ; - r = s6_svstatus_read(ares[pids.aresid].sa.s + ares[pids.aresid].live.scandir, &status) ; + r = s6_svstatus_read(pids.res->sa.s + pids.res->live.scandir, &status) ; pid_t pid = !r ? 0 : status.pid ; @@ -109,4 +109,4 @@ void svc_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apid apids[pos] = pids ; } -} \ No newline at end of file +} diff --git a/src/lib66/svc/svc_launch.c b/src/lib66/svc/svc_launch.c index e637489c3792fb92190a86705af748db3f719b90..c4806d04f8fdf2ba23f8bc10eddb14b58e82a549 100644 --- a/src/lib66/svc/svc_launch.c +++ b/src/lib66/svc/svc_launch.c @@ -43,8 +43,6 @@ static unsigned int napid = 0 ; static unsigned int npid = 0 ; -static resolve_service_t_ref pares = 0 ; -static unsigned int pareslen = 0 ; static char data[DATASIZE + 1] ; static char updown[4] ; static uint8_t opt_updown = 0 ; @@ -109,19 +107,6 @@ static inline void kill_all(pidservice_t *apids) while (j--) kill(apids[j].pid, SIGKILL) ; } -static int pidservice_get_id(pidservice_t *apids, unsigned int id) -{ - log_flow() ; - - unsigned int pos = 0 ; - - for (; pos < napid ; pos++) { - if (apids[pos].vertex == id) - return (unsigned int) pos ; - } - return -1 ; -} - static int check_action(pidservice_t *apids, unsigned int pos, unsigned int receive, unsigned int what) { unsigned int p = char2enum[receive] ; @@ -161,16 +146,16 @@ static void notify(pidservice_t *apids, unsigned int pos, char const *sig, unsig if (apids[pos].notif[i] == apids[idx].vertex && !FLAGS_ISSET(apids[idx].state, flag)) { - size_t nlen = uint_fmt(fmt, apids[pos].aresid) ; + size_t nlen = uint_fmt(fmt, pos) ; fmt[nlen] = 0 ; size_t len = nlen + 1 + 2 ; char s[len + 1] ; auto_strings(s, fmt, ":", sig, "@") ; - log_trace("sends notification ", sig, " to: ", pares[apids[idx].aresid].sa.s + pares[apids[idx].aresid].name, " from: ", pares[apids[pos].aresid].sa.s + pares[apids[pos].aresid].name) ; + log_trace("sends notification ", sig, " to: ", apids[idx].res->sa.s + apids[idx].res->name, " from: ", apids[pos].res->sa.s + apids[pos].res->name) ; if (write(apids[idx].pipe[1], s, strlen(s)) < 0) - log_dieusys(LOG_EXIT_SYS, "send notif to: ", pares[apids[idx].aresid].sa.s + pares[apids[idx].aresid].name) ; + log_dieusys(LOG_EXIT_SYS, "send notif to: ", apids[idx].res->sa.s + apids[idx].res->name) ; } } } @@ -186,8 +171,8 @@ static void announce(unsigned int pos, pidservice_t *apids, unsigned int what, u int fd = 0 ; char fmt[UINT_FMT] ; - char const *name = pares[apids[pos].aresid].sa.s + pares[apids[pos].aresid].name ; - char const *scandir = pares[apids[pos].aresid].sa.s + pares[apids[pos].aresid].live.scandir ; + char const *name = apids[pos].res->sa.s + apids[pos].res->name ; + char const *scandir = apids[pos].res->sa.s + apids[pos].res->live.scandir ; size_t scandirlen = strlen(scandir) ; char file[scandirlen + 6] ; @@ -197,7 +182,7 @@ static void announce(unsigned int pos, pidservice_t *apids, unsigned int what, u if (success) { - if (pares[apids[pos].aresid].type == TYPE_CLASSIC) { + if (apids[pos].res->type == TYPE_CLASSIC) { fd = open_trunc(file) ; if (fd < 0) @@ -205,17 +190,17 @@ static void announce(unsigned int pos, pidservice_t *apids, unsigned int what, u fd_close(fd) ; } - notify(apids, pos, "F", what) ; - fmt[uint_fmt(fmt, exitcode)] = 0 ; - log_1_warn("Unable to ", reloadmsg == 1 ? "restart" : reloadmsg > 1 ? "reload" : what ? "stop" : "start", " service: ", name, " -- exited with signal: ", fmt) ; + log_1_warn("unable to ", reloadmsg == 1 ? "restart" : reloadmsg > 1 ? "reload" : what ? "stop" : "start", " service: ", name, " -- exited with signal: ", fmt) ; + + notify(apids, pos, "F", what) ; FLAGS_SET(apids[pos].state, SVC_FLAGS_BLOCK|SVC_FLAGS_FATAL) ; } else { - if (!state_messenger(&pares[apids[pos].aresid], STATE_FLAGS_ISUP, \ + if (!state_messenger(apids[pos].res, STATE_FLAGS_ISUP, \ data[1] == 'a' || \ data[1] == 'h' || \ data[1] == 'U' || \ @@ -223,7 +208,7 @@ static void announce(unsigned int pos, pidservice_t *apids, unsigned int what, u ? STATE_FLAGS_TRUE : what ? STATE_FLAGS_FALSE : STATE_FLAGS_TRUE)) log_dieu(LOG_EXIT_SYS, "send message to state of: ", name) ; - if (!pares[apids[pos].aresid].execute.down && pares[apids[pos].aresid].type == TYPE_CLASSIC) { + if (!apids[pos].res->execute.down && apids[pos].res->type == TYPE_CLASSIC) { if (!what) { @@ -242,12 +227,12 @@ static void announce(unsigned int pos, pidservice_t *apids, unsigned int what, u } } + log_info("Successfully ", reloadmsg == 1 ? "restarted" : reloadmsg > 1 ? "reloaded" : what ? "stopped" : "started", " service: ", name) ; + notify(apids, pos, what ? "D" : "U", what) ; FLAGS_CLEAR(apids[pos].state, SVC_FLAGS_BLOCK) ; FLAGS_SET(apids[pos].state, flag|SVC_FLAGS_UNBLOCK) ; - - log_info("Successfully ", reloadmsg == 1 ? "restarted" : reloadmsg > 1 ? "reloaded" : what ? "stopped" : "started", " service: ", name) ; } } @@ -269,7 +254,7 @@ static int handle_signal(pidservice_t *apids, unsigned int what, graph_t *graph, for (;;) { unsigned int pos = 0 ; - int wstat ; + int wstat = 0 ; pid_t r = wait_nohang(&wstat) ; if (r < 0) { @@ -290,17 +275,16 @@ static int handle_signal(pidservice_t *apids, unsigned int what, graph_t *graph, if (!WIFSIGNALED(wstat) && !WEXITSTATUS(wstat)) { announce(pos, apids, what, 0, 0) ; + npid-- ; } else { ok = WIFSIGNALED(wstat) ? WTERMSIG(wstat) : WEXITSTATUS(wstat) ; announce(pos, apids, what, 1, ok) ; - + npid-- ; kill_all(apids) ; break ; } - - npid-- ; } } break ; @@ -318,23 +302,23 @@ static int handle_signal(pidservice_t *apids, unsigned int what, graph_t *graph, return ok ; } -unsigned int compute_timeout(unsigned int idx, unsigned int what) +unsigned int compute_timeout(resolve_service_t *res, unsigned int what) { unsigned int timeout = 0 ; if (!what) { - if (pares[idx].type == TYPE_ONESHOT && pares[idx].execute.timeout.up) - timeout = pares[idx].execute.timeout.up ; - else if (pares[idx].type == TYPE_CLASSIC && pares[idx].execute.timeout.kill) - timeout = pares[idx].execute.timeout.kill ; + if (res->type == TYPE_ONESHOT && res->execute.timeout.up) + timeout = res->execute.timeout.up ; + else if (res->type == TYPE_CLASSIC && res->execute.timeout.kill) + timeout = res->execute.timeout.kill ; } else { - if (pares[idx].type == TYPE_ONESHOT && pares[idx].execute.timeout.down) - timeout = pares[idx].execute.timeout.down ; - else if (pares[idx].type == TYPE_CLASSIC && pares[idx].execute.timeout.finish) - timeout = pares[idx].execute.timeout.finish ; + if (res->type == TYPE_ONESHOT && res->execute.timeout.down) + timeout = res->execute.timeout.down ; + else if (res->type == TYPE_CLASSIC && res->execute.timeout.finish) + timeout = res->execute.timeout.finish ; } if (!timeout && PINFO->opt_timeout) @@ -348,8 +332,7 @@ static int doit(pidservice_t *apids, unsigned int napid, unsigned int idx, unsig { log_flow() ; - unsigned int pidx = apids[idx].aresid ; - uint8_t type = pares[pidx].type ; + uint8_t type = apids[idx].res->type ; pid_t pid ; int wstat ; @@ -358,17 +341,17 @@ static int doit(pidservice_t *apids, unsigned int napid, unsigned int idx, unsig unsigned int timeout = 0 ; - timeout = compute_timeout(pidx, what) ; + timeout = compute_timeout(apids[idx].res, what) ; tfmt[uint_fmt(tfmt, timeout)] = 0 ; if (type == TYPE_CLASSIC) { - char *scandir = pares[pidx].sa.s + pares[pidx].live.scandir ; + char *scandir = apids[idx].res->sa.s + apids[idx].res->live.scandir ; if (updown[2] == 'U' || updown[2] == 'D' || updown[2] == 'R') { - if (!pares[pidx].notify) + if (!apids[idx].res->notify) updown[2] = updown[2] == 'U' ? 'u' : updown[2] == 'D' ? 'd' : updown[2] == 'R' ? 'r' : updown[2] ; } @@ -402,17 +385,9 @@ static int doit(pidservice_t *apids, unsigned int napid, unsigned int idx, unsig } else if (type == TYPE_ONESHOT) { - char *sa = pares[pidx].sa.s ; - char *name = sa + pares[pidx].name ; - size_t namelen = strlen(name) ; - char *home = pares[pidx].sa.s + pares[pidx].path.home ; - size_t homelen = strlen(home) ; - - char script[homelen + SS_SYSTEM_LEN + SS_SERVICE_LEN + SS_SVC_LEN + 1 + namelen + 7 + 1] ; - auto_strings(script, home, SS_SYSTEM, SS_SERVICE, SS_SVC, "/", name) ; - - char *oneshotdir = pares[pidx].sa.s + pares[pidx].live.oneshotddir ; - char *scandir = pares[pidx].sa.s + pares[pidx].live.scandir ; + char *servicedir = apids[idx].res->sa.s + apids[idx].res->live.servicedir ; + char *oneshotdir = apids[idx].res->sa.s + apids[idx].res->live.oneshotddir ; + char *scandir = apids[idx].res->sa.s + apids[idx].res->live.scandir ; char oneshot[strlen(oneshotdir) + 2 + 1] ; auto_strings(oneshot, oneshotdir, "/s") ; @@ -427,7 +402,7 @@ static int doit(pidservice_t *apids, unsigned int napid, unsigned int idx, unsig newargv[m++] = "--" ; newargv[m++] = oneshot ; newargv[m++] = !what ? "up" : "down" ; - newargv[m++] = script ; + newargv[m++] = servicedir ; newargv[m++] = 0 ; log_trace("sending ", !what ? "up" : "down", " to: ", scandir) ; @@ -457,7 +432,7 @@ static int doit(pidservice_t *apids, unsigned int napid, unsigned int idx, unsig newargv[m++] = "--" ; newargv[m++] = oneshot ; newargv[m++] = "up" ; - newargv[m++] = script ; + newargv[m++] = servicedir ; newargv[m++] = 0 ; pid = child_spawn0(newargv[0], newargv, (char const *const *) environ) ; @@ -478,19 +453,19 @@ static int doit(pidservice_t *apids, unsigned int napid, unsigned int idx, unsig } else if (type == TYPE_MODULE) { - return svc_compute_ns(pares, pareslen, pidx, what, PINFO, updown, opt_updown, reloadmsg, data, PROPAGATE, apids, napid) ; + return svc_compute_ns(apids[idx].res, what, PINFO, updown, opt_updown, reloadmsg, data, PROPAGATE, apids, napid) ; } /* should be never reached*/ return 0 ; } -static int async_deps(pidservice_t *apids, unsigned int i, unsigned int what, ssexec_t *info, tain *deadline) +static int async_deps(struct resolve_hash_s **hres, pidservice_t *apids, unsigned int i, unsigned int what, ssexec_t *info, tain *deadline) { log_flow() ; int r ; - unsigned int pos = 0, id = 0, ilog = 0, idx = 0 ; + unsigned int pos = 0, id = 0, idx = 0 ; char buf[(UINT_FMT*2)*SS_MAX_SERVICE + 1] ; tain dead ; @@ -504,7 +479,7 @@ static int async_deps(pidservice_t *apids, unsigned int i, unsigned int what, ss memset(visit, 0, (n + 1) * sizeof(unsigned int)); - log_trace("waiting dependencies for: ", pares[apids[i].aresid].sa.s + pares[apids[i].aresid].name) ; + log_trace("waiting dependencies for: ", apids[i].res->sa.s + apids[i].res->name) ; while (pos < n) { @@ -515,7 +490,7 @@ static int async_deps(pidservice_t *apids, unsigned int i, unsigned int what, ss if (!r) { errno = ETIMEDOUT ; - log_dieusys(LOG_EXIT_SYS,"time out", pares[apids[i].aresid].sa.s + pares[apids[i].aresid].name) ; + log_dieusys(LOG_EXIT_SYS,"timed out", apids[i].res->sa.s + apids[i].res->name) ; } if (x.revents & IOPAUSE_READ) { @@ -547,11 +522,11 @@ static int async_deps(pidservice_t *apids, unsigned int i, unsigned int what, ss /** * the received string have the format: - * index_of_the_ares_array_of_the_service_dependency:signal_receive + * apids_array_id:signal_receive * * typically: * - 10:D - * - 30:u + * - 8:u * - ... * * Split it and check the signal receive.*/ @@ -566,24 +541,18 @@ static int async_deps(pidservice_t *apids, unsigned int i, unsigned int what, ss if (!uint0_scan(line, &id)) log_dieusys(LOG_EXIT_SYS, "retrieve service number -- please make a bug report") ; - ilog = id ; - - log_trace(pares[apids[i].aresid].sa.s + pares[apids[i].aresid].name, " acknowledges: ", pc, " from: ", pares[ilog].sa.s + pares[ilog].name) ; + log_trace(apids[i].res->sa.s + apids[i].res->name, " acknowledges: ", pc, " from: ", apids[id].res->sa.s + apids[id].res->name) ; if (!visit[pos]) { - id = pidservice_get_id(apids, id) ; - if (id < 0) - log_dieu(LOG_EXIT_SYS, "get apidservice id -- please make a bug report") ; - id = check_action(apids, id, c, what) ; if (id < 0) - log_die(LOG_EXIT_SYS, "service dependency: ", pares[ilog].sa.s + pares[ilog].name, " of: ", pares[apids[i].aresid].sa.s + pares[apids[i].aresid].name," crashed") ; + log_die(LOG_EXIT_SYS, "service dependency: ", apids[id].res->sa.s + apids[id].res->name, " of: ", apids[i].res->sa.s + apids[i].res->name," crashed") ; if (!id) continue ; - visit[pos++]++ ; + visit[pos++] ; } } } @@ -594,7 +563,7 @@ static int async_deps(pidservice_t *apids, unsigned int i, unsigned int what, ss return 1 ; } -static int async(pidservice_t *apids, unsigned int napid, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, tain *deadline) +static int async(struct resolve_hash_s **hres, pidservice_t *apids, unsigned int napid, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, tain *deadline) { log_flow() ; @@ -611,17 +580,15 @@ static int async(pidservice_t *apids, unsigned int napid, unsigned int i, unsign FLAGS_SET(apids[i].state, SVC_FLAGS_BLOCK) ; if (apids[i].nedge) - if (!async_deps(apids, i, what, info, deadline)) - log_warnu_return(LOG_EXIT_ZERO, !what ? "start" : "stop", " dependencies of service: ", name) ; + if (!async_deps(hres, apids, i, what, info, deadline)) + log_warnu_return(LOG_EXIT_SYS, !what ? "start" : "stop", " dependencies of service: ", name) ; e = doit(apids, napid, i, what, deadline) ; } else { log_warn("skipping service: ", name, " -- already in ", what ? "stopping" : "starting", " process") ; - notify(apids, i, what ? "d" : "u", what) ; - } } else { @@ -634,7 +601,7 @@ static int async(pidservice_t *apids, unsigned int napid, unsigned int i, unsign return e ; } -int svc_launch(pidservice_t *apids, unsigned int len, uint8_t what, graph_t *graph, resolve_service_t *ares, unsigned int areslen, ssexec_t *info, char const *rise, uint8_t rise_opt, uint8_t msg, char const *signal, uint8_t propagate) +int svc_launch(pidservice_t *apids, unsigned int len, uint8_t what, graph_t *graph, struct resolve_hash_s **hres, ssexec_t *info, char const *rise, uint8_t rise_opt, uint8_t msg, char const *signal, uint8_t propagate) { log_flow() ; @@ -653,8 +620,6 @@ int svc_launch(pidservice_t *apids, unsigned int len, uint8_t what, graph_t *gra opt_updown = rise_opt ; reloadmsg = msg ; auto_strings(data, signal) ; - pares = ares ; - pareslen = areslen ; if (info->opt_timeout) tain_from_millisecs(&deadline, info->timeout) ; @@ -700,7 +665,7 @@ int svc_launch(pidservice_t *apids, unsigned int len, uint8_t what, graph_t *gra close(apidservice[pos].pipe[1]) ; - e = async(apidservice, napid, pos, what, info, graph, &deadline) ; + e = async(hres, apidservice, napid, pos, what, info, graph, &deadline) ; goto end ; } @@ -734,11 +699,11 @@ int svc_launch(pidservice_t *apids, unsigned int len, uint8_t what, graph_t *gra selfpipe_finish() ; - end: - for (pos = 0 ; pos < napid ; pos++) { - close(apidservice[pos].pipe[1]) ; - close(apidservice[pos].pipe[0]) ; - } + for (pos = 0 ; pos < napid ; pos++) { + close(apidservice[pos].pipe[1]) ; + close(apidservice[pos].pipe[0]) ; + } + end: return e ; } diff --git a/src/lib66/svc/svc_unsupervise.c b/src/lib66/svc/svc_unsupervise.c index 9533ae1ae64a2eed3cb201accd3572c94ba7ecfa..e48f0562385b95f70a1f95fda057d7a9da90e617 100644 --- a/src/lib66/svc/svc_unsupervise.c +++ b/src/lib66/svc/svc_unsupervise.c @@ -50,13 +50,12 @@ static void sanitize_it(resolve_service_t *res) } /** this function considers that the service is already down except for the logger */ -void svc_unsupervise(unsigned int *alist, unsigned int alen, graph_t *g, resolve_service_t *ares, unsigned int areslen, ssexec_t *info) +void svc_unsupervise(unsigned int *alist, unsigned int alen, graph_t *g, struct resolve_hash_s **hres, ssexec_t *info) { log_flow() ; unsigned int pos = 0 ; size_t bpos = 0 ; - stralloc sa = STRALLOC_ZERO ; if (!alen) return ; @@ -65,15 +64,15 @@ void svc_unsupervise(unsigned int *alist, unsigned int alen, graph_t *g, resolve char *name = g->data.s + genalloc_s(graph_hash_t,&g->hash)[alist[pos]].vertex ; - int aresid = service_resolve_array_search(ares, areslen, name) ; - if (aresid < 0) - log_dieu(LOG_EXIT_SYS,"find ares id of: ", name, " -- please make a bug reports") ; + struct resolve_hash_s *hash = hash_search(hres, name) ; + if (hash == NULL) + log_dieu(LOG_EXIT_SYS,"find hash id of: ", name, " -- please make a bug reports") ; - sanitize_it(&ares[aresid]) ; + sanitize_it(&hash->res) ; - if (ares[aresid].type == TYPE_MODULE && ares[aresid].dependencies.ncontents) { + if (hash->res.type == TYPE_MODULE && hash->res.dependencies.ncontents) { - sa.len = 0, bpos = 0 ; + bpos = 0 ; _init_stack_(stk, strlen(hash->res.sa.s + hash->res.dependencies.contents)) ; @@ -82,14 +81,13 @@ void svc_unsupervise(unsigned int *alist, unsigned int alen, graph_t *g, resolve FOREACH_STK(&stk, bpos) { - int aresid = service_resolve_array_search(ares, areslen, sa.s + bpos) ; - if (aresid < 0) - log_dieu(LOG_EXIT_SYS,"find ares id of: ", sa.s + bpos, " -- please make a bug reports") ; + struct resolve_hash_s *h = hash_search(hres, stk.s + bpos) ; + if (h == NULL) + log_dieu(LOG_EXIT_SYS,"find hash id of: ", stk.s + bpos, " -- please make a bug reports") ; - sanitize_it(&ares[aresid]) ; + sanitize_it(&h->res) ; } } } - stralloc_free(&sa) ; }