From a4589e294a72b719b9de43bd8a4ad52a618cc9d2 Mon Sep 17 00:00:00 2001
From: obarun <eric@obarun.org>
Date: Sat, 4 Dec 2021 20:51:47 +1100
Subject: [PATCH] complete reframe of resolve API function: allow to use
 different struct of resolve in function of the object to deal with. Split
 service and tree resolve function to separated file.

---
 src/include/66/resolve.h |  163 +--
 src/include/66/service.h |  171 ++-
 src/include/66/utils.h   |    8 +-
 src/lib66/resolve.c      |  449 ++++++++
 src/lib66/service.c      | 1869 +++++++++++++++++++++++++++++++++
 src/lib66/ss_resolve.c   | 2120 --------------------------------------
 src/lib66/ss_service.c   |  186 ----
 7 files changed, 2542 insertions(+), 2424 deletions(-)
 create mode 100644 src/lib66/resolve.c
 create mode 100644 src/lib66/service.c
 delete mode 100644 src/lib66/ss_resolve.c
 delete mode 100644 src/lib66/ss_service.c

diff --git a/src/include/66/resolve.h b/src/include/66/resolve.h
index 4e3822e1..32f3951c 100644
--- a/src/include/66/resolve.h
+++ b/src/include/66/resolve.h
@@ -27,6 +27,9 @@
 
 #include <66/ssexec.h>
 #include <66/parser.h>
+#include <66/tree.h>
+#include <66/service.h>
+
 
 #define SS_RESOLVE "/.resolve"
 #define SS_RESOLVE_LEN (sizeof SS_RESOLVE - 1)
@@ -38,118 +41,57 @@
 #define SS_SIMPLE 0
 #define SS_DOUBLE 1
 
-typedef struct ss_resolve_s ss_resolve_t, *ss_resolve_t_ref ;
-struct ss_resolve_s
+typedef struct resolve_wrapper_s resolve_wrapper_t, *resolve_wrapper_t_ref ;
+struct resolve_wrapper_s
 {
-    uint32_t salen ;
-    stralloc sa ;
-
-    uint32_t name ;
-    uint32_t description ;
-    uint32_t version ;
-    uint32_t logger ;
-    uint32_t logreal ;
-    uint32_t logassoc ;
-    uint32_t dstlog ;
-    uint32_t deps ; // for module -> list of s6-rc service
-    uint32_t optsdeps ; //optional dependencies
-    uint32_t extdeps ; //external dependencies
-    uint32_t contents ; // module -> list of s6-rc and s6 service
-    uint32_t src ;  //frontend source
-    uint32_t srconf ; //configuration file source
-    uint32_t live ; //run/66
-    uint32_t runat ; //livetree->longrun,scandir->svc
-    uint32_t tree ; //var/lib/66/system/tree
-    uint32_t treename ;
-    uint32_t state ; //run/66/state/uid/treename/
-    uint32_t exec_run ;
-    uint32_t exec_log_run ;
-    uint32_t real_exec_run ;
-    uint32_t real_exec_log_run ;
-    uint32_t exec_finish ;
-    uint32_t real_exec_finish ;
-
-    uint32_t type ;
-    uint32_t ndeps ;
-    uint32_t noptsdeps ;
-    uint32_t nextdeps ;
-    uint32_t ncontents ;
-    uint32_t down ;
-    uint32_t disen ;//disable->0,enable->1
+    uint8_t type ;
+    void *obj ;
 } ;
-#define RESOLVE_ZERO { 0,STRALLOC_ZERO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
 
-typedef enum ss_resolve_enum_e ss_resolve_enum_t, *ss_resolve_enum_t_ref;
-enum ss_resolve_enum_e
-{
-    SS_RESOLVE_ENUM_NAME = 0,
-    SS_RESOLVE_ENUM_DESCRIPTION,
-    SS_RESOLVE_ENUM_VERSION,
-    SS_RESOLVE_ENUM_LOGGER,
-    SS_RESOLVE_ENUM_LOGREAL,
-    SS_RESOLVE_ENUM_LOGASSOC,
-    SS_RESOLVE_ENUM_DSTLOG,
-    SS_RESOLVE_ENUM_DEPS,
-    SS_RESOLVE_ENUM_OPTSDEPS,
-    SS_RESOLVE_ENUM_EXTDEPS,
-    SS_RESOLVE_ENUM_CONTENTS,
-    SS_RESOLVE_ENUM_SRC,
-    SS_RESOLVE_ENUM_SRCONF,
-    SS_RESOLVE_ENUM_LIVE,
-    SS_RESOLVE_ENUM_RUNAT,
-    SS_RESOLVE_ENUM_TREE,
-    SS_RESOLVE_ENUM_TREENAME,
-    SS_RESOLVE_ENUM_STATE,
-    SS_RESOLVE_ENUM_EXEC_RUN,
-    SS_RESOLVE_ENUM_EXEC_LOG_RUN,
-    SS_RESOLVE_ENUM_REAL_EXEC_RUN,
-    SS_RESOLVE_ENUM_REAL_EXEC_LOG_RUN,
-    SS_RESOLVE_ENUM_EXEC_FINISH,
-    SS_RESOLVE_ENUM_REAL_EXEC_FINISH,
-    SS_RESOLVE_ENUM_TYPE,
-    SS_RESOLVE_ENUM_NDEPS,
-    SS_RESOLVE_ENUM_NOPTSDEPS,
-    SS_RESOLVE_ENUM_NEXTDEPS,
-    SS_RESOLVE_ENUM_NCONTENTS,
-    SS_RESOLVE_ENUM_DOWN,
-    SS_RESOLVE_ENUM_DISEN,
-    SS_RESOLVE_ENUM_ENDOFKEY
-} ;
-
-typedef struct ss_resolve_field_table_s ss_resolve_field_table_t, *ss_resolve_field_table_t_ref ;
-struct ss_resolve_field_table_s
-{
-    char *field ;
-} ;
+#define RESOLVE_SET_SAWRES(wres) \
+    stralloc_ref sawres ; \
+    if (wres->type == SERVICE_STRUCT) sawres = (&((resolve_service_t *)wres->obj)->sa) ; \
+    else if (wres->type == TREE_STRUCT) sawres = (&((resolve_tree_t *)wres->obj)->sa) ;
 
-extern ss_resolve_field_table_t ss_resolve_field_table[] ;
+/**
+ *
+ * General API
+ *
+ * */
+
+extern resolve_wrapper_t *resolve_set_struct(uint8_t type, void *s) ;
+extern int resolve_init(resolve_wrapper_t *wres) ;
+extern int resolve_read(resolve_wrapper_t *wres, char const *src, char const *name) ;
+extern int resolve_write(resolve_wrapper_t *wres, char const *dst, char const *name) ;
+extern int resolve_check(char const *src, char const *name) ;
+extern int resolve_append(genalloc *ga, resolve_wrapper_t *wres) ;
+extern int resolve_search(genalloc *ga, char const *name, uint8_t type) ;
+extern int resolve_cmp(genalloc *ga, char const *name, uint8_t type) ;
+extern void resolve_rmfile(char const *src,char const *name) ;
+extern ssize_t resolve_add_string(resolve_wrapper_t *wres, char const *data) ;
+
+/**
+ *
+ * Freed
+ *
+ * */
 
-/** Graph struct */
-typedef struct ss_resolve_graph_ndeps_s ss_resolve_graph_ndeps_t ;
-struct ss_resolve_graph_ndeps_s
-{
-    uint32_t idx ;//uint32_t
-    genalloc ndeps ;//uint32_t
-} ;
-#define RESOLVE_GRAPH_NDEPS_ZERO { 0 , GENALLOC_ZERO }
+extern void resolve_free(resolve_wrapper_t *wres) ;
+extern void resolve_deep_free(uint8_t type, genalloc *g) ;
 
-typedef struct ss_resolve_graph_s ss_resolve_graph_t, *ss_resolve_graph_t_ref ;
-struct ss_resolve_graph_s
-{
-    genalloc name ;//ss_resolve_t
-    genalloc cp ; //ss_resolve_graph_ndeps_t
-    genalloc sorted ;//ss_resolve_t
-} ;
-#define RESOLVE_GRAPH_ZERO { GENALLOC_ZERO , GENALLOC_ZERO , GENALLOC_ZERO }
+/**
+ *
+ * CDB
+ *
+ * */
 
-typedef enum visit_e visit ;
-enum visit_e
-{
-    SS_WHITE = 0,
-    SS_GRAY,
-    SS_BLACK
-} ;
+extern int resolve_read_cdb(resolve_wrapper_t *wres, char const *name) ;
+extern int resolve_write_cdb(resolve_wrapper_t *wres, char const *dst, char const *name) ;
+extern int resolve_add_cdb(cdbmaker *c, char const *key, char const *data) ;
+extern int resolve_add_cdb_uint(cdbmaker *c, char const *key, uint32_t data) ;
+extern int resolve_find_cdb(stralloc *result, cdb const *c, char const *key) ;
 
+/*
 extern ss_resolve_t const ss_resolve_zero ;
 extern void ss_resolve_init(ss_resolve_t *res) ;
 extern void ss_resolve_free(ss_resolve_t *res) ;
@@ -182,21 +124,14 @@ extern int ss_resolve_sort_byfile_first(stralloc *sort, char const *src) ;
 extern int ss_resolve_svtree(stralloc *svtree,char const *svname,char const *tree) ;
 extern int ss_resolve_modify_field(ss_resolve_t *res, ss_resolve_enum_t field, char const *data) ;
 extern int ss_resolve_put_field_to_sa(stralloc *sa,ss_resolve_t *res, ss_resolve_enum_t field) ;
+*/
 
-/** Graph function */
-extern void ss_resolve_graph_ndeps_free(ss_resolve_graph_ndeps_t *graph) ;
-extern void ss_resolve_graph_free(ss_resolve_graph_t *graph) ;
-
-extern int ss_resolve_graph_src(ss_resolve_graph_t *graph, char const *dir, unsigned int reverse, unsigned int what) ;
-extern int ss_resolve_graph_build(ss_resolve_graph_t *graph,ss_resolve_t *res,char const *src,unsigned int reverse) ;
-extern int ss_resolve_graph_sort(ss_resolve_graph_t *graph) ;
-extern int ss_resolve_dfs(ss_resolve_graph_t *graph, unsigned int idx, visit *c,unsigned int *ename,unsigned int *edeps) ;
-extern int ss_resolve_graph_publish(ss_resolve_graph_t *graph,unsigned int reverse) ;
-/** cdb */
+/** cdb
 extern int ss_resolve_read_cdb(ss_resolve_t *dres, char const *name) ;
 extern int ss_resolve_write_cdb(ss_resolve_t *res, char const *dst, char const *name) ;
 extern int ss_resolve_add_cdb(cdbmaker *c,char const *key,char const *data) ;
 extern int ss_resolve_add_cdb_uint(cdbmaker *c, char const *key,uint32_t data) ;
 extern int ss_resolve_find_cdb(stralloc *result, cdb const *c,char const *key) ;
+*/
 
 #endif
diff --git a/src/include/66/service.h b/src/include/66/service.h
index 71f150fd..769b15b0 100644
--- a/src/include/66/service.h
+++ b/src/include/66/service.h
@@ -15,9 +15,176 @@
 #ifndef SS_SERVICE_H
 #define SS_SERVICE_H
 
+#include <stdint.h>
+
 #include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/cdb.h>
+#include <skalibs/cdbmake.h>
+
+#include <66/parser.h>
+#include <66/ssexec.h>
+
+
+/** Graph struct */
+typedef struct ss_resolve_graph_ndeps_s ss_resolve_graph_ndeps_t ;
+struct ss_resolve_graph_ndeps_s
+{
+    uint32_t idx ;//uint32_t
+    genalloc ndeps ;//uint32_t
+} ;
+#define RESOLVE_GRAPH_NDEPS_ZERO { 0 , GENALLOC_ZERO }
+
+typedef struct ss_resolve_graph_s ss_resolve_graph_t, *ss_resolve_graph_t_ref ;
+struct ss_resolve_graph_s
+{
+    genalloc name ;//resolve_service_t
+    genalloc cp ; //ss_resolve_graph_ndeps_t
+    genalloc sorted ;//resolve_service_t
+} ;
+#define RESOLVE_GRAPH_ZERO { GENALLOC_ZERO , GENALLOC_ZERO , GENALLOC_ZERO }
+
+typedef enum visit_e visit ;
+enum visit_e
+{
+    SS_WHITE = 0,
+    SS_GRAY,
+    SS_BLACK
+} ;
+
+
+#define SERVICE_STRUCT 0
+
+typedef struct resolve_service_s resolve_service_t, *resolve_service_t_ref ;
+struct resolve_service_s
+{
+    uint32_t salen ;
+    stralloc sa ;
+
+    uint32_t name ;
+    uint32_t description ;
+    uint32_t version ;
+    uint32_t logger ;
+    uint32_t logreal ;
+    uint32_t logassoc ;
+    uint32_t dstlog ;
+    uint32_t deps ; // for module -> list of s6-rc service
+    uint32_t optsdeps ; //optional dependencies
+    uint32_t extdeps ; //external dependencies
+    uint32_t contents ; // module -> list of s6-rc and s6 service
+    uint32_t src ;  //frontend source
+    uint32_t srconf ; //configuration file source
+    uint32_t live ; //run/66
+    uint32_t runat ; //livetree->longrun,scandir->svc
+    uint32_t tree ; //var/lib/66/system/tree
+    uint32_t treename ;
+    uint32_t state ; //run/66/state/uid/treename/
+    uint32_t exec_run ;
+    uint32_t exec_log_run ;
+    uint32_t real_exec_run ;
+    uint32_t real_exec_log_run ;
+    uint32_t exec_finish ;
+    uint32_t real_exec_finish ;
+
+    uint32_t type ;
+    uint32_t ndeps ;
+    uint32_t noptsdeps ;
+    uint32_t nextdeps ;
+    uint32_t ncontents ;
+    uint32_t down ;
+    uint32_t disen ;//disable->0,enable->1
+} ;
+#define RESOLVE_SERVICE_ZERO { 0,STRALLOC_ZERO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
+
+typedef enum resolve_service_enum_e resolve_service_enum_t, *resolve_service_enum_t_ref;
+enum resolve_service_enum_e
+{
+    SERVICE_ENUM_NAME = 0,
+    SERVICE_ENUM_DESCRIPTION,
+    SERVICE_ENUM_VERSION,
+    SERVICE_ENUM_LOGGER,
+    SERVICE_ENUM_LOGREAL,
+    SERVICE_ENUM_LOGASSOC,
+    SERVICE_ENUM_DSTLOG,
+    SERVICE_ENUM_DEPS,
+    SERVICE_ENUM_OPTSDEPS,
+    SERVICE_ENUM_EXTDEPS,
+    SERVICE_ENUM_CONTENTS,
+    SERVICE_ENUM_SRC,
+    SERVICE_ENUM_SRCONF,
+    SERVICE_ENUM_LIVE,
+    SERVICE_ENUM_RUNAT,
+    SERVICE_ENUM_TREE,
+    SERVICE_ENUM_TREENAME,
+    SERVICE_ENUM_STATE,
+    SERVICE_ENUM_EXEC_RUN,
+    SERVICE_ENUM_EXEC_LOG_RUN,
+    SERVICE_ENUM_REAL_EXEC_RUN,
+    SERVICE_ENUM_REAL_EXEC_LOG_RUN,
+    SERVICE_ENUM_EXEC_FINISH,
+    SERVICE_ENUM_REAL_EXEC_FINISH,
+    SERVICE_ENUM_TYPE,
+    SERVICE_ENUM_NDEPS,
+    SERVICE_ENUM_NOPTSDEPS,
+    SERVICE_ENUM_NEXTDEPS,
+    SERVICE_ENUM_NCONTENTS,
+    SERVICE_ENUM_DOWN,
+    SERVICE_ENUM_DISEN,
+    SERVICE_ENUM_ENDOFKEY
+} ;
+
+typedef struct resolve_service_field_table_s resolve_service_field_table_t, *resolve_service_field_table_t_ref ;
+struct resolve_service_field_table_s
+{
+    char *field ;
+} ;
+
+extern resolve_service_field_table_t resolve_service_field_table[] ;
+
+extern int service_isenabled(char const *sv) ;
+extern int service_isenabledat(stralloc *tree, char const *sv) ;
+extern int service_frontend_src(stralloc *sasrc, char const *name, char const *src) ;
+extern int service_frontend_path(stralloc *sasrc,char const *sv, uid_t owner,char const *directory_forced) ;
+extern int service_endof_dir(char const *dir, char const *name) ;
+extern int service_cmp_basedir(char const *dir) ;
+
+/**
+ *
+ * Resolve API
+ *
+ * */
+
+extern int service_read_cdb(cdb *c, resolve_service_t *res) ;
+extern int service_write_cdb(cdbmaker *c, resolve_service_t *sres) ;
+extern int service_resolve_copy(resolve_service_t *dst, resolve_service_t *res) ;
+extern int service_resolve_sort_bytype(genalloc *gares, stralloc *list, char const *src) ;
+extern int service_resolve_svtree(stralloc *svtree, char const *svname, char const *tree) ;
+extern int service_resolve_setnwrite(sv_alltype *services, ssexec_t *info, char const *dst) ;
+extern int service_resolve_setlognwrite(resolve_service_t *sv, char const *dst) ;
+extern int service_resolve_write_master(ssexec_t *info, ss_resolve_graph_t *graph, char const *dir, unsigned int reverse) ;
+extern int service_resolve_modify_field(resolve_service_t *res, resolve_service_enum_t field, char const *data) ;
+extern int service_resolve_field_to_sa(stralloc *sa, resolve_service_t *res, resolve_service_enum_t field) ;
+/**
+ *
+ * obsolete function
+ *
+ *
+ * */
+extern int service_resolve_add_deps(genalloc *tokeep, resolve_service_t *res, char const *src) ;
+extern int service_resolve_add_rdeps(genalloc *tokeep, resolve_service_t *res, char const *src) ;
+extern int service_resolve_add_logger(genalloc *ga,char const *src) ;
+
+
+
+/** Graph function */
+extern void ss_resolve_graph_ndeps_free(ss_resolve_graph_ndeps_t *graph) ;
+extern void ss_resolve_graph_free(ss_resolve_graph_t *graph) ;
+
+extern int ss_resolve_graph_src(ss_resolve_graph_t *graph, char const *dir, unsigned int reverse, unsigned int what) ;
 
-int service_isenabled(char const *sv) ;
-int service_isenabledat(stralloc *tree, char const *sv) ;
+extern int ss_resolve_graph_build(ss_resolve_graph_t *graph,resolve_service_t *res,char const *src,unsigned int reverse) ;
+extern int ss_resolve_graph_sort(ss_resolve_graph_t *graph) ;
+extern int ss_resolve_dfs(ss_resolve_graph_t *graph, unsigned int idx, visit *c,unsigned int *ename,unsigned int *edeps) ;
+extern int ss_resolve_graph_publish(ss_resolve_graph_t *graph,unsigned int reverse) ;
 
 #endif
diff --git a/src/include/66/utils.h b/src/include/66/utils.h
index 0a14b585..3490e94b 100644
--- a/src/include/66/utils.h
+++ b/src/include/66/utils.h
@@ -24,7 +24,7 @@
 #include <skalibs/genalloc.h>
 
 #include <66/ssexec.h>
-#include <66/resolve.h>
+#include <66/service.h>
 
 #define MYUID getuid()
 #define YOURUID(passto,owner) youruid(passto,owner)
@@ -44,11 +44,15 @@ extern int set_livestate(stralloc *live,uid_t owner) ;
 extern int set_ownerhome(stralloc *base,uid_t owner) ;
 extern int set_ownersysdir(stralloc *base,uid_t owner) ;
 extern int read_svfile(stralloc *sasv,char const *name,char const *src) ;
-extern int module_in_cmdline(genalloc *gares, ss_resolve_t *res, char const *dir) ;
+extern int module_in_cmdline(genalloc *gares, resolve_service_t *res, char const *dir) ;
 extern int module_search_service(char const *src, genalloc *gares, char const *name,uint8_t *found, char module_name[256]) ;
 /** ss_instance.c file */
 extern int instance_check(char const *svname) ;
 extern int instance_splitname(stralloc *sa,char const *name,int len,int what) ;
 extern int instance_create(stralloc *sasv,char const *svname, char const *regex, int len) ;
 
+extern int module_path(stralloc *sdir, stralloc *mdir, char const *sv,char const *frontend_src, uid_t owner) ;
+extern int sa_pointo(stralloc *sa, ssexec_t *info, int type, unsigned int where) ;
+extern int create_live(ssexec_t *info) ;
+
 #endif
diff --git a/src/lib66/resolve.c b/src/lib66/resolve.c
new file mode 100644
index 00000000..177fdb28
--- /dev/null
+++ b/src/lib66/resolve.c
@@ -0,0 +1,449 @@
+/*
+ * resolve.c
+ *
+ * Copyright (c) 2018-2021 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 <stdint.h>
+#include <unistd.h>//close, fsync
+#include <stdlib.h>//mkstemp, malloc, free
+#include <sys/types.h>//ssize_t
+#include <stdio.h>//rename
+
+#include <oblibs/log.h>
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/cdb.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/cdbmake.h>
+#include <skalibs/posixplz.h>//unlink
+#include <skalibs/types.h>//uint##_pack
+
+#include <66/resolve.h>
+#include <66/service.h>
+#include <66/tree.h>
+
+/**
+ *
+ * MAIN API
+ *
+ * */
+
+resolve_wrapper_t *resolve_set_struct(uint8_t type, void *s)
+{
+    log_flow() ;
+
+    resolve_wrapper_t *wres = malloc(sizeof(resolve_wrapper_t)) ;
+
+    wres->obj = s ;
+    wres->type = type ;
+    return wres ;
+} ;
+
+int resolve_init(resolve_wrapper_t *wres)
+{
+    log_flow() ;
+
+    RESOLVE_SET_SAWRES(wres) ;
+
+    sawres->len = 0 ;
+
+    return resolve_add_string(wres,"") ;
+}
+
+int resolve_read(resolve_wrapper_t *wres, char const *src, char const *name)
+{
+    log_flow() ;
+
+    size_t srclen = strlen(src) ;
+    size_t namelen = strlen(name) ;
+
+    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
+    auto_strings(tmp,src,SS_RESOLVE,"/",name) ;
+
+    if (!resolve_read_cdb(wres,tmp))
+        return 0 ;
+
+    return 1 ;
+}
+
+int resolve_write(resolve_wrapper_t *wres, char const *dst, char const *name)
+{
+    log_flow() ;
+
+    size_t dstlen = strlen(dst) ;
+    size_t namelen = strlen(name) ;
+
+    char tmp[dstlen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
+    auto_strings(tmp,dst,SS_RESOLVE,"/") ;
+
+    if (!resolve_write_cdb(wres,tmp,name))
+        return 0 ;
+
+    return 1 ;
+}
+
+int resolve_check(char const *src, char const *name)
+{
+    log_flow() ;
+
+    int r ;
+    size_t srclen = strlen(src) ;
+    size_t namelen = strlen(name) ;
+
+    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
+    auto_strings(tmp, src, SS_RESOLVE, "/", name) ;
+
+    r = scan_mode(tmp,S_IFREG) ;
+    if (r <= 0)
+        return 0 ;
+
+    return 1 ;
+}
+
+int resolve_append(genalloc *ga, resolve_wrapper_t *wres)
+{
+    log_flow() ;
+
+    int e = 0 ;
+
+    if (wres->type == SERVICE_STRUCT) {
+
+        resolve_service_t cp = RESOLVE_SERVICE_ZERO ;
+        if (!service_resolve_copy(&cp, ((resolve_service_t *)wres->obj)))
+            goto err ;
+
+        if (!genalloc_append(resolve_service_t, ga, &cp))
+            goto err ;
+
+    } else if (wres->type == TREE_STRUCT) {
+
+        resolve_tree_t cp = RESOLVE_TREE_ZERO ;
+        if (!tree_resolve_copy(&cp, ((resolve_tree_t *)wres->obj)))
+            goto err ;
+
+        if (!genalloc_append(resolve_tree_t, ga, &cp))
+            goto err ;
+
+    }
+
+    e = 1 ;
+    err:
+        return e ;
+}
+
+int resolve_search(genalloc *ga, char const *name, uint8_t type)
+{
+    log_flow() ;
+
+    size_t len, pos = 0 ;
+
+    if (type == SERVICE_STRUCT) {
+
+        len = genalloc_len(resolve_service_t, ga) ;
+
+        for (;pos < len ; pos++) {
+
+            char *s = genalloc_s(resolve_service_t,ga)[pos].sa.s + genalloc_s(resolve_service_t,ga)[pos].name ;
+            if (!strcmp(name,s))
+                return pos ;
+        }
+
+    } else if (type == TREE_STRUCT) {
+
+        len = genalloc_len(resolve_tree_t, ga) ;
+
+        for (;pos < len ; pos++) {
+
+            char *s = genalloc_s(resolve_tree_t,ga)[pos].sa.s + genalloc_s(resolve_tree_t,ga)[pos].name ;
+            if (!strcmp(name,s))
+                return pos ;
+        }
+    }
+
+    return -1 ;
+}
+
+int resolve_cmp(genalloc *ga, char const *name, uint8_t type)
+{
+    log_flow() ;
+
+    size_t len, pos = 0 ;
+
+    if (type == SERVICE_STRUCT) {
+
+        len = genalloc_len(resolve_service_t, ga) ;
+
+        for (;pos < len ; pos++) {
+
+            char *str = genalloc_s(resolve_service_t, ga)[pos].sa.s ;
+            char *s = str + genalloc_s(resolve_service_t, ga)[pos].name ;
+            if (!strcmp(name,s))
+                return 1 ;
+        }
+
+    } else if (type == TREE_STRUCT) {
+
+        len = genalloc_len(resolve_tree_t, ga) ;
+
+        for (;pos < len ; pos++) {
+
+            char *str = genalloc_s(resolve_tree_t, ga)[pos].sa.s ;
+            char *s = str + genalloc_s(resolve_tree_t, ga)[pos].name ;
+            if (!strcmp(name,s))
+                return 1 ;
+        }
+    }
+
+    return 0 ;
+}
+
+void resolve_rmfile(char const *src,char const *name)
+{
+    log_flow() ;
+
+    size_t srclen = strlen(src) ;
+    size_t namelen = strlen(name) ;
+
+    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen +1] ;
+    auto_strings(tmp, src, SS_RESOLVE, "/", name) ;
+
+    unlink_void(tmp) ;
+}
+
+ssize_t resolve_add_string(resolve_wrapper_t *wres, char const *data)
+{
+    log_flow() ;
+
+    RESOLVE_SET_SAWRES(wres) ;
+
+    ssize_t baselen = sawres->len ;
+
+    if (!data) {
+
+        if (!stralloc_catb(sawres,"",1))
+            log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;
+
+        return baselen ;
+    }
+
+    size_t datalen = strlen(data) ;
+
+    if (!stralloc_catb(sawres,data,datalen + 1))
+        log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;
+
+    return baselen ;
+}
+
+/**
+ *
+ * FREED
+ *
+ * */
+
+void resolve_free(resolve_wrapper_t *wres)
+{
+    log_flow() ;
+
+    RESOLVE_SET_SAWRES(wres) ;
+
+    stralloc_free(sawres) ;
+
+    free(wres) ;
+}
+
+void resolve_deep_free(uint8_t type, genalloc *g)
+{
+    log_flow() ;
+
+    size_t pos = 0 ;
+
+    if (type == SERVICE_STRUCT) {
+
+        for (; pos < genalloc_len(resolve_service_t, g) ; pos++)
+            stralloc_free(&genalloc_s(resolve_service_t, g)[pos].sa) ;
+
+        genalloc_free(resolve_service_t, g) ;
+
+    } else if (type == TREE_STRUCT) {
+
+        for (; pos < genalloc_len(resolve_tree_t, g) ; pos++)
+            stralloc_free(&genalloc_s(resolve_tree_t, g)[pos].sa) ;
+
+         genalloc_free(resolve_tree_t, g) ;
+    }
+
+}
+
+/**
+ *
+ * CDB
+ *
+ * */
+
+int resolve_read_cdb(resolve_wrapper_t *wres, char const *name)
+{
+    log_flow() ;
+
+    int fd, e = 0 ;
+    cdb c = CDB_ZERO ;
+
+    fd = open_readb(name) ;
+    if (fd < 0) {
+        log_warnusys("open: ",name) ;
+        goto err_fd ;
+    }
+
+    if (!cdb_init_fromfd(&c, fd)) {
+        log_warnusys("cdb_init: ", name) ;
+        goto err ;
+    }
+
+    if (wres->type == SERVICE_STRUCT) {
+
+        if (!service_read_cdb(&c, ((resolve_service_t *)wres->obj)))
+            goto err ;
+
+    } else if (wres->type == TREE_STRUCT){
+
+        if (!tree_read_cdb(&c, ((resolve_tree_t *)wres->obj)))
+            goto err ;
+
+    }
+
+    e = 1 ;
+
+    err:
+        close(fd) ;
+    err_fd:
+        cdb_free(&c) ;
+        return e ;
+}
+
+int resolve_write_cdb(resolve_wrapper_t *wres, char const *dst, char const *name)
+{
+    log_flow() ;
+
+    int fd ;
+    size_t dstlen = strlen(dst), namelen = strlen(name);
+    cdbmaker c = CDBMAKER_ZERO ;
+    char tfile[dstlen + 1 + namelen + namelen + 9] ;
+    char dfile[dstlen + 1 + namelen + 1] ;
+
+    auto_strings(dfile,dst,"/",name) ;
+
+    auto_strings(tfile,dst,"/",name,":",name,":","XXXXXX") ;
+
+    fd = mkstemp(tfile) ;
+    if (fd < 0 || ndelay_off(fd)) {
+        log_warnusys("mkstemp: ", tfile) ;
+        goto err_fd ;
+    }
+
+    if (!cdbmake_start(&c, fd)) {
+        log_warnusys("cdbmake_start") ;
+        goto err ;
+    }
+
+    if (wres->type == SERVICE_STRUCT) {
+
+        if (!service_write_cdb(&c, ((resolve_service_t *)wres->obj)))
+            goto err ;
+
+    } else if (wres->type == TREE_STRUCT) {
+
+        if (!tree_write_cdb(&c, ((resolve_tree_t *)wres->obj)))
+            goto err ;
+
+    }
+
+    if (!cdbmake_finish(&c) || fsync(fd) < 0) {
+        log_warnusys("write to: ", tfile) ;
+        goto err ;
+    }
+
+    close(fd) ;
+
+    if (rename(tfile, dfile) < 0) {
+        log_warnusys("rename ", tfile, " to ", dfile) ;
+        goto err_fd ;
+    }
+
+    return 1 ;
+
+    err:
+        close(fd) ;
+    err_fd:
+        unlink_void(tfile) ;
+        return 0 ;
+}
+
+int resolve_add_cdb(cdbmaker *c, char const *key, char const *data)
+{
+    log_flow() ;
+
+    size_t klen = strlen(key) ;
+    size_t dlen = strlen(data) ;
+
+    if (!cdbmake_add(c,key,klen,dlen ? data : 0,dlen))
+        log_warnsys_return(LOG_EXIT_ZERO,"cdb_make_add: ",key) ;
+
+    return 1 ;
+}
+
+int resolve_add_cdb_uint(cdbmaker *c, char const *key, uint32_t data)
+{
+    log_flow() ;
+
+    char pack[4] ;
+    size_t klen = strlen(key) ;
+
+    uint32_pack_big(pack, data) ;
+    if (!cdbmake_add(c,key,klen,pack,4))
+        log_warnsys_return(LOG_EXIT_ZERO,"cdb_make_add: ",key) ;
+
+    return 1 ;
+}
+
+int resolve_find_cdb(stralloc *result, cdb const *c, char const *key)
+{
+    log_flow() ;
+
+    uint32_t x = 0 ;
+    size_t klen = strlen(key) ;
+    cdb_data cdata ;
+
+    result->len = 0 ;
+
+    int r = cdb_find(c, &cdata, key, klen) ;
+    if (r == -1)
+        log_warnusys_return(LOG_EXIT_LESSONE,"search on cdb key: ",key) ;
+
+    if (!r)
+        log_warnusys_return(LOG_EXIT_ZERO,"unknown cdb key: ",key) ;
+
+    char pack[cdata.len + 1] ;
+    memcpy(pack,cdata.s, cdata.len) ;
+    pack[cdata.len] = 0 ;
+
+    uint32_unpack_big(pack, &x) ;
+
+    if (!auto_stra(result,pack))
+        log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;
+
+    return x ;
+}
+
+
diff --git a/src/lib66/service.c b/src/lib66/service.c
new file mode 100644
index 00000000..73fe1d2d
--- /dev/null
+++ b/src/lib66/service.c
@@ -0,0 +1,1869 @@
+/*
+ * service.c
+ *
+ * Copyright (c) 2018-2021 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 <stdint.h>
+#include <stdlib.h>//free
+#include <unistd.h>//getuid
+#include <sys/stat.h>
+
+#include <oblibs/log.h>
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+#include <oblibs/sastr.h>
+#include <oblibs/files.h>
+
+#include <skalibs/djbunix.h>//openreadnclose
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/cdb.h>
+#include <skalibs/cdbmake.h>
+#include <skalibs/types.h>
+
+#include <66/utils.h>
+#include <66/parser.h>
+#include <66/enum.h>
+#include <66/constants.h>
+#include <66/resolve.h>
+#include <66/ssexec.h>
+#include <66/service.h>
+#include <66/state.h>
+
+/** @Return 0 if not found
+ * @Return 1 if found
+ * @Return 2 if found but marked disabled
+ * @Return -1 system error */
+int service_isenabled(char const *sv)
+{
+
+    log_flow() ;
+
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
+    size_t newlen = 0, pos = 0 ;
+    int e = -1 ;
+    char const *exclude[3] = { SS_BACKUP + 1, SS_RESOLVE + 1, 0 } ;
+
+    if (!set_ownersysdir(&sa, getuid())) {
+
+        log_warnusys("set owner directory") ;
+        stralloc_free(&sa) ;
+        return 0 ;
+    }
+
+    char tmp[sa.len + SS_SYSTEM_LEN + 2] ;
+    auto_strings(tmp, sa.s, SS_SYSTEM) ;
+
+    // no tree exist yet
+    if (!scan_mode(tmp, S_IFDIR))
+        goto empty ;
+
+    auto_strings(tmp, sa.s, SS_SYSTEM, "/") ;
+
+    newlen = sa.len + SS_SYSTEM_LEN + 1 ;
+    sa.len = 0 ;
+
+    if (!sastr_dir_get(&sa, tmp, exclude, S_IFDIR)) {
+
+        log_warnu("get list of trees from: ", tmp) ;
+        goto freed ;
+    }
+
+    FOREACH_SASTR(&sa, pos) {
+
+        char *treename = sa.s + pos ;
+
+        char trees[newlen + strlen(treename) + SS_SVDIRS_LEN + 1] ;
+        auto_strings(trees, tmp, treename, SS_SVDIRS) ;
+
+        if (resolve_check(trees, sv)) {
+
+            if (!resolve_read(wres, trees, sv)) {
+
+                log_warnu("read resolve file: ", trees, "/", sv) ;
+                goto freed ;
+            }
+
+            if (res.disen) {
+
+                log_trace(sv, " enabled at tree: ", treename) ;
+
+                e = 1 ;
+                goto freed ;
+
+            } else {
+
+                e = 2 ;
+                goto freed ;
+            }
+        }
+    }
+    empty:
+        e = 0 ;
+    freed:
+        stralloc_free(&sa) ;
+        resolve_free(wres) ;
+        return e ;
+}
+
+/** @Return 0 if not found
+ * @Return 1 if found
+ * @Return 2 if found but marked disabled
+ * @Return -1 system error */
+int service_isenabledat(stralloc *tree, char const *sv)
+{
+
+    log_flow() ;
+
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
+    size_t newlen = 0, pos = 0 ;
+    int e = -1 ;
+    char const *exclude[3] = { SS_BACKUP + 1, SS_RESOLVE + 1, 0 } ;
+
+    if (!set_ownersysdir(&sa, getuid())) {
+
+        log_warnusys("set owner directory") ;
+        stralloc_free(&sa) ;
+        return 0 ;
+    }
+
+    char tmp[sa.len + SS_SYSTEM_LEN + 2] ;
+    auto_strings(tmp, sa.s, SS_SYSTEM) ;
+
+    // no tree exist yet
+    if (!scan_mode(tmp, S_IFDIR))
+        goto empty ;
+
+    auto_strings(tmp, sa.s, SS_SYSTEM, "/") ;
+
+    newlen = sa.len + SS_SYSTEM_LEN + 1 ;
+    sa.len = 0 ;
+
+    if (!sastr_dir_get(&sa, tmp, exclude, S_IFDIR)) {
+
+        log_warnu("get list of trees from: ", tmp) ;
+        goto freed ;
+    }
+
+    FOREACH_SASTR(&sa, pos) {
+
+        char *treename = sa.s + pos ;
+
+        char trees[newlen + strlen(treename) + SS_SVDIRS_LEN + 1] ;
+        auto_strings(trees, tmp, treename, SS_SVDIRS) ;
+
+        if (resolve_check(trees, sv)) {
+
+            if (!resolve_read(wres, trees, sv)) {
+
+                log_warnu("read resolve file: ", trees, "/", sv) ;
+                goto freed ;
+            }
+
+            if (res.disen) {
+
+                log_trace(sv, " enabled at tree: ", treename) ;
+                e = 1 ;
+
+            } else {
+
+                log_trace(sv, " disabled at tree: ", treename) ;
+                e = 2 ;
+            }
+
+            if (!auto_stra(tree, treename)) {
+                e = -1 ;
+                goto freed ;
+            }
+            goto freed ;
+        }
+    }
+    empty:
+        e = 0 ;
+    freed:
+        stralloc_free(&sa) ;
+        resolve_free(wres) ;
+        return e ;
+}
+
+int service_frontend_src(stralloc *sasrc, char const *name, char const *src)
+{
+    log_flow() ;
+
+    int  insta, equal = 0, e = -1, r = 0, found = 0 ;
+    stralloc tmp = STRALLOC_ZERO ;
+    stralloc sort = STRALLOC_ZERO ;
+    size_t pos = 0, dpos = 0 ;
+
+    char const *exclude[1] = { 0 } ;
+
+    if (!sastr_dir_get_recursive(&sort, src, exclude, S_IFREG|S_IFDIR, 1))
+        goto err ;
+
+
+    FOREACH_SASTR(&sort, pos) {
+
+        char *dname = sort.s + pos ;
+
+        struct stat st ;
+        /** use stat instead of lstat to accept symlink */
+        if (stat(dname,&st) == -1)
+            goto err ;
+
+        size_t dnamelen = strlen(dname) ;
+        char bname[dnamelen + 1] ;
+
+        if (!ob_basename(bname,dname))
+            goto err ;
+
+        equal = strcmp(name, bname) ;
+
+        insta = instance_check(bname) ;
+
+        if (insta > 0) {
+
+            if (!instance_splitname(&tmp, bname, insta, SS_INSTANCE_TEMPLATE))
+                goto err ;
+
+            equal = strcmp(tmp.s,bname) ;
+        }
+
+        if (!equal) {
+
+            found = 1 ;
+
+            if (S_ISREG(st.st_mode)) {
+
+                if (sastr_cmp(sasrc, dname) == -1)
+                    if (!sastr_add_string(sasrc, dname))
+                        goto err ;
+
+                break ;
+
+            } else if (S_ISDIR(st.st_mode)) {
+
+                if (!insta) {
+                    log_warn("invalid name format for: ", dname," -- directory instance name are case reserved") ;
+                    goto err ;
+                }
+
+                int rd = service_endof_dir(dname, bname) ;
+                if (rd == -1)
+                    goto err ;
+
+                if (!rd) {
+                    /** user ask to deal which each frontend file
+                     * inside the directory */
+                    tmp.len = 0 ;
+
+                    if (!sastr_dir_get_recursive(&tmp, dname, exclude, S_IFREG|S_IFDIR, 0))
+                        goto err ;
+
+                    /** directory may be empty. */
+                    if (!tmp.len)
+                        found = 0 ;
+
+                    dpos = 0 ;
+                    FOREACH_SASTR(&tmp, dpos) {
+
+                        r = service_frontend_src(sasrc, tmp.s + dpos, dname) ;
+                        if (r < 0)
+                            /** system error */
+                            goto err ;
+                        if (!r)
+                            /** nothing found on empty sub-directory */
+                            found = 0 ;
+                    }
+
+                    break ;
+
+                }
+            }
+        }
+    }
+
+    e = found ;
+
+    err:
+        stralloc_free(&tmp) ;
+        stralloc_free(&sort) ;
+        return e ;
+}
+
+int service_frontend_path(stralloc *sasrc,char const *sv, uid_t owner,char const *directory_forced)
+{
+    log_flow() ;
+
+    int r ;
+    char const *src = 0 ;
+    int err = -1 ;
+    stralloc home = STRALLOC_ZERO ;
+    if (directory_forced)
+    {
+        if (!service_cmp_basedir(directory_forced)) { log_warn("invalid base service directory: ",directory_forced) ; goto err ; }
+        src = directory_forced ;
+        r = service_frontend_src(sasrc,sv,src) ;
+        if (r == -1){ log_warnusys("parse source directory: ",src) ; goto err ; }
+        if (!r) { log_warnu("find service: ",sv) ; err = 0 ; goto err ; }
+    }
+    else
+    {
+        if (!owner) src = SS_SERVICE_ADMDIR ;
+        else
+        {
+            if (!set_ownerhome(&home,owner)) { log_warnusys("set home directory") ; goto err ; }
+            if (!stralloc_cats(&home,SS_SERVICE_USERDIR)) { log_warnsys("stralloc") ; goto err ; }
+            if (!stralloc_0(&home)) { log_warnsys("stralloc") ; goto err ; }
+            home.len-- ;
+            src = home.s ;
+        }
+
+        r = service_frontend_src(sasrc,sv,src) ;
+        if (r == -1){ log_warnusys("parse source directory: ",src) ; goto err ; }
+        if (!r)
+        {
+            src = SS_SERVICE_ADMDIR ;
+            r = service_frontend_src(sasrc,sv,src) ;
+            if (r == -1) { log_warnusys("parse source directory: ",src) ; goto err ; }
+            if (!r)
+            {
+                src = SS_SERVICE_SYSDIR ;
+                r = service_frontend_src(sasrc,sv,src) ;
+                if (r == -1) { log_warnusys("parse source directory: ",src) ; goto err ; }
+                if (!r) { log_warnu("find service: ",sv) ; err = 0 ; goto err ; }
+            }
+        }
+    }
+    stralloc_free(&home) ;
+    return 1 ;
+    err:
+        stralloc_free(&home) ;
+        return err ;
+}
+
+int service_endof_dir(char const *dir, char const *name)
+{
+    log_flow() ;
+
+    size_t dirlen = strlen(dir) ;
+    size_t namelen = strlen(name) ;
+    char t[dirlen + 1 + namelen + 1] ;
+    auto_strings(t, dir, "/", name) ;
+
+    int r = scan_mode(t,S_IFREG) ;
+
+    if (!ob_basename(t,dir))
+        return -1 ;
+
+    if (!strcmp(t,name) && (r > 0))
+        return 1 ;
+
+    return 0 ;
+}
+
+int service_cmp_basedir(char const *dir)
+{
+    log_flow() ;
+
+    /** dir can be 0, so nothing to do */
+    if (!dir) return 1 ;
+    size_t len = strlen(dir) ;
+    uid_t owner = MYUID ;
+    stralloc home = STRALLOC_ZERO ;
+
+    char system[len + 1] ;
+    char adm[len + 1] ;
+    char user[len + 1] ;
+
+    if (owner)
+    {
+        if (!set_ownerhome(&home,owner)) { log_warnusys("set home directory") ; goto err ; }
+        if (!auto_stra(&home,SS_SERVICE_USERDIR)) { log_warnsys("stralloc") ; goto err ; }
+        auto_strings(user,dir) ;
+        user[strlen(home.s)] = 0 ;
+    }
+
+    if (len < strlen(SS_SERVICE_SYSDIR))
+        if (len < strlen(SS_SERVICE_ADMDIR))
+            if (owner) {
+                if (len < strlen(home.s))
+                    goto err ;
+            } else goto err ;
+
+    auto_strings(system,dir) ;
+    auto_strings(adm,dir) ;
+
+    system[strlen(SS_SERVICE_SYSDIR)] = 0 ;
+    adm[strlen(SS_SERVICE_ADMDIR)] = 0 ;
+
+    if (strcmp(SS_SERVICE_SYSDIR,system))
+        if (strcmp(SS_SERVICE_ADMDIR,adm))
+            if (owner) {
+                if (strcmp(home.s,user))
+                    goto err ;
+            } else goto err ;
+
+    stralloc_free(&home) ;
+    return 1 ;
+    err:
+        stralloc_free(&home) ;
+        return 0 ;
+}
+
+/**
+ *
+ * RESOLVE API
+ *
+ * */
+
+resolve_service_field_table_t resolve_service_field_table[] = {
+
+    [SERVICE_ENUM_NAME] = { .field = "name" },
+    [SERVICE_ENUM_DESCRIPTION] = { .field = "description" },
+    [SERVICE_ENUM_VERSION] = { .field = "version" },
+    [SERVICE_ENUM_LOGGER] = { .field = "logger" },
+    [SERVICE_ENUM_LOGREAL] = { .field = "logreal" },
+    [SERVICE_ENUM_LOGASSOC] = { .field = "logassoc" },
+    [SERVICE_ENUM_DSTLOG] = { .field = "dstlog" },
+    [SERVICE_ENUM_DEPS] = { .field = "deps" },
+    [SERVICE_ENUM_OPTSDEPS] = { .field = "optsdeps" },
+    [SERVICE_ENUM_EXTDEPS] = { .field = "extdeps" },
+    [SERVICE_ENUM_CONTENTS] = { .field = "contents" },
+    [SERVICE_ENUM_SRC] = { .field = "src" },
+    [SERVICE_ENUM_SRCONF] = { .field = "srconf" },
+    [SERVICE_ENUM_LIVE] = { .field = "live" },
+    [SERVICE_ENUM_RUNAT] = { .field = "runat" },
+    [SERVICE_ENUM_TREE] = { .field = "tree" },
+    [SERVICE_ENUM_TREENAME] = { .field = "treename" },
+    [SERVICE_ENUM_STATE] = { .field = "state" },
+    [SERVICE_ENUM_EXEC_RUN] = { .field = "exec_run" },
+    [SERVICE_ENUM_EXEC_LOG_RUN] = { .field = "exec_log_run" },
+    [SERVICE_ENUM_REAL_EXEC_RUN] = { .field = "real_exec_run" },
+    [SERVICE_ENUM_REAL_EXEC_LOG_RUN] = { .field = "real_exec_log_run" },
+    [SERVICE_ENUM_EXEC_FINISH] = { .field = "exec_finish" },
+    [SERVICE_ENUM_REAL_EXEC_FINISH] = { .field = "real_exec_finish" },
+    [SERVICE_ENUM_TYPE] = { .field = "type" },
+    [SERVICE_ENUM_NDEPS] = { .field = "ndeps" },
+    [SERVICE_ENUM_NOPTSDEPS] = { .field = "noptsdeps" },
+    [SERVICE_ENUM_NEXTDEPS] = { .field = "nextdeps" },
+    [SERVICE_ENUM_NCONTENTS] = { .field = "ncontents" },
+    [SERVICE_ENUM_DOWN] = { .field = "down" },
+    [SERVICE_ENUM_DISEN] = { .field = "disen" },
+    [SERVICE_ENUM_ENDOFKEY] = { .field = 0 }
+} ;
+
+int service_read_cdb(cdb *c, resolve_service_t *res)
+{
+    log_flow() ;
+
+    stralloc tmp = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres ;
+    uint32_t x ;
+
+    wres = resolve_set_struct(SERVICE_STRUCT, res) ;
+
+    /* name */
+    resolve_find_cdb(&tmp,c,"name") ;
+    res->name = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* description */
+    resolve_find_cdb(&tmp,c,"description") ;
+    res->description = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* version */
+    resolve_find_cdb(&tmp,c,"version") ;
+    res->version = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* logger */
+    resolve_find_cdb(&tmp,c,"logger") ;
+    res->logger = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* logreal */
+    resolve_find_cdb(&tmp,c,"logreal") ;
+    res->logreal = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* logassoc */
+    resolve_find_cdb(&tmp,c,"logassoc") ;
+    res->logassoc = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* dstlog */
+    resolve_find_cdb(&tmp,c,"dstlog") ;
+    res->dstlog = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* deps */
+    resolve_find_cdb(&tmp,c,"deps") ;
+    res->deps = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* optsdeps */
+    resolve_find_cdb(&tmp,c,"optsdeps") ;
+    res->optsdeps = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* extdeps */
+    resolve_find_cdb(&tmp,c,"extdeps") ;
+    res->extdeps = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* contents */
+    resolve_find_cdb(&tmp,c,"contents") ;
+    res->contents = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* src */
+    resolve_find_cdb(&tmp,c,"src") ;
+    res->src = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* srconf */
+    resolve_find_cdb(&tmp,c,"srconf") ;
+    res->srconf = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* live */
+    resolve_find_cdb(&tmp,c,"live") ;
+    res->live = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* runat */
+    resolve_find_cdb(&tmp,c,"runat") ;
+    res->runat = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* tree */
+    resolve_find_cdb(&tmp,c,"tree") ;
+    res->tree = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* treename */
+    resolve_find_cdb(&tmp,c,"treename") ;
+    res->treename = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* state */
+    resolve_find_cdb(&tmp,c,"state") ;
+    res->state = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* exec_run */
+    resolve_find_cdb(&tmp,c,"exec_run") ;
+    res->exec_run = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* exec_log_run */
+    resolve_find_cdb(&tmp,c,"exec_log_run") ;
+    res->exec_log_run = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* real_exec_run */
+    resolve_find_cdb(&tmp,c,"real_exec_run") ;
+    res->real_exec_run = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* real_exec_log_run */
+    resolve_find_cdb(&tmp,c,"real_exec_log_run") ;
+    res->real_exec_log_run = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* exec_finish */
+    resolve_find_cdb(&tmp,c,"exec_finish") ;
+    res->exec_finish = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* real_exec_finish */
+    resolve_find_cdb(&tmp,c,"real_exec_finish") ;
+    res->real_exec_finish = tmp.len ? resolve_add_string(wres,tmp.s) : 0 ;
+
+    /* type */
+    x = resolve_find_cdb(&tmp,c,"type") ;
+    res->type = x ;
+
+    /* ndeps */
+    x = resolve_find_cdb(&tmp,c,"ndeps") ;
+    res->ndeps = x ;
+
+    /* noptsdeps */
+    x = resolve_find_cdb(&tmp,c,"noptsdeps") ;
+    res->noptsdeps = x ;
+
+    /* nextdeps */
+    x = resolve_find_cdb(&tmp,c,"nextdeps") ;
+    res->nextdeps = x ;
+
+    /* ncontents */
+    x = resolve_find_cdb(&tmp,c,"ncontents") ;
+    res->ncontents = x ;
+
+    /* down */
+    x = resolve_find_cdb(&tmp,c,"down") ;
+    res->down = x ;
+
+    /* disen */
+    x = resolve_find_cdb(&tmp,c,"disen") ;
+    res->disen = x ;
+
+    free(wres) ;
+    stralloc_free(&tmp) ;
+
+    return 1 ;
+}
+
+int service_write_cdb(cdbmaker *c, resolve_service_t *sres)
+{
+
+    log_flow() ;
+
+    char *str = sres->sa.s ;
+
+    /* name */
+    if (!resolve_add_cdb(c,"name",str + sres->name) ||
+
+    /* description */
+    !resolve_add_cdb(c,"description",str + sres->description) ||
+
+    /* version */
+    !resolve_add_cdb(c,"version",str + sres->version) ||
+
+    /* logger */
+    !resolve_add_cdb(c,"logger",str + sres->logger) ||
+
+    /* logreal */
+    !resolve_add_cdb(c,"logreal",str + sres->logreal) ||
+
+    /* logassoc */
+    !resolve_add_cdb(c,"logassoc",str + sres->logassoc) ||
+
+    /* dstlog */
+    !resolve_add_cdb(c,"dstlog",str + sres->dstlog) ||
+
+    /* deps */
+    !resolve_add_cdb(c,"deps",str + sres->deps) ||
+
+    /* optsdeps */
+    !resolve_add_cdb(c,"optsdeps",str + sres->optsdeps) ||
+
+    /* extdeps */
+    !resolve_add_cdb(c,"extdeps",str + sres->extdeps) ||
+
+    /* contents */
+    !resolve_add_cdb(c,"contents",str + sres->contents) ||
+
+    /* src */
+    !resolve_add_cdb(c,"src",str + sres->src) ||
+
+    /* srconf */
+    !resolve_add_cdb(c,"srconf",str + sres->srconf) ||
+
+    /* live */
+    !resolve_add_cdb(c,"live",str + sres->live) ||
+
+    /* runat */
+    !resolve_add_cdb(c,"runat",str + sres->runat) ||
+
+    /* tree */
+    !resolve_add_cdb(c,"tree",str + sres->tree) ||
+
+    /* treename */
+    !resolve_add_cdb(c,"treename",str + sres->treename) ||
+
+    /* dstlog */
+    !resolve_add_cdb(c,"dstlog",str + sres->dstlog) ||
+
+    /* state */
+    !resolve_add_cdb(c,"state",str + sres->state) ||
+
+    /* exec_run */
+    !resolve_add_cdb(c,"exec_run",str + sres->exec_run) ||
+
+    /* exec_log_run */
+    !resolve_add_cdb(c,"exec_log_run",str + sres->exec_log_run) ||
+
+    /* real_exec_run */
+    !resolve_add_cdb(c,"real_exec_run",str + sres->real_exec_run) ||
+
+    /* real_exec_log_run */
+    !resolve_add_cdb(c,"real_exec_log_run",str + sres->real_exec_log_run) ||
+
+    /* exec_finish */
+    !resolve_add_cdb(c,"exec_finish",str + sres->exec_finish) ||
+
+    /* real_exec_finish */
+    !resolve_add_cdb(c,"real_exec_finish",str + sres->real_exec_finish) ||
+
+    /* type */
+    !resolve_add_cdb_uint(c,"type",sres->type) ||
+
+    /* ndeps */
+    !resolve_add_cdb_uint(c,"ndeps",sres->ndeps) ||
+
+    /* noptsdeps */
+    !resolve_add_cdb_uint(c,"noptsdeps",sres->noptsdeps) ||
+
+    /* nextdeps */
+    !resolve_add_cdb_uint(c,"nextdeps",sres->nextdeps) ||
+
+    /* ncontents */
+    !resolve_add_cdb_uint(c,"ncontents",sres->ncontents) ||
+
+    /* down */
+    !resolve_add_cdb_uint(c,"down",sres->down) ||
+
+    /* disen */
+    !resolve_add_cdb_uint(c,"disen",sres->disen)) return 0 ;
+
+    return 1 ;
+}
+
+int service_resolve_copy(resolve_service_t *dst, resolve_service_t *res)
+{
+    log_flow() ;
+
+    stralloc_free(&dst->sa) ;
+
+    size_t len = res->sa.len - 1 ;
+    dst->salen = res->salen ;
+
+    if (!stralloc_catb(&dst->sa,res->sa.s,len) ||
+        !stralloc_0(&dst->sa))
+            return 0 ;
+
+    dst->name = res->name ;
+    dst->description = res->description ;
+    dst->version = res->version ;
+    dst->logger = res->logger ;
+    dst->logreal = res->logreal ;
+    dst->logassoc = res->logassoc ;
+    dst->dstlog = res->dstlog ;
+    dst->deps = res->deps ;
+    dst->optsdeps = res->optsdeps ;
+    dst->extdeps = res->extdeps ;
+    dst->contents = res->contents ;
+    dst->src = res->src ;
+    dst->srconf = res->srconf ;
+    dst->live = res->live ;
+    dst->runat = res->runat ;
+    dst->tree = res->tree ;
+    dst->treename = res->treename ;
+    dst->state = res->state ;
+    dst->exec_run = res->exec_run ;
+    dst->exec_log_run = res->exec_log_run ;
+    dst->real_exec_run = res->real_exec_run ;
+    dst->real_exec_log_run = res->real_exec_log_run ;
+    dst->exec_finish = res->exec_finish ;
+    dst->real_exec_finish = res->real_exec_finish ;
+    dst->type = res->type ;
+    dst->ndeps = res->ndeps ;
+    dst->noptsdeps = res->noptsdeps ;
+    dst->nextdeps = res->nextdeps ;
+    dst->ncontents = res->ncontents ;
+    dst->down = res->down ;
+    dst->disen = res->disen ;
+
+    return 1 ;
+}
+
+int service_resolve_sort_bytype(genalloc *gares, stralloc *list, char const *src)
+{
+    log_flow() ;
+
+    size_t pos = 0 ;
+    int e = 0 ;
+
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
+
+    size_t classic_list = 0, module_list = 0 ;
+
+    FOREACH_SASTR(list, pos) {
+
+        char *name = list->s + pos ;
+
+        resolve_service_t cp = RESOLVE_SERVICE_ZERO ;
+
+        if (!resolve_read(wres, src, name))
+            log_warnu_return(LOG_EXIT_ZERO,"read resolve file of: ", src, name) ;
+
+        if (!service_resolve_copy(&cp, &res))
+            goto err ;
+
+        switch (res.type) {
+
+            case TYPE_CLASSIC:
+
+                if (!genalloc_insertb(resolve_service_t, gares, 0, &cp, 1))
+                    goto err ;
+
+                classic_list++ ;
+                module_list = classic_list ;
+
+                break ;
+
+            case TYPE_MODULE:
+
+                if (!genalloc_insertb(resolve_service_t, gares, classic_list, &cp, 1))
+                    goto err ;
+
+                module_list++ ;
+
+                break ;
+
+            case TYPE_BUNDLE:
+            case TYPE_LONGRUN:
+            case TYPE_ONESHOT:
+
+                if (!genalloc_insertb(resolve_service_t, gares, module_list, &cp, 1))
+                    goto err ;
+
+                break ;
+
+            default: log_warn_return(LOG_EXIT_ZERO,"unknown action") ;
+        }
+    }
+
+    e = 1 ;
+
+    err:
+        resolve_free(wres) ;
+        return e ;
+}
+
+/** @Return -1 system error
+ * @Return 0 no tree exist yet
+ * @Return 1 svname doesn't exist
+ * @Return 2 on success
+ * @Return > 2, service exist on different tree */
+int service_resolve_svtree(stralloc *svtree, char const *svname, char const *tree)
+{
+    log_flow() ;
+
+    uint8_t found = 1, copied = 0 ;
+    uid_t owner = getuid() ;
+    size_t pos = 0, newlen ;
+    stralloc satree = STRALLOC_ZERO ;
+    stralloc tmp = STRALLOC_ZERO ;
+    char const *exclude[3] = { SS_BACKUP + 1, SS_RESOLVE + 1, 0 } ;
+
+    if (!set_ownersysdir(svtree,owner)) { log_warnusys("set owner directory") ; goto err ; }
+    if (!auto_stra(svtree,SS_SYSTEM)) goto err ;
+
+    if (!scan_mode(svtree->s,S_IFDIR))
+    {
+        found = 0 ;
+        goto freed ;
+    }
+
+    if (!auto_stra(svtree,"/")) goto err ;
+    newlen = svtree->len ;
+
+    if (!stralloc_copy(&tmp,svtree)) goto err ;
+
+    if (!sastr_dir_get(&satree, svtree->s, exclude, S_IFDIR)) {
+        log_warnu("get list of trees from directory: ",svtree->s) ;
+        goto err ;
+    }
+
+    if (satree.len)
+    {
+
+        FOREACH_SASTR(&satree, pos) {
+
+            tmp.len = newlen ;
+            char *name = satree.s + pos ;
+
+            if (!auto_stra(&tmp,name,SS_SVDIRS)) goto err ;
+            if (resolve_check(tmp.s,svname)) {
+
+                if (!tree || (tree && !strcmp(name,tree))){
+                    svtree->len = 0 ;
+                    if (!stralloc_copy(svtree,&tmp)) goto err ;
+                    copied = 1 ;
+                }
+                found++ ;
+            }
+        }
+    }
+    else
+    {
+        found = 0 ;
+        goto freed ;
+    }
+
+    if (found > 2 && tree) found = 2 ;
+    if (!copied) found = 1 ;
+    if (!stralloc_0(svtree)) goto err ;
+    freed:
+    stralloc_free(&satree) ;
+    stralloc_free(&tmp) ;
+    return found ;
+    err:
+        stralloc_free(&satree) ;
+        stralloc_free(&tmp) ;
+        return -1 ;
+}
+
+int service_resolve_setnwrite(sv_alltype *services, ssexec_t *info, char const *dst)
+{
+    log_flow() ;
+
+    int e = 0 ;
+    char ownerstr[UID_FMT] ;
+    size_t ownerlen = uid_fmt(ownerstr,info->owner), id, nid ;
+    ownerstr[ownerlen] = 0 ;
+
+    stralloc destlog = STRALLOC_ZERO ;
+    stralloc ndeps = STRALLOC_ZERO ;
+    stralloc other_deps = STRALLOC_ZERO ;
+
+    ss_state_t sta = STATE_ZERO ;
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
+
+    resolve_init(wres) ;
+
+    char *name = keep.s + services->cname.name ;
+    size_t namelen = strlen(name) ;
+    char logname[namelen + SS_LOG_SUFFIX_LEN + 1] ;
+    char logreal[namelen + SS_LOG_SUFFIX_LEN + 1] ;
+    char stmp[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + 1 + namelen + SS_LOG_SUFFIX_LEN + 1] ;
+
+    size_t livelen = info->live.len - 1 ;
+    char state[livelen + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len + 1 + namelen + 1] ;
+    auto_strings(state, info->live.s, SS_STATE, "/", ownerstr, "/", info->treename.s) ;
+
+
+    res.type = services->cname.itype ;
+    res.name = resolve_add_string(wres,name) ;
+    res.description = resolve_add_string(wres,keep.s + services->cname.description) ;
+    res.version = resolve_add_string(wres,keep.s + services->cname.version) ;
+    res.tree = resolve_add_string(wres,info->tree.s) ;
+    res.treename = resolve_add_string(wres,info->treename.s) ;
+    res.live = resolve_add_string(wres,info->live.s) ;
+    res.state = resolve_add_string(wres,state) ;
+    res.src = resolve_add_string(wres,keep.s + services->src) ;
+
+    if (services->srconf > 0)
+        res.srconf = resolve_add_string(wres,keep.s + services->srconf) ;
+
+    if (res.type == TYPE_ONESHOT) {
+
+        if (services->type.oneshot.up.exec >= 0) {
+
+            res.exec_run = resolve_add_string(wres,keep.s + services->type.oneshot.up.exec) ;
+            res.real_exec_run = resolve_add_string(wres,keep.s + services->type.oneshot.up.real_exec) ;
+        }
+
+        if (services->type.oneshot.down.exec >= 0) {
+
+            res.exec_finish = resolve_add_string(wres,keep.s + services->type.oneshot.down.exec) ;
+            res.real_exec_finish = resolve_add_string(wres,keep.s + services->type.oneshot.down.real_exec) ;
+        }
+    }
+
+    if (res.type == TYPE_CLASSIC || res.type == TYPE_LONGRUN) {
+
+        if (services->type.classic_longrun.run.exec >= 0) {
+            res.exec_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.run.exec) ;
+            res.real_exec_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.run.real_exec) ;
+        }
+
+        if (services->type.classic_longrun.finish.exec >= 0) {
+
+            res.exec_finish = resolve_add_string(wres,keep.s + services->type.classic_longrun.finish.exec) ;
+            res.real_exec_finish = resolve_add_string(wres,keep.s + services->type.classic_longrun.finish.real_exec) ;
+        }
+    }
+
+    res.ndeps = services->cname.nga ;
+    res.noptsdeps = services->cname.nopts ;
+    res.nextdeps = services->cname.next ;
+    res.ncontents = services->cname.ncontents ;
+
+    if (services->flags[0])
+        res.down = 1 ;
+
+    res.disen = 1 ;
+
+    if (res.type == TYPE_CLASSIC) {
+
+        auto_strings(stmp, info->scandir.s, "/", name) ;
+        res.runat = resolve_add_string(wres,stmp) ;
+
+    } else if (res.type >= TYPE_BUNDLE) {
+
+        auto_strings(stmp, info->livetree.s, "/", info->treename.s, SS_SVDIRS, "/", name) ;
+        res.runat = resolve_add_string(wres,stmp) ;
+    }
+
+    if (state_check(state,name)) {
+
+        if (!state_read(&sta,state,name)) {
+            log_warnusys("read state file of: ",name) ;
+            goto err ;
+        }
+
+        if (!sta.init)
+            state_setflag(&sta,SS_FLAGS_RELOAD,SS_FLAGS_TRUE) ;
+
+        if (sta.init) {
+
+            state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_TRUE) ;
+
+        } else {
+
+            state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_FALSE) ;
+        }
+
+        state_setflag(&sta,SS_FLAGS_UNSUPERVISE,SS_FLAGS_FALSE) ;
+
+        if (!state_write(&sta,res.sa.s + res.state,name)) {
+            log_warnusys("write state file of: ",name) ;
+            goto err ;
+        }
+    }
+
+    if (res.ndeps)
+    {
+        id = services->cname.idga, nid = res.ndeps ;
+        for (;nid; id += strlen(deps.s + id) + 1, nid--) {
+
+            if (!stralloc_catb(&ndeps,deps.s + id,strlen(deps.s + id)) ||
+                !stralloc_catb(&ndeps," ",1)) {
+                    log_warnsys("stralloc") ;
+                    goto err ;
+                }
+        }
+        ndeps.len-- ;
+
+        if (!stralloc_0(&ndeps)) {
+            log_warnsys("stralloc") ;
+            goto err ;
+        }
+
+        res.deps = resolve_add_string(wres,ndeps.s) ;
+    }
+
+    if (res.noptsdeps)
+    {
+        id = services->cname.idopts, nid = res.noptsdeps ;
+        for (;nid; id += strlen(deps.s + id) + 1, nid--) {
+
+            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
+                !stralloc_catb(&other_deps," ",1)) {
+                    log_warnsys("stralloc") ;
+                    goto err ;
+                }
+        }
+        other_deps.len-- ;
+
+        if (!stralloc_0(&other_deps)) {
+            log_warnsys("stralloc") ;
+            goto err ;
+        }
+
+        res.optsdeps = resolve_add_string(wres,other_deps.s) ;
+    }
+
+    if (res.nextdeps)
+    {
+        other_deps.len = 0 ;
+        id = services->cname.idext, nid = res.nextdeps ;
+        for (;nid; id += strlen(deps.s + id) + 1, nid--) {
+
+            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
+                !stralloc_catb(&other_deps," ",1)){
+                    log_warnsys("stralloc") ;
+                    goto err ;
+                }
+        }
+        other_deps.len-- ;
+
+        if (!stralloc_0(&other_deps)){
+            log_warnsys("stralloc") ;
+            goto err ;
+        }
+
+        res.extdeps = resolve_add_string(wres,other_deps.s) ;
+    }
+
+    if (res.ncontents) {
+
+        other_deps.len = 0 ;
+        id = services->cname.idcontents, nid = res.ncontents ;
+        for (;nid; id += strlen(deps.s + id) + 1, nid--) {
+
+            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
+                !stralloc_catb(&other_deps," ",1)) {
+                    log_warnsys("stralloc") ;
+                    goto err ;
+                }
+        }
+        other_deps.len-- ;
+        if (!stralloc_0(&other_deps)) {
+            log_warnsys("stralloc") ;
+            goto err ;
+        }
+        res.contents = resolve_add_string(wres,other_deps.s) ;
+    }
+
+    if (services->opts[0]) {
+
+        // destination of the logger
+        if (services->type.classic_longrun.log.destination < 0) {
+
+            if(info->owner > 0) {
+
+                if (!auto_stra(&destlog, get_userhome(info->owner), "/", SS_LOGGER_USERDIR, name)) {
+                    log_warnsys("stralloc") ;
+                    goto err ;
+                }
+
+            } else {
+
+                if (!auto_stra(&destlog, SS_LOGGER_SYSDIR, name)) {
+                    log_warnsys("stralloc") ;
+                    goto err ;
+                }
+            }
+
+        } else {
+
+            if (!auto_stra(&destlog,keep.s + services->type.classic_longrun.log.destination)) {
+                log_warnsys("stralloc") ;
+                goto err ;
+            }
+        }
+
+        res.dstlog = resolve_add_string(wres,destlog.s) ;
+
+        if ((res.type == TYPE_CLASSIC) || (res.type == TYPE_LONGRUN)) {
+
+            auto_strings(logname, name, SS_LOG_SUFFIX) ;
+            auto_strings(logreal, name) ;
+
+            if (res.type == TYPE_CLASSIC) {
+                auto_strings(logreal + namelen, "/log") ;
+
+            } else {
+
+                auto_strings(logreal + namelen,"-log") ;
+            }
+
+            res.logger = resolve_add_string(wres,logname) ;
+            res.logreal = resolve_add_string(wres,logreal) ;
+            if (ndeps.len)
+                ndeps.len--;
+
+            if (!stralloc_catb(&ndeps," ",1) ||
+                !stralloc_cats(&ndeps,res.sa.s + res.logger) ||
+                !stralloc_0(&ndeps)) {
+                    log_warnsys("stralloc") ;
+                    goto err ;
+                }
+
+            res.deps = resolve_add_string(wres,ndeps.s) ;
+
+            if (res.type == TYPE_CLASSIC) {
+
+                res.ndeps = 1 ;
+
+            } else if (res.type == TYPE_LONGRUN) {
+
+                res.ndeps += 1 ;
+            }
+
+            if (services->type.classic_longrun.log.run.exec >= 0)
+                res.exec_log_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.log.run.exec) ;
+
+            if (services->type.classic_longrun.log.run.real_exec >= 0)
+                res.real_exec_log_run = resolve_add_string(wres,keep.s + services->type.classic_longrun.log.run.real_exec) ;
+
+            if (!service_resolve_setlognwrite(&res,dst))
+                goto err ;
+        }
+    }
+
+    if (!resolve_write(wres,dst,res.sa.s + res.name)) {
+
+        log_warnusys("write resolve file: ",dst,SS_RESOLVE,"/",res.sa.s + res.name) ;
+        goto err ;
+    }
+
+    e = 1 ;
+
+    err:
+        resolve_free(wres) ;
+        stralloc_free(&ndeps) ;
+        stralloc_free(&other_deps) ;
+        stralloc_free(&destlog) ;
+        return e ;
+}
+
+int service_resolve_setlognwrite(resolve_service_t *sv, char const *dst)
+{
+    log_flow() ;
+
+    if (!sv->logger) return 1 ;
+
+    int e = 0 ;
+    ss_state_t sta = STATE_ZERO ;
+
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
+
+    resolve_init(wres) ;
+
+    char *str = sv->sa.s ;
+    size_t svlen = strlen(str + sv->name) ;
+    char descrip[svlen + 7 + 1] ;
+    auto_strings(descrip, str + sv->name, " logger") ;
+
+    size_t runlen = strlen(str + sv->runat) ;
+    char live[runlen + 4 + 1] ;
+    memcpy(live,str + sv->runat,runlen) ;
+    if (sv->type >= TYPE_BUNDLE) {
+
+        memcpy(live + runlen,"-log",4)  ;
+
+    } else memcpy(live + runlen,"/log",4)  ;
+
+    live[runlen + 4] = 0 ;
+
+    res.type = sv->type ;
+    res.name = resolve_add_string(wres,str + sv->logger) ;
+    res.description = resolve_add_string(wres,descrip) ;
+    res.version = resolve_add_string(wres,str + sv->version) ;
+    res.logreal = resolve_add_string(wres,str + sv->logreal) ;
+    res.logassoc = resolve_add_string(wres,str + sv->name) ;
+    res.dstlog = resolve_add_string(wres,str + sv->dstlog) ;
+    res.live = resolve_add_string(wres,str + sv->live) ;
+    res.runat = resolve_add_string(wres,live) ;
+    res.tree = resolve_add_string(wres,str + sv->tree) ;
+    res.treename = resolve_add_string(wres,str + sv->treename) ;
+    res.state = resolve_add_string(wres,str + sv->state) ;
+    res.src = resolve_add_string(wres,str + sv->src) ;
+    res.down = sv->down ;
+    res.disen = sv->disen ;
+
+    if (sv->exec_log_run > 0)
+        res.exec_log_run = resolve_add_string(wres,str + sv->exec_log_run) ;
+
+    if (sv->real_exec_log_run > 0)
+        res.real_exec_log_run = resolve_add_string(wres,str + sv->real_exec_log_run) ;
+
+    if (state_check(str + sv->state,str + sv->logger)) {
+
+        if (!state_read(&sta,str + sv->state,str + sv->logger)) {
+
+            log_warnusys("read state file of: ",str + sv->logger) ;
+            goto err ;
+        }
+
+        if (!sta.init)
+            state_setflag(&sta,SS_FLAGS_RELOAD,SS_FLAGS_TRUE) ;
+
+        state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_FALSE) ;
+        state_setflag(&sta,SS_FLAGS_UNSUPERVISE,SS_FLAGS_FALSE) ;
+
+        if (!state_write(&sta,str + sv->state,str + sv->logger)) {
+            log_warnusys("write state file of: ",str + sv->logger) ;
+            goto err ;
+        }
+    }
+
+    if (!resolve_write(wres,dst,res.sa.s + res.name)) {
+        log_warnusys("write resolve file: ",dst,SS_RESOLVE,"/",res.sa.s + res.name) ;
+        goto err ;
+    }
+
+    e = 1 ;
+
+    err:
+        resolve_free(wres) ;
+        return e ;
+}
+
+int service_resolve_modify_field(resolve_service_t *res, resolve_service_enum_t field, char const *data)
+{
+    log_flow() ;
+
+    uint32_t ifield ;
+    int e = 0 ;
+
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, res) ;
+
+    switch(field) {
+
+        case SERVICE_ENUM_NAME:
+            res->name = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_DESCRIPTION:
+            res->description = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_VERSION:
+            res->version = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_LOGGER:
+            res->logger = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_LOGREAL:
+            res->logreal = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_LOGASSOC:
+            res->logassoc = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_DSTLOG:
+            res->dstlog = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_DEPS:
+            res->deps = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_OPTSDEPS:
+            res->optsdeps = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_EXTDEPS:
+            res->extdeps = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_CONTENTS:
+            res->contents = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_SRC:
+            res->src = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_SRCONF:
+            res->srconf = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_LIVE:
+            res->live = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_RUNAT:
+            res->runat = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_TREE:
+            res->tree = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_TREENAME:
+            res->treename = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_STATE:
+            res->state = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_EXEC_RUN:
+            res->exec_run = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_EXEC_LOG_RUN:
+            res->exec_log_run = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_REAL_EXEC_RUN:
+            res->real_exec_run = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_REAL_EXEC_LOG_RUN:
+            res->real_exec_log_run = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_EXEC_FINISH:
+            res->exec_finish = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_REAL_EXEC_FINISH:
+            res->real_exec_finish = resolve_add_string(wres,data) ;
+            break ;
+
+        case SERVICE_ENUM_TYPE:
+            if (!uint0_scan(data, &ifield)) goto err ;
+            res->type = ifield ;
+            break ;
+
+        case SERVICE_ENUM_NDEPS:
+            if (!uint0_scan(data, &ifield)) goto err ;
+            res->ndeps = ifield ;
+            break ;
+
+        case SERVICE_ENUM_NOPTSDEPS:
+            if (!uint0_scan(data, &ifield)) goto err ;
+            res->noptsdeps = ifield ;
+            break ;
+
+        case SERVICE_ENUM_NEXTDEPS:
+            if (!uint0_scan(data, &ifield)) goto err ;
+            res->nextdeps = ifield ;
+            break ;
+
+        case SERVICE_ENUM_NCONTENTS:
+            if (!uint0_scan(data, &ifield)) goto err ;
+            res->ncontents = ifield ;
+            break ;
+
+        case SERVICE_ENUM_DOWN:
+            if (!uint0_scan(data, &ifield)) goto err ;
+            res->down = ifield ;
+            break ;
+
+        case SERVICE_ENUM_DISEN:
+            if (!uint0_scan(data, &ifield)) goto err ;
+            res->disen = ifield ;
+            break ;
+
+        default:
+            break ;
+    }
+
+    e = 1 ;
+
+    err:
+        free(wres) ;
+        return e ;
+
+}
+
+int service_resolve_field_to_sa(stralloc *sa, resolve_service_t *res, resolve_service_enum_t field)
+{
+    log_flow() ;
+
+    uint32_t ifield ;
+
+    switch(field) {
+
+        case SERVICE_ENUM_NAME:
+            ifield = res->name ;
+            break ;
+
+        case SERVICE_ENUM_DESCRIPTION:
+            ifield = res->description ;
+            break ;
+
+        case SERVICE_ENUM_VERSION:
+            ifield = res->version ;
+            break ;
+
+        case SERVICE_ENUM_LOGGER:
+            ifield = res->logger ;
+            break ;
+
+        case SERVICE_ENUM_LOGREAL:
+            ifield = res->logreal ;
+            break ;
+
+        case SERVICE_ENUM_LOGASSOC:
+            ifield = res->logassoc ;
+            break ;
+
+        case SERVICE_ENUM_DSTLOG:
+            ifield = res->dstlog ;
+            break ;
+
+        case SERVICE_ENUM_DEPS:
+            ifield = res->deps ;
+            break ;
+
+        case SERVICE_ENUM_OPTSDEPS:
+            ifield = res->optsdeps ;
+            break ;
+
+        case SERVICE_ENUM_EXTDEPS:
+            ifield = res->extdeps ;
+            break ;
+
+        case SERVICE_ENUM_CONTENTS:
+            ifield = res->contents ;
+            break ;
+
+        case SERVICE_ENUM_SRC:
+            ifield = res->src ;
+            break ;
+
+        case SERVICE_ENUM_SRCONF:
+            ifield = res->srconf ;
+            break ;
+
+        case SERVICE_ENUM_LIVE:
+            ifield = res->live ;
+            break ;
+
+        case SERVICE_ENUM_RUNAT:
+            ifield = res->runat ;
+            break ;
+
+        case SERVICE_ENUM_TREE:
+            ifield = res->tree ;
+            break ;
+
+        case SERVICE_ENUM_TREENAME:
+            ifield = res->treename ;
+            break ;
+
+        case SERVICE_ENUM_STATE:
+            ifield = res->state ;
+            break ;
+
+        case SERVICE_ENUM_EXEC_RUN:
+            ifield = res->exec_run ;
+            break ;
+
+        case SERVICE_ENUM_EXEC_LOG_RUN:
+            ifield = res->exec_log_run ;
+            break ;
+
+        case SERVICE_ENUM_REAL_EXEC_RUN:
+            ifield = res->real_exec_run ;
+            break ;
+
+        case SERVICE_ENUM_REAL_EXEC_LOG_RUN:
+            ifield = res->real_exec_log_run ;
+            break ;
+
+        case SERVICE_ENUM_EXEC_FINISH:
+            ifield = res->exec_finish ;
+            break ;
+
+        case SERVICE_ENUM_REAL_EXEC_FINISH:
+            ifield = res->real_exec_finish ;
+            break ;
+
+        case SERVICE_ENUM_TYPE:
+            ifield = res->type ;
+            break ;
+
+        case SERVICE_ENUM_NDEPS:
+            ifield = res->ndeps ;
+            break ;
+
+        case SERVICE_ENUM_NOPTSDEPS:
+            ifield = res->noptsdeps ;
+            break ;
+
+        case SERVICE_ENUM_NEXTDEPS:
+            ifield = res->nextdeps ;
+            break ;
+
+        case SERVICE_ENUM_NCONTENTS:
+            ifield = res->ncontents ;
+            break ;
+
+        case SERVICE_ENUM_DOWN:
+            ifield = res->down ;
+            break ;
+
+        case SERVICE_ENUM_DISEN:
+            ifield = res->disen ;
+            break ;
+
+        default:
+            return 0 ;
+    }
+
+    if (!auto_stra(sa,res->sa.s + ifield))
+        return 0 ;
+
+    return 1 ;
+}
+
+int service_resolve_add_deps(genalloc *tokeep, resolve_service_t *res, char const *src)
+{
+    log_flow() ;
+
+    int e = 0 ;
+    size_t pos = 0 ;
+    stralloc tmp = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, res) ;
+
+    char *name = res->sa.s + res->name ;
+    char *deps = res->sa.s + res->deps ;
+    if (!resolve_cmp(tokeep, name, SERVICE_STRUCT) && (!obstr_equal(name,SS_MASTER+1)))
+        if (!resolve_append(tokeep,wres)) goto err ;
+
+    if (res->ndeps)
+    {
+        if (!sastr_clean_string(&tmp,deps)) return 0 ;
+        for (;pos < tmp.len ; pos += strlen(tmp.s + pos) + 1)
+        {
+            resolve_service_t dres = RESOLVE_SERVICE_ZERO ;
+            resolve_wrapper_t_ref dwres = resolve_set_struct(SERVICE_STRUCT, &dres) ;
+            char *dname = tmp.s + pos ;
+            if (!resolve_check(src,dname)) goto err ;
+            if (!resolve_read(dwres,src,dname)) goto err ;
+            if (dres.ndeps && !resolve_cmp(tokeep, dname, SERVICE_STRUCT))
+            {
+                if (!service_resolve_add_deps(tokeep,&dres,src)) goto err ;
+            }
+            if (!resolve_cmp(tokeep, dname, SERVICE_STRUCT))
+            {
+                if (!resolve_append(tokeep,dwres)) goto err ;
+            }
+            resolve_free(dwres) ;
+        }
+    }
+
+    e = 1 ;
+
+    err:
+        stralloc_free(&tmp) ;
+        free(wres) ;
+        return e ;
+}
+
+int service_resolve_add_rdeps(genalloc *tokeep, resolve_service_t *res, char const *src)
+{
+    log_flow() ;
+
+    int type, e = 0 ;
+    stralloc tmp = STRALLOC_ZERO ;
+    stralloc nsv = STRALLOC_ZERO ;
+    ss_state_t sta = STATE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, res) ;
+    char const *exclude[2] = { SS_MASTER + 1, 0 } ;
+
+    char *name = res->sa.s + res->name ;
+    size_t srclen = strlen(src), a = 0, b = 0, c = 0 ;
+    char s[srclen + SS_RESOLVE_LEN + 1] ;
+    memcpy(s,src,srclen) ;
+    memcpy(s + srclen,SS_RESOLVE,SS_RESOLVE_LEN) ;
+    s[srclen + SS_RESOLVE_LEN] = 0 ;
+
+    if (res->type == TYPE_CLASSIC) type = 0 ;
+    else type = 1 ;
+
+    if (!sastr_dir_get(&nsv,s,exclude,S_IFREG)) goto err ;
+
+    if (!resolve_cmp(tokeep, name, SERVICE_STRUCT) && (!obstr_equal(name,SS_MASTER+1)))
+    {
+        if (!resolve_append(tokeep,wres)) goto err ;
+    }
+    if ((res->type == TYPE_BUNDLE || res->type == TYPE_MODULE) && res->ndeps)
+    {
+        uint32_t deps = res->type == TYPE_MODULE ? res->contents : res->deps ;
+        if (!sastr_clean_string(&tmp,res->sa.s + deps)) goto err ;
+        resolve_service_t dres = RESOLVE_SERVICE_ZERO ;
+        resolve_wrapper_t_ref dwres = resolve_set_struct(SERVICE_STRUCT, &dres) ;
+        for (; a < tmp.len ; a += strlen(tmp.s + a) + 1)
+        {
+            char *name = tmp.s + a ;
+            if (!resolve_check(src,name)) goto err ;
+            if (!resolve_read(dwres,src,name)) goto err ;
+            if (dres.type == TYPE_CLASSIC) continue ;
+            if (!resolve_cmp(tokeep, name, SERVICE_STRUCT))
+            {
+                if (!resolve_append(tokeep,dwres)) goto err ;
+                if (!service_resolve_add_rdeps(tokeep,&dres,src)) goto err ;
+            }
+            resolve_free(dwres) ;
+        }
+    }
+    for (; b < nsv.len ; b += strlen(nsv.s + b) +1)
+    {
+        int dtype = 0 ;
+        tmp.len = 0 ;
+        resolve_service_t dres = RESOLVE_SERVICE_ZERO ;
+        resolve_wrapper_t_ref dwres = resolve_set_struct(SERVICE_STRUCT, &dres) ;
+        char *dname = nsv.s + b ;
+        if (obstr_equal(name,dname)) { resolve_free(wres) ; continue ; }
+        if (!resolve_check(src,dname)) goto err ;
+        if (!resolve_read(dwres,src,dname)) goto err ;
+
+        if (dres.type == TYPE_CLASSIC) dtype = 0 ;
+        else dtype = 1 ;
+
+        if (state_check(dres.sa.s + dres.state,dname))
+        {
+            if (!state_read(&sta,dres.sa.s + dres.state,dname)) goto err ;
+            if (dtype != type || (!dres.disen && !sta.unsupervise)){ resolve_free(dwres) ; continue ; }
+        }
+        else if (dtype != type || (!dres.disen)){ resolve_free(dwres) ; continue ; }
+        if (dres.type == TYPE_BUNDLE && !dres.ndeps){ resolve_free(dwres) ; continue ; }
+
+        if (!resolve_cmp(tokeep, dname, SERVICE_STRUCT))
+        {
+            if (dres.ndeps)// || (dres.type == TYPE_BUNDLE && dres.ndeps) || )
+            {
+                if (!sastr_clean_string(&tmp,dres.sa.s + dres.deps)) goto err ;
+                /** we must check every service inside the module to not add as
+                 * rdeps a service declared inside the module.
+                 * eg.
+                 * module boot@system declare tty-rc@tty1
+                 * we don't want boot@system as rdeps of tty-rc@tty1 but only
+                 * service inside the module as rdeps of tty-rc@tty1 */
+                if (dres.type == TYPE_MODULE)
+                    for (c = 0 ; c < tmp.len ; c += strlen(tmp.s + c) + 1)
+                        if (obstr_equal(name,tmp.s + c)) goto skip ;
+
+                for (c = 0 ; c < tmp.len ; c += strlen(tmp.s + c) + 1)
+                {
+                    if (obstr_equal(name,tmp.s + c))
+                    {
+                        if (!resolve_append(tokeep,dwres)) goto err ;
+                        if (!service_resolve_add_rdeps(tokeep,&dres,src)) goto err ;
+                        resolve_free(dwres) ;
+                        break ;
+                    }
+                }
+            }
+        }
+        skip:
+        resolve_free(dwres) ;
+    }
+
+    e = 1 ;
+    err:
+        free(wres) ;
+        stralloc_free(&nsv) ;
+        stralloc_free(&tmp) ;
+        return e ;
+}
+
+int service_resolve_add_logger(genalloc *ga,char const *src)
+{
+    log_flow() ;
+
+    int e = 0 ;
+    size_t i = 0 ;
+    genalloc gatmp = GENALLOC_ZERO ;
+
+    for (; i < genalloc_len(resolve_service_t,ga) ; i++)
+    {
+        resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+        resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
+        resolve_service_t dres = RESOLVE_SERVICE_ZERO ;
+        resolve_wrapper_t_ref dwres = resolve_set_struct(SERVICE_STRUCT, &dres) ;
+        if (!service_resolve_copy(&res,&genalloc_s(resolve_service_t,ga)[i])) goto err ;
+
+        char *string = res.sa.s ;
+        char *name = string + res.name ;
+        if (!resolve_cmp(&gatmp, name, SERVICE_STRUCT))
+        {
+            if (!resolve_append(&gatmp,wres))
+                goto err ;
+
+            if (res.logger)
+            {
+                if (!resolve_check(src,string + res.logger)) goto err ;
+                if (!resolve_read(dwres,src,string + res.logger))
+                    goto err ;
+                if (!resolve_cmp(&gatmp, string + res.logger, SERVICE_STRUCT))
+                    if (!resolve_append(&gatmp,dwres)) goto err ;
+            }
+        }
+        resolve_free(wres) ;
+        resolve_free(dwres) ;
+    }
+    resolve_deep_free(SERVICE_STRUCT, ga) ;
+    if (!genalloc_copy(resolve_service_t,ga,&gatmp)) goto err ;
+
+    e = 1 ;
+
+    err:
+        genalloc_free(resolve_service_t,&gatmp) ;
+        resolve_deep_free(SERVICE_STRUCT, &gatmp) ;
+        return e ;
+}
+
+int service_resolve_write_master(ssexec_t *info, ss_resolve_graph_t *graph,char const *dir, unsigned int reverse)
+{
+    log_flow() ;
+
+    int r, e = 0 ;
+    size_t i = 0 ;
+    char ownerstr[UID_FMT] ;
+    size_t ownerlen = uid_fmt(ownerstr,info->owner) ;
+    ownerstr[ownerlen] = 0 ;
+
+    stralloc in = STRALLOC_ZERO ;
+    stralloc inres = STRALLOC_ZERO ;
+    stralloc gain = STRALLOC_ZERO ;
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
+
+    size_t dirlen = strlen(dir) ;
+
+    resolve_init(wres) ;
+
+    char runat[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + SS_MASTER_LEN + 1] ;
+    auto_strings(runat, info->livetree.s, "/", info->treename.s, SS_SVDIRS, SS_MASTER) ;
+
+    char dst[dirlen + SS_DB_LEN + SS_SRC_LEN + SS_MASTER_LEN + 1] ;
+    auto_strings(dst, dir, SS_DB, SS_SRC, SS_MASTER) ;
+
+    size_t livelen = info->live.len - 1 ;
+    char state[livelen + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len + 1] ;
+    auto_strings(state, info->live.s, SS_STATE, "/", ownerstr, "/", info->treename.s) ;
+
+    if (reverse)
+    {
+        size_t dstlen = strlen(dst) ;
+        char file[dstlen + 1 + SS_CONTENTS_LEN + 1] ;
+        auto_strings(file, dst, "/", SS_CONTENTS) ;
+
+        size_t filesize=file_get_size(file) ;
+
+        r = openreadfileclose(file,&gain,filesize) ;
+        if(!r) goto err ;
+        /** ensure that we have an empty line at the end of the string*/
+        if (!auto_stra(&gain,"\n")) goto err ;
+        if (!sastr_clean_element(&gain)) goto err ;
+    }
+
+    for (; i < genalloc_len(resolve_service_t,&graph->sorted); i++)
+    {
+        char *string = genalloc_s(resolve_service_t,&graph->sorted)[i].sa.s ;
+        char *name = string + genalloc_s(resolve_service_t,&graph->sorted)[i].name ;
+        if (reverse)
+            if (sastr_cmp(&gain,name) == -1) continue ;
+
+        if (!stralloc_cats(&in,name)) goto err ;
+        if (!stralloc_cats(&in,"\n")) goto err ;
+
+        if (!stralloc_cats(&inres,name)) goto err ;
+        if (!stralloc_cats(&inres," ")) goto err ;
+    }
+
+    if (inres.len) inres.len--;
+    if (!stralloc_0(&inres)) goto err ;
+
+    r = file_write_unsafe(dst,SS_CONTENTS,in.s,in.len) ;
+    if (!r)
+    {
+        log_warnusys("write: ",dst,"contents") ;
+        goto err ;
+    }
+
+    res.name = resolve_add_string(wres,SS_MASTER+1) ;
+    res.description = resolve_add_string(wres,"inner bundle - do not use it") ;
+    res.treename = resolve_add_string(wres,info->treename.s) ;
+    res.tree = resolve_add_string(wres,info->tree.s) ;
+    res.live = resolve_add_string(wres,info->live.s) ;
+    res.type = TYPE_BUNDLE ;
+    res.deps = resolve_add_string(wres,inres.s) ;
+    res.ndeps = genalloc_len(resolve_service_t,&graph->sorted) ;
+    res.runat = resolve_add_string(wres,runat) ;
+    res.state = resolve_add_string(wres,state) ;
+
+    if (!resolve_write(wres,dir,SS_MASTER+1)) goto err ;
+
+    e = 1 ;
+
+    err:
+        resolve_free(wres) ;
+        stralloc_free(&in) ;
+        stralloc_free(&inres) ;
+        stralloc_free(&gain) ;
+        return e ;
+}
+
diff --git a/src/lib66/ss_resolve.c b/src/lib66/ss_resolve.c
deleted file mode 100644
index 12afd2db..00000000
--- a/src/lib66/ss_resolve.c
+++ /dev/null
@@ -1,2120 +0,0 @@
-/*
- * ss_resolve.c
- *
- * Copyright (c) 2018-2021 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 <sys/stat.h>
-#include <stdint.h>
-#include <stdlib.h>//realpath
-#include <sys/types.h>
-#include <stdio.h> //rename
-
-#include <oblibs/types.h>
-#include <oblibs/log.h>
-#include <oblibs/directory.h>
-#include <oblibs/files.h>
-#include <oblibs/string.h>
-#include <oblibs/sastr.h>
-
-#include <skalibs/stralloc.h>
-#include <skalibs/djbunix.h>
-#include <skalibs/direntry.h>
-#include <skalibs/unix-transactional.h>
-#include <skalibs/diuint32.h>
-#include <skalibs/cdbmake.h>
-#include <skalibs/cdb.h>
-#include <skalibs/posixplz.h>//unlink_void
-
-#include <66/constants.h>
-#include <66/utils.h>
-#include <66/enum.h>
-#include <66/parser.h>//resolve need to find stralloc keep
-#include <66/resolve.h>
-#include <66/ssexec.h>
-#include <66/state.h>
-
-#include <s6/supervise.h>
-
-ss_resolve_field_table_t ss_resolve_field_table[] = {
-
-    [SS_RESOLVE_ENUM_NAME] = { .field = "name" },
-    [SS_RESOLVE_ENUM_DESCRIPTION] = { .field = "description" },
-    [SS_RESOLVE_ENUM_VERSION] = { .field = "version" },
-    [SS_RESOLVE_ENUM_LOGGER] = { .field = "logger" },
-    [SS_RESOLVE_ENUM_LOGREAL] = { .field = "logreal" },
-    [SS_RESOLVE_ENUM_LOGASSOC] = { .field = "logassoc" },
-    [SS_RESOLVE_ENUM_DSTLOG] = { .field = "dstlog" },
-    [SS_RESOLVE_ENUM_DEPS] = { .field = "deps" },
-    [SS_RESOLVE_ENUM_OPTSDEPS] = { .field = "optsdeps" },
-    [SS_RESOLVE_ENUM_EXTDEPS] = { .field = "extdeps" },
-    [SS_RESOLVE_ENUM_CONTENTS] = { .field = "contents" },
-    [SS_RESOLVE_ENUM_SRC] = { .field = "src" },
-    [SS_RESOLVE_ENUM_SRCONF] = { .field = "srconf" },
-    [SS_RESOLVE_ENUM_LIVE] = { .field = "live" },
-    [SS_RESOLVE_ENUM_RUNAT] = { .field = "runat" },
-    [SS_RESOLVE_ENUM_TREE] = { .field = "tree" },
-    [SS_RESOLVE_ENUM_TREENAME] = { .field = "treename" },
-    [SS_RESOLVE_ENUM_STATE] = { .field = "state" },
-    [SS_RESOLVE_ENUM_EXEC_RUN] = { .field = "exec_run" },
-    [SS_RESOLVE_ENUM_EXEC_LOG_RUN] = { .field = "exec_log_run" },
-    [SS_RESOLVE_ENUM_REAL_EXEC_RUN] = { .field = "real_exec_run" },
-    [SS_RESOLVE_ENUM_REAL_EXEC_LOG_RUN] = { .field = "real_exec_log_run" },
-    [SS_RESOLVE_ENUM_EXEC_FINISH] = { .field = "exec_finish" },
-    [SS_RESOLVE_ENUM_REAL_EXEC_FINISH] = { .field = "real_exec_finish" },
-    [SS_RESOLVE_ENUM_TYPE] = { .field = "type" },
-    [SS_RESOLVE_ENUM_NDEPS] = { .field = "ndeps" },
-    [SS_RESOLVE_ENUM_NOPTSDEPS] = { .field = "noptsdeps" },
-    [SS_RESOLVE_ENUM_NEXTDEPS] = { .field = "nextdeps" },
-    [SS_RESOLVE_ENUM_NCONTENTS] = { .field = "ncontents" },
-    [SS_RESOLVE_ENUM_DOWN] = { .field = "down" },
-    [SS_RESOLVE_ENUM_DISEN] = { .field = "disen" },
-    [SS_RESOLVE_ENUM_ENDOFKEY] = { .field = 0 }
-} ;
-
-void ss_resolve_free(ss_resolve_t *res)
-{
-    log_flow() ;
-
-    stralloc_free(&res->sa) ;
-}
-
-void ss_resolve_init(ss_resolve_t *res)
-{
-    log_flow() ;
-
-    res->sa.len = 0 ;
-    ss_resolve_add_string(res,"") ;
-}
-
-int ss_resolve_pointo(stralloc *sa,ssexec_t *info,int type, unsigned int where)
-{
-    log_flow() ;
-
-    sa->len = 0 ;
-
-    char ownerstr[UID_FMT] ;
-    size_t ownerlen = uid_fmt(ownerstr,info->owner) ;
-    ownerstr[ownerlen] = 0 ;
-
-    if (where == SS_RESOLVE_STATE) {
-
-        if (!auto_stra(sa, info->live.s, SS_STATE + 1, "/", ownerstr, "/", info->treename.s))
-            goto err ;
-
-    } else if (where == SS_RESOLVE_SRC) {
-
-        if (!auto_stra(sa, info->tree.s, SS_SVDIRS))
-            goto err ;
-
-    } else if (where == SS_RESOLVE_BACK) {
-
-        if (!auto_stra(sa, info->base.s, SS_SYSTEM, SS_BACKUP, "/", info->treename.s))
-            goto err ;
-
-    } else if (where == SS_RESOLVE_LIVE) {
-
-        if (!auto_stra(sa, info->live.s, SS_STATE + 1, "/", ownerstr, "/", info->treename.s, SS_SVDIRS))
-            goto err ;
-    }
-
-    if (type >= 0 && where) {
-
-        if (type == TYPE_CLASSIC) {
-
-            if (!auto_stra(sa, SS_SVC))
-                goto err ;
-
-        } else if (!auto_stra(sa, SS_DB))
-            goto err ;
-    }
-
-    return 1 ;
-
-    err:
-        return 0 ;
-}
-
-/* @sdir -> service dir
- * @mdir -> module dir */
-int ss_resolve_module_path(stralloc *sdir, stralloc *mdir, char const *sv,char const *frontend_src, uid_t owner)
-{
-    log_flow() ;
-
-    int r, insta ;
-    stralloc sainsta = STRALLOC_ZERO ;
-    stralloc mhome = STRALLOC_ZERO ; // module user dir
-    stralloc shome = STRALLOC_ZERO ; // service user dir
-    char const *src = 0 ;
-    char const *dest = 0 ;
-
-    insta = instance_check(sv) ;
-    instance_splitname(&sainsta,sv,insta,SS_INSTANCE_TEMPLATE) ;
-
-    if (!owner)
-    {
-        src = SS_MODULE_ADMDIR ;
-        dest = frontend_src ;
-    }
-    else
-    {
-        if (!set_ownerhome(&mhome,owner)) log_warnusys_return(LOG_EXIT_ZERO,"set home directory") ;
-        if (!stralloc_cats(&mhome,SS_MODULE_USERDIR)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        if (!stralloc_0(&mhome)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        mhome.len-- ;
-        src = mhome.s ;
-
-        if (!set_ownerhome(&shome,owner)) log_warnusys_return(LOG_EXIT_ZERO,"set home directory") ;
-        if (!stralloc_cats(&shome,SS_SERVICE_USERDIR)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        if (!stralloc_0(&shome)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        shome.len-- ;
-        dest = shome.s ;
-
-    }
-    if (!auto_stra(mdir,src,sainsta.s)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-    r = scan_mode(mdir->s,S_IFDIR) ;
-    if (!r || r == -1)
-    {
-        mdir->len = 0 ;
-        src = SS_MODULE_ADMDIR ;
-        if (!auto_stra(mdir,src,sainsta.s)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        r = scan_mode(mdir->s,S_IFDIR) ;
-        if (!r || r == -1)
-        {
-            mdir->len = 0 ;
-            src = SS_MODULE_SYSDIR ;
-            if (!auto_stra(mdir,src,sainsta.s)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-            r = scan_mode(mdir->s,S_IFDIR) ;
-            if (!r || r == -1) log_warnu_return(LOG_EXIT_ZERO,"find module: ",sv) ;
-        }
-
-    }
-    if (!auto_stra(sdir,dest,sv)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-
-    stralloc_free(&sainsta) ;
-    stralloc_free(&mhome) ;
-    stralloc_free(&shome) ;
-    return 1 ;
-}
-
-int ss_resolve_src_path(stralloc *sasrc,char const *sv, uid_t owner,char const *directory_forced)
-{
-    log_flow() ;
-
-    int r ;
-    char const *src = 0 ;
-    int found = 0, err = -1 ;
-    stralloc home = STRALLOC_ZERO ;
-    if (directory_forced)
-    {
-        if (!ss_resolve_cmp_service_basedir(directory_forced)) { log_warn("invalid base service directory: ",directory_forced) ; goto err ; }
-        src = directory_forced ;
-        r = ss_resolve_src(sasrc,sv,src,&found) ;
-        if (r == -1){ log_warnusys("parse source directory: ",src) ; goto err ; }
-        if (!r) { log_warnu("find service: ",sv) ; err = 0 ; goto err ; }
-    }
-    else
-    {
-        if (!owner) src = SS_SERVICE_ADMDIR ;
-        else
-        {
-            if (!set_ownerhome(&home,owner)) { log_warnusys("set home directory") ; goto err ; }
-            if (!stralloc_cats(&home,SS_SERVICE_USERDIR)) { log_warnsys("stralloc") ; goto err ; }
-            if (!stralloc_0(&home)) { log_warnsys("stralloc") ; goto err ; }
-            home.len-- ;
-            src = home.s ;
-        }
-
-        r = ss_resolve_src(sasrc,sv,src,&found) ;
-        if (r == -1){ log_warnusys("parse source directory: ",src) ; goto err ; }
-        if (!r)
-        {
-            found = 0 ;
-            src = SS_SERVICE_ADMDIR ;
-            r = ss_resolve_src(sasrc,sv,src,&found) ;
-            if (r == -1) { log_warnusys("parse source directory: ",src) ; goto err ; }
-            if (!r)
-            {
-                found = 0 ;
-                src = SS_SERVICE_SYSDIR ;
-                r = ss_resolve_src(sasrc,sv,src,&found) ;
-                if (r == -1) { log_warnusys("parse source directory: ",src) ; goto err ; }
-                if (!r) { log_warnu("find service: ",sv) ; err = 0 ; goto err ; }
-            }
-        }
-    }
-    stralloc_free(&home) ;
-    return 1 ;
-    err:
-        stralloc_free(&home) ;
-        return err ;
-}
-
-int ss_resolve_src(stralloc *sasrc, char const *name, char const *src,int *found)
-{
-    log_flow() ;
-
-    int r, obr, insta ;
-    size_t i, len, namelen = strlen(name), srclen = strlen(src), pos = 0 ;
-    stralloc sainsta = STRALLOC_ZERO ;
-    stralloc satmp = STRALLOC_ZERO ;
-    stralloc sort = STRALLOC_ZERO ;
-    char const *exclude[1] = { 0 } ;
-
-    if (!ss_resolve_sort_byfile_first(&sort,src))
-    {
-        log_warnu("sort directory: ",src) ;
-        goto err ;
-    }
-
-    for (; pos < sort.len ; pos += strlen(sort.s + pos) + 1)
-    {
-        char *dname = sort.s + pos ;
-        size_t dnamelen = strlen(dname) ;
-        char bname[dnamelen + 1] ;
-
-        if (!ob_basename(bname,dname)) goto err ;
-
-        if (scan_mode(dname,S_IFDIR) > 0)
-        {
-            *found = ss_resolve_src(sasrc,name,dname,found) ;
-            if (*found < 0) goto err ;
-        }
-        obr = 0 ;
-        insta = 0 ;
-        obr = obstr_equal(name,bname) ;
-        insta = instance_check(name) ;
-
-        if (insta > 0)
-        {
-            if (!instance_splitname(&sainsta,name,insta,SS_INSTANCE_TEMPLATE)) goto err ;
-            obr = obstr_equal(sainsta.s,bname) ;
-        }
-
-        if (obr)
-        {
-            *found = 1 ;
-            if (scan_mode(dname,S_IFDIR) > 0)
-            {
-                int rd = ss_resolve_service_isdir(dname,bname) ;
-                if (rd == -1) goto err ;
-                if (!rd)
-                    r = sastr_dir_get(&satmp,dname,exclude,S_IFREG|S_IFDIR) ;
-                else r = sastr_dir_get(&satmp,dname,exclude,S_IFREG) ;
-                if (!r)
-                {
-                    log_warnusys("get services from directory: ",dname) ;
-                    goto err ;
-                }
-                i = 0, len = satmp.len ;
-
-                for (;i < len; i += strlen(satmp.s + i) + 1)
-                {
-                    size_t tlen = strlen(satmp.s+i) ;
-                    char t[dnamelen + 1 + tlen + 2];
-
-                    auto_strings(t,dname,"/",satmp.s + i,"/") ;
-
-                    r = scan_mode(t,S_IFDIR) ;
-                    if (r == 1)
-                    {
-                        t[dnamelen + 1] = 0 ;
-                        *found = ss_resolve_src(sasrc,satmp.s+i,t,found) ;
-                        if (*found < 0) goto err ;
-                    }
-                    else
-                    {
-                        char t[dnamelen + tlen + 1] ;
-                        auto_strings(t,dname,satmp.s + i) ;
-                        if (sastr_cmp(sasrc,t) == -1)
-                        {
-                            if (!stralloc_cats(sasrc,dname)) goto err ;
-                            if (!stralloc_catb(sasrc,satmp.s+i,tlen+1)) goto err ;
-                        }
-                    }
-                }
-                break ;
-            }
-            else if (scan_mode(dname,S_IFREG) > 0)
-            {
-                char t[srclen + namelen + 1] ;
-                auto_strings(t,src,name) ;
-                if (sastr_cmp(sasrc,t) == -1)
-                {
-                    if (!stralloc_cats(sasrc,src)) goto err ;
-                    if (!stralloc_catb(sasrc,name,namelen+1)) goto err ;
-                }
-                break ;
-            }
-            else goto err ;
-        }
-    }
-
-    stralloc_free(&sainsta) ;
-    stralloc_free(&satmp) ;
-    stralloc_free(&sort) ;
-
-    return (*found) ;
-
-    err:
-        stralloc_free(&sainsta) ;
-        stralloc_free(&satmp) ;
-        stralloc_free(&sort) ;
-        return -1 ;
-}
-
-void ss_resolve_rmfile(char const *src,char const *name)
-{
-    log_flow() ;
-
-    size_t srclen = strlen(src) ;
-    size_t namelen = strlen(name) ;
-
-    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen +1] ;
-    memcpy(tmp,src,srclen) ;
-    memcpy(tmp + srclen, SS_RESOLVE,SS_RESOLVE_LEN) ;
-    tmp[srclen + SS_RESOLVE_LEN] = '/' ;
-    memcpy(tmp + srclen + SS_RESOLVE_LEN + 1, name, namelen) ;
-    tmp[srclen + SS_RESOLVE_LEN + 1 + namelen] = 0 ;
-
-    unlink_void(tmp) ;
-}
-
-ssize_t ss_resolve_add_string(ss_resolve_t *res, char const *data)
-{
-    log_flow() ;
-
-    ssize_t baselen = res->sa.len ;
-    if (!data)
-    {
-        if (!stralloc_catb(&res->sa,"",1)) log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;
-        return baselen ;
-    }
-    size_t datalen = strlen(data) ;
-    if (!stralloc_catb(&res->sa,data,datalen + 1)) log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;
-    return baselen ;
-}
-
-int ss_resolve_write(ss_resolve_t *res, char const *dst, char const *name)
-{
-    log_flow() ;
-
-    size_t dstlen = strlen(dst) ;
-    size_t namelen = strlen(name) ;
-
-    char tmp[dstlen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
-    auto_strings(tmp,dst,SS_RESOLVE,"/") ;
-
-    if (!ss_resolve_write_cdb(res,tmp,name)) return 0 ;
-
-    return 1 ;
-}
-
-int ss_resolve_read(ss_resolve_t *res, char const *src, char const *name)
-{
-    log_flow() ;
-
-    size_t srclen = strlen(src) ;
-    size_t namelen = strlen(name) ;
-
-    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
-    auto_strings(tmp,src,SS_RESOLVE,"/",name) ;
-
-    if (!ss_resolve_read_cdb(res,tmp)) return 0 ;
-
-    return 1 ;
-}
-
-/** not used
- *
- *
- *
- *
- *
-int ss_resolve_check_insrc(ssexec_t *info, char const *name)
-{
-    log_flow() ;
-
-    stralloc sares = STRALLOC_ZERO ;
-    if (!ss_resolve_pointo(&sares,info,SS_NOTYPE,SS_RESOLVE_SRC)) goto err ;
-    if (!ss_resolve_check(sares.s,name)) goto err ;
-    stralloc_free(&sares) ;
-    return 1 ;
-    err:
-        stralloc_free(&sares) ;
-        return 0 ;
-}
-*
-*
-*/
-
-int ss_resolve_check(char const *src, char const *name)
-{
-    log_flow() ;
-
-    int r ;
-    size_t srclen = strlen(src) ;
-    size_t namelen = strlen(name) ;
-    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
-    memcpy(tmp,src,srclen) ;
-    memcpy(tmp + srclen, SS_RESOLVE,SS_RESOLVE_LEN) ;
-    tmp[srclen + SS_RESOLVE_LEN] = '/' ;
-    memcpy(tmp + srclen + SS_RESOLVE_LEN + 1,name,namelen) ;
-    tmp[srclen + SS_RESOLVE_LEN + 1 + namelen] = 0 ;
-    r = scan_mode(tmp,S_IFREG) ;
-    if (!r || r < 0) return 0 ;
-    return 1 ;
-}
-
-int ss_resolve_setnwrite(sv_alltype *services, ssexec_t *info, char const *dst)
-{
-    log_flow() ;
-
-    char ownerstr[UID_FMT] ;
-    size_t ownerlen = uid_fmt(ownerstr,info->owner), id, nid ;
-    ownerstr[ownerlen] = 0 ;
-
-    stralloc destlog = STRALLOC_ZERO ;
-    stralloc ndeps = STRALLOC_ZERO ;
-    stralloc other_deps = STRALLOC_ZERO ;
-
-    ss_state_t sta = STATE_ZERO ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-    ss_resolve_init(&res) ;
-
-    char *name = keep.s + services->cname.name ;
-    size_t namelen = strlen(name) ;
-    char logname[namelen + SS_LOG_SUFFIX_LEN + 1] ;
-    char logreal[namelen + SS_LOG_SUFFIX_LEN + 1] ;
-    char stmp[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + 1 + namelen + SS_LOG_SUFFIX_LEN + 1] ;
-
-    size_t livelen = info->live.len - 1 ;
-    char state[livelen + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len + 1 + namelen + 1] ;
-    memcpy(state,info->live.s,livelen) ;
-    memcpy(state + livelen, SS_STATE,SS_STATE_LEN) ;
-    state[livelen+ SS_STATE_LEN] = '/' ;
-    memcpy(state + livelen + SS_STATE_LEN + 1,ownerstr,ownerlen) ;
-    state[livelen + SS_STATE_LEN + 1 + ownerlen] = '/' ;
-    memcpy(state + livelen + SS_STATE_LEN + 1 + ownerlen + 1,info->treename.s,info->treename.len) ;
-    state[livelen + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len] = 0 ;
-
-    res.type = services->cname.itype ;
-    res.name = ss_resolve_add_string(&res,name) ;
-    res.description = ss_resolve_add_string(&res,keep.s + services->cname.description) ;
-    res.version = ss_resolve_add_string(&res,keep.s + services->cname.version) ;
-    res.tree = ss_resolve_add_string(&res,info->tree.s) ;
-    res.treename = ss_resolve_add_string(&res,info->treename.s) ;
-    res.live = ss_resolve_add_string(&res,info->live.s) ;
-    res.state = ss_resolve_add_string(&res,state) ;
-    res.src = ss_resolve_add_string(&res,keep.s + services->src) ;
-    if (services->srconf > 0)
-        res.srconf = ss_resolve_add_string(&res,keep.s + services->srconf) ;
-
-    if (res.type == TYPE_ONESHOT)
-    {
-        if (services->type.oneshot.up.exec >= 0)
-        {
-            res.exec_run = ss_resolve_add_string(&res,keep.s + services->type.oneshot.up.exec) ;
-            res.real_exec_run = ss_resolve_add_string(&res,keep.s + services->type.oneshot.up.real_exec) ;
-        }
-        if (services->type.oneshot.down.exec >= 0)
-        {
-            res.exec_finish = ss_resolve_add_string(&res,keep.s + services->type.oneshot.down.exec) ;
-            res.real_exec_finish = ss_resolve_add_string(&res,keep.s + services->type.oneshot.down.real_exec) ;
-        }
-    }
-    if (res.type == TYPE_CLASSIC || res.type == TYPE_LONGRUN)
-    {
-        if (services->type.classic_longrun.run.exec >= 0)
-        {
-            res.exec_run = ss_resolve_add_string(&res,keep.s + services->type.classic_longrun.run.exec) ;
-            res.real_exec_run = ss_resolve_add_string(&res,keep.s + services->type.classic_longrun.run.real_exec) ;
-        }
-        if (services->type.classic_longrun.finish.exec >= 0)
-        {
-            res.exec_finish = ss_resolve_add_string(&res,keep.s + services->type.classic_longrun.finish.exec) ;
-            res.real_exec_finish = ss_resolve_add_string(&res,keep.s + services->type.classic_longrun.finish.real_exec) ;
-        }
-    }
-
-    res.ndeps = services->cname.nga ;
-    res.noptsdeps = services->cname.nopts ;
-    res.nextdeps = services->cname.next ;
-    res.ncontents = services->cname.ncontents ;
-    if (services->flags[0]) res.down = 1 ;
-    res.disen = 1 ;
-    if (res.type == TYPE_CLASSIC)
-    {
-        memcpy(stmp,info->scandir.s,info->scandir.len) ;
-        stmp[info->scandir.len] = '/' ;
-        memcpy(stmp + info->scandir.len + 1,name,namelen) ;
-        stmp[info->scandir.len + 1 + namelen] = 0 ;
-        res.runat = ss_resolve_add_string(&res,stmp) ;
-    }
-    else if (res.type >= TYPE_BUNDLE)
-    {
-        memcpy(stmp,info->livetree.s,info->livetree.len) ;
-        stmp[info->livetree.len] = '/' ;
-        memcpy(stmp + info->livetree.len + 1,info->treename.s,info->treename.len) ;
-        memcpy(stmp + info->livetree.len + 1 + info->treename.len, SS_SVDIRS,SS_SVDIRS_LEN) ;
-        stmp[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN] = '/' ;
-        memcpy(stmp + info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + 1, name,namelen) ;
-        stmp[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + 1 + namelen] = 0 ;
-        res.runat = ss_resolve_add_string(&res,stmp) ;
-    }
-
-    if (ss_state_check(state,name))
-    {
-        if (!ss_state_read(&sta,state,name)) { log_warnusys("read state file of: ",name) ; goto err ; }
-        if (!sta.init)
-            ss_state_setflag(&sta,SS_FLAGS_RELOAD,SS_FLAGS_TRUE) ;
-        if (sta.init) {
-            ss_state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_TRUE) ;
-        } else {
-            ss_state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_FALSE) ;
-        }
-        ss_state_setflag(&sta,SS_FLAGS_UNSUPERVISE,SS_FLAGS_FALSE) ;
-        if (!ss_state_write(&sta,res.sa.s + res.state,name)){ log_warnusys("write state file of: ",name) ; goto err ; }
-    }
-
-    if (res.ndeps)
-    {
-        id = services->cname.idga, nid = res.ndeps ;
-        for (;nid; id += strlen(deps.s + id) + 1, nid--)
-        {
-            if (!stralloc_catb(&ndeps,deps.s + id,strlen(deps.s + id)) ||
-            !stralloc_catb(&ndeps," ",1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        }
-        ndeps.len-- ;
-        if (!stralloc_0(&ndeps)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        res.deps = ss_resolve_add_string(&res,ndeps.s) ;
-    }
-
-    if (res.noptsdeps)
-    {
-        id = services->cname.idopts, nid = res.noptsdeps ;
-        for (;nid; id += strlen(deps.s + id) + 1, nid--)
-        {
-            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
-            !stralloc_catb(&other_deps," ",1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        }
-        other_deps.len-- ;
-        if (!stralloc_0(&other_deps)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        res.optsdeps = ss_resolve_add_string(&res,other_deps.s) ;
-    }
-
-    if (res.nextdeps)
-    {
-        other_deps.len = 0 ;
-        id = services->cname.idext, nid = res.nextdeps ;
-        for (;nid; id += strlen(deps.s + id) + 1, nid--)
-        {
-            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
-            !stralloc_catb(&other_deps," ",1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        }
-        other_deps.len-- ;
-        if (!stralloc_0(&other_deps)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        res.extdeps = ss_resolve_add_string(&res,other_deps.s) ;
-    }
-
-    if (res.ncontents)
-    {
-        other_deps.len = 0 ;
-        id = services->cname.idcontents, nid = res.ncontents ;
-        for (;nid; id += strlen(deps.s + id) + 1, nid--)
-        {
-            if (!stralloc_catb(&other_deps,deps.s + id,strlen(deps.s + id)) ||
-            !stralloc_catb(&other_deps," ",1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        }
-        other_deps.len-- ;
-        if (!stralloc_0(&other_deps)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        res.contents = ss_resolve_add_string(&res,other_deps.s) ;
-    }
-
-    if (services->opts[0])
-    {
-        // destination of the logger
-        if (services->type.classic_longrun.log.destination < 0)
-        {
-            if(info->owner > 0)
-            {
-                if (!stralloc_cats(&destlog,get_userhome(info->owner))) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-                if (!stralloc_cats(&destlog,"/")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-                if (!stralloc_cats(&destlog,SS_LOGGER_USERDIR)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-                if (!stralloc_cats(&destlog,name)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-            }
-            else
-            {
-                if (!stralloc_cats(&destlog,SS_LOGGER_SYSDIR)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-                if (!stralloc_cats(&destlog,name)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-            }
-        }
-        else
-        {
-            if (!stralloc_cats(&destlog,keep.s+services->type.classic_longrun.log.destination)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-        }
-        if (!stralloc_0(&destlog)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-
-        res.dstlog = ss_resolve_add_string(&res,destlog.s) ;
-
-        if ((res.type == TYPE_CLASSIC) || (res.type == TYPE_LONGRUN))
-        {
-            memcpy(logname,name,namelen) ;
-            memcpy(logname + namelen,SS_LOG_SUFFIX,SS_LOG_SUFFIX_LEN) ;
-            logname[namelen + SS_LOG_SUFFIX_LEN] = 0 ;
-
-            memcpy(logreal,name,namelen) ;
-            if (res.type == TYPE_CLASSIC)
-            {
-                memcpy(logreal + namelen,"/log",SS_LOG_SUFFIX_LEN) ;
-            }
-            else memcpy(logreal + namelen,"-log",SS_LOG_SUFFIX_LEN) ;
-            logreal[namelen + SS_LOG_SUFFIX_LEN] = 0 ;
-
-            res.logger = ss_resolve_add_string(&res,logname) ;
-            res.logreal = ss_resolve_add_string(&res,logreal) ;
-            if (ndeps.len) ndeps.len--;
-            if (!stralloc_catb(&ndeps," ",1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-            if (!stralloc_cats(&ndeps,res.sa.s + res.logger)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-            if (!stralloc_0(&ndeps)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-            res.deps = ss_resolve_add_string(&res,ndeps.s) ;
-            if (res.type == TYPE_CLASSIC) res.ndeps = 1 ;
-            else if (res.type == TYPE_LONGRUN) res.ndeps += 1 ;
-
-            if (services->type.classic_longrun.log.run.exec >= 0)
-                res.exec_log_run = ss_resolve_add_string(&res,keep.s + services->type.classic_longrun.log.run.exec) ;
-
-            if (services->type.classic_longrun.log.run.real_exec >= 0)
-                res.real_exec_log_run = ss_resolve_add_string(&res,keep.s + services->type.classic_longrun.log.run.real_exec) ;
-
-            if (!ss_resolve_setlognwrite(&res,dst,info)) goto err ;
-        }
-    }
-
-    if (!ss_resolve_write(&res,dst,res.sa.s + res.name))
-    {
-        log_warnusys("write resolve file: ",dst,SS_RESOLVE,"/",res.sa.s + res.name) ;
-        goto err ;
-    }
-
-    ss_resolve_free(&res) ;
-    stralloc_free(&ndeps) ;
-    stralloc_free(&other_deps) ;
-    stralloc_free(&destlog) ;
-    return 1 ;
-
-    err:
-        ss_resolve_free(&res) ;
-        stralloc_free(&ndeps) ;
-        stralloc_free(&other_deps) ;
-        stralloc_free(&destlog) ;
-        return 0 ;
-}
-
-int ss_resolve_setlognwrite(ss_resolve_t *sv, char const *dst,ssexec_t *info)
-{
-    log_flow() ;
-
-    if (!sv->logger) return 1 ;
-
-    ss_state_t sta = STATE_ZERO ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-    ss_resolve_init(&res) ;
-
-    char *string = sv->sa.s ;
-    size_t svlen = strlen(string + sv->name) ;
-    char descrip[svlen + 7 + 1] ;
-    memcpy(descrip,string + sv->name,svlen) ;
-    memcpy(descrip + svlen," logger",7) ;
-    descrip[svlen + 7] = 0 ;
-
-    size_t runlen = strlen(string + sv->runat) ;
-    char live[runlen + 4 + 1] ;
-    memcpy(live,string + sv->runat,runlen) ;
-    if (sv->type >= TYPE_BUNDLE)
-    {
-        memcpy(live + runlen,"-log",4)  ;
-    }else memcpy(live + runlen,"/log",4)  ;
-    live[runlen + 4] = 0 ;
-
-    res.type = sv->type ;
-    res.name = ss_resolve_add_string(&res,string + sv->logger) ;
-    res.description = ss_resolve_add_string(&res,descrip) ;
-    /*** temporary check here, version is not mandatory yet */
-    if (sv->version > 0)
-        res.version = ss_resolve_add_string(&res,string + sv->version) ;
-    res.logreal = ss_resolve_add_string(&res,string + sv->logreal) ;
-    res.logassoc = ss_resolve_add_string(&res,string + sv->name) ;
-    res.dstlog = ss_resolve_add_string(&res,string + sv->dstlog) ;
-    res.live = ss_resolve_add_string(&res,string + sv->live) ;
-    res.runat = ss_resolve_add_string(&res,live) ;
-    res.tree = ss_resolve_add_string(&res,string + sv->tree) ;
-    res.treename = ss_resolve_add_string(&res,string + sv->treename) ;
-    res.state = ss_resolve_add_string(&res,string + sv->state) ;
-    res.src = ss_resolve_add_string(&res,string + sv->src) ;
-    res.down = sv->down ;
-    res.disen = sv->disen ;
-    if (sv->exec_log_run >= 0)
-        res.exec_log_run = ss_resolve_add_string(&res,string + sv->exec_log_run) ;
-    if (sv->real_exec_log_run >= 0)
-        res.real_exec_log_run = ss_resolve_add_string(&res,string + sv->real_exec_log_run) ;
-
-    if (ss_state_check(string + sv->state,string + sv->logger))
-    {
-        if (!ss_state_read(&sta,string + sv->state,string + sv->logger)) { log_warnusys("read state file of: ",string + sv->logger) ; goto err ; }
-        if (!sta.init)
-            ss_state_setflag(&sta,SS_FLAGS_RELOAD,SS_FLAGS_TRUE) ;
-        ss_state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_FALSE) ;
-        ss_state_setflag(&sta,SS_FLAGS_UNSUPERVISE,SS_FLAGS_FALSE) ;
-        if (!ss_state_write(&sta,string + sv->state,string + sv->logger)){ log_warnusys("write state file of: ",string + sv->logger) ; goto err ; }
-    }
-
-    if (!ss_resolve_write(&res,dst,res.sa.s + res.name))
-    {
-        log_warnusys("write resolve file: ",dst,SS_RESOLVE,"/",res.sa.s + res.name) ;
-        goto err ;
-    }
-    ss_resolve_free(&res) ;
-    return 1 ;
-    err:
-        ss_resolve_free(&res) ;
-        return 0 ;
-}
-
-int ss_resolve_cmp(genalloc *ga,char const *name)
-{
-    log_flow() ;
-
-    unsigned int i = 0 ;
-    for (;i < genalloc_len(ss_resolve_t,ga) ; i++)
-    {
-        char *string = genalloc_s(ss_resolve_t,ga)[i].sa.s ;
-        char *s = string + genalloc_s(ss_resolve_t,ga)[i].name ;
-        if (!strcmp(name,s)) return 1 ;
-    }
-    return 0 ;
-}
-
-int ss_resolve_copy(ss_resolve_t *dst,ss_resolve_t *res)
-{
-    log_flow() ;
-
-    ss_resolve_free(dst) ;
-    size_t len = res->sa.len - 1 ;
-    dst->salen = res->salen ;
-    if (!stralloc_catb(&dst->sa,res->sa.s,len)) return 0 ;
-    dst->name = res->name ;
-    dst->description = res->description ;
-    dst->version = res->version ;
-    dst->logger = res->logger ;
-    dst->logreal = res->logreal ;
-    dst->logassoc = res->logassoc ;
-    dst->dstlog = res->dstlog ;
-    dst->deps = res->deps ;
-    dst->optsdeps = res->optsdeps ;
-    dst->extdeps = res->extdeps ;
-    dst->contents = res->contents ;
-    dst->src = res->src ;
-    dst->srconf = res->srconf ;
-    dst->live = res->live ;
-    dst->runat = res->runat ;
-    dst->tree = res->tree ;
-    dst->treename = res->treename ;
-    dst->state = res->state ;
-    dst->exec_run = res->exec_run ;
-    dst->exec_log_run = res->exec_log_run ;
-    dst->real_exec_run = res->real_exec_run ;
-    dst->real_exec_log_run = res->real_exec_log_run ;
-    dst->exec_finish = res->exec_finish ;
-    dst->real_exec_finish = res->real_exec_finish ;
-    dst->type = res->type ;
-    dst->ndeps = res->ndeps ;
-    dst->noptsdeps = res->noptsdeps ;
-    dst->nextdeps = res->nextdeps ;
-    dst->ncontents = res->ncontents ;
-    dst->down = res->down ;
-    dst->disen = res->disen ;
-
-    if (!stralloc_0(&dst->sa)) return 0 ;
-    return 1 ;
-}
-
-int ss_resolve_append(genalloc *ga,ss_resolve_t *res)
-{
-    log_flow() ;
-
-    ss_resolve_t cp = RESOLVE_ZERO ;
-    if (!ss_resolve_copy(&cp,res)) goto err ;
-    if (!genalloc_append(ss_resolve_t,ga,&cp)) goto err ;
-    return 1 ;
-    err:
-        ss_resolve_free(&cp) ;
-        return 0 ;
-}
-
-int ss_resolve_add_deps(genalloc *tokeep,ss_resolve_t *res, char const *src)
-{
-    log_flow() ;
-
-    size_t pos = 0 ;
-    stralloc tmp = STRALLOC_ZERO ;
-
-    char *name = res->sa.s + res->name ;
-    char *deps = res->sa.s + res->deps ;
-    if (!ss_resolve_cmp(tokeep,name) && (!obstr_equal(name,SS_MASTER+1)))
-        if (!ss_resolve_append(tokeep,res)) goto err ;
-
-    if (res->ndeps)
-    {
-        if (!sastr_clean_string(&tmp,deps)) return 0 ;
-        for (;pos < tmp.len ; pos += strlen(tmp.s + pos) + 1)
-        {
-            ss_resolve_t dres = RESOLVE_ZERO ;
-            char *dname = tmp.s + pos ;
-            if (!ss_resolve_check(src,dname)) goto err ;
-            if (!ss_resolve_read(&dres,src,dname)) goto err ;
-            if (dres.ndeps && !ss_resolve_cmp(tokeep,dname))
-            {
-                if (!ss_resolve_add_deps(tokeep,&dres,src)) goto err ;
-            }
-            if (!ss_resolve_cmp(tokeep,dname))
-            {
-                if (!ss_resolve_append(tokeep,&dres)) goto err ;
-            }
-            ss_resolve_free(&dres) ;
-        }
-    }
-    stralloc_free(&tmp) ;
-    return 1 ;
-    err:
-        stralloc_free(&tmp) ;
-        return 0 ;
-}
-
-int ss_resolve_add_rdeps(genalloc *tokeep, ss_resolve_t *res, char const *src)
-{
-    log_flow() ;
-
-    int type ;
-    stralloc tmp = STRALLOC_ZERO ;
-    stralloc nsv = STRALLOC_ZERO ;
-    ss_state_t sta = STATE_ZERO ;
-    char const *exclude[2] = { SS_MASTER + 1, 0 } ;
-
-    char *name = res->sa.s + res->name ;
-    size_t srclen = strlen(src), a = 0, b = 0, c = 0 ;
-    char s[srclen + SS_RESOLVE_LEN + 1] ;
-    memcpy(s,src,srclen) ;
-    memcpy(s + srclen,SS_RESOLVE,SS_RESOLVE_LEN) ;
-    s[srclen + SS_RESOLVE_LEN] = 0 ;
-
-    if (res->type == TYPE_CLASSIC) type = 0 ;
-    else type = 1 ;
-
-    if (!sastr_dir_get(&nsv,s,exclude,S_IFREG)) goto err ;
-
-    if (!ss_resolve_cmp(tokeep,name) && (!obstr_equal(name,SS_MASTER+1)))
-    {
-        if (!ss_resolve_append(tokeep,res)) goto err ;
-    }
-    if ((res->type == TYPE_BUNDLE || res->type == TYPE_MODULE) && res->ndeps)
-    {
-        uint32_t deps = res->type == TYPE_MODULE ? res->contents : res->deps ;
-        if (!sastr_clean_string(&tmp,res->sa.s + deps)) goto err ;
-        ss_resolve_t dres = RESOLVE_ZERO ;
-        for (; a < tmp.len ; a += strlen(tmp.s + a) + 1)
-        {
-            char *name = tmp.s + a ;
-            if (!ss_resolve_check(src,name)) goto err ;
-            if (!ss_resolve_read(&dres,src,name)) goto err ;
-            if (dres.type == TYPE_CLASSIC) continue ;
-            if (!ss_resolve_cmp(tokeep,name))
-            {
-                if (!ss_resolve_append(tokeep,&dres)) goto err ;
-                if (!ss_resolve_add_rdeps(tokeep,&dres,src)) goto err ;
-            }
-            ss_resolve_free(&dres) ;
-        }
-    }
-    for (; b < nsv.len ; b += strlen(nsv.s + b) +1)
-    {
-        int dtype = 0 ;
-        tmp.len = 0 ;
-        ss_resolve_t dres = RESOLVE_ZERO ;
-        char *dname = nsv.s + b ;
-        if (obstr_equal(name,dname)) { ss_resolve_free(&dres) ; continue ; }
-        if (!ss_resolve_check(src,dname)) goto err ;
-        if (!ss_resolve_read(&dres,src,dname)) goto err ;
-
-        if (dres.type == TYPE_CLASSIC) dtype = 0 ;
-        else dtype = 1 ;
-
-        if (ss_state_check(dres.sa.s + dres.state,dname))
-        {
-            if (!ss_state_read(&sta,dres.sa.s + dres.state,dname)) goto err ;
-            if (dtype != type || (!dres.disen && !sta.unsupervise)){ ss_resolve_free(&dres) ; continue ; }
-        }
-        else if (dtype != type || (!dres.disen)){ ss_resolve_free(&dres) ; continue ; }
-        if (dres.type == TYPE_BUNDLE && !dres.ndeps){ ss_resolve_free(&dres) ; continue ; }
-
-        if (!ss_resolve_cmp(tokeep,dname))
-        {
-            if (dres.ndeps)// || (dres.type == TYPE_BUNDLE && dres.ndeps) || )
-            {
-                if (!sastr_clean_string(&tmp,dres.sa.s + dres.deps)) goto err ;
-                /** we must check every service inside the module to not add as
-                 * rdeps a service declared inside the module.
-                 * eg.
-                 * module boot@system declare tty-rc@tty1
-                 * we don't want boot@system as rdeps of tty-rc@tty1 but only
-                 * service inside the module as rdeps of tty-rc@tty1 */
-                if (dres.type == TYPE_MODULE)
-                    for (c = 0 ; c < tmp.len ; c += strlen(tmp.s + c) + 1)
-                        if (obstr_equal(name,tmp.s + c)) goto skip ;
-
-                for (c = 0 ; c < tmp.len ; c += strlen(tmp.s + c) + 1)
-                {
-                    if (obstr_equal(name,tmp.s + c))
-                    {
-                        if (!ss_resolve_append(tokeep,&dres)) goto err ;
-                        if (!ss_resolve_add_rdeps(tokeep,&dres,src)) goto err ;
-                        ss_resolve_free(&dres) ;
-                        break ;
-                    }
-                }
-            }
-        }
-        skip:
-        ss_resolve_free(&dres) ;
-    }
-
-    stralloc_free(&nsv) ;
-    stralloc_free(&tmp) ;
-    return 1 ;
-    err:
-        stralloc_free(&nsv) ;
-        stralloc_free(&tmp) ;
-        return 0 ;
-}
-
-int ss_resolve_add_logger(genalloc *ga,char const *src)
-{
-    log_flow() ;
-
-    size_t i = 0 ;
-    genalloc gatmp = GENALLOC_ZERO ;
-
-    for (; i < genalloc_len(ss_resolve_t,ga) ; i++)
-    {
-        ss_resolve_t res = RESOLVE_ZERO ;
-        ss_resolve_t dres = RESOLVE_ZERO ;
-        if (!ss_resolve_copy(&res,&genalloc_s(ss_resolve_t,ga)[i])) goto err ;
-
-        char *string = res.sa.s ;
-        char *name = string + res.name ;
-        if (!ss_resolve_cmp(&gatmp,name))
-        {
-            if (!ss_resolve_append(&gatmp,&res))
-                goto err ;
-
-            if (res.logger)
-            {
-                if (!ss_resolve_check(src,string + res.logger)) goto err ;
-                if (!ss_resolve_read(&dres,src,string + res.logger))
-                    goto err ;
-                if (!ss_resolve_cmp(&gatmp,string + res.logger))
-                    if (!ss_resolve_append(&gatmp,&dres)) goto err ;
-            }
-        }
-        ss_resolve_free(&res) ;
-        ss_resolve_free(&dres) ;
-    }
-    genalloc_deepfree(ss_resolve_t,ga,ss_resolve_free) ;
-    if (!genalloc_copy(ss_resolve_t,ga,&gatmp)) goto err ;
-
-    genalloc_free(ss_resolve_t,&gatmp) ;
-    return 1 ;
-    err:
-        genalloc_deepfree(ss_resolve_t,&gatmp,ss_resolve_free) ;
-        return 0 ;
-}
-
-int ss_resolve_create_live(ssexec_t *info)
-{
-    log_flow() ;
-
-    int r ;
-    gid_t gidowner ;
-    if (!yourgid(&gidowner,info->owner)) return 0 ;
-    stralloc sares = STRALLOC_ZERO ;
-    stralloc ressrc = STRALLOC_ZERO ;
-
-    if (!ss_resolve_pointo(&ressrc,info,SS_NOTYPE,SS_RESOLVE_SRC)) goto err ;
-
-    if (!ss_resolve_pointo(&sares,info,SS_NOTYPE,SS_RESOLVE_STATE)) goto err ;
-    r = scan_mode(sares.s,S_IFDIR) ;
-    if (r < 0) goto err ;
-    if (!r)
-    {
-        ssize_t len = get_rlen_until(sares.s,'/',sares.len) ;
-        sares.len-- ;
-        char sym[sares.len + SS_SVDIRS_LEN + 1] ;
-        memcpy(sym,sares.s,sares.len) ;
-        sym[sares.len] = 0 ;
-
-        r = dir_create_parent(sym,0700) ;
-        if (!r) goto err ;
-        sym[len] = 0 ;
-        if (chown(sym,info->owner,gidowner) < 0) goto err ;
-        memcpy(sym,sares.s,sares.len) ;
-        memcpy(sym + sares.len, SS_SVDIRS, SS_SVDIRS_LEN) ;
-        sym[sares.len + SS_SVDIRS_LEN] = 0 ;
-
-        log_trace("point symlink: ",sym," to ",ressrc.s) ;
-        if (symlink(ressrc.s,sym) < 0)
-        {
-            log_warnusys("symlink: ", sym) ;
-            goto err ;
-        }
-    }
-    /** live/state/uid/treename/init file */
-    if (!file_write_unsafe(sares.s,"init","",0)) goto err ;
-
-    stralloc_free(&ressrc) ;
-    stralloc_free(&sares) ;
-
-    return 1 ;
-    err:
-        stralloc_free(&ressrc) ;
-        stralloc_free(&sares) ;
-        return 0 ;
-}
-
-int ss_resolve_search(genalloc *ga,char const *name)
-{
-    log_flow() ;
-
-    unsigned int i = 0 ;
-    for (; i < genalloc_len(ss_resolve_t,ga) ; i++)
-    {
-        char *s = genalloc_s(ss_resolve_t,ga)[i].sa.s + genalloc_s(ss_resolve_t,ga)[i].name ;
-        if (obstr_equal(name,s)) return i ;
-    }
-    return -1 ;
-}
-
-int ss_resolve_write_master(ssexec_t *info,ss_resolve_graph_t *graph,char const *dir, unsigned int reverse)
-{
-    log_flow() ;
-
-    int r ;
-    size_t i = 0 ;
-    char ownerstr[UID_FMT] ;
-    size_t ownerlen = uid_fmt(ownerstr,info->owner) ;
-    ownerstr[ownerlen] = 0 ;
-
-    stralloc in = STRALLOC_ZERO ;
-    stralloc inres = STRALLOC_ZERO ;
-    stralloc gain = STRALLOC_ZERO ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-
-    size_t dirlen = strlen(dir) ;
-
-    char runat[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + SS_MASTER_LEN + 1] ;
-    memcpy(runat,info->livetree.s,info->livetree.len) ;
-    runat[info->livetree.len] = '/' ;
-    memcpy(runat + info->livetree.len + 1,info->treename.s,info->treename.len) ;
-    memcpy(runat + info->livetree.len + 1 + info->treename.len, SS_SVDIRS,SS_SVDIRS_LEN) ;
-    memcpy(runat + info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN, SS_MASTER, SS_MASTER_LEN) ;
-    runat[info->livetree.len + 1 + info->treename.len + SS_SVDIRS_LEN + SS_MASTER_LEN] = 0 ;
-
-    char dst[dirlen + SS_DB_LEN + SS_SRC_LEN + SS_MASTER_LEN + 1] ;
-    memcpy(dst, dir, dirlen) ;
-    memcpy(dst + dirlen, SS_DB, SS_DB_LEN) ;
-    memcpy(dst + dirlen + SS_DB_LEN, SS_SRC, SS_SRC_LEN) ;
-    memcpy(dst + dirlen + SS_DB_LEN + SS_SRC_LEN, SS_MASTER, SS_MASTER_LEN) ;
-    dst[dirlen + SS_DB_LEN + SS_SRC_LEN + SS_MASTER_LEN] = 0 ;
-
-    size_t livelen = info->live.len - 1 ;
-    char state[livelen + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len + 1] ;
-    memcpy(state,info->live.s,livelen) ;
-    memcpy(state + livelen, SS_STATE,SS_STATE_LEN) ;
-    state[livelen+ SS_STATE_LEN] = '/' ;
-    memcpy(state + livelen + SS_STATE_LEN + 1,ownerstr,ownerlen) ;
-    state[livelen + SS_STATE_LEN + 1 + ownerlen] = '/' ;
-    memcpy(state + livelen + SS_STATE_LEN + 1 + ownerlen + 1,info->treename.s,info->treename.len) ;
-    state[livelen + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len] = 0 ;
-
-    if (reverse)
-    {
-        size_t dstlen = strlen(dst) ;
-        char file[dstlen + 1 + SS_CONTENTS_LEN + 1] ;
-        memcpy(file,dst,dstlen) ;
-        file[dstlen] = '/' ;
-        memcpy(file + dstlen + 1, SS_CONTENTS,SS_CONTENTS_LEN) ;
-        file[dstlen + 1 + SS_CONTENTS_LEN] = 0 ;
-        size_t filesize=file_get_size(file) ;
-
-        r = openreadfileclose(file,&gain,filesize) ;
-        if(!r) goto err ;
-        /** ensure that we have an empty line at the end of the string*/
-        if (!stralloc_cats(&gain,"\n")) goto err ;
-        if (!stralloc_0(&gain)) goto err ;
-        if (!sastr_clean_element(&gain)) goto err ;
-    }
-
-    for (; i < genalloc_len(ss_resolve_t,&graph->sorted); i++)
-    {
-        char *string = genalloc_s(ss_resolve_t,&graph->sorted)[i].sa.s ;
-        char *name = string + genalloc_s(ss_resolve_t,&graph->sorted)[i].name ;
-        if (reverse)
-            if (sastr_cmp(&gain,name) == -1) continue ;
-
-        if (!stralloc_cats(&in,name)) goto err ;
-        if (!stralloc_cats(&in,"\n")) goto err ;
-
-        if (!stralloc_cats(&inres,name)) goto err ;
-        if (!stralloc_cats(&inres," ")) goto err ;
-    }
-
-    if (inres.len) inres.len--;
-    if (!stralloc_0(&inres)) goto err ;
-
-    r = file_write_unsafe(dst,SS_CONTENTS,in.s,in.len) ;
-    if (!r)
-    {
-        log_warnusys("write: ",dst,"contents") ;
-        goto err ;
-    }
-
-    ss_resolve_init(&res) ;
-    res.name = ss_resolve_add_string(&res,SS_MASTER+1) ;
-    res.description = ss_resolve_add_string(&res,"inner bundle - do not use it") ;
-    res.treename = ss_resolve_add_string(&res,info->treename.s) ;
-    res.tree = ss_resolve_add_string(&res,info->tree.s) ;
-    res.live = ss_resolve_add_string(&res,info->live.s) ;
-    res.type = TYPE_BUNDLE ;
-    res.deps = ss_resolve_add_string(&res,inres.s) ;
-    res.ndeps = genalloc_len(ss_resolve_t,&graph->sorted) ;
-    res.runat = ss_resolve_add_string(&res,runat) ;
-    res.state = ss_resolve_add_string(&res,state) ;
-
-    if (!ss_resolve_write(&res,dir,SS_MASTER+1)) goto err ;
-
-    stralloc_free(&in) ;
-    stralloc_free(&inres) ;
-    ss_resolve_free(&res) ;
-    stralloc_free(&gain) ;
-    return 1 ;
-
-    err:
-        ss_resolve_free(&res) ;
-        stralloc_free(&in) ;
-        stralloc_free(&inres) ;
-        stralloc_free(&gain) ;
-        return 0 ;
-}
-
-int ss_resolve_sort_bytype(genalloc *gares,stralloc *list,char const *src)
-{
-    log_flow() ;
-
-    size_t pos = 0 ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-
-    /** search for classic first */
-    for (pos = 0 ;pos < list->len; pos += strlen(list->s + pos) + 1)
-    {
-        char *name = list->s + pos ;
-        if (!ss_resolve_read(&res,src,name))
-            log_warnu_return(LOG_EXIT_ZERO,"read resolve file of: ",name) ;
-        if (res.type == TYPE_CLASSIC)
-            if (ss_resolve_search(gares,name) == -1)
-                if (!ss_resolve_append(gares,&res))
-                    log_warnu_return(LOG_EXIT_ZERO,"append genalloc") ;
-    }
-
-    /** second pass for module */
-    for (pos = 0 ;pos < list->len; pos += strlen(list->s + pos) + 1)
-    {
-        char *name = list->s + pos ;
-        if (!ss_resolve_read(&res,src,name))
-            log_warnu_return(LOG_EXIT_ZERO,"read resolve file of: ",name) ;
-        if (res.type == TYPE_MODULE)
-            if (ss_resolve_search(gares,name) == -1)
-                if (!ss_resolve_append(gares,&res))
-                    log_warnu_return(LOG_EXIT_ZERO,"append genalloc") ;
-    }
-
-    /** finally add s6-rc services */
-    for (pos = 0 ;pos < list->len; pos += strlen(list->s + pos) + 1)
-    {
-        char *name = list->s + pos ;
-        if (!ss_resolve_read(&res,src,name))
-            log_warnu_return(LOG_EXIT_ZERO,"read resolve file of: ",name) ;
-        if (res.type != TYPE_CLASSIC && res.type != TYPE_MODULE)
-            if (ss_resolve_search(gares,name) == -1)
-                if (!ss_resolve_append(gares,&res))
-                    log_warnu_return(LOG_EXIT_ZERO,"append genalloc") ;
-    }
-
-    ss_resolve_free(&res) ;
-    return 1 ;
-}
-
-int ss_resolve_cmp_service_basedir(char const *dir)
-{
-    log_flow() ;
-
-    /** dir can be 0, so nothing to do */
-    if (!dir) return 1 ;
-    size_t len = strlen(dir) ;
-    uid_t owner = MYUID ;
-    stralloc home = STRALLOC_ZERO ;
-
-    char system[len + 1] ;
-    char adm[len + 1] ;
-    char user[len + 1] ;
-
-    if (owner)
-    {
-        if (!set_ownerhome(&home,owner)) { log_warnusys("set home directory") ; goto err ; }
-        if (!auto_stra(&home,SS_SERVICE_USERDIR)) { log_warnsys("stralloc") ; goto err ; }
-        auto_strings(user,dir) ;
-        user[strlen(home.s)] = 0 ;
-    }
-
-    if (len < strlen(SS_SERVICE_SYSDIR))
-        if (len < strlen(SS_SERVICE_ADMDIR))
-            if (owner) {
-                if (len < strlen(home.s))
-                    goto err ;
-            } else goto err ;
-
-    auto_strings(system,dir) ;
-    auto_strings(adm,dir) ;
-
-    system[strlen(SS_SERVICE_SYSDIR)] = 0 ;
-    adm[strlen(SS_SERVICE_ADMDIR)] = 0 ;
-
-    if (strcmp(SS_SERVICE_SYSDIR,system))
-        if (strcmp(SS_SERVICE_ADMDIR,adm))
-            if (owner) {
-                if (strcmp(home.s,user))
-                    goto err ;
-            } else goto err ;
-
-    stralloc_free(&home) ;
-    return 1 ;
-    err:
-        stralloc_free(&home) ;
-        return 0 ;
-}
-
-int ss_resolve_service_isdir(char const *dir, char const *name)
-{
-    log_flow() ;
-
-    size_t dirlen = strlen(dir) ;
-    size_t namelen = strlen(name) ;
-    char t[dirlen + 1 + namelen + 1] ;
-    memcpy(t,dir,dirlen) ;
-    t[dirlen] = '/' ;
-    memcpy(t + dirlen + 1, name, namelen) ;
-    t[dirlen + 1 + namelen] = 0 ;
-    int r = scan_mode(t,S_IFREG) ;
-    if (!ob_basename(t,dir)) return -1 ;
-    if (!strcmp(t,name) && r) return 1 ;
-    return 0 ;
-}
-
-int ss_resolve_sort_byfile_first(stralloc *sort, char const *src)
-{
-    log_flow() ;
-
-    int fdsrc ;
-    stralloc tmp = STRALLOC_ZERO ;
-
-    DIR *dir = opendir(src) ;
-    if (!dir)
-    {
-        log_warnusys("open : ", src) ;
-        goto errstra ;
-    }
-    fdsrc = dir_fd(dir) ;
-
-    for (;;)
-    {
-        tmp.len = 0 ;
-        struct stat st ;
-        direntry *d ;
-        d = readdir(dir) ;
-        if (!d) break ;
-        if (d->d_name[0] == '.')
-        if (((d->d_name[1] == '.') && !d->d_name[2]) || !d->d_name[1])
-            continue ;
-
-        if (stat_at(fdsrc, d->d_name, &st) < 0)
-        {
-            log_warnusys("stat ", src, d->d_name) ;
-            goto errdir ;
-        }
-
-        if (S_ISREG(st.st_mode))
-        {
-            if (!auto_stra(&tmp,src,d->d_name)) goto errdir ;
-            if (!stralloc_insertb(sort,0,tmp.s,strlen(tmp.s) + 1)) goto errdir ;
-        }
-        else if(S_ISDIR(st.st_mode))
-        {
-            if (!auto_stra(&tmp,src,d->d_name,"/")) goto errdir ;
-            if (!stralloc_insertb(sort,sort->len,tmp.s,strlen(tmp.s) + 1)) goto errdir ;
-        }
-    }
-
-    dir_close(dir) ;
-    stralloc_free(&tmp) ;
-
-    return 1 ;
-
-    errdir:
-        dir_close(dir) ;
-    errstra:
-        stralloc_free(&tmp) ;
-        return 0 ;
-}
-
-/** @Return -1 system error
- * @Return 0 no tree exist yet
- * @Return 1 svname doesn't exist
- * @Return 2 on success
- * @Return > 2, service exist on different tree */
-int ss_resolve_svtree(stralloc *svtree,char const *svname,char const *tree)
-{
-    log_flow() ;
-
-    uint8_t found = 1, copied = 0 ;
-    uid_t owner = getuid() ;
-    size_t pos, newlen ;
-    stralloc satree = STRALLOC_ZERO ;
-    stralloc tmp = STRALLOC_ZERO ;
-    char const *exclude[3] = { SS_BACKUP + 1, SS_RESOLVE + 1, 0 } ;
-
-    if (!set_ownersysdir(svtree,owner)) { log_warnusys("set owner directory") ; goto err ; }
-    if (!auto_stra(svtree,SS_SYSTEM)) goto err ;
-
-    if (!scan_mode(svtree->s,S_IFDIR))
-    {
-        found = 0 ;
-        goto freed ;
-    }
-
-    if (!auto_stra(svtree,"/")) goto err ;
-    newlen = svtree->len ;
-
-    if (!stralloc_copy(&tmp,svtree)) goto err ;
-
-    if (!sastr_dir_get(&satree, svtree->s,exclude, S_IFDIR)) {
-        log_warnu("get list of trees from directory: ",svtree->s) ;
-        goto err ;
-    }
-
-    if (satree.len)
-    {
-        for(pos = 0 ; pos < satree.len ; pos += strlen(satree.s + pos) + 1)
-        {
-            tmp.len = newlen ;
-            char *name = satree.s + pos ;
-
-            if (!auto_stra(&tmp,name,SS_SVDIRS)) goto err ;
-            if (ss_resolve_check(tmp.s,svname))
-            {
-                if (!tree || (tree && !strcmp(name,tree))){
-                    svtree->len = 0 ;
-                    if (!stralloc_copy(svtree,&tmp)) goto err ;
-                    copied = 1 ;
-                }
-                found++ ;
-            }
-        }
-    }
-    else
-    {
-        found = 0 ;
-        goto freed ;
-    }
-
-    if (found > 2 && tree) found = 2 ;
-    if (!copied) found = 1 ;
-    if (!stralloc_0(svtree)) goto err ;
-    freed:
-    stralloc_free(&satree) ;
-    stralloc_free(&tmp) ;
-    return found ;
-    err:
-        stralloc_free(&satree) ;
-        stralloc_free(&tmp) ;
-        return -1 ;
-}
-
-int ss_resolve_add_cdb_uint(cdbmaker *c, char const *key,uint32_t data)
-{
-    log_flow() ;
-
-    char pack[4] ;
-    size_t klen = strlen(key) ;
-
-    uint32_pack_big(pack, data) ;
-    if (!cdbmake_add(c,key,klen,pack,4))
-        log_warnsys_return(LOG_EXIT_ZERO,"cdb_make_add: ",key) ;
-
-    return 1 ;
-}
-
-int ss_resolve_add_cdb(cdbmaker *c,char const *key,char const *data)
-{
-    log_flow() ;
-
-    size_t klen = strlen(key) ;
-    size_t dlen = strlen(data) ;
-
-    if (!cdbmake_add(c,key,klen,dlen ? data : 0,dlen))
-        log_warnsys_return(LOG_EXIT_ZERO,"cdb_make_add: ",key) ;
-
-    return 1 ;
-}
-
-int ss_resolve_write_cdb(ss_resolve_t *res, char const *dst, char const *name)
-{
-    log_flow() ;
-
-    int fd ;
-    size_t dstlen = strlen(dst), namelen = strlen(name);
-    cdbmaker c = CDBMAKER_ZERO ;
-    char tfile[dstlen + 1 + namelen + namelen + 9] ;
-    char dfile[dstlen + 1 + namelen + 1] ;
-
-    char *str = res->sa.s ;
-
-    auto_strings(dfile,dst,"/",name) ;
-
-    auto_strings(tfile,dst,"/",name,":",name,":","XXXXXX") ;
-
-    fd = mkstemp(tfile) ;
-    if (fd < 0 || ndelay_off(fd)) {
-        log_warnusys("mkstemp: ", tfile) ;
-        goto err_fd ;
-    }
-
-    if (!cdbmake_start(&c, fd)) {
-        log_warnusys("cdbmake_start") ;
-        goto err ;
-    }
-
-    /* name */
-    if (!ss_resolve_add_cdb(&c,"name",str + res->name) ||
-
-    /* description */
-    !ss_resolve_add_cdb(&c,"description",str + res->description) ||
-
-    /* version */
-    !ss_resolve_add_cdb(&c,"version",str + res->version) ||
-
-    /* logger */
-    !ss_resolve_add_cdb(&c,"logger",str + res->logger) ||
-
-    /* logreal */
-    !ss_resolve_add_cdb(&c,"logreal",str + res->logreal) ||
-
-    /* logassoc */
-    !ss_resolve_add_cdb(&c,"logassoc",str + res->logassoc) ||
-
-    /* dstlog */
-    !ss_resolve_add_cdb(&c,"dstlog",str + res->dstlog) ||
-
-    /* deps */
-    !ss_resolve_add_cdb(&c,"deps",str + res->deps) ||
-
-    /* optsdeps */
-    !ss_resolve_add_cdb(&c,"optsdeps",str + res->optsdeps) ||
-
-    /* extdeps */
-    !ss_resolve_add_cdb(&c,"extdeps",str + res->extdeps) ||
-
-    /* contents */
-    !ss_resolve_add_cdb(&c,"contents",str + res->contents) ||
-
-    /* src */
-    !ss_resolve_add_cdb(&c,"src",str + res->src) ||
-
-    /* srconf */
-    !ss_resolve_add_cdb(&c,"srconf",str + res->srconf) ||
-
-    /* live */
-    !ss_resolve_add_cdb(&c,"live",str + res->live) ||
-
-    /* runat */
-    !ss_resolve_add_cdb(&c,"runat",str + res->runat) ||
-
-    /* tree */
-    !ss_resolve_add_cdb(&c,"tree",str + res->tree) ||
-
-    /* treename */
-    !ss_resolve_add_cdb(&c,"treename",str + res->treename) ||
-
-    /* dstlog */
-    !ss_resolve_add_cdb(&c,"dstlog",str + res->dstlog) ||
-
-    /* state */
-    !ss_resolve_add_cdb(&c,"state",str + res->state) ||
-
-    /* exec_run */
-    !ss_resolve_add_cdb(&c,"exec_run",str + res->exec_run) ||
-
-    /* exec_log_run */
-    !ss_resolve_add_cdb(&c,"exec_log_run",str + res->exec_log_run) ||
-
-    /* real_exec_run */
-    !ss_resolve_add_cdb(&c,"real_exec_run",str + res->real_exec_run) ||
-
-    /* real_exec_log_run */
-    !ss_resolve_add_cdb(&c,"real_exec_log_run",str + res->real_exec_log_run) ||
-
-    /* exec_finish */
-    !ss_resolve_add_cdb(&c,"exec_finish",str + res->exec_finish) ||
-
-    /* real_exec_finish */
-    !ss_resolve_add_cdb(&c,"real_exec_finish",str + res->real_exec_finish) ||
-
-    /* type */
-    !ss_resolve_add_cdb_uint(&c,"type",res->type) ||
-
-    /* ndeps */
-    !ss_resolve_add_cdb_uint(&c,"ndeps",res->ndeps) ||
-
-    /* noptsdeps */
-    !ss_resolve_add_cdb_uint(&c,"noptsdeps",res->noptsdeps) ||
-
-    /* nextdeps */
-    !ss_resolve_add_cdb_uint(&c,"nextdeps",res->nextdeps) ||
-
-    /* ncontents */
-    !ss_resolve_add_cdb_uint(&c,"ncontents",res->ncontents) ||
-
-    /* down */
-    !ss_resolve_add_cdb_uint(&c,"down",res->down) ||
-
-    /* disen */
-    !ss_resolve_add_cdb_uint(&c,"disen",res->disen)) goto err ;
-
-    if (!cdbmake_finish(&c) || fsync(fd) < 0) {
-        log_warnusys("write to: ", tfile) ;
-        goto err ;
-    }
-
-    close(fd) ;
-
-    if (rename(tfile, dfile) < 0) {
-        log_warnusys("rename ", tfile, " to ", dfile) ;
-        goto err_fd ;
-    }
-
-    return 1 ;
-
-    err:
-        close(fd) ;
-    err_fd:
-        unlink_void(tfile) ;
-        return 0 ;
-}
-
-int ss_resolve_find_cdb(stralloc *result, cdb const *c,char const *key)
-{
-    log_flow() ;
-
-    uint32_t x = 0 ;
-    size_t klen = strlen(key) ;
-    cdb_data cdata ;
-
-    result->len = 0 ;
-
-    int r = cdb_find(c, &cdata, key, klen) ;
-    if (r == -1)
-        log_warnusys_return(LOG_EXIT_LESSONE,"search on cdb key: ",key) ;
-
-    if (!r)
-        log_warnusys_return(LOG_EXIT_ZERO,"unknown cdb key: ",key) ;
-
-    char pack[cdata.len + 1] ;
-    memcpy(pack,cdata.s, cdata.len) ;
-    pack[cdata.len] = 0 ;
-
-    uint32_unpack_big(pack, &x) ;
-
-    if (!auto_stra(result,pack))
-        log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;
-
-    return x ;
-
-}
-
-int ss_resolve_read_cdb(ss_resolve_t *dres, char const *name)
-{
-    log_flow() ;
-
-    int fd ;
-    uint32_t x ;
-
-    cdb c = CDB_ZERO ;
-    stralloc tmp = STRALLOC_ZERO ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-
-    fd = open_readb(name) ;
-    if (fd < 0) {
-        log_warnusys("open: ",name) ;
-        goto err_fd ;
-    }
-    if (!cdb_init_fromfd(&c, fd)) {
-        log_warnusys("cdb_init: ", name) ;
-        goto err ;
-    }
-
-    ss_resolve_init(&res) ;
-
-    /* name */
-    ss_resolve_find_cdb(&tmp,&c,"name") ;
-    res.name = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* description */
-    ss_resolve_find_cdb(&tmp,&c,"description") ;
-    res.description = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* version */
-    ss_resolve_find_cdb(&tmp,&c,"version") ;
-    res.version = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* logger */
-    ss_resolve_find_cdb(&tmp,&c,"logger") ;
-    res.logger = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* logreal */
-    ss_resolve_find_cdb(&tmp,&c,"logreal") ;
-    res.logreal = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* logassoc */
-    ss_resolve_find_cdb(&tmp,&c,"logassoc") ;
-    res.logassoc = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* dstlog */
-    ss_resolve_find_cdb(&tmp,&c,"dstlog") ;
-    res.dstlog = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* deps */
-    ss_resolve_find_cdb(&tmp,&c,"deps") ;
-    res.deps = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* optsdeps */
-    ss_resolve_find_cdb(&tmp,&c,"optsdeps") ;
-    res.optsdeps = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* extdeps */
-    ss_resolve_find_cdb(&tmp,&c,"extdeps") ;
-    res.extdeps = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* contents */
-    ss_resolve_find_cdb(&tmp,&c,"contents") ;
-    res.contents = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* src */
-    ss_resolve_find_cdb(&tmp,&c,"src") ;
-    res.src = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* srconf */
-    ss_resolve_find_cdb(&tmp,&c,"srconf") ;
-    res.srconf = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* live */
-    ss_resolve_find_cdb(&tmp,&c,"live") ;
-    res.live = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* runat */
-    ss_resolve_find_cdb(&tmp,&c,"runat") ;
-    res.runat = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* tree */
-    ss_resolve_find_cdb(&tmp,&c,"tree") ;
-    res.tree = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* treename */
-    ss_resolve_find_cdb(&tmp,&c,"treename") ;
-    res.treename = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* state */
-    ss_resolve_find_cdb(&tmp,&c,"state") ;
-    res.state = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* exec_run */
-    ss_resolve_find_cdb(&tmp,&c,"exec_run") ;
-    res.exec_run = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* exec_log_run */
-    ss_resolve_find_cdb(&tmp,&c,"exec_log_run") ;
-    res.exec_log_run = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* real_exec_run */
-    ss_resolve_find_cdb(&tmp,&c,"real_exec_run") ;
-    res.real_exec_run = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* real_exec_log_run */
-    ss_resolve_find_cdb(&tmp,&c,"real_exec_log_run") ;
-    res.real_exec_log_run = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* exec_finish */
-    ss_resolve_find_cdb(&tmp,&c,"exec_finish") ;
-    res.exec_finish = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* real_exec_finish */
-    ss_resolve_find_cdb(&tmp,&c,"real_exec_finish") ;
-    res.real_exec_finish = tmp.len ? ss_resolve_add_string(&res,tmp.s) : 0 ;
-
-    /* type */
-    x = ss_resolve_find_cdb(&tmp,&c,"type") ;
-    res.type = x ;
-
-    /* ndeps */
-    x = ss_resolve_find_cdb(&tmp,&c,"ndeps") ;
-    res.ndeps = x ;
-
-    /* noptsdeps */
-    x = ss_resolve_find_cdb(&tmp,&c,"noptsdeps") ;
-    res.noptsdeps = x ;
-
-    /* nextdeps */
-    x = ss_resolve_find_cdb(&tmp,&c,"nextdeps") ;
-    res.nextdeps = x ;
-
-    /* ncontents */
-    x = ss_resolve_find_cdb(&tmp,&c,"ncontents") ;
-    res.ncontents = x ;
-
-    /* down */
-    x = ss_resolve_find_cdb(&tmp,&c,"down") ;
-    res.down = x ;
-
-    /* disen */
-    x = ss_resolve_find_cdb(&tmp,&c,"disen") ;
-    res.disen = x ;
-
-    if (!ss_resolve_copy(dres,&res)) goto err ;
-
-    close(fd) ;
-    cdb_free(&c) ;
-    ss_resolve_free(&res) ;
-    stralloc_free(&tmp) ;
-
-    return 1 ;
-
-    err:
-        close(fd) ;
-    err_fd:
-        cdb_free(&c) ;
-        ss_resolve_free(&res) ;
-        stralloc_free(&tmp) ;
-        return 0 ;
-}
-
-int ss_resolve_modify_field(ss_resolve_t *res, ss_resolve_enum_t field, char const *data)
-{
-    log_flow() ;
-
-    uint32_t ifield ;
-
-    switch(field)
-    {
-        case SS_RESOLVE_ENUM_NAME:
-            res->name = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DESCRIPTION:
-            res->description = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_VERSION:
-            res->version = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LOGGER:
-            res->logger = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LOGREAL:
-            res->logreal = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LOGASSOC:
-            res->logassoc = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DSTLOG:
-            res->dstlog = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DEPS:
-            res->deps = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_OPTSDEPS:
-            res->optsdeps = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXTDEPS:
-            res->extdeps = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_CONTENTS:
-            res->contents = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_SRC:
-            res->src = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_SRCONF:
-            res->srconf = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LIVE:
-            res->live = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_RUNAT:
-            res->runat = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_TREE:
-            res->tree = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_TREENAME:
-            res->treename = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_STATE:
-            res->state = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXEC_RUN:
-            res->exec_run = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXEC_LOG_RUN:
-            res->exec_log_run = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_REAL_EXEC_RUN:
-            res->real_exec_run = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_REAL_EXEC_LOG_RUN:
-            res->real_exec_log_run = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXEC_FINISH:
-            res->exec_finish = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_REAL_EXEC_FINISH:
-            res->real_exec_finish = ss_resolve_add_string(res,data) ;
-            break ;
-
-        case SS_RESOLVE_ENUM_TYPE:
-            if (!uint0_scan(data, &ifield)) return 0 ;
-            res->type = ifield ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NDEPS:
-            if (!uint0_scan(data, &ifield)) return 0 ;
-            res->ndeps = ifield ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NOPTSDEPS:
-            if (!uint0_scan(data, &ifield)) return 0 ;
-            res->noptsdeps = ifield ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NEXTDEPS:
-            if (!uint0_scan(data, &ifield)) return 0 ;
-            res->nextdeps = ifield ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NCONTENTS:
-            if (!uint0_scan(data, &ifield)) return 0 ;
-            res->ncontents = ifield ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DOWN:
-            if (!uint0_scan(data, &ifield)) return 0 ;
-            res->down = ifield ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DISEN:
-            if (!uint0_scan(data, &ifield)) return 0 ;
-            res->disen = ifield ;
-            break ;
-
-        default:
-            break ;
-    }
-    return 1 ;
-}
-
-int ss_resolve_put_field_to_sa(stralloc *sa,ss_resolve_t *res, ss_resolve_enum_t field)
-{
-    log_flow() ;
-
-    uint32_t ifield ;
-
-    switch(field)
-    {
-        case SS_RESOLVE_ENUM_NAME:
-            ifield = res->name ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DESCRIPTION:
-            ifield = res->description ;
-            break ;
-
-        case SS_RESOLVE_ENUM_VERSION:
-            ifield = res->version ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LOGGER:
-            ifield = res->logger ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LOGREAL:
-            ifield = res->logreal ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LOGASSOC:
-            ifield = res->logassoc ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DSTLOG:
-            ifield = res->dstlog ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DEPS:
-            ifield = res->deps ;
-            break ;
-
-        case SS_RESOLVE_ENUM_OPTSDEPS:
-            ifield = res->optsdeps ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXTDEPS:
-            ifield = res->extdeps ;
-            break ;
-
-        case SS_RESOLVE_ENUM_CONTENTS:
-            ifield = res->contents ;
-            break ;
-
-        case SS_RESOLVE_ENUM_SRC:
-            ifield = res->src ;
-            break ;
-
-        case SS_RESOLVE_ENUM_SRCONF:
-            ifield = res->srconf ;
-            break ;
-
-        case SS_RESOLVE_ENUM_LIVE:
-            ifield = res->live ;
-            break ;
-
-        case SS_RESOLVE_ENUM_RUNAT:
-            ifield = res->runat ;
-            break ;
-
-        case SS_RESOLVE_ENUM_TREE:
-            ifield = res->tree ;
-            break ;
-
-        case SS_RESOLVE_ENUM_TREENAME:
-            ifield = res->treename ;
-            break ;
-
-        case SS_RESOLVE_ENUM_STATE:
-            ifield = res->state ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXEC_RUN:
-            ifield = res->exec_run ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXEC_LOG_RUN:
-            ifield = res->exec_log_run ;
-            break ;
-
-        case SS_RESOLVE_ENUM_REAL_EXEC_RUN:
-            ifield = res->real_exec_run ;
-            break ;
-
-        case SS_RESOLVE_ENUM_REAL_EXEC_LOG_RUN:
-            ifield = res->real_exec_log_run ;
-            break ;
-
-        case SS_RESOLVE_ENUM_EXEC_FINISH:
-            ifield = res->exec_finish ;
-            break ;
-
-        case SS_RESOLVE_ENUM_REAL_EXEC_FINISH:
-            ifield = res->real_exec_finish ;
-            break ;
-
-        case SS_RESOLVE_ENUM_TYPE:
-            ifield = res->type ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NDEPS:
-            ifield = res->ndeps ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NOPTSDEPS:
-            ifield = res->noptsdeps ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NEXTDEPS:
-            ifield = res->nextdeps ;
-            break ;
-
-        case SS_RESOLVE_ENUM_NCONTENTS:
-            ifield = res->ncontents ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DOWN:
-            ifield = res->down ;
-            break ;
-
-        case SS_RESOLVE_ENUM_DISEN:
-            ifield = res->disen ;
-            break ;
-
-        default:
-            return 0 ;
-    }
-
-    if (!auto_stra(sa,res->sa.s + ifield))
-        return 0 ;
-
-    return 1 ;
-}
diff --git a/src/lib66/ss_service.c b/src/lib66/ss_service.c
deleted file mode 100644
index ab94fc42..00000000
--- a/src/lib66/ss_service.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * service.c
- *
- * Copyright (c) 2018-2021 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 <unistd.h>
-#include <sys/stat.h>
-
-#include <oblibs/log.h>
-#include <oblibs/string.h>
-#include <oblibs/types.h>
-#include <oblibs/sastr.h>
-
-#include <skalibs/stralloc.h>
-
-#include <66/utils.h>
-#include <66/constants.h>
-#include <66/resolve.h>
-#include <66/ssexec.h>
-
-/** @Return 0 if not found
- * @Return 1 if found
- * @Return 2 if found but marked disabled
- * @Return -1 system error */
-int service_isenabled(char const *sv)
-{
-
-    log_flow() ;
-
-    stralloc sa = STRALLOC_ZERO ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-    size_t newlen = 0, pos = 0 ;
-    int e = -1 ;
-    char const *exclude[3] = { SS_BACKUP + 1, SS_RESOLVE + 1, 0 } ;
-
-    if (!set_ownersysdir(&sa, getuid())) {
-
-        log_warnusys("set owner directory") ;
-        stralloc_free(&sa) ;
-        return 0 ;
-    }
-
-    char tmp[sa.len + SS_SYSTEM_LEN + 2] ;
-    auto_strings(tmp, sa.s, SS_SYSTEM) ;
-
-    // no tree exist yet
-    if (!scan_mode(tmp, S_IFDIR))
-        goto empty ;
-
-    auto_strings(tmp, sa.s, SS_SYSTEM, "/") ;
-
-    newlen = sa.len + SS_SYSTEM_LEN + 1 ;
-    sa.len = 0 ;
-
-    if (!sastr_dir_get(&sa, tmp, exclude, S_IFDIR)) {
-
-        log_warnu("get list of trees from: ", tmp) ;
-        goto freed ;
-    }
-
-    FOREACH_SASTR(&sa, pos) {
-
-        char *treename = sa.s + pos ;
-
-        char trees[newlen + strlen(treename) + SS_SVDIRS_LEN + 1] ;
-        auto_strings(trees, tmp, treename, SS_SVDIRS) ;
-
-        if (ss_resolve_check(trees, sv)) {
-
-            if (!ss_resolve_read(&res, trees, sv)) {
-
-                log_warnu("read resolve file: ", trees, "/", sv) ;
-                goto freed ;
-            }
-
-            if (res.disen) {
-
-                log_trace(sv, " enabled at tree: ", treename) ;
-
-                e = 1 ;
-                goto freed ;
-
-            } else {
-
-                e = 2 ;
-                goto freed ;
-            }
-        }
-    }
-    empty:
-        e = 0 ;
-    freed:
-        stralloc_free(&sa) ;
-        ss_resolve_free(&res) ;
-        return e ;
-}
-
-/** @Return 0 if not found
- * @Return 1 if found
- * @Return 2 if found but marked disabled
- * @Return -1 system error */
-int service_isenabledat(stralloc *tree, char const *sv)
-{
-
-    log_flow() ;
-
-    stralloc sa = STRALLOC_ZERO ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-    size_t newlen = 0, pos = 0 ;
-    int e = -1 ;
-    char const *exclude[3] = { SS_BACKUP + 1, SS_RESOLVE + 1, 0 } ;
-
-    if (!set_ownersysdir(&sa, getuid())) {
-
-        log_warnusys("set owner directory") ;
-        stralloc_free(&sa) ;
-        return 0 ;
-    }
-
-    char tmp[sa.len + SS_SYSTEM_LEN + 2] ;
-    auto_strings(tmp, sa.s, SS_SYSTEM) ;
-
-    // no tree exist yet
-    if (!scan_mode(tmp, S_IFDIR))
-        goto empty ;
-
-    auto_strings(tmp, sa.s, SS_SYSTEM, "/") ;
-
-    newlen = sa.len + SS_SYSTEM_LEN + 1 ;
-    sa.len = 0 ;
-
-    if (!sastr_dir_get(&sa, tmp, exclude, S_IFDIR)) {
-
-        log_warnu("get list of trees from: ", tmp) ;
-        goto freed ;
-    }
-
-    FOREACH_SASTR(&sa, pos) {
-
-        char *treename = sa.s + pos ;
-
-        char trees[newlen + strlen(treename) + SS_SVDIRS_LEN + 1] ;
-        auto_strings(trees, tmp, treename, SS_SVDIRS) ;
-
-        if (ss_resolve_check(trees, sv)) {
-
-            if (!ss_resolve_read(&res, trees, sv)) {
-
-                log_warnu("read resolve file: ", trees, "/", sv) ;
-                goto freed ;
-            }
-
-            if (res.disen) {
-
-                log_trace(sv, " enabled at tree: ", treename) ;
-                e = 1 ;
-
-            } else {
-
-                log_trace(sv, " disabled at tree: ", treename) ;
-                e = 2 ;
-            }
-
-            if (!auto_stra(tree, treename)) {
-                e = -1 ;
-                goto freed ;
-            }
-            goto freed ;
-        }
-    }
-    empty:
-        e = 0 ;
-    freed:
-        stralloc_free(&sa) ;
-        ss_resolve_free(&res) ;
-        return e ;
-}
-- 
GitLab