From 6468a372c707ac556c7c232467fc96a6632d57df Mon Sep 17 00:00:00 2001
From: obarun <eric@obarun.org>
Date: Thu, 29 Sep 2022 20:59:36 +1100
Subject: [PATCH] revamp parse process

---
 src/include/66/parser.h                    | 348 +-------
 src/lib66/parse/deps-lib/deps              |  23 +-
 src/lib66/parse/parse_clean_line.c         |  42 +
 src/lib66/parse/parse_clean_list.c         |  35 +
 src/lib66/parse/parse_clean_quotes.c       |  41 +
 src/lib66/parse/parse_clean_runas.c        | 102 +++
 src/lib66/parse/parse_compute_list.c       |  77 ++
 src/lib66/parse/parse_contents.c           | 137 +++
 src/lib66/parse/parse_dependencies.c       | 110 +++
 src/lib66/parse/parse_error.c              |  65 ++
 src/lib66/parse/parse_frontend.c           | 251 ++++++
 src/lib66/parse/parse_line_g.c             |  53 ++
 src/lib66/parse/parse_mandatory.c          |  90 ++
 src/lib66/parse/parse_module.c             | 980 +++++++++------------
 src/lib66/parse/parse_parentheses.c        |  87 ++
 src/lib66/parse/parse_section.c            |  72 ++
 src/lib66/parse/parse_split_from_section.c | 223 +++++
 src/lib66/parse/parse_store_environ.c      |  66 ++
 src/lib66/parse/parse_store_g.c            |  67 ++
 src/lib66/parse/parse_store_logger.c       | 122 +++
 src/lib66/parse/parse_store_main.c         | 370 ++++++++
 src/lib66/parse/parse_store_regex.c        |  78 ++
 src/lib66/parse/parse_store_start_stop.c   | 105 +++
 23 files changed, 2690 insertions(+), 854 deletions(-)
 create mode 100644 src/lib66/parse/parse_clean_line.c
 create mode 100644 src/lib66/parse/parse_clean_list.c
 create mode 100644 src/lib66/parse/parse_clean_quotes.c
 create mode 100644 src/lib66/parse/parse_clean_runas.c
 create mode 100644 src/lib66/parse/parse_compute_list.c
 create mode 100644 src/lib66/parse/parse_contents.c
 create mode 100644 src/lib66/parse/parse_dependencies.c
 create mode 100644 src/lib66/parse/parse_error.c
 create mode 100644 src/lib66/parse/parse_frontend.c
 create mode 100644 src/lib66/parse/parse_line_g.c
 create mode 100644 src/lib66/parse/parse_mandatory.c
 create mode 100644 src/lib66/parse/parse_parentheses.c
 create mode 100644 src/lib66/parse/parse_section.c
 create mode 100644 src/lib66/parse/parse_split_from_section.c
 create mode 100644 src/lib66/parse/parse_store_environ.c
 create mode 100644 src/lib66/parse/parse_store_g.c
 create mode 100644 src/lib66/parse/parse_store_logger.c
 create mode 100644 src/lib66/parse/parse_store_main.c
 create mode 100644 src/lib66/parse/parse_store_regex.c
 create mode 100644 src/lib66/parse/parse_store_start_stop.c

diff --git a/src/include/66/parser.h b/src/include/66/parser.h
index 602d993f..7db31619 100644
--- a/src/include/66/parser.h
+++ b/src/include/66/parser.h
@@ -15,338 +15,66 @@
 #ifndef SS_PARSER_H
 #define SS_PARSER_H
 
-#include <66/enum.h>
-
 #include <sys/types.h>
 #include <stdint.h>
 
 #include <oblibs/mill.h>
 
 #include <skalibs/stralloc.h>
-#include <skalibs/genalloc.h>
-#include <skalibs/types.h>
-#include <skalibs/avltree.h>
 
 #include <66/ssexec.h>
+#include <66/service.h>
 
-extern stralloc keep ;
-extern stralloc deps ;
-extern genalloc gasv ;
-
-/**struct for run and finish file*/
-typedef struct sv_exec_s sv_exec,*sv_exec_ref ;
-struct sv_exec_s
-{
-    int build ;
-    int runas ;
-    int shebang ;
-    int exec ;
-    int real_exec ;
-} ;
-
-typedef struct sv_execlog_s sv_execlog,*sv_execlog_ref ;
-struct sv_execlog_s
-{
-    sv_exec run ;
-    /**timeout[0]->kill,timeout[1]->finish
-     * kill[0][X] enabled,kill[0][0] not enabled*/
-    uint32_t timeout[2][UINT_FMT] ;
-    int destination ;
-    uint32_t backup ;
-    uint32_t maxsize ;
-    int timestamp ;
-    int idga ; //pos in stralloc deps
-    unsigned int nga ; //number of deps in stralloc deps
-} ;
-
-typedef struct sv_classic_longrun_s sv_classic_longrun,*sv_classic_ref ;
-struct sv_classic_longrun_s
-{
-    sv_exec run ;
-    sv_exec finish ;
-    sv_execlog log ;
-} ;
-
-typedef struct sv_oneshot_s sv_oneshot,*sv_oneshot_ref ;
-struct sv_oneshot_s
-{
-    sv_exec up ;
-    sv_exec down ;
-    sv_execlog log ;
-} ;
-
-typedef struct sv_module_s sv_module,*sv_module_ref ;
-struct sv_module_s
-{
-    int configure ;
-    int iddir ; // pos in stralloc keep -> @directories
-    unsigned int ndir ; //number of regex directories in stralloc keep -> @directories
-    int idfiles ; // pos in stralloc keep -> @files
-    unsigned int nfiles ; //number of regex files in stralloc keep -> @files
-    int start_infiles ; // pos in stralloc keep of the start of the string -> @infiles
-    int end_infiles ; // pos in stralloc keep of the end of the string -> @infiles
-    int idaddservices ; // pos in stralloc keep -> @addservices
-    unsigned int naddservices ; // number of addon services in stralloc keep > @addservices
-} ;
-
-typedef struct sv_type_s sv_type_t,*sv_type_t_ref ;
-struct sv_type_s
-{
-    sv_classic_longrun classic_longrun ;
-    sv_oneshot oneshot ;
-    sv_module module ;
-} ;
-
-typedef struct sv_name_s sv_name_t, *sv_name_t_ref ;
-struct sv_name_s
-{
-    int itype ; //servcie type: classic->bundle->longrun->oneshot->modules
-    int name ; //pos in keep
-    int description ; //pos in keep
-    int version ; // pos in keep
-    int intree ; // pos in keep
-    int idga ; //pos in stralloc deps -> @depends
-    unsigned int nga ; //number of deps in stralloc deps -> @depends
-    int idopts ; // pos in stralloc deps -> @optsdepends
-    unsigned int nopts ; // number of optional depends in stralloc deps-> @optsdepends
-    int idext ; // pos in stralloc deps -> @extdepends
-    unsigned int next ; // number of optinal depends in stralloc deps -> @extdepends
-    int logname ; //pos in keep
-    int dstlog ; //pos in keep
-    int idcontents ; // pos in stralloc deps -> @contents
-    unsigned int ncontents ; // number of service inside a bundle
-} ;
-
-
-typedef struct sv_alltype_s sv_alltype,*sv_alltype_ref ;
-struct sv_alltype_s
-{
-    sv_type_t type ;
-    sv_name_t cname ;//cname, Container Name
-    /**opts[0]->logger,opts[1]->pipeline,[2]->env
-     * logger[1] enabled,logger[0] not enabled*/
-    unsigned int opts[3] ;
-    /**0->no notification*/
-    /**flags[0]->down
-     * down[1] enabled,down[0] not enabled*/
-    unsigned int flags[1] ;
-    uint32_t notification ;
-    /** array of uid_t
-     * the first element of the table
-     * is reserved to know the number of
-     * user set e.g user[0]=3->3 user*/
-    uid_t user[256] ;
-    /**timeout[0]->kill,timeout[1]->finish
-    * timeout[2]->up,timeout[3]->down
-    * timeout-kill[0][X] enabled,timeout-kill[0][0] not enabled*/
-    uint32_t timeout[4][UINT_FMT] ;
-    uint32_t src ;// original source of the service
-    uint32_t death ;//max-death-tally file
-    /** array of uint32_t
-     * the first element of the table
-     * is reserved to know the number of
-     * dir/file to copy e.g hiercopy[0]=3->3 dir/file to copy */
-    uint32_t hiercopy[24] ; //dir/file to copy
-    int signal ;//down-signal file
-    int pipeline ; //pos in deps
-    stralloc saenv ;
-    /* path of the environment file, this is only concern the write
-     * process, the read process could be different if conf/sysadmin/service
-     * exist */
-    uint32_t srconf ;
-    /** set the CONF variable for each service.
-     * useful in case of module. We do not overwrite
-     * the configuration of the module but we overwrite
-     * the configuration of each service inside a module */
-    uint8_t overwrite_conf ;
-
-} ;
-
-#define SV_EXEC_ZERO \
-{ \
-    -1 , \
-    -1 , \
-    -1 , \
-    -1 , \
-    -1 \
-}
+#define parse_error_return(ret, nerr, idsec, idkey) do { \
+    parse_error(nerr, idsec, idkey) ; \
+    return ret ; \
+} while (0)
 
-#define SV_EXECLOG_ZERO \
-{ \
-    SV_EXEC_ZERO, \
-    { { 0 } } , \
-    -1 , \
-    0 , \
-    0 , \
-    -1 , \
-    -1 , \
-    0 \
-}
+#define parse_error_type(type, idsec, idkey ) do { \
+    if (type == TYPE_BUNDLE || type == TYPE_MODULE) \
+        log_warn_return(LOG_EXIT_ONE, "key: ", get_key_by_enum(idsec, idkey), " is not valid for type ", get_key_by_enum(ENUM_TYPE, type), " -- ignoring it") ; \
+} while (0)
 
-#define SV_CLASSIC_LONGRUN_ZERO \
-{ \
-    SV_EXEC_ZERO, \
-    SV_EXEC_ZERO, \
-    SV_EXECLOG_ZERO \
-}
-
-#define SV_ONESHOT_ZERO \
-{ \
-    SV_EXEC_ZERO, \
-    SV_EXEC_ZERO, \
-    SV_EXECLOG_ZERO \
-}
-
-#define SV_TYPE_ZERO \
-{ \
-    SV_CLASSIC_LONGRUN_ZERO , \
-    SV_ONESHOT_ZERO , \
-    SV_MODULE_ZERO \
-}
-
-#define SV_MODULE_ZERO \
-{ \
-    -1 , \
-    -1 , \
-    0 , \
-    -1 , \
-    0 , \
-    -1 , \
-    -1 , \
-    -1 , \
-    0 \
-}
-
-#define SV_NAME_ZERO \
-{ \
-    -1 , \
-    -1 , \
-    -1 , \
-    -1 , \
-    -1 , \
-    -1 , \
-    0 , \
-    -1 , \
-    0 , \
-    -1 , \
-    0 , \
-    -1 , \
-    -1 , \
-    -1 , \
-    0 \
-}
-
-#define SV_ALLTYPE_ZERO \
-{ \
-    SV_TYPE_ZERO , \
-    SV_NAME_ZERO , \
-    { 1,0,0 } , \
-    { 0 } , \
-    0 , \
-    { 0 } , \
-    { { 0 } } , \
-    0 , \
-    0 , \
-    { 0 } , \
-    -1 , \
-    -1 , \
-    STRALLOC_ZERO , \
-    0 , \
-    0 \
-}
-
-extern sv_alltype const sv_alltype_zero ;
-extern sv_name_t const sv_name_zero ;//set in sv_alltype_zero.c
-
-typedef struct keynocheck_s keynocheck, *keynocheck_t_ref;
-struct keynocheck_s
-{
-    int idsec ;
-    int idkey ;
-    int expected ;
-    stralloc val ;
-
-} ;
-#define KEYNOCHECK_ZERO { .idsec = -1, .idkey = -1, .expected = -1, .val = STRALLOC_ZERO }
-extern keynocheck const keynocheck_zero ;//set in sv_alltype_zero.c
-
-typedef struct section_s section_t,*section_t_ref ;
-struct section_s
-{
-    stralloc main ;
-    stralloc start ;
-    stralloc stop ;
-    stralloc logger ;
-    stralloc environment ;
-    stralloc regex ;
-    uint32_t idx[6] ; //[0] == 0 -> no, [0] == 1-> yes
-    char const *file ;
-} ;
-#define SECTION_ZERO { .main = STRALLOC_ZERO , \
-                        .start = STRALLOC_ZERO , \
-                        .stop = STRALLOC_ZERO , \
-                        .logger = STRALLOC_ZERO , \
-                        .environment = STRALLOC_ZERO , \
-                        .regex = STRALLOC_ZERO , \
-                        .idx = { 0 } , \
-                        .file = 0 }
+/** mill configuration */
+extern parse_mill_t MILL_GET_SECTION_NAME ;
+extern parse_mill_t MILL_GET_KEY ;
+extern parse_mill_t MILL_GET_VALUE ;
 
 /** freed and cleanup*/
-extern void sv_alltype_free(sv_alltype *sv) ;
-extern void keynocheck_free(keynocheck *nocheck) ;
-extern void section_free(section_t *sec) ;
-extern void freed_parser(void) ;
 extern void ssexec_enable_cleanup(void) ;
 
-/** enable phase */
+/** main */
 extern void start_parser(char const *sv, ssexec_t *info, uint8_t disable_module, char const *directory_forced) ;
-extern int parse_service(char const *sv, stralloc *parsed_list, ssexec_t *info, uint8_t force, uint8_t conf) ;
-int parse_service_alldeps(sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force, char const *directory_forced) ;
-extern int parse_service_deps(sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force, char const *directory_forced) ;
-extern int parse_service_optsdeps(stralloc *rebuild, sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force, uint8_t field, char const *directory_forced) ;
-extern int parser(sv_alltype *service,stralloc *src,char const *svname,int svtype) ;
+
+extern void parser(char const *sv, char const *dst, ssexec_t *info, uint8_t force, uint8_t conf) ;
+extern int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, unsigned int *residx, char const *forced_directory) ;
+extern int parse_dependencies(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force,uint8_t conf, char const *forced_directory) ;
 
 /** split */
-extern int section_get_range(section_t *sasection,stralloc *src) ;
-extern int key_get_range(genalloc *ga, section_t *sasection) ;
-extern int check_mandatory(sv_alltype *service, section_t *sasection) ;
-extern int nocheck_toservice(keynocheck *nocheck, int svtype, sv_alltype *service) ;
+extern int parse_section(stralloc *secname, char const *str, size_t *pos) ;
+extern int parse_split_from_section(resolve_service_t *res, stralloc *secname, char *str, char const *svname) ;
+extern int parse_contents(resolve_wrapper_t_ref wres, char const *contents, char const *svname) ;
+extern int parse_compute_list(resolve_wrapper_t_ref wres, stralloc *sa, uint32_t *res, uint8_t opts) ;
 
 /** store */
-extern int keep_common(sv_alltype *service,keynocheck *nocheck,int svtype) ;
-extern int keep_runfinish(sv_exec *exec,keynocheck *nocheck) ;
-extern int keep_logger(sv_execlog *log,keynocheck *nocheck) ;
-extern int keep_environ(sv_alltype *service,keynocheck *nocheck) ;
-extern int keep_regex(sv_module *module,keynocheck *nocheck) ;
+extern int parse_store_g(resolve_service_t *res, char *store, int idsec, int idkey) ;
+extern int parse_store_main(resolve_service_t *res, char *store, int idsec, int idkey) ;
+extern int parse_store_start_stop(resolve_service_t *res, char *store, int idsec, int idkey) ;
+extern int parse_store_logger(resolve_service_t *res, char *store, int idsec, int idkey) ;
+extern int parse_store_environ(resolve_service_t *res, char *store, int idsec, int idkey) ;
+extern int parse_store_regex(resolve_service_t *res, char *store, int idsec, int idkey) ;
 
 /** helper */
-extern int get_svtype(sv_alltype *sv_before, char const *contents) ;
-extern int get_svtype_from_file(char const *file) ;
-extern int get_svintree(sv_alltype *sv_before, char const *contents) ;
-extern int add_pipe(sv_alltype *sv, stralloc *sa) ;
-
-/** write */
-extern void start_write(stralloc *tostart,unsigned int *nclassic,unsigned int *nlongrun,char const *workdir, genalloc *gasv,ssexec_t *info) ;
-extern int write_services(sv_alltype *sv, char const *workdir, uint8_t force,uint8_t conf) ;
-extern int write_classic(sv_alltype *sv, char const *dst, uint8_t force, uint8_t conf) ;
-extern int write_longrun(sv_alltype *sv,char const *dst, uint8_t force, uint8_t conf) ;
-extern int write_oneshot(sv_alltype *sv,char const *dst, uint8_t conf) ;
-extern int write_bundle(sv_alltype *sv, char const *dst) ;
-extern int write_common(sv_alltype *sv, char const *dst,uint8_t conf) ;
-extern int write_exec(sv_alltype *sv, sv_exec *exec,char const *name,char const *dst,mode_t mode) ;
-extern int write_uint(char const *dst, char const *name, uint32_t ui) ;
-extern int write_logger(sv_alltype *sv, sv_execlog *log,char const *name, char const *dst, mode_t mode, uint8_t force) ;
-extern int write_consprod(sv_alltype *sv,char const *prodname,char const *consname,char const *proddst,char const *consdst) ;
-extern int write_dependencies(unsigned int nga,unsigned int idga,char const *dst,char const *filename) ;
-extern int write_env(char const *name,char const *contents,char const *dst) ;
-extern int write_oneshot_logger(stralloc *destlog, sv_alltype *sv) ;
+extern int parse_line_g(char *store, parse_mill_t *config, char const *str, size_t *pos) ;
+extern int parse_parentheses(char *store, char const *str, size_t *pos) ;
+extern int parse_clean_runas(char const *str, int idsec, int idkey) ;
+extern int parse_clean_quotes(char *str) ;
+extern int parse_clean_list(stralloc *sa, char const *str) ;
+extern int parse_clean_line(char *str)  ;
+extern int parse_mandatory(resolve_service_t *res) ;
+extern void parse_error(int ierr, int idsec, int idkey) ;
 
 /** module */
-extern int parse_module(sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force) ;
-extern int regex_get_file_name(char *filename,char const *str) ;
-extern int regex_get_replace(char *replace, char const *str) ;
-extern int regex_get_regex(char *regex, char const *str) ;
-extern int regex_replace(stralloc *list,sv_alltype *sv_before,char const *svname) ;
-extern int regex_rename(stralloc *list, int id, unsigned int nid, char const *sdir) ;
-extern int regex_configure(sv_alltype *sv_before,ssexec_t *info, char const *module_dir,char const *module_name, uint8_t conf) ;
+extern void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force) ;
+
 #endif
diff --git a/src/lib66/parse/deps-lib/deps b/src/lib66/parse/deps-lib/deps
index d1a8772b..d802130c 100644
--- a/src/lib66/parse/deps-lib/deps
+++ b/src/lib66/parse/deps-lib/deps
@@ -1,8 +1,25 @@
+parse_clean_line.o
+parse_clean_list.o
+parse_clean_quotes.o
+parse_clean_runas.o
+parse_compute_list.o
+parse_contents.o
+parse_dependencies.o
+parse_error.o
+parse_frontend.o
+parse_line_g.o
+parse_mandatory.o
 parse_module.o
+parse_parentheses.o
+parse_section.o
 parse_service.o
-parser.o
-parser_utils.o
-parser_write.o
+parse_split_from_section.o
+parse_store_environ.o
+parse_store_g.o
+parse_store_logger.o
+parse_store_main.o
+parse_store_regex.o
+parse_store_start_stop.o
 -ls6
 -loblibs
 -lexecline
diff --git a/src/lib66/parse/parse_clean_line.c b/src/lib66/parse/parse_clean_line.c
new file mode 100644
index 00000000..375c13d2
--- /dev/null
+++ b/src/lib66/parse/parse_clean_line.c
@@ -0,0 +1,42 @@
+/*
+ * parse_clean_line.c
+ *
+ * Copyright (c) 2018-2022 Eric Vidal <eric@obarun.org>
+ *
+ * All rights reserved.
+ *
+ * This file is part of Obarun. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution.
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file./
+ */
+
+#include <stddef.h>
+
+#include <oblibs/mill.h>
+#include <oblibs/string.h>
+
+#include <skalibs/stralloc.h>
+
+int parse_clean_line(char *str)
+{
+
+    int r = 0, e = 0 ;
+    size_t tpos = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+
+    wild_zero_all(&MILL_CLEAN_LINE) ;
+    r = mill_element(&sa, str, &MILL_CLEAN_LINE, &tpos) ;
+    if (r <= 0)
+        goto err ;
+
+    auto_strings(str, sa.s) ;
+
+    e = 1 ;
+
+    err:
+        stralloc_free(&sa) ;
+        return e ;
+
+}
diff --git a/src/lib66/parse/parse_clean_list.c b/src/lib66/parse/parse_clean_list.c
new file mode 100644
index 00000000..31c9ebc8
--- /dev/null
+++ b/src/lib66/parse/parse_clean_list.c
@@ -0,0 +1,35 @@
+/*
+ * parse_clean_list.c
+ *
+ * Copyright (c) 2018-2022 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 <oblibs/string.h>
+#include <oblibs/sastr.h>
+
+#include <skalibs/stralloc.h>
+
+int parse_clean_list(stralloc *sa, char const *str)
+{
+    int e = 0 ;
+    sa->len = 0 ;
+
+    if (!auto_stra(sa, str))
+        goto err ;
+
+    if (!sastr_clean_element(sa))
+        goto err ;
+
+    e = 1 ;
+
+    err:
+        return e ;
+}
diff --git a/src/lib66/parse/parse_clean_quotes.c b/src/lib66/parse/parse_clean_quotes.c
new file mode 100644
index 00000000..067def0a
--- /dev/null
+++ b/src/lib66/parse/parse_clean_quotes.c
@@ -0,0 +1,41 @@
+/*
+ * parse_clean_quotes.c
+ *
+ * Copyright (c) 2018-2022 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 <oblibs/string.h>
+#include <oblibs/sastr.h>
+
+#include <skalibs/stralloc.h>
+
+int parse_clean_quotes(char *str)
+{
+    int e = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (!auto_stra(&sa, str))
+        goto err ;
+
+    if (!sastr_clean_element(&sa))
+        goto err ;
+
+    if (!sastr_rebuild_in_oneline(&sa))
+        goto err ;
+
+    auto_strings(str, sa.s) ;
+
+    e = 1 ;
+
+    err:
+        stralloc_free(&sa) ;
+        return e ;
+}
diff --git a/src/lib66/parse/parse_clean_runas.c b/src/lib66/parse/parse_clean_runas.c
new file mode 100644
index 00000000..3db2aaf2
--- /dev/null
+++ b/src/lib66/parse/parse_clean_runas.c
@@ -0,0 +1,102 @@
+/*
+ * parser_clean_runas.c
+ *
+ * Copyright (c) 2018-2022 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/types.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+
+#include <skalibs/types.h>
+
+#include <66/parser.h>
+#include <66/utils.h>
+
+int parse_clean_runas(char const *str, int idsec, int idkey)
+{
+    size_t len = strlen(str) ;
+    char file[len + 1] ;
+    auto_strings(file, str) ;
+
+    char *colon ;
+    colon = strchr(file,':') ;
+
+    if (colon) {
+
+        *colon = 0 ;
+
+        uid_t uid ;
+        gid_t gid ;
+        size_t uid_strlen ;
+        size_t gid_strlen ;
+        static char uid_str[UID_FMT] ;
+        static char gid_str[GID_FMT] ;
+
+        /** on format :gid, get the uid of
+         * the owner of the process */
+        if (!*file) {
+
+            uid = getuid() ;
+
+        }
+        else {
+
+            if (get_uidbyname(file, &uid) == -1)
+                parse_error_return(0, 0, idsec, idkey) ;
+        }
+
+        uid_strlen = uid_fmt(uid_str,uid) ;
+        uid_str[uid_strlen] = 0 ;
+
+        /** on format uid:, get the gid of
+         * the owner of the process */
+        if (!*(colon + 1)) {
+
+            if (!yourgid(&gid,uid))
+                parse_error_return(0, 0, idsec, idkey) ;
+        }
+        else {
+
+            if (get_gidbygroup(colon + 1,&gid) == -1)
+                parse_error_return(0, 0, idsec, idkey) ;
+        }
+        gid_strlen = gid_fmt(gid_str,gid) ;
+        gid_str[gid_strlen] = 0 ;
+
+
+        auto_strings((char *)str, uid_str, ":", gid_str) ;
+
+    } else {
+
+        int e = errno ;
+        errno = 0 ;
+
+        struct passwd *pw = getpwnam(str);
+
+        if (!pw) {
+
+            if (!errno)
+                errno = ESRCH ;
+
+            parse_error_return(0, 0, idsec, idkey) ;
+        }
+
+        errno = e ;
+
+    }
+
+    return 1 ;
+}
diff --git a/src/lib66/parse/parse_compute_list.c b/src/lib66/parse/parse_compute_list.c
new file mode 100644
index 00000000..b85f0a1d
--- /dev/null
+++ b/src/lib66/parse/parse_compute_list.c
@@ -0,0 +1,77 @@
+/*
+ * parse_compute_list.c
+ *
+ * Copyright (c) 2018-2022 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> // getuid
+
+#include <oblibs/string.h>
+#include <oblibs/sastr.h>
+#include <oblibs/log.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/service.h>
+
+/**
+ * @opts -> 1 : build list of optional deps
+ * */
+int parse_compute_list(resolve_wrapper_t_ref wres, stralloc *sa, uint32_t *res, uint8_t opts)
+{
+    int r, found = 0 ;
+    size_t len = sa->len, pos = 0 ;
+    char t[len + 1] ;
+    char f[len + 1] ;
+
+    memset(f, 0, len) ;
+    memset(t, 0, len) ;
+
+    sastr_to_char(t, sa) ;
+
+    for (; pos < len ; pos += strlen(t + pos) + 1) {
+
+        if (t[pos] == '#')
+            continue ;
+
+        if (opts) {
+
+            sa->len = 0 ;
+
+            r = service_frontend_path(sa, t + pos, getuid(), 0) ;
+            if (r == -1)
+                log_dieu(LOG_EXIT_SYS, "get frontend service file of: ", t + pos) ;
+
+            if (!r)
+                continue ;
+
+            found++ ;
+
+        }
+
+        auto_strings(f + strlen(f), t + pos, " ") ;
+
+        (*res)++ ;
+
+        if (found)
+            break ;
+    }
+
+    f[strlen(f) - 1] = 0 ;
+
+    return resolve_add_string(wres, f) ;
+
+}
+
diff --git a/src/lib66/parse/parse_contents.c b/src/lib66/parse/parse_contents.c
new file mode 100644
index 00000000..517a1d99
--- /dev/null
+++ b/src/lib66/parse/parse_contents.c
@@ -0,0 +1,137 @@
+/*
+ * parse_contents.c
+ *
+ * Copyright (c) 2018-2022 Eric Vidal <eric@obarun.org>
+ *
+ * All rights reserved.
+ *
+ * This file is part of Obarun. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution.
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file./
+ */
+
+#include <string.h>
+
+#include <oblibs/log.h>
+#include <oblibs/string.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/enum.h>
+
+int parse_contents(resolve_wrapper_t_ref wres, char const *contents, char const *svname)
+{
+    log_flow() ;
+
+    size_t clen = strlen(contents), pos = 0, start = 0, len = 0 ;
+
+    stralloc secname = STRALLOC_ZERO ;
+    stralloc sadir = STRALLOC_ZERO ;
+
+    int e = 0, found = 0 ;
+
+    while (pos < clen) {
+
+        found = 0 ;
+
+        /** keep the starting point of the beginning
+         * of the section search process */
+        start = pos ;
+
+        // get the section name
+        found = parse_section(&secname, contents, &pos) ;
+
+        if (found == -1)
+            log_die_nomem("stralloc") ;
+
+        // we are not able to find any section and we are at the start of the file
+        if (!found && !start) {
+            log_warn("invalid frontend file of: ", svname, " -- no section found") ;
+            goto err ;
+        }
+
+        if (!start && strcmp(secname.s, enum_str_section[SECTION_MAIN])) {
+            log_warn("invalid frontend file of: ", svname, " -- section [main] must be set first") ;
+            goto err ;
+        }
+
+        // not more section, end of file. We copy the rest of the file
+        if (!found) {
+
+            len = clen - start ;
+
+            char tmp[clen + 1] ;
+
+            auto_strings(tmp, contents + start + 1) ;
+
+            if (!parse_split_from_section((resolve_service_t *)wres->obj, &secname, tmp, svname))
+                goto err ;
+
+            break ;
+        }
+        else {
+
+            /** again, keep the starting point of the begin
+             * of the section search process */
+            start = pos ;
+
+            found = 0 ;
+
+            /* search for the next section
+             * we don't want to keep the section name to
+             * avoid a double entry at the next pass of the loop */
+            len = secname.len ;
+            found = parse_section(&secname, contents, &pos) ;
+            secname.len = len ;
+
+            if (found == -1)
+                log_die_nomem("stralloc") ;
+
+            int r = get_rlen_until(contents, '\n', pos - 1) ;
+
+            // found a new one
+            if (found) {
+
+                len = r - start ;
+
+                char tmp[clen + 1] ;
+                memcpy(tmp, contents + start + 1, len) ;
+                tmp[len] = 0 ;
+
+                if (!parse_split_from_section((resolve_service_t *)wres->obj, &secname, tmp, svname))
+                    goto err ;
+
+                // jump the contents of the section just parsed
+                start += len ;
+            }
+            else {
+
+                len = clen - start  ;
+
+                char tmp[clen + 1] ;
+
+                auto_strings(tmp, contents + start + 1) ;
+
+                if (!parse_split_from_section((resolve_service_t *)wres->obj, &secname, tmp, svname))
+                    goto err ;
+
+                // end of file
+                break ;
+            }
+            /** restart the next research from the end of the previous
+             * copy A.K.A start of the next section just found previously */
+            pos = start ;
+        }
+    }
+
+    e = 1 ;
+
+    err:
+        stralloc_free(&secname) ;
+        stralloc_free(&sadir) ;
+        return e ;
+}
diff --git a/src/lib66/parse/parse_dependencies.c b/src/lib66/parse/parse_dependencies.c
new file mode 100644
index 00000000..84265424
--- /dev/null
+++ b/src/lib66/parse/parse_dependencies.c
@@ -0,0 +1,110 @@
+/*
+ * parse_dependencies.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 <unistd.h> // getuid
+
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+#include <oblibs/string.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/resolve.h>
+#include <66/service.h>
+#include <66/parser.h>
+#include <66/ssexec.h>
+#include <66/utils.h>
+#include <66/constants.h>
+
+int parse_dependencies(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, char const *forced_directory)
+{
+    log_flow() ;
+
+    size_t pos = 0, len = 0 ;
+    int r, e = 0 ;
+    unsigned int residx = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (res->dependencies.ndepends) {
+
+        if (!sastr_clean_string(&sa, res->sa.s + res->dependencies.depends)) {
+            log_warnu("clean the string") ;
+            goto freed ;
+        }
+
+        char t[sa.len] ;
+
+        sastr_to_char(t, &sa) ;
+
+        len = sa.len ;
+
+        for (; pos < len ; pos += strlen(t + pos) + 1) {
+
+            sa.len = 0 ;
+            char name[strlen(t + pos)] ;
+            char ainsta[strlen(t + pos)] ;
+            int insta = -1 ;
+
+            log_trace("parse dependencies: ", t + pos, " of service: ", res->sa.s + res->name) ;
+
+            insta = instance_check(t + pos) ;
+
+            if (insta > 0) {
+
+                if (!instance_splitname(&sa, t + pos, insta, SS_INSTANCE_TEMPLATE))
+                    log_die(LOG_EXIT_SYS, "split instance service of: ", t + pos) ;
+
+                auto_strings(name, sa.s) ;
+                sa.len = 0 ;
+
+                if (!instance_splitname(&sa, t + pos, insta, SS_INSTANCE_NAME))
+                    log_die(LOG_EXIT_SYS, "split instance service of: ", t + pos) ;
+
+                auto_strings(ainsta, sa.s) ;
+                sa.len = 0 ;
+
+            } else {
+
+                auto_strings(name, t + pos) ;
+            }
+
+            r = service_frontend_path(&sa, name, getuid(), forced_directory) ;
+            if (r < 1) {
+                log_warnu( "get frontend service file of: ", t + pos) ;
+                goto freed ;
+            }
+
+            if (insta > 0) {
+                sa.len-- ;
+                if (!stralloc_catb(&sa, ainsta, strlen(ainsta)))
+                    log_die_nomem("stralloc") ;
+            }
+
+            if (!stralloc_0(&sa))
+                log_die_nomem("stralloc") ;
+
+            /** nothing to do with the exit code */
+            parse_frontend(sa.s, ares, areslen, info, force, conf, &residx, forced_directory) ;
+        }
+
+    } else
+        log_trace("no dependencies found for: ", res->sa.s + res->name) ;
+
+    e = 1 ;
+
+    freed:
+        stralloc_free(&sa) ;
+        return e ;
+}
diff --git a/src/lib66/parse/parse_error.c b/src/lib66/parse/parse_error.c
new file mode 100644
index 00000000..f8aeb93d
--- /dev/null
+++ b/src/lib66/parse/parse_error.c
@@ -0,0 +1,65 @@
+/*
+ * parse_error.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 <oblibs/log.h>
+
+#include <66/enum.h>
+
+void parse_error(int ierr, int idsec, int idkey)
+{
+    log_flow() ;
+
+    char const *section = get_key_by_enum(ENUM_SECTION, idsec) ;
+    /* start stop enum are the same, enum_all must increase by one to match
+     * the correct list
+     * */
+    char const *key = get_key_by_enum(idsec < 2 ? idsec + 1 : idsec,idkey) ;
+
+    switch(ierr)
+    {
+        case 0:
+            log_warn("invalid value for key: ",key,": in section: ",section) ;
+            break ;
+        case 1:
+            log_warn("multiple definition of key: ",key,": in section: ",section) ;
+            break ;
+        case 2:
+            log_warn("same value for key: ",key,": in section: ",section) ;
+            break ;
+        case 3:
+            log_warn("key: ",key,": must be an integrer value in section: ",section) ;
+            break ;
+        case 4:
+            log_warn("key: ",key,": must be an absolute path in section: ",section) ;
+            break ;
+        case 5:
+            log_warn("key: ",key,": must be set in section: ",section) ;
+            break ;
+        case 6:
+            log_warn("invalid format of key: ",key,": in section: ",section) ;
+            break ;
+        case 7:
+            log_warnu("parse key: ",key,": in section: ",section) ;
+            break ;
+        case 8:
+            log_warnu("clean value of key: ",key,": in section: ",section) ;
+            break ;
+        case 9:
+            log_warn("empty value of key: ",key,": in section: ",section) ;
+            break ;
+        default:
+            log_warn("unknown parse_err number") ;
+            break ;
+    }
+}
diff --git a/src/lib66/parse/parse_frontend.c b/src/lib66/parse/parse_frontend.c
new file mode 100644
index 00000000..d9d30760
--- /dev/null
+++ b/src/lib66/parse/parse_frontend.c
@@ -0,0 +1,251 @@
+/*
+ * parse_frontend.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 <stdint.h>
+#include <string.h>
+#include <stdlib.h> //free
+
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+#include <oblibs/environ.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/utils.h>
+#include <66/constants.h>
+#include <66/ssexec.h>
+#include <66/service.h>
+#include <66/tree.h>
+#include <66/config.h>
+#include <66/resolve.h>
+#include <66/environ.h>
+#include <66/enum.h>
+#include <66/state.h> // service_is_g flag
+#include <66/parser.h>
+
+static void parse_service_instance(stralloc *frontend, char const *svsrc, char const *sv, int insta)
+{
+    log_flow() ;
+
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (!instance_splitname(&sa, sv, insta, SS_INSTANCE_TEMPLATE))
+        log_die(LOG_EXIT_SYS, "split instance service of: ", sv) ;
+
+    log_trace("read frontend service of: ", svsrc, sa.s) ;
+
+    if (read_svfile(frontend, sa.s, svsrc) <= 0)
+        log_dieusys(LOG_EXIT_SYS, "read frontend service of: ", svsrc, sa.s) ;
+
+    stralloc_free(&sa) ;
+
+    if (!instance_create(frontend, sv, SS_INSTANCE_REGEX, insta))
+        log_die(LOG_EXIT_SYS, "create instance service: ", sv) ;
+
+}
+
+static void set_info(ssexec_t *info)
+{
+    log_flow() ;
+
+    info->tree.len = 0 ;
+    int r = ssexec_set_treeinfo(info) ;
+    if (r == -4) log_die(LOG_EXIT_USER,"You're not allowed to use the tree: ",info->tree.s) ;
+    if (r == -3) log_dieu(LOG_EXIT_USER,"find the current tree. You must use the -t options") ;
+    if (r == -2) log_dieu(LOG_EXIT_USER,"set the tree name") ;
+    if (r == -1) log_dieu(LOG_EXIT_USER,"parse seed file") ;
+    if (!r) log_dieusys(LOG_EXIT_SYS,"find tree: ", info->treename.s) ;
+
+}
+
+static void already_parsed(char const *sv, char const *atree, ssexec_t *info)
+{
+    log_info("ignoring service: ", sv, " -- already present at tree: ", atree) ;
+    /** we don't care about the use of the -t option. The define of the
+     * info->tree and info->treename is just made to avoid segmentation fault
+     * at the rest of the process. The service is not parsed or enabled again anyway. */
+    info->treename.len = 0 ;
+    if (!auto_stra(&info->treename, atree))
+        log_die_nomem("stralloc") ;
+    set_info(info) ;
+}
+
+/* @sv -> name of the service to parse with
+ * the path of the frontend file source
+ * @Die on fail
+ * @Return 1 on success
+ * @Return 2 -> already parsed */
+int parse_frontend(char const *sv, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force, uint8_t conf, unsigned int *residx, char const *forced_directory)
+{
+    log_flow() ;
+
+    int insta, r ;
+    size_t svlen = strlen(sv) ;
+    char svname[svlen + 1], svsrc[svlen + 1] ;
+    char atree[SS_MAX_TREENAME + 1] ;
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (!ob_basename(svname, sv))
+        log_dieu(LOG_EXIT_SYS, "get basename of: ", sv) ;
+
+    if (!ob_dirname(svsrc, sv))
+        log_dieu(LOG_EXIT_SYS, "get dirname of: ", sv) ;
+
+    if (service_resolve_array_search(ares, *areslen, svname) >= 0)
+        log_warn_return(2, "ignoring: ", svname, " service -- already appended to the selection") ;
+
+    log_trace("parse service: ", sv) ;
+
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
+
+    resolve_init(wres) ;
+
+    insta = instance_check(svname) ;
+
+    if (!insta) {
+
+        log_die(LOG_EXIT_SYS, "invalid instance name: ", svname) ;
+
+    } else if (insta > 0) {
+
+        parse_service_instance(&sa, svsrc, svname, insta) ;
+
+    } else {
+
+        log_trace("read frontend service of: ", sv) ;
+
+        if (read_svfile(&sa, svname, svsrc) <= 0)
+            log_dieusys(LOG_EXIT_SYS, "read frontend service of: ", sv) ;
+    }
+
+    char file[sa.len + 1] ;
+    auto_strings(file, sa.s) ;
+
+    r = service_is_g(atree, svname, STATE_FLAGS_ISPARSED) ;
+    if (r == -1)
+        log_dieu(LOG_EXIT_SYS, "check already parsed services") ;
+
+    if (r) {
+
+        if (!force) {
+
+            already_parsed(svname, atree, info) ;
+            return 2 ;
+
+        } else if (!info->skip_opt_tree) {
+            /* -t option was used */
+            if (strcmp(info->treename.s, atree))
+                log_die(LOG_EXIT_SYS,"you can not enable again a service already set on another tree -- current: ", atree, " asked: ", info->treename.s, ". Try first to disable it") ;
+
+        }
+
+    }
+
+    if (info->skip_opt_tree) {
+
+        /** @intree may not exist */
+        r = sastr_find(&sa, get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_INTREE)) ;
+        if (r == -1)
+            goto follow ;
+
+        if (!environ_get_val_of_key(&sa, get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_INTREE)))
+            log_dieu(LOG_EXIT_SYS, "get field intree of service: ", sv) ;
+
+        if (!sastr_clean_element(&sa))
+            log_dieu(LOG_EXIT_SYS, "clean field intree of service: ", sv) ;
+
+        res.intree = resolve_add_string(wres, sa.s) ;
+
+        info->treename.len = 0 ;
+        if (!auto_stra(&info->treename, res.sa.s + res.intree) ||
+            !auto_stra(&sa, file))
+                log_die_nomem("stralloc") ;
+
+    }
+
+    follow:
+
+    if (!environ_get_val_of_key(&sa, get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_TYPE)))
+        log_dieu(LOG_EXIT_SYS, "get field ", get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_TYPE)," of service: ", svname) ;
+
+    char store[sa.len + 1] ;
+    auto_strings(store, sa.s) ;
+
+    if (!parse_store_main(&res, store, SECTION_MAIN, KEY_MAIN_TYPE))
+        log_dieu(LOG_EXIT_SYS, "store field type of service: ", svname) ;
+
+    stralloc_free(&sa) ;
+
+    res.name = resolve_add_string(wres, svname) ;
+    res.owner = info->owner ;
+    res.ownerstr = resolve_add_string(wres, info->ownerstr) ;
+
+    res.path.frontend = resolve_add_string(wres, svsrc) ;
+
+    // keep overwrite_conf
+    res.environ.env_overwrite = conf ;
+
+    /** try to create the tree if not exist yet with
+     * the help of the seed files */
+    set_info(info) ;
+
+    /** contents of directory should be listed by service_frontend_path
+     * except for module type */
+    if (scan_mode(sv,S_IFDIR) == 1 && res.type != TYPE_MODULE)
+        goto freed ;
+
+    if (!parse_contents(wres, file, svname))
+        log_dieu(LOG_EXIT_SYS, "parse file of service: ", svname) ;
+
+    if (!parse_mandatory(&res))
+        log_die(LOG_EXIT_SYS, "some mandatory field is missing for service: ", svname) ;
+
+    /** append res.dependencies.depends list with the optional dependencies list */
+    if (res.dependencies.noptsdeps) {
+
+        if (res.dependencies.ndepends) {
+            size_t len = strlen(res.sa.s + res.dependencies.depends) ;
+            char t[len + 1] ;
+            auto_strings(t + len, " ", res.sa.s + res.dependencies.optsdeps) ;
+            res.dependencies.depends = resolve_add_string(wres, t) ;
+
+        } else {
+
+            res.dependencies.depends = resolve_add_string(wres, res.sa.s + res.dependencies.optsdeps) ;
+        }
+    }
+
+    if (!parse_dependencies(&res, ares, areslen, info, force, conf, forced_directory))
+        log_dieu(LOG_EXIT_SYS, "parse dependencies of service: ", svname) ;
+
+    service_resolve_compute(&res, info) ;
+
+    if (res.type == TYPE_MODULE)
+        parse_module(&res, ares, areslen, info, force) ;
+
+    log_warn("add service: ", svname) ;
+
+    if (service_resolve_array_search(ares, *areslen, svname) < 0) {
+        (*residx) = *areslen ;
+        ares[(*areslen)++] = res ;
+    }
+
+    freed:
+
+        free(wres) ;
+        return 1 ;
+}
diff --git a/src/lib66/parse/parse_line_g.c b/src/lib66/parse/parse_line_g.c
new file mode 100644
index 00000000..e4646b30
--- /dev/null
+++ b/src/lib66/parse/parse_line_g.c
@@ -0,0 +1,53 @@
+/*
+ * parser_line_g.c
+ *
+ * Copyright (c) 2018-2022 Eric Vidal <eric@obarun.org>
+ *
+ * All rights reserved.
+ *
+ * This file is part of Obarun. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution.
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file./
+ */
+
+#include <stddef.h>
+
+#include <oblibs/string.h>
+#include <oblibs/mill.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+
+/* @Return 2 if bad format */
+int parse_line_g(char *store, parse_mill_t *config, char const *str, size_t *pos)
+{
+    int r = 0, e = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+
+    r = mill_element(&sa, str, config, pos) ;
+    if (r <= 0 || !sa.len)
+        goto err ;
+
+    if (!stralloc_0(&sa))
+        goto err ;
+
+    if (sa.s[0] == ' ')
+        goto err ;
+
+    r = get_len_until(str, '\n') ;
+    if (r < 1)
+        r = 0 ;
+
+    (*pos) = r + 1 ; // +1 remove '\n'
+
+    e = 1 ;
+
+    auto_strings(store, sa.s) ;
+
+    err:
+        stralloc_free(&sa) ;
+        return e ;
+}
diff --git a/src/lib66/parse/parse_mandatory.c b/src/lib66/parse/parse_mandatory.c
new file mode 100644
index 00000000..4c09d650
--- /dev/null
+++ b/src/lib66/parse/parse_mandatory.c
@@ -0,0 +1,90 @@
+/*
+ * parse_mandatory.c
+ *
+ * Copyright (c) 2018-2022 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 <oblibs/log.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/enum.h>
+
+int parse_mandatory(resolve_service_t *res)
+{
+    log_flow() ;
+
+    if (!res->description)
+        log_warn_return(LOG_EXIT_ZERO,"key @description at section [main] must be set") ;
+
+    if (!res->user)
+        log_warn_return(LOG_EXIT_ZERO,"key @user at section [main] must be set") ;
+
+    if (!res->version)
+        log_warn_return(LOG_EXIT_ZERO,"key @version at section [main] must be set") ;
+
+    switch (res->type) {
+
+        case TYPE_ONESHOT:
+
+            if (!strcmp(res->sa.s + res->execute.run.build, "custom") && !res->execute.run.shebang)
+                    log_warn_return(LOG_EXIT_ZERO,"custom build asked at section [start] -- key @shebang must be set") ;
+
+            if (!res->execute.run.run_user)
+                    log_warn_return(LOG_EXIT_ZERO,"key @execute at section [start] must be set") ;
+
+            if (!strcmp(res->sa.s + res->execute.finish.build, "custom") && !res->execute.finish.shebang)
+                    log_warn_return(LOG_EXIT_ZERO,"custom build asked at section [stop] -- key @shebang must be set") ;
+
+            break ;
+
+        case TYPE_CLASSIC:
+
+             if (!strcmp(res->sa.s + res->execute.run.build, "custom") && !res->execute.run.shebang)
+                    log_warn_return(LOG_EXIT_ZERO,"custom build asked at section [start] -- key @shebang must be set") ;
+
+            if (!res->execute.run.run_user)
+                    log_warn_return(LOG_EXIT_ZERO,"key @execute at section [start] must be set") ;
+
+
+            if (!strcmp(res->sa.s + res->execute.finish.build, "custom") && !res->execute.finish.shebang)
+                    log_warn_return(LOG_EXIT_ZERO,"custom build asked at section [stop] -- key @shebang must be set") ;
+
+            if (!strcmp(res->sa.s + res->logger.execute.finish.build, "custom") && !res->logger.execute.finish.shebang)
+                    log_warn_return(LOG_EXIT_ZERO,"custom build asked at section [stop] -- key @shebang must be set") ;
+
+            break ;
+
+        case TYPE_MODULE:
+
+            /*
+
+            if (!sasection->idx[SECTION_REGEX])
+                log_warn_return(LOG_EXIT_ZERO,"section [regex] must be set") ;
+
+            if (service->type.module.iddir < 0)
+                log_warn_return(LOG_EXIT_ZERO,"key @directories at section [regex] must be set") ;
+
+            if (service->type.module.idfiles < 0)
+                log_warn_return(LOG_EXIT_ZERO,"key @files at section [regex] must be set") ;
+
+            if (service->type.module.start_infiles < 0)
+                log_warn_return(LOG_EXIT_ZERO,"key @infiles at section [regex] must be set") ;
+
+            break ;
+
+            */
+
+        /** really nothing to do here */
+        default: break ;
+    }
+    return 1 ;
+}
diff --git a/src/lib66/parse/parse_module.c b/src/lib66/parse/parse_module.c
index 1ad8206f..992b6ef5 100644
--- a/src/lib66/parse/parse_module.c
+++ b/src/lib66/parse/parse_module.c
@@ -1,7 +1,7 @@
 /*
  * parse_module.c
  *
- * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
+ * Copyright (c) 2018-2022 Eric Vidal <eric@obarun.org>
  *
  * All rights reserved.
  *
@@ -12,31 +12,35 @@
  * except according to the terms contained in the LICENSE file./
  */
 
-#include <66/parser.h>
-
 #include <string.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h> //chdir, unlink
+#include <stdlib.h>
 #include <stdio.h> //rename
-#include <unistd.h> //chdir
 
 #include <oblibs/string.h>
-#include <oblibs/types.h>
 #include <oblibs/log.h>
+#include <oblibs/mill.h>
 #include <oblibs/sastr.h>
+#include <oblibs/types.h>
+#include <oblibs/directory.h>
 #include <oblibs/environ.h>
 #include <oblibs/files.h>
-#include <oblibs/mill.h>
-#include <oblibs/directory.h>
 
 #include <skalibs/stralloc.h>
-#include <skalibs/djbunix.h>
-#include <skalibs/env.h>
-#include <skalibs/bytestr.h>//byte_count
-#include <skalibs/genalloc.h>
+#include <skalibs/djbunix.h> //hiercopy
+#include <skalibs/env.h> //hiercopy
+#include <skalibs/bytestr.h>
 
-#include <66/resolve.h>
+#include <66/write.h>
 #include <66/utils.h>
-#include <66/constants.h>
 #include <66/environ.h>
+#include <66/resolve.h>
+#include <66/service.h>
+#include <66/constants.h>
+#include <66/utils.h>
 
 #define SS_MODULE_CONFIG_DIR "/configure"
 #define SS_MODULE_CONFIG_DIR_LEN (sizeof SS_MODULE_CONFIG_DIR - 1)
@@ -47,716 +51,610 @@
 #define SS_MODULE_SERVICE_INSTANCE "/service@"
 #define SS_MODULE_SERVICE_INSTANCE_LEN (sizeof SS_MODULE_SERVICE_INSTANCE - 1)
 
-static int check_dir(char const *src,char const *dir)
+static void instance_splitname_to_char(char *store, char const *name, int len, int what)
 {
     log_flow() ;
 
-    int r ;
-    size_t srclen = strlen(src) ;
-    size_t dirlen = strlen(dir) ;
+    char const *copy ;
+    size_t tlen = len + 1, clen = 0 ;
+
+    char template[tlen + 1] ;
+    memcpy(template,name,tlen) ;
+    template[tlen] = 0 ;
+
+    copy = name + tlen ;
 
-    char tsrc[srclen + dirlen + 1] ;
-    auto_strings(tsrc,src,dir) ;
+    if (!what) {
 
-    r = scan_mode(tsrc,S_IFDIR) ;
-    if (r < 0) { errno = EEXIST ; log_warnusys_return(LOG_EXIT_ZERO,"conflicting format of: ",tsrc) ; }
-    if (!r) {
+        auto_strings(store, template) ;
 
-        if (!dir_create_parent(tsrc,0755))
-            log_warnusys_return(LOG_EXIT_ZERO,"create directory: ",tsrc) ;
+    } else {
+
+        clen = strlen(copy) ;
+        memcpy(store, copy, clen) ;
+        store[clen] = 0 ;
     }
 
-    return 1 ;
 }
 
-static int get_list(stralloc *list, stralloc *sdir,size_t len, char const *svname, mode_t mode)
+static void parse_module_check_dir(char const *src,char const *dir)
 {
     log_flow() ;
 
-    sdir->len = len ;
-    if (!auto_stra(sdir,SS_MODULE_SERVICE)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-
-    char const *exclude[1] = { 0 } ;
-    if (!sastr_dir_get_recursive(list,sdir->s,exclude,mode,1))
-        log_warnusys_return(LOG_EXIT_ZERO,"get file(s) of module: ",svname) ;
-
-    sdir->len = len ;
+    int r ;
+    size_t srclen = strlen(src) ;
+    size_t dirlen = strlen(dir) ;
 
-    if (!auto_stra(sdir,SS_MODULE_SERVICE_INSTANCE)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
+    char t[srclen + dirlen + 1] ;
+    auto_strings(t, src, dir) ;
 
-    if (!sastr_dir_get_recursive(list,sdir->s,exclude,mode,1))
-        log_warnusys_return(LOG_EXIT_ZERO,"get file(s) of module: ",svname) ;
+    r = scan_mode(t,S_IFDIR) ;
+    if (r < 0) {
+        errno = EEXIST ;
+        log_diesys(LOG_EXIT_ZERO, "conflicting format of: ", t) ;
+    }
 
-    return 1 ;
+    if (!r)
+        if (!dir_create_parent(t, 0755))
+            log_dieusys(LOG_EXIT_ZERO, "create directory: ", t) ;
 }
 
-static int rebuild_list(sv_alltype *alltype,stralloc *list,stralloc *sv_all_type, stralloc *module_service)
+static void parse_module_check_name(char const *src, char const *name)
 {
     log_flow() ;
 
-    size_t pos, id, did, nid, dnid ;
-    sv_alltype_ref sv ;
-    id = alltype->cname.idga, nid = alltype->cname.nga ;
-    for (; nid ; id += strlen(deps.s + id) + 1, nid--)
-    {
-        char *deps_name = deps.s + id ;
-        /** if we check the dependencies of a module which was declared
-         * inside the main module, the recursive operation enter on infinite loop.
-         * So, break it by dependency addition comparison */
-        if (sastr_cmp(sv_all_type,deps_name) == -1) {
-
-            for (pos = 0 ; pos < genalloc_len(sv_alltype,&gasv) ; pos++) {
-
-                sv = &genalloc_s(sv_alltype,&gasv)[pos] ;
-                int type = sv->cname.itype == TYPE_MODULE ? 1 : 0 ;
-                char *n = keep.s + sv->cname.name ;
+    char basename[strlen(src)] ;
+    int insta = -1 ;
 
-                if (!strcmp(n,deps_name)) {
+    if (!ob_basename(basename, src))
+        log_dieu(LOG_EXIT_SYS, "get basename of: ", src) ;
 
-                    if (!stralloc_catb(list,keep.s + sv->src,strlen(keep.s + sv->src) + 1))
-                        return 0 ;
+    insta = instance_check(name) ;
 
-                    if (!sv->cname.nga)
-                        continue ;
-
-                    did = type ? sv->cname.idcontents : sv->cname.idga, dnid = type ? sv->cname.ncontents : sv->cname.nga ;
-
-                    for (;dnid; did += strlen(deps.s + did) + 1, dnid--) {
-
-                        if (sastr_cmp(list,deps.s + did) >= 0)
-                            continue ;
+    if (insta <= 0)
+        log_die(LOG_EXIT_SYS, "invalid module instance name: ", name) ;
 
-                        if (!rebuild_list(sv,list,sv_all_type,module_service))
-                            log_warnu(LOG_EXIT_ZERO,"rebuild dependencies list of: ",deps.s + did) ;
-                    }
-                }
-            }
+    if (basename[0] != '@')
+        log_die(LOG_EXIT_USER, "invalid directory name for module: ", name, " -- directory name must start with a '@' character") ;
+}
 
-            if (!stralloc_catb(sv_all_type,deps_name,strlen(deps_name) + 1))
-                return 0 ;
-        }
+static int parse_module_ownerhome(char *store)
+{
+    log_flow() ;
 
-        if (!stralloc_catb(module_service,deps_name,strlen(deps_name) + 1))
-            return 0 ;
+    char const *user_home = 0 ;
+    int e = errno ;
+    struct passwd *st = getpwuid(getuid()) ;
+    errno = 0 ;
+    if (!st) {
+        if (!errno) errno = ESRCH ;
+        return 0 ;
     }
-
-    if (!sastr_sortndrop_element(module_service))
+    user_home = st->pw_dir ;
+    errno = e ;
+    if (!user_home)
         return 0 ;
 
+    auto_strings(store, user_home, "/") ;
+
     return 1 ;
 }
 
-/** return 1 on success
- * return 0 on failure
- * return 2 on already enabled
- * @svname do not contents the path of the frontend file*/
-
-int parse_module(sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force)
+/* 0 filename undefine
+ * -1 system error
+ * should return at least 2 meaning :: no file define*/
+static int regex_get_file_name(char *filename, char const *str)
 {
     log_flow() ;
 
-    int r, err = 1, insta = -1, minsta = -1, svtype = -1, from_ext_insta = 0, already_parsed = 0 ;
-    size_t pos = 0, id, nid, newlen ;
-    stralloc sdir = STRALLOC_ZERO ; // service dir
-    stralloc list = STRALLOC_ZERO ;
-    stralloc tmp = STRALLOC_ZERO ;
-    stralloc addonsv = STRALLOC_ZERO ;
-    char *sv = keep.s + alltype->cname.name ;
-    char src[strlen(keep.s + alltype->src) + 1] ;
-    uint8_t conf = alltype->overwrite_conf ;
-
-    if (!ob_dirname(src, keep.s + alltype->src))
-        log_dieu(LOG_EXIT_SYS,"get dirname of: ", keep.s + alltype->src) ;
+    int r ;
+    size_t pos = 0 ;
+    stralloc kp = STRALLOC_ZERO ;
 
-    log_trace("start parse process of module: ",sv) ;
+    parse_mill_t MILL_GET_COLON = {
+    .open = ':', .close = ':',
+    .skip = " \t\r", .skiplen = 3,
+    .forceclose = 1,
+    .inner.debug = "get_colon" } ;
 
-    /** should be always right,
-     * be paranoid and check it */
-    insta = instance_check(sv) ;
-    if (insta <= 0)
-        log_die(LOG_EXIT_SYS, "invalid module instance name: ",sv);
+    r = mill_element(&kp, str, &MILL_GET_COLON, &pos) ;
+    if (r == -1)
+        log_dieu(LOG_EXIT_SYS, "get filename of line: ", str) ;
 
-    minsta = insta ;
+    auto_strings(filename, kp.s) ;
 
-    if (!module_path(&sdir, &tmp, sv, src, info->owner))
-        log_dieu(LOG_EXIT_SYS,"resolve source of module: ",sv);
+    stralloc_free(&kp) ;
+    return pos ;
+}
 
-    /** check mandatory directories:
-     * module/module_name, module/module_name/{configure,service,service@} */
-    if (!check_dir(tmp.s, "")) return 0 ;
-    if (!check_dir(tmp.s, SS_MODULE_CONFIG_DIR)) return 0 ;
-    if (!check_dir(tmp.s, SS_MODULE_SERVICE)) return 0 ;
-    if (!check_dir(tmp.s, SS_MODULE_SERVICE_INSTANCE)) return 0 ;
+static void regex_get_replace(char *replace, char const *str)
+{
+    log_flow() ;
 
-    newlen = sdir.len ;
+    int pos = get_len_until(str,'=') ;
+    if (!pos || pos == -1)
+       log_dieu(LOG_EXIT_SYS,"replace string of line: ", str) ;
+    char tmp[pos + 1] ;
+    memcpy(tmp,str,pos) ;
+    tmp[pos] = 0 ;
+    auto_strings(replace, tmp) ;
+}
 
-    char permanent_sdir[sdir.len + 2] ;
-    auto_strings(permanent_sdir, sdir.s, "/") ;
+static void regex_get_regex(char *regex, char const *str)
+{
+    log_flow() ;
 
-    r = scan_mode(sdir.s, S_IFDIR) ;
-    if (r < 0) { errno = EEXIST ; log_dieusys(LOG_EXIT_SYS,"conflicting format of: ", sdir.s) ; }
-    else if (!r) {
+    size_t len = strlen(str) ;
+    int pos = get_len_until(str,'=') ;
+    if (!pos || pos == -1)
+        log_dieu(LOG_EXIT_SYS, "get regex string of line: ", str) ;
+    pos++ ; // remove '='
+    char tmp[len + 1] ;
+    memcpy(tmp,str + pos,len-pos) ;
+    tmp[len-pos] = 0 ;
+    auto_strings(regex,tmp) ;
+}
 
-        if (!hiercopy(tmp.s, sdir.s))
-            log_dieusys(LOG_EXIT_SYS, "copy: ", tmp.s, " to: ", sdir.s) ;
+static void get_list(stralloc *list, char const *src, char const *name, mode_t mode)
+{
+    log_flow() ;
 
-    } else {
+    list->len = 0 ;
+    char const *exclude[2] = { SS_MODULE_CONFIG_DIR + 1, 0 } ;
 
-        /** Must reconfigure all services of the module */
-        if (force < 2) {
+    char t[strlen(src) + 1] ;
 
-            log_warn("skip configuration of the module: ", sv, " -- already configured") ;
-            err = 2 ;
-            goto make_deps ;
-        }
+    auto_strings(t, src) ;
 
-        if (rm_rf(sdir.s) < 0)
-            log_dieusys (LOG_EXIT_SYS, "remove: ", sdir.s) ;
+    if (!sastr_dir_get_recursive(list, t, exclude, mode, 1))
+        log_dieusys(LOG_EXIT_SYS,"get file(s) of module: ", name) ;
 
-        if (!hiercopy(tmp.s, sdir.s))
-            log_dieusys(LOG_EXIT_SYS,"copy: ", tmp.s, " to: ", sdir.s) ;
-    }
+}
 
-    /** regex file content */
-    list.len = 0 ;
+static void regex_replace(stralloc *list, resolve_service_t *res)
+{
+    log_flow() ;
 
-    if (!get_list(&list, &sdir, newlen, sv, S_IFREG)) return 0 ;
-    if (!regex_replace(&list, alltype, sv)) return 0 ;
+    int r ;
+    size_t pos = 0, idx = 0 ;
 
-    /* regex directories name */
-    if (!get_list(&list, &sdir, newlen, sv, S_IFDIR)) return 0 ;
-    if (!regex_rename(&list, alltype->type.module.iddir, alltype->type.module.ndir, sdir.s)) return 0 ;
+    stralloc frontend = STRALLOC_ZERO ;
+    stralloc sa = STRALLOC_ZERO ;
 
-    /* regex files name */
-    list.len = 0 ;
+    if (!res->regex.ninfiles)
+        return ;
 
-    if (!get_list(&list,&sdir, newlen, sv, S_IFREG)) return 0 ;
-    if (!regex_rename(&list, alltype->type.module.idfiles, alltype->type.module.nfiles, sdir.s)) return 0 ;
+    if (!sastr_clean_string(&sa, res->sa.s + res->regex.infiles))
+        log_dieu(LOG_EXIT_SYS, "clean string") ;
 
-    /* launch configure script */
-    if (!regex_configure(alltype, info, permanent_sdir, sv, conf)) return 0 ;
+    FOREACH_SASTR(list, pos) {
 
-    make_deps:
+        frontend.len = idx = 0 ;
+        char *str = list->s + pos ;
+        size_t len = strlen(str) ;
+        char bname[len + 1] ;
+        char dname[len + 1] ;
 
-    tmp.len = 0 ;
-    list.len = 0 ;
+        if (!ob_basename(bname, str))
+            log_dieu(LOG_EXIT_SYS, "get basename of: ", str) ;
 
-    if (!auto_stra(&tmp, permanent_sdir, SS_MODULE_SERVICE + 1))
-        log_die_nomem("stralloc") ;
+        if (!ob_dirname(dname, str))
+            log_dieu(LOG_EXIT_SYS, "get dirname of: ", str) ;
 
-    /** get all services */
-    char const *exclude[1] = { 0 } ;
-    if (!sastr_dir_get_recursive(&list, tmp.s, exclude, S_IFREG, 1))
-        log_dieusys(LOG_EXIT_SYS, "get file(s) of module: ", sv) ;
+        //log_trace("read service file of: ", dname, bname) ;
+        r = read_svfile(&frontend, bname, dname) ;
+        if (!r)
+            log_dieusys(LOG_EXIT_SYS, "read file: ", str) ;
+        else if (r == -1)
+            continue ;
 
-    /** add addon services */
-    if (alltype->type.module.naddservices > 0) {
+        {
+            FOREACH_SASTR(&sa, idx) {
 
-        id = alltype->type.module.idaddservices, nid = alltype->type.module.naddservices ;
-        for (; nid ; id += strlen(keep.s + id) + 1, nid--) {
+                int all = 0, fpos = 0 ;
+                char const *line = sa.s + idx ;
+                size_t linelen = strlen(line) ;
+                char filename[SS_MAX_SERVICE_NAME + 1] ;
+                char replace[linelen + 1] ;
+                char regex[linelen + 1] ;
 
-            char *name = keep.s + id ;
-            if (service_frontend_path(&list, name, info->owner,0) < 1)
-                    log_die(LOG_EXIT_SYS, "resolve source path of: ", name) ;
-        }
-    }
+                if (linelen >= SS_MAX_PATH_LEN)
+                    log_die(LOG_EXIT_SYS, "limit exceeded in service: ", res->sa.s + res->name) ;
 
-    tmp.len = 0 ;
-    sdir.len = 0 ;
+                if ((line[0] != ':') || (get_sep_before(line + 1, ':', '=') < 0))
+                    log_die(LOG_EXIT_SYS, "bad format in line: ", line, " of key @infiles field") ;
 
-    /** remake the depends field.
-     * incoporate the module services dependencies inside the list to parse
-     * and each dependency of each module service dependency.
-     * Do it recursively. */
-    if (!rebuild_list(alltype, &list, &tmp, &sdir))
-        log_dieu(LOG_EXIT_SYS,"rebuild dependencies list of: ", sv) ;
+                memset(filename, 0, SS_MAX_SERVICE_NAME + 1) ;
+                memset(replace, 0, linelen + 1) ;
+                memset(regex, 0, linelen + 1) ;
 
-    /** parse all services of the modules */
-    for (pos = 0 ; pos < list.len ; pos += strlen(list.s + pos) + 1) {
+                fpos = regex_get_file_name(filename, line) ;
+                if (fpos < 3) all = 1 ;
 
-        insta = 0, svtype = -1, from_ext_insta = 0, already_parsed = 0 ;
-        char *svname = list.s + pos ;
-        size_t len = strlen(svname) ;
-        char bname[len + 1] ;
-        char *pbname = 0 ;
+                regex_get_replace(replace, line + fpos) ;
 
-        addonsv.len = 0 ;
+                regex_get_regex(regex, line + fpos) ;
 
-        if (sastr_cmp(parsed_list, svname) >= 0) {
+                if (!strcmp(bname, filename) || all) {
 
-            /** already parsed ? */
-            size_t idx = 0 ;
-            for (; idx < genalloc_len(sv_alltype, &gasv) ; idx++) {
+                    if (!sastr_replace_all(&frontend, replace, regex))
+                        log_dieu(LOG_EXIT_SYS, "replace: ", replace, " by: ", regex, " in file: ", str) ;
 
-                char *name = keep.s + genalloc_s(sv_alltype, &gasv)[idx].src ;
+                    if (!stralloc_0(&frontend))
+                        log_dieusys(LOG_EXIT_SYS, "stralloc") ;
 
-                if (!strcmp(name, svname)) {
+                    frontend.len-- ;
 
-                    svname = name ;
-                    break ;
+                    if (!file_write_unsafe(dname, bname, frontend.s, frontend.len))
+                        log_dieusys(LOG_EXIT_SYS, "write: ", dname, "/", bname) ;
                 }
             }
-            already_parsed = 1 ;
         }
+    }
 
-        if (!ob_basename(bname,svname))
-            log_dieu(LOG_EXIT_SYS,"find basename of: ", svname) ;
-
-        pbname = bname ;
+    stralloc_free(&sa) ;
+}
 
-        /** detect cyclic call. Sub-module cannot call it itself*/
-        if (!strcmp(sv, bname))
-            log_die(LOG_EXIT_SYS,"cyclic call detected -- ", sv, " call ", bname) ;
+static void regex_rename(stralloc *list, resolve_service_t *res, uint32_t element)
+{
+    log_flow() ;
 
-        insta = instance_check(bname) ;
-        if (!insta) log_die(LOG_EXIT_SYS,"invalid instance name: ", svname) ;
-        if (insta > 0) {
+    stralloc sa = STRALLOC_ZERO ;
 
-            /** we can't know the origin of the instanciated service.
-             * Search first at service@ directory, if it not found
-             * pass through the classic service_frontend_path() */
+    if (!element)
+        return ;
 
-            pbname = bname ;
-            if (!already_parsed) {
+    if (!sastr_clean_string(&sa, res->sa.s + element))
+        log_dieu(LOG_EXIT_SYS, "clean string") ;
 
-                size_t l = strlen(permanent_sdir) ;
-                char tmp[l + SS_MODULE_SERVICE_INSTANCE_LEN + 2] ;
-                auto_strings(tmp, permanent_sdir, SS_MODULE_SERVICE_INSTANCE + 1, "/") ;
+    size_t pos = 0, idx = 0, salen = sa.len ;
+    char t[sa.len] ;
 
-                r = service_frontend_src(&addonsv, pbname, tmp) ;
+    sastr_to_char(t, &sa) ;
 
-                if (r == -1) log_dieusys(LOG_EXIT_SYS,"parse source directory: ", tmp) ;
-                if (!r) {
+    for (; pos < salen ; pos += strlen(t + pos) + 1) {
 
-                    if (service_frontend_path(&addonsv, pbname, info->owner, 0) < 1)
-                        log_dieu(LOG_EXIT_SYS,"resolve source path of: ", pbname) ;
-                }
-                svname = addonsv.s ;
-            }
-            from_ext_insta++ ;
-            len = strlen(svname) ;
-        }
+        idx = 0 ;
+        char *line = t + pos ;
+        char replace[SS_MAX_PATH] = { 0 } ;
+        char regex[SS_MAX_PATH] = { 0 } ;
 
-        if (!already_parsed)
-            start_parser(svname, info, 0, permanent_sdir) ;
+        regex_get_replace(replace,line) ;
 
-        char ext_insta[len + 1] ;
-        if (from_ext_insta) {
+        regex_get_regex(regex,line) ;
 
-            size_t len = strlen(svname) ;
-            r = get_rlen_until(svname, '@', len) + 1 ;
-            size_t newlen = len - (len - r) ;
-            auto_strings(ext_insta, svname) ;
-            ext_insta[newlen] = 0 ;
-            svname = ext_insta ;
-        }
+        FOREACH_SASTR(list, idx) {
 
-        /** we want the configuration file for each service inside
-         * the configuration directory of the module.
-         * In case of sub-module, we skip it.
-         * Also, we skip every dependency of the sub-module,
-         * each module contains its own services.*/
-        char *version = keep.s + alltype->cname.version ;
+            sa.len = 0 ;
+            char *str = list->s + idx ;
+            size_t len = strlen(str) ;
+            char dname[len + 1] ;
 
-        {
-            stralloc tmpenv = STRALLOC_ZERO ;
-            /** SS_MAX_SERVICE is the maximum of services set at compile time
-             * that can be supervised by s6-svscan. 500 is the default which
-             * should be large enough for the majority of the cases */
-            size_t pos, spos, id, nid, idmodule[SS_MAX_SERVICE] = { 0 } ;
-            sv_alltype_ref svref ;
+            if (!ob_dirname(dname, str))
+                log_dieu(LOG_EXIT_SYS, "get dirname of: ", str) ;
 
-            if (!env_resolve_conf(&tmpenv, sv, info->owner))
-                log_dieu(LOG_EXIT_SYS,"get path of the configuration file") ;
+            if (!sabasename(&sa, str, len))
+                log_dieu(LOG_EXIT_SYS, "get basename of: ", str) ;
 
-            if (!auto_stra(&tmpenv, "/"))
+            if (!stralloc_0(&sa))
                 log_die_nomem("stralloc") ;
 
-            /** search first for all sub-modules */
-            for (pos = 0 ; pos < genalloc_len(sv_alltype,&gasv); pos++) {
-
-                if (genalloc_s(sv_alltype,&gasv)[pos].cname.itype == TYPE_MODULE) {
+            if (!sastr_replace(&sa, replace, regex))
+                log_dieu(LOG_EXIT_SYS, "replace: ", replace, " by: ", regex, " in file: ", str) ;
 
-                    idmodule[pos] = 1 ;
+            if (!stralloc_0(&sa))
+                log_die_nomem("stralloc") ;
 
-                    svref = &genalloc_s(sv_alltype,&gasv)[pos] ;
+            char new[len + sa.len + 1] ;
+            auto_strings(new, dname, sa.s) ;
 
-                    id = svref->cname.idcontents, nid = svref->cname.ncontents ;
-                    for (;nid; id += strlen(deps.s + id) + 1, nid--) {
+            /** do not try to rename the same directory */
+            if (strcmp(str, new)) {
 
-                        char *name = deps.s + id ;
+                log_trace("rename: ", str, " to: ", new) ;
+                if (rename(str, new) == -1)
+                    //log_warnusys( "rename: ", str, " to: ", new) ;
+                    log_dieusys(LOG_EXIT_SYS, "rename: ", str, " to: ", new) ;
 
-                        for (spos = 0 ; spos < genalloc_len(sv_alltype,&gasv);spos++)
-                            if (!strcmp(name,keep.s + genalloc_s(sv_alltype,&gasv)[spos].cname.name))
-                                idmodule[spos] = 1 ;
-                    }
-                }
+                break ;
             }
+        }
+    }
+    stralloc_free(&sa) ;
+}
 
-            for (pos = 0 ; pos < genalloc_len(sv_alltype,&gasv); pos++) {
-
-                if (!genalloc_s(sv_alltype,&gasv)[pos].opts[2] ||
-                idmodule[pos]) continue ;
-                char *n = keep.s + genalloc_s(sv_alltype,&gasv)[pos].cname.name ;
-
-                if (!strcmp(n,bname)) {
-
-                    genalloc_s(sv_alltype,&gasv)[pos].srconf = keep.len ;
-                    if (!auto_stra(&tmpenv,version,"/",bname)) log_warn_return(LOG_EXIT_ZERO,"stralloc") ;
+static void regex_configure(resolve_service_t *res, ssexec_t *info, char const *path, char const *name)
+{
+    log_flow() ;
 
-                    if (!stralloc_catb(&keep,tmpenv.s,strlen(tmpenv.s) + 1))
-                        log_die_nomem("stralloc") ;
-                    break ;
-                }
-            }
-            stralloc_free(&tmpenv) ;
-        }
+    int wstat, r ;
+    pid_t pid ;
+    size_t clen = res->regex.configure > 0 ? 1 : 0 ;
+    size_t pathlen = strlen(path), n ;
 
-        svtype = get_svtype_from_file(svname) ;
-        if (svtype == -1) log_dieu(LOG_EXIT_SYS,"get svtype of: ",svname) ;
+    stralloc env = STRALLOC_ZERO ;
 
-        if (sastr_cmp(&sdir,pbname) == -1)
-            if (!stralloc_catb(&sdir,pbname,strlen(pbname) + 1))
-                log_die_nomem("stralloc") ;
+    char const *newargv[2 + clen] ;
+    unsigned int m = 0 ;
 
-        if (sastr_cmp(&tmp,pbname) == -1)
-            if (svtype != TYPE_CLASSIC)
-                if (!stralloc_catb(&tmp,pbname,strlen(pbname) + 1))
-                    log_die_nomem("stralloc") ;
-    }
+    char pwd[pathlen + 1 + SS_MODULE_CONFIG_DIR_LEN + 1] ;
+    auto_strings(pwd, path, "/", SS_MODULE_CONFIG_DIR + 1) ;
 
-    /** prefix each service inside the module with the name of the module */
-    list.len = 0 ;
-    if (!instance_splitname(&list,sv,minsta,SS_INSTANCE_NAME))
-            log_dieu(LOG_EXIT_SYS, "split instance service: ",sv) ;
+    char config_script[pathlen + 1 + SS_MODULE_CONFIG_DIR_LEN + 1 + SS_MODULE_CONFIG_SCRIPT_LEN + 1] ;
+    auto_strings(config_script, path, "/", SS_MODULE_CONFIG_DIR + 1, "/", SS_MODULE_CONFIG_SCRIPT) ;
 
-    list.len-- ; //instance_splitname close the string
+    r = scan_mode(config_script, S_IFREG) ;
+    if (r > 0)
+    {
+        /** export ssexec_t info value on the environment */
+        {
+            char verbo[UINT_FMT];
+            verbo[uid_fmt(verbo, VERBOSITY)] = 0 ;
+            if (!auto_stra(&env, \
+            "MOD_NAME=", name, "\n", \
+            "MOD_BASE=", res->sa.s + res->path.home, "\n", \
+            "MOD_LIVE=", res->sa.s + res->live.livedir, "\n", \
+            "MOD_TREE=", res->sa.s + res->path.tree, "\n", \
+            "MOD_SCANDIR=", res->sa.s + res->live.scandir, "\n", \
+            "MOD_TREENAME=", res->sa.s + res->treename, "\n", \
+            "MOD_OWNER=", res->sa.s + res->ownerstr, "\n", \
+            "MOD_COLOR=", info->opt_color ? "1" : "0", "\n", \
+            "MOD_VERBOSITY=", verbo, "\n", \
+            "MOD_MODULE_DIR=", path, "\n", \
+            "MOD_SKEL_DIR=", SS_SKEL_DIR, "\n", \
+            "MOD_SERVICE_SYSDIR=", SS_SERVICE_SYSDIR, "\n", \
+            "MOD_SERVICE_ADMDIR=", SS_SERVICE_ADMDIR, "\n", \
+            "MOD_SERVICE_ADMCONFDIR=", SS_SERVICE_ADMCONFDIR, "\n", \
+            "MOD_MODULE_SYSDIR=", SS_MODULE_SYSDIR, "\n", \
+            "MOD_MODULE_ADMDIR=", SS_MODULE_ADMDIR, "\n", \
+            "MOD_SCRIPT_SYSDIR=", SS_SCRIPT_SYSDIR, "\n", \
+            "MOD_USER_DIR=", SS_USER_DIR, "\n", \
+            "MOD_SERVICE_USERDIR=", SS_SERVICE_USERDIR, "\n", \
+            "MOD_SERVICE_USERCONFDIR=", SS_SERVICE_USERCONFDIR, "\n", \
+            "MOD_MODULE_USERDIR=", SS_MODULE_USERDIR, "\n", \
+            "MOD_SCRIPT_USERDIR=", SS_SCRIPT_USERDIR, "\n"))
+                log_dieu(LOG_EXIT_SYS, "append environment variables") ;
+        }
 
-    if (!auto_stra(&list,"-"))
-        log_die_nomem("stralloc") ;
+        /** environment is not mandatory */
+        if (res->environ.env > 0)
+        {
+            stralloc oenv = STRALLOC_ZERO ;
+            stralloc dst = STRALLOC_ZERO ;
+            char name[strlen(res->sa.s + res->name) + 2] ;
+            auto_strings(name, ".", res->sa.s + res->name) ;
 
-    alltype->cname.idga = deps.len ;
-    alltype->cname.nga = 0 ;
-    for (pos = 0 ;pos < tmp.len ; pos += strlen(tmp.s + pos) + 1) {
+            if (!env_prepare_for_write(&dst, &oenv, res))
+                log_dieu(LOG_EXIT_SYS, "prepare environment") ;
 
-        if (!stralloc_catb(&deps,list.s, list.len) ||
-            !stralloc_catb(&deps,tmp.s + pos,strlen(tmp.s + pos) + 1))
-                log_die_nomem("stralloc") ;
+            write_environ(name, oenv.s, dst.s) ;
 
-        alltype->cname.nga++ ;
-    }
+            /** Reads all files from the directory */
+            if (!environ_clean_envfile(&env, dst.s))
+                log_dieu(LOG_EXIT_SYS, "read environment") ;
 
-    alltype->cname.idcontents = deps.len ;
-    for (pos = 0 ;pos < sdir.len ; pos += strlen(sdir.s + pos) + 1) {
+            if (!environ_remove_unexport(&env, &env))
+                log_dieu(LOG_EXIT_SYS, "remove exclamation mark from environment variables") ;
 
-        if (!stralloc_catb(&deps,list.s, list.len) ||
-            !stralloc_catb(&deps,sdir.s + pos,strlen(sdir.s + pos) + 1))
-                log_die_nomem("stralloc") ;
+            stralloc_free(&oenv) ;
+            stralloc_free(&dst) ;
+        }
 
-        alltype->cname.ncontents++ ;
-    }
+        if (!sastr_split_string_in_nline(&env))
+            log_dieu(LOG_EXIT_SYS, "rebuild environment") ;
 
-    tmp.len = 0 ;
-    if (!auto_stra(&tmp,permanent_sdir,SS_MODULE_CONFIG_DIR + 1))
-        log_die_nomem("stralloc") ;
+        n = env_len((const char *const *)environ) + 1 + byte_count(env.s,env.len,'\0') ;
+        char const *newenv[n + 1] ;
 
-    if (rm_rf(tmp.s) < 0)
-        log_dieusys(LOG_EXIT_SYS,"remove: ",tmp.s) ;
+        if (!env_merge (newenv, n ,(const char *const *)environ,env_len((const char *const *)environ), env.s, env.len))
+            log_dieu(LOG_EXIT_SYS, "build environment") ;
 
-    stralloc_free(&sdir) ;
-    stralloc_free(&list) ;
-    stralloc_free(&tmp) ;
-    stralloc_free(&addonsv) ;
+        if (chdir(pwd) < 0)
+            log_dieu(LOG_EXIT_SYS, "chdir to: ", pwd) ;
 
-    return err ;
-}
+        m = 0 ;
+        newargv[m++] = config_script ;
 
-/* helper */
+        if (res->regex.configure > 0)
+            newargv[m++] = res->sa.s + res->regex.configure ;
 
-/* 0 filename undefine
- * -1 system error
- * should return at least 2 meaning :: no file define*/
-int regex_get_file_name(char *filename,char const *str)
-{
-    log_flow() ;
+        newargv[m++] = 0 ;
 
-    int r ;
-    size_t pos = 0 ;
-    stralloc kp = STRALLOC_ZERO ;
+        log_info("launch script configure of module: ", name) ;
 
-    parse_mill_t MILL_GET_COLON = {
-    .open = ':', .close = ':',
-    .skip = " \t\r", .skiplen = 3,
-    .forceclose = 1,
-    .inner.debug = "get_colon" } ;
+        pid = child_spawn0(newargv[0], newargv, newenv) ;
 
-    r = mill_element(&kp,str,&MILL_GET_COLON,&pos) ;
-    if (r == -1) goto err ;
+        if (waitpid_nointr(pid, &wstat, 0) < 0)
+            log_dieusys(LOG_EXIT_SYS, "wait for: ", config_script) ;
 
-    auto_strings(filename,kp.s) ;
+        if (wstat)
+            log_dieu(LOG_EXIT_SYS, "run: ", config_script) ;
+    }
 
-    stralloc_free(&kp) ;
-    return pos ;
-    err:
-        stralloc_free(&kp) ;
-        return -1 ;
+    stralloc_free(&env) ;
 }
 
-int regex_get_replace(char *replace, char const *str)
+void parse_module(resolve_service_t *res, resolve_service_t *ares, unsigned int *areslen, ssexec_t *info, uint8_t force)
 {
     log_flow() ;
 
-    int pos = get_len_until(str,'=') ;
-    if (!pos || pos == -1) return 0 ;
-    char tmp[pos + 1] ;
-    memcpy(tmp,str,pos) ;
-    tmp[pos] = 0 ;
-    auto_strings(replace,tmp) ;
-    return 1 ;
-}
+    int r, insta = -1 ;
+    unsigned int residx = 0 ;
+    size_t pos = 0, pathlen = 0 ;
+    char *name = res->sa.s + res->name ;
+    char *src = res->sa.s + res->path.frontend ;
+    char path[SS_MAX_PATH_LEN] ;
+    char ainsta[strlen(name)] ;
+    stralloc list = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = 0 ;
 
-int regex_get_regex(char *regex, char const *str)
-{
-    log_flow() ;
+    log_trace("parse module: ", name) ;
 
-    size_t len = strlen(str) ;
-    int pos = get_len_until(str,'=') ;
-    if (!pos || pos == -1) return 0 ;
-    pos++ ; // remove '='
-    char tmp[len + 1] ;
-    memcpy(tmp,str + pos,len-pos) ;
-    tmp[len-pos] = 0 ;
-    auto_strings(regex,tmp) ;
-    return 1 ;
-}
+    insta = instance_check(name) ;
+    instance_splitname_to_char(ainsta, name, insta, 0) ;
 
-int regex_replace(stralloc *list,sv_alltype *alltype,char const *svname)
-{
-    log_flow() ;
+    size_t prefixlen = strlen(ainsta) ;
+    size_t len = prefixlen + SS_MAX_SERVICE_NAME ;
 
-    int r ;
-    size_t in = 0, pos, inlen ;
+    char prefix[len + 1] ;
+    auto_strings(prefix, ainsta) ;
+    //prefix[insta] = '-' ;
+    prefix[insta] = 0 ;
 
-    stralloc tmp = STRALLOC_ZERO ;
+    if (!getuid()) {
 
-    for (; in < list->len; in += strlen(list->s + in) + 1)
-    {
-        tmp.len = 0 ;
-        char *str = list->s + in ;
-        size_t len = strlen(str) ;
-        char bname[len + 1] ;
-        char dname[len + 1] ;
-        if (!ob_basename(bname,str)) log_warnu_return(LOG_EXIT_ZERO,"get basename of: ",str) ;
-        if (!ob_dirname(dname,str)) log_warnu_return(LOG_EXIT_ZERO,"get dirname of: ",str) ;
+        auto_strings(path, SS_SERVICE_ADMDIR, name) ;
 
-        log_trace("read service file of: ",dname,bname) ;
-        r = read_svfile(&tmp,bname,dname) ;
-        if (!r) log_warnusys_return(LOG_EXIT_ZERO,"read file: ",str) ;
-        if (r == -1) continue ;
+    } else {
 
-        pos = alltype->type.module.start_infiles, inlen = alltype->type.module.end_infiles ;
-        for (; pos < inlen ; pos += strlen(keep.s + pos) + 1)
-        {
-            int all = 0, fpos = 0 ;
-            char filename[512] = { 0 } ;
-            char replace[512] = { 0 } ;
-            char regex[512] = { 0 } ;
-            char const *line = keep.s + pos ;
+        if (!parse_module_ownerhome(path))
+            log_dieusys(LOG_EXIT_SYS, "unable to find the home directory of the user") ;
 
-            if (strlen(line) >= 511) log_warn_return(LOG_EXIT_ZERO,"limit exceeded in service: ", svname) ;
-            if ((line[0] != ':') || (get_sep_before(line + 1,':','=') < 0))
-                log_warn_return(LOG_EXIT_ZERO,"bad format in line: ",line," of key @infiles field") ;
+        pathlen = strlen(path) ;
+        auto_strings(path + pathlen, SS_SERVICE_USERDIR, name) ;
+    }
 
-            fpos = regex_get_file_name(filename,line) ;
+    uint8_t conf = res->environ.env_overwrite ;
 
-            if (fpos == -1)  log_warnu_return(LOG_EXIT_ZERO,"get filename of line: ",line) ;
-            else if (fpos < 3) all = 1 ;
+    /** Check the validity of the module directory.
+     * The frontend file of the module must be located in
+     * a directory with a name in the format @template_name:
+     *      - frontend file -> scandir@
+     *      - directory name containing the frontend service file -> @scandir */
+    parse_module_check_name(src, name) ;
 
-            if (!regex_get_replace(replace,line+fpos)) log_warnu_return(LOG_EXIT_ZERO,"replace string of line: ",line) ;
+    /** check mandatory directories
+     * res->frontend/module_name/{configure,service,service@} */
+    parse_module_check_dir(src, SS_MODULE_CONFIG_DIR) ;
+    parse_module_check_dir(src, SS_MODULE_SERVICE) ;
+    parse_module_check_dir(src, SS_MODULE_SERVICE_INSTANCE) ;
 
-            if (!regex_get_regex(regex,line+fpos)) log_warnu_return(LOG_EXIT_ZERO,"regex string of line: ",line) ;
+    r = scan_mode(path, S_IFDIR) ;
+    if (r == -1) {
+        errno = EEXIST ;
+        log_dieusys(LOG_EXIT_SYS, "conflicting format of: ", path) ;
 
-            if (obstr_equal(bname,filename) || all)
-            {
-                if (!sastr_replace_all(&tmp,replace,regex))
-                    log_warnu_return(LOG_EXIT_ZERO,"replace: ",replace," by: ", regex," in file: ",str) ;
+    } else if (!r) {
 
-                if (!stralloc_0(&tmp))
-                    log_warnusys_return(LOG_EXIT_ZERO,"stralloc") ;
+        if (!hiercopy(src, path))
+            log_dieusys(LOG_EXIT_SYS, "copy: ", src, " to: ", path) ;
 
-                tmp.len-- ;
+    } else {
 
-                if (!file_write_unsafe(dname,bname,tmp.s,tmp.len))
-                    log_warnusys_return(LOG_EXIT_ZERO,"write: ",dname,"/","filename") ;
-            }
-        }
-    }
-    stralloc_free(&tmp) ;
+        /** Must reconfigure all services of the module */
+        if (force < 2) {
 
-    return 1 ;
-}
+            log_warn("skip configuration of the module: ", name, " -- already configured") ;
+            goto deps ;
+        }
 
-int regex_rename(stralloc *list, int id, unsigned int nid, char const *sdir)
-{
-    log_flow() ;
+        if (rm_rf(path) < 0)
+            log_dieusys (LOG_EXIT_SYS, "remove: ", path) ;
 
-    stralloc tmp = STRALLOC_ZERO ;
-    size_t pos = id, len = nid, in ;
+        if (!hiercopy(src, path))
+            log_dieusys(LOG_EXIT_SYS,"copy: ", src, " to: ", path) ;
+    }
 
-    pos = id, len = nid ;
+    pathlen = strlen(path) ;
+    /** remove the original service frontend file inside the copied directory
+     * to avoid double frontend service file for a same service.*/
+    auto_strings(path + pathlen, "/", ainsta) ;
 
-    for (;len; pos += strlen(keep.s + pos) + 1,len--)
-    {
-        char *line = keep.s + pos ;
-        char replace[512] = { 0 } ;
-        char regex[512] = { 0 } ;
-        if (!regex_get_replace(replace,line)) log_warnu_return(LOG_EXIT_ZERO,"replace string of line: ",line) ;
-        if (!regex_get_regex(regex,line)) log_warnu_return(LOG_EXIT_ZERO,"regex string of line: ",line) ;
+    if (unlink(path) < 0)
+        log_dieusys(LOG_EXIT_ZERO, "unlink: ", path) ;
 
-        for (in = 0 ; in < list->len; in += strlen(list->s + in) + 1)
-        {
-            tmp.len = 0 ;
-            char *str = list->s + in ;
-            size_t len = strlen(str) ;
-            char dname[len + 1] ;
-            if (!ob_dirname(dname,str)) log_warnu_return(LOG_EXIT_ZERO,"get dirname of: ",str) ;
+    path[pathlen] = 0 ;
 
-            if (!sabasename(&tmp,str,len)) log_warnusys_return(LOG_EXIT_ZERO,"get basename of: ",str) ;
-            if (!stralloc_0(&tmp)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
+    /** contents */
+    get_list(&list, path, name, S_IFREG) ;
+    regex_replace(&list, res) ;
 
-            if (!sastr_replace(&tmp,replace,regex))
-                log_warnu_return(LOG_EXIT_ZERO,"replace: ",replace," by: ", regex," in file: ",str) ;
+    /** directories */
+    get_list(&list, path, name, S_IFDIR) ;
+    regex_rename(&list, res, res->regex.directories) ;
 
-            if (!stralloc_0(&tmp))
-                log_warnu_return(LOG_EXIT_ZERO,"stralloc") ;
+    /** filename */
+    get_list(&list, path, name, S_IFREG) ;
+    regex_rename(&list, res, res->regex.files) ;
 
-            char new[len + tmp.len + 1] ;
-            auto_strings(new,dname,tmp.s) ;
-            /** do not try to rename the same directory */
-            if (!obstr_equal(str,new))
-            {
-                log_trace("rename: ",str," to: ",new) ;
-                if (rename(str,new) == -1)
-                    log_warnusys_return(LOG_EXIT_ZERO,"rename: ",str," to: ",new) ;
-            }
-        }
-    }
-    stralloc_free(&tmp) ;
+    /** configure script */
+    regex_configure(res, info, path, name) ;
 
-    return 1 ;
-}
+    deps:
 
-int regex_configure(sv_alltype *alltype,ssexec_t *info, char const *module_dir,char const *module_name,uint8_t conf)
-{
-    log_flow() ;
+    list.len = 0 ;
 
-    int wstat, r ;
-    pid_t pid ;
-    size_t clen = alltype->type.module.configure > 0 ? 1 : 0 ;
-    size_t module_dirlen = strlen(module_dir), n ;
+    if (!auto_stra(&list, path))
+        log_die_nomem("stralloc") ;
 
-    stralloc env = STRALLOC_ZERO ;
+    char t[list.len] ;
 
-    char const *newargv[2 + clen] ;
-    unsigned int m = 0 ;
+    sastr_to_char(t, &list) ;
 
-    char pwd[module_dirlen + SS_MODULE_CONFIG_DIR_LEN + 1] ;
-    auto_strings(pwd,module_dir,SS_MODULE_CONFIG_DIR + 1) ;
+    list.len = 0 ;
+    char const *exclude[3] = { SS_MODULE_CONFIG_DIR + 1, SS_MODULE_SERVICE_INSTANCE + 1, 0 } ;
+    if (!sastr_dir_get_recursive(&list, t, exclude, S_IFREG, 1))
+        log_dieusys(LOG_EXIT_SYS, "get file(s) of module: ", name) ;
 
-    char config_script[module_dirlen + SS_MODULE_CONFIG_DIR_LEN + 1 + SS_MODULE_CONFIG_SCRIPT_LEN + 1] ;
-    auto_strings(config_script,module_dir,SS_MODULE_CONFIG_DIR + 1,"/",SS_MODULE_CONFIG_SCRIPT) ;
+    char l[list.len] ;
+    size_t llen = list.len ;
 
-    r = scan_mode(config_script,S_IFREG) ;
-    if (r > 0)
-    {
-        /** export ssexec_t info value on the environment */
-        {
-            char owner[UID_FMT];
-            owner[uid_fmt(owner,info->owner)] = 0 ;
-            char verbo[UINT_FMT];
-            verbo[uid_fmt(verbo,VERBOSITY)] = 0 ;
-            if (!auto_stra(&env, \
-            "MOD_NAME=",module_name,"\n", \
-            "MOD_BASE=",info->base.s,"\n", \
-            "MOD_LIVE=",info->live.s,"\n", \
-            "MOD_TREE=",info->tree.s,"\n", \
-            "MOD_SCANDIR=",info->scandir.s,"\n", \
-            "MOD_TREENAME=",info->treename.s,"\n", \
-            "MOD_OWNER=",owner,"\n", \
-            "MOD_COLOR=",info->opt_color ? "1" : "0","\n", \
-            "MOD_VERBOSITY=",verbo,"\n", \
-            "MOD_MODULE_DIR=",module_dir,"\n", \
-            "MOD_SKEL_DIR=",SS_SKEL_DIR,"\n", \
-            "MOD_SERVICE_SYSDIR=",SS_SERVICE_SYSDIR,"\n", \
-            "MOD_SERVICE_ADMDIR=",SS_SERVICE_ADMDIR,"\n", \
-            "MOD_SERVICE_ADMCONFDIR=",SS_SERVICE_ADMCONFDIR,"\n", \
-            "MOD_MODULE_SYSDIR=",SS_MODULE_SYSDIR,"\n", \
-            "MOD_MODULE_ADMDIR=",SS_MODULE_ADMDIR,"\n", \
-            "MOD_SCRIPT_SYSDIR=",SS_SCRIPT_SYSDIR,"\n", \
-            "MOD_USER_DIR=",SS_USER_DIR,"\n", \
-            "MOD_SERVICE_USERDIR=",SS_SERVICE_USERDIR,"\n", \
-            "MOD_SERVICE_USERCONFDIR=",SS_SERVICE_USERCONFDIR,"\n", \
-            "MOD_MODULE_USERDIR=",SS_MODULE_USERDIR,"\n", \
-            "MOD_SCRIPT_USERDIR=",SS_SCRIPT_USERDIR,"\n"))
-                log_warnu_return(LOG_EXIT_ZERO,"append environment variables") ;
-        }
-        /** environment is not mandatory */
-        if (alltype->opts[2] > 0)
-        {
-            stralloc oenv = STRALLOC_ZERO ;
-            stralloc name = STRALLOC_ZERO ;
-            stralloc dst = STRALLOC_ZERO ;
+    sastr_to_char(l, &list) ;
 
-            if (!env_prepare_for_write(&name,&dst,&oenv,alltype,conf))
-                return 0 ;
+    list.len = 0 ;
 
-            if (!write_env(name.s,oenv.s,dst.s))
-                log_warnu_return(LOG_EXIT_ZERO,"write environment") ;
+    for (pos = 0 ; pos < llen ; pos += strlen(l + pos) + 1) {
 
-            /** Reads all file from the directory */
-            if (!environ_clean_envfile(&env,dst.s))
-                log_warnu_return(LOG_EXIT_ZERO,"prepare environment") ;
+        char *dname = l + pos ;
+        char ainsta[pathlen + SS_MODULE_SERVICE_INSTANCE_LEN + 1 + SS_MAX_SERVICE_NAME + 1] ;
+        size_t namelen = strlen(dname) ;
+        char bname[namelen] ;
 
-            if (!environ_remove_unexport(&env,&env))
-                log_warnu_return(LOG_EXIT_ZERO,"remove exclamation mark from environment variables") ;
+        if (!ob_basename(bname,dname))
+            log_dieu(LOG_EXIT_SYS, "find basename of: ", dname) ;
 
-            stralloc_free(&name) ;
-            stralloc_free(&oenv) ;
-            stralloc_free(&dst) ;
+        if (instance_check(bname) > 0) {
+            auto_strings(ainsta, path, SS_MODULE_SERVICE_INSTANCE, "/", bname) ;
+            dname = ainsta ;
         }
 
-        if (!sastr_split_string_in_nline(&env))
-            log_warnu_return(LOG_EXIT_ZERO,"rebuild environment") ;
+        if (!sastr_add_string(&list, bname))
+            log_die_nomem("stralloc") ;
 
-        n = env_len((const char *const *)environ) + 1 + byte_count(env.s,env.len,'\0') ;
-        char const *newenv[n + 1] ;
+        if (!strcmp(name, bname))
+            log_die(LOG_EXIT_SYS, "cyclic call detected -- ", name, " call ", bname) ;
 
-        if (!env_merge (newenv, n ,(const char *const *)environ,env_len((const char *const *)environ),env.s, env.len))
-            log_warnusys_return(LOG_EXIT_ZERO,"build environment") ;
+        /** nothing to do with the exit code */
+        parse_frontend(dname, ares, areslen, info, force, conf, &residx, path) ;
 
-        if (chdir(pwd) < 0)
-            log_warnusys_return(LOG_EXIT_ZERO,"chdir to: ",pwd) ;
+        wres = resolve_set_struct(DATA_SERVICE, &ares[residx]) ;
 
-        m = 0 ;
-        newargv[m++] = config_script ;
+        ares[residx].inmodule = resolve_add_string(wres, prefix - 1) ;
+    }
 
-        if (alltype->type.module.configure > 0)
-            newargv[m++] = keep.s + alltype->type.module.configure ;
+    char deps[list.len] ;
 
-        newargv[m++] = 0 ;
+    sastr_to_char(deps, &list) ;
 
-        log_info("launch script configure of module: ",module_name) ;
+    llen = list.len ;
 
-        pid = child_spawn0(newargv[0],newargv,newenv) ;
+    list.len = 0 ;
 
-        if (waitpid_nointr(pid,&wstat, 0) < 0)
-            log_warnusys_return(LOG_EXIT_ZERO,"wait for: ",config_script) ;
+    /* rebuild the dependencies list incorporating the services defined inside
+     * the module. */
 
-        if (wstat)
-            log_warnu_return(LOG_EXIT_ZERO,"run: ",config_script) ;
-    }
+    if (res->dependencies.ndepends)
+        if (!sastr_clean_string(&list, res->sa.s + res->dependencies.depends))
+            log_dieu(LOG_EXIT_SYS, "clean string") ;
 
-    stralloc_free(&env) ;
+    for (pos = 0 ; pos < llen ; pos += strlen(deps + pos) + 1)
+        if (!sastr_add_string(&list, deps + pos))
+            log_die_nomem("stralloc") ;
 
-    return 1 ;
+    wres = resolve_set_struct(DATA_SERVICE, res) ;
+
+    res->dependencies.depends = parse_compute_list(wres, &list, &res->dependencies.ndepends, 0) ;
+
+    free(wres) ;
+    stralloc_free(&list) ;
 }
diff --git a/src/lib66/parse/parse_parentheses.c b/src/lib66/parse/parse_parentheses.c
new file mode 100644
index 00000000..fc3bbd6c
--- /dev/null
+++ b/src/lib66/parse/parse_parentheses.c
@@ -0,0 +1,87 @@
+/*
+ * parser_parentheses.c
+ *
+ * Copyright (c) 2018-2022 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 <oblibs/string.h>
+
+#include <66/parser.h>
+
+static char parse_char_next(char const *s, size_t *pos)
+{
+    char c = 0 ;
+    size_t slen = strlen(s) ;
+    if (*pos > slen) return -1 ;
+    c = s[*pos] ;
+    (*pos)++ ;
+    return c ;
+}
+
+int parse_parentheses(char *store, char const *str, size_t *pos)
+{
+    int open = 0, close = 0 ;
+    uint8_t parentheses = 1 ;
+    size_t o = 0, slen = strlen(str) ;
+
+    open = get_sep_before(str, '=', '(') ;
+    if (open <= 0)
+        return 0 ;
+    close = get_sep_before(str, '(', ')') ;
+    if (close < 0)
+        return 0 ;
+    open += get_len_until(str + open + 1, '(') ; // +1 remove '='
+    open += 2 ; // +2 remove '('
+
+
+    char line[slen + 1] ;
+    auto_strings(line, str + open) ;
+    size_t len = strlen(line) ;
+
+    while(parentheses && o < len) {
+
+        char c = parse_char_next(line, &o) ;
+
+        switch(c) {
+
+            case '(':
+                parentheses++ ;
+                break ;
+            case ')':
+                parentheses-- ;
+                break ;
+            case -1:
+                return 0 ;
+            default:
+                break ;
+        }
+    }
+
+    if (parentheses)
+        return 0 ;
+
+    (*pos) = open + len ;
+
+    open = get_len_until(str, '\n') ;
+    if (open < 1)
+        open = 0 ;
+
+    (*pos) = open + 1 ; // +1 remove '\n'
+
+    len = len - (len - o) - 1 ;
+    memcpy(store, line, len) ;
+    store[len] = 0 ;
+
+    return 1 ;
+}
diff --git a/src/lib66/parse/parse_section.c b/src/lib66/parse/parse_section.c
new file mode 100644
index 00000000..014c5abd
--- /dev/null
+++ b/src/lib66/parse/parse_section.c
@@ -0,0 +1,72 @@
+/*
+ * parse_section.c
+ *
+ * Copyright (c) 2018-2022 Eric Vidal <eric@obarun.org>
+ *
+ * All rights reserved.
+ *
+ * This file is part of Obarun. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution.
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file./
+ */
+
+#include <string.h>
+
+#include <oblibs/mill.h>
+#include <oblibs/log.h>
+#include <oblibs/string.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+#include <66/enum.h>
+
+int parse_section(stralloc *secname, char const *str, size_t *pos)
+{
+    int id = -1 ;
+    size_t len = strlen(str) ;
+    size_t newpos = 0, found = 0 ;
+
+    stralloc tmp = STRALLOC_ZERO ;
+
+    while ((*pos) < len) {
+        tmp.len = 0 ;
+        newpos = 0 ;
+
+        if (mill_element(&tmp, str + (*pos), &MILL_GET_SECTION_NAME, &newpos) == -1)
+            goto end ;
+
+        if (tmp.len) {
+            if (!stralloc_0(&tmp))
+               return -1 ;
+
+            found = 1 ;
+
+            // check the validity of the section name
+            id = get_enum_by_key(tmp.s) ;
+
+            if (id < 0) {
+                log_warn("invalid section name: ", tmp.s, " -- ignoring it") ;
+                newpos-- ; // " retrieve the last ']'"
+                // find the start of the section and pass the next line
+                id = get_len_until(str + (newpos - tmp.len), '\n') ;
+                newpos = newpos - tmp.len + id + 1 ;
+                found = 0 ;
+            }
+        }
+
+        (*pos) += newpos ;
+
+        if (found) break ;
+    }
+
+    if (found)
+        if (!stralloc_catb(secname, tmp.s, strlen(tmp.s) + 1))
+            return -1 ;
+
+    end:
+        stralloc_free(&tmp) ;
+        return found ? 1 : 0 ;
+}
diff --git a/src/lib66/parse/parse_split_from_section.c b/src/lib66/parse/parse_split_from_section.c
new file mode 100644
index 00000000..f1ac67b6
--- /dev/null
+++ b/src/lib66/parse/parse_split_from_section.c
@@ -0,0 +1,223 @@
+/*
+ * parse_split_from_section.c
+ *
+ * Copyright (c) 2018-2022 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/types.h>
+
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+#include <oblibs/string.h>
+#include <oblibs/mill.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/enum.h>
+
+static ssize_t parse_get_previous_element(stralloc *sa, size_t where)
+{
+    size_t n = sastr_nelement(sa) ;
+    n-- ;
+    if ((n - where) < n)
+        return -1 ;
+
+    return sastr_find_element_byid(sa,n - where) ;
+}
+
+/* *
+ * For now the ability to comment an entire section when
+ * commenting the section name is not available anymore
+ * */
+int parse_split_from_section(resolve_service_t *res, stralloc *secname, char *str, char const *svname)
+{
+    log_flow() ;
+
+    int e = 0, r = 0, found = 0, skip = 0 ;
+
+    key_all_t const *list = total_list ;
+    stralloc sakey = STRALLOC_ZERO ;
+
+    // cpos -> current, ipos -> idx pos, tpos -> temporary pos, end -> end the parse process
+    size_t len = strlen(str), cpos = 0, ipos = 0, tpos = 0, end = 0 ;
+    char tline[len + 1] ;
+    char store[len + 1] ;
+    char *line ;
+
+    // find the name of the current section
+    ssize_t previous_sec = parse_get_previous_element(secname, 0) ;
+
+    if (previous_sec == -1) {
+        log_warn("get previous section") ;
+        goto err ;
+    }
+
+    int id = get_enum_by_key(secname->s + previous_sec) ;
+
+    if (id < 0) {
+        log_warn("invalid section name: ", secname->s + previous_sec, " for service: ", svname) ;
+        goto err ;
+    }
+
+    log_trace("parsing section: ", secname->s + previous_sec) ;
+
+    if (!strcmp(secname->s + previous_sec, enum_str_section[SECTION_ENV])) {
+        str[strlen(str)] = 0 ;
+
+        if (!parse_store_g(res, str, SECTION_ENV, KEY_ENVIRON_ENVAL)) {
+            log_warnu("store resolve file of: ", svname) ;
+            goto err ;
+        }
+
+        goto end ;
+    }
+
+    while(cpos < len) {
+
+        skip = 0 ;
+        ipos = 0 ;
+        tpos = 0 ;
+        end = 0 ;
+        sakey.len = 0 ;
+        line = (char *)str + cpos ; // (char *) shut up compiler
+
+        /** comment must be the first character found
+         * at the begin of the line */
+        if (line[tpos] == '#') {
+            cpos += get_len_until(line, '\n') + 1 ;
+            continue ;
+        }
+
+        // empty line or no more key=value?
+        while (get_sep_before(line, '=', '\n') < 1){
+
+                // Try to see if it's an empty line.
+                r = get_len_until(line, '\n') ;
+                if (r < 0) {
+                    // end of string
+                    end++ ;
+                    break ;
+                }
+
+                cpos += r + 1 ; // +1 to remove '\n'
+
+                if (cpos >= len) {
+                    // end of string
+                    end++ ;
+                    break ;
+                }
+
+                line = (char *)str + cpos ;
+        }
+
+        if (end)
+            break ;
+
+        // get a cleaned key string
+        wild_zero_all(&MILL_GET_KEY) ;
+        r = mill_element(&sakey, line, &MILL_GET_KEY, &tpos) ;
+        if (r < 1) {
+            log_warnu("get key at frontend service file of service: ", svname, " from line: ", line, " -- please make a bug report") ;
+            goto err ;
+        } else if (!r || tpos + cpos >= len) {
+                // '=' was not find or end of string?
+                break ;
+        }
+
+        // copy the string to parse
+        auto_strings(tline, line) ;
+
+        tpos = 0 ;
+
+        // loop around all keys for the section
+        while (*total_list[id].list[ipos].name) {
+
+            found = 0 ;
+
+            // look for a valid key name
+            if (*list[id].list[ipos].name && !strcmp(sakey.s, *list[id].list[ipos].name)) {
+
+                found = 1 ;
+
+                log_trace("parsing key: ", get_key_by_key_all(id, ipos)) ;
+
+                switch(list[id].list[ipos].expected) {
+
+                    case EXPECT_QUOTE:
+
+                        r = get_len_until(tline, '\n') ;
+
+                        if (r >= 0)
+                            /** user migth forgot to close the double-quotes.
+                             * so, only keep the line and not the complete string
+                             * +1 for the parse_line_g which search for the '\n' character */
+                            tline[r + 1] = 0 ;
+
+                        wild_zero_all(&MILL_GET_DOUBLE_QUOTE) ;
+                        if (!parse_line_g(store, &MILL_GET_DOUBLE_QUOTE, tline, &tpos))
+                            parse_error_return(0, 6, id, ipos) ;
+
+                        break ;
+
+                    case EXPECT_BRACKET:
+
+                        if (!parse_parentheses(store, tline, &tpos))
+                            parse_error_return(0, 6, id, ipos) ;
+
+                        break ;
+
+                    case EXPECT_LINE:
+                    case EXPECT_UINT:
+                    case EXPECT_SLASH:
+
+                        wild_zero_all(&MILL_GET_VALUE) ;
+                        if (!parse_line_g(store, &MILL_GET_VALUE, tline, &tpos))
+                            parse_error_return(0, 6, id, ipos) ;
+
+                        break ;
+
+                    default:
+                        return 0 ;
+                }
+            }
+
+            cpos += tpos ;
+
+            if (found) {
+
+                if (!parse_store_g(res, store, id, ipos)) {
+                    log_warnu("store resolve file of: ", svname) ;
+                    goto err ;
+                } ;
+
+                break ;
+            }
+
+            ipos++ ;
+        }
+
+        if (!found && r >= 0) {
+            log_warn("unknown key: ", sakey.s," : in section: ",  secname->s + previous_sec, " -- ignoring it") ;
+            tpos = get_len_until(line, '\n') ;
+            cpos += tpos + 1 ;
+        }
+    }
+    end:
+
+    e = 1 ;
+
+    err:
+        stralloc_free(&sakey) ;
+        return e ;
+}
diff --git a/src/lib66/parse/parse_store_environ.c b/src/lib66/parse/parse_store_environ.c
new file mode 100644
index 00000000..2f4d644f
--- /dev/null
+++ b/src/lib66/parse/parse_store_environ.c
@@ -0,0 +1,66 @@
+/*
+ * parse_store_environ.c
+ *
+ * Copyright (c) 2018-2022 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 <stdlib.h> //free
+
+#include <oblibs/string.h>
+#include <oblibs/log.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/enum.h>
+#include <66/utils.h>
+#include <66/environ.h>
+
+#include <stdio.h>
+
+int parse_store_environ(resolve_service_t *res, char *store, int idsec, int idkey)
+{
+    int e = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ;
+
+    switch(idkey) {
+
+        case KEY_ENVIRON_ENVAL:
+
+            if (!auto_stra(&sa, store))
+                goto err ;
+
+            if (!env_clean_with_comment(&sa))
+                log_warnu_return(LOG_EXIT_ZERO,"clean environment value") ;
+
+            res->environ.env = resolve_add_string(wres, sa.s) ;
+
+            sa.len = 0 ;
+            if (!env_resolve_conf(&sa, res->sa.s + res->name, MYUID))
+                goto err ;
+
+            res->environ.envdir = resolve_add_string(wres, sa.s) ;
+
+            break ;
+
+        default:
+            log_warn_return(LOG_EXIT_ZERO, "unknown key: ", get_key_by_key_all(idsec, idkey)) ;
+    }
+
+    e = 1 ;
+
+    err :
+        stralloc_free(&sa) ;
+        free(wres) ;
+        return e ;
+}
diff --git a/src/lib66/parse/parse_store_g.c b/src/lib66/parse/parse_store_g.c
new file mode 100644
index 00000000..f0a2a770
--- /dev/null
+++ b/src/lib66/parse/parse_store_g.c
@@ -0,0 +1,67 @@
+/*
+ * parse_store_g.c
+ *
+ * Copyright (c) 2018-2022 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 <oblibs/log.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/enum.h>
+
+int parse_store_g(resolve_service_t *res, char *store, int idsec, int idkey)
+{
+    log_trace("storing key: ", get_key_by_key_all(idsec, idkey)) ;
+
+    switch(idsec) {
+
+
+        case SECTION_MAIN:
+
+            if (!parse_store_main(res, store, idsec, idkey))
+                log_warnu_return(LOG_EXIT_ZERO, "store value of section: ", enum_str_section[SECTION_MAIN]);
+
+            break ;
+
+        case SECTION_START:
+        case SECTION_STOP:
+
+            if (!parse_store_start_stop(res, store, idsec, idkey))
+                log_warnu_return(LOG_EXIT_ZERO, "store value of section: ", enum_str_section[SECTION_START]);
+
+            break ;
+
+        case SECTION_LOG:
+
+            if (!parse_store_logger(res, store, idsec, idkey))
+                log_warnu_return(LOG_EXIT_ZERO, "store value of section: ", enum_str_section[SECTION_LOG]);
+
+
+            break ;
+
+        case SECTION_ENV:
+
+            if (!parse_store_environ(res, store, idsec, idkey))
+                log_warnu_return(LOG_EXIT_ZERO, "store value of section: ", enum_str_section[SECTION_ENV]);
+
+            break ;
+
+        case SECTION_REGEX:
+
+            if (!parse_store_regex(res, store, idsec, idkey))
+                log_warnu_return(LOG_EXIT_ZERO, "store value of section: ", enum_str_section[SECTION_REGEX]);
+
+            break ;
+    }
+
+    return 1 ;
+}
diff --git a/src/lib66/parse/parse_store_logger.c b/src/lib66/parse/parse_store_logger.c
new file mode 100644
index 00000000..9dad2be5
--- /dev/null
+++ b/src/lib66/parse/parse_store_logger.c
@@ -0,0 +1,122 @@
+/*
+ * parse_store_logger.c
+ *
+ * Copyright (c) 2018-2022 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 <stdlib.h> //free
+
+#include <oblibs/log.h>
+
+#include <skalibs/types.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/service.h>
+#include <66/enum.h>
+
+int parse_store_logger(resolve_service_t *res, char *store, int idsec, int idkey)
+{
+    int r = 0, e = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ;
+
+    switch(idkey) {
+
+        case KEY_LOGGER_BUILD:
+
+            if (!parse_store_start_stop(res, store, idsec, KEY_STARTSTOP_BUILD))
+                goto err ;
+
+            break ;
+
+        case KEY_LOGGER_RUNAS:
+
+            if (!parse_store_start_stop(res, store, idsec, KEY_STARTSTOP_RUNAS))
+                goto err ;
+
+            break ;
+
+        case KEY_LOGGER_SHEBANG:
+
+            if (!parse_store_start_stop(res, store, idsec, KEY_STARTSTOP_SHEBANG))
+                goto err ;
+
+            break ;
+
+        case KEY_LOGGER_EXEC:
+
+            if (!parse_store_start_stop(res, store, idsec, KEY_STARTSTOP_EXEC))
+                goto err ;
+
+            break ;
+
+        case KEY_LOGGER_T_KILL:
+
+            if (!uint320_scan(store, &res->logger.execute.timeout.kill))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_LOGGER_T_FINISH:
+
+            if (!uint320_scan(store, &res->logger.execute.timeout.finish))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_LOGGER_DESTINATION:
+
+            if (!parse_clean_line(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            if (store[0] != '/')
+                parse_error_return(0, 4, idsec, idkey) ;
+
+            res->logger.destination = resolve_add_string(wres, store) ;
+
+           break ;
+
+        case KEY_LOGGER_BACKUP:
+
+            if (!uint320_scan(store, &res->logger.backup))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_LOGGER_MAXSIZE:
+
+            if (!uint320_scan(store, &res->logger.maxsize))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_LOGGER_TIMESTP:
+
+            r = get_enum_by_key(store) ;
+            if (r == -1)
+                parse_error_return(0, 0, idsec, idkey) ;
+
+            res->logger.timestamp = (uint32_t)r ;
+
+            break ;
+
+        default:
+            log_warn_return(LOG_EXIT_ZERO, "unknown key: ", get_key_by_key_all(idsec, idkey)) ;
+    }
+
+    e = 1 ;
+
+    err :
+        stralloc_free(&sa) ;
+        free(wres) ;
+        return e ;
+}
diff --git a/src/lib66/parse/parse_store_main.c b/src/lib66/parse/parse_store_main.c
new file mode 100644
index 00000000..29331239
--- /dev/null
+++ b/src/lib66/parse/parse_store_main.c
@@ -0,0 +1,370 @@
+/*
+ * parse_store_main.c
+ *
+ * Copyright (c) 2018-2022 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 <pwd.h>
+
+#include <oblibs/string.h>
+#include <oblibs/sastr.h>
+#include <oblibs/log.h>
+#include <oblibs/directory.h>
+#include <oblibs/types.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/types.h>
+#include <skalibs/sig.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/constants.h>
+#include <66/service.h>
+#include <66/enum.h>
+#include <66/utils.h>
+
+int parse_store_main(resolve_service_t *res, char *store, int idsec, int idkey)
+{
+    int r = 0, e = 0 ;
+    size_t pos = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ;
+
+    switch(idkey) {
+
+        case KEY_MAIN_DESCRIPTION:
+
+            if (!parse_clean_quotes(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->description = resolve_add_string(wres, store) ;
+
+            break ;
+
+        case KEY_MAIN_VERSION:
+
+            if (!parse_clean_line(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            if (!auto_stra(&sa, store))
+                goto err ;
+
+            r = version_scan(&sa, store, SS_CONFIG_VERSION_NDOT) ;
+            if (r == -1)
+                goto err ;
+
+            if (!r)
+                parse_error_return(0, 0, idsec, idkey) ;
+
+            res->version = resolve_add_string(wres, sa.s) ;
+
+            break ;
+
+        case KEY_MAIN_TYPE:
+
+            if (!parse_clean_line(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            if (!strcmp(store, "longrun")) {
+                log_1_warn("deprecated type longrun -- convert it automatically to classic type") ;
+                res->type = 0 ;
+                break ;
+            }
+
+            r = get_enum_by_key(store) ;
+            if (r == -1)
+                parse_error_return(0, 0, idsec, idkey) ;
+
+            res->type = (uint32_t)r ;
+
+            break ;
+
+        case KEY_MAIN_NOTIFY:
+
+            parse_error_type(res->type,ENUM_KEY_SECTION_MAIN, idkey) ;
+
+            if (!uint320_scan(store, &res->notify))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            if (res->notify < 3)
+                parse_error_return(0, 0, idsec, idkey) ;
+
+            break ;
+
+        case KEY_MAIN_DEATH:
+
+
+            if (!uint320_scan(store, &res->maxdeath))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_MAIN_FLAGS:
+
+            parse_error_type(res->type,ENUM_KEY_SECTION_MAIN, idkey) ;
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            {
+                pos = 0 ;
+                FOREACH_SASTR(&sa, pos) {
+
+                    r = get_enum_by_key_one(sa.s + pos, ENUM_FLAGS) ;
+
+                    if (r == -1)
+                        parse_error_return(0, 0, idsec, idkey) ;
+
+                    if (r == FLAGS_DOWN)
+                        res->execute.down = 1 ;/**0 means not enabled*/
+
+                    if (r == FLAGS_EARLIER)
+                        res->earlier = 1 ;/**0 means not enabled*/
+                }
+            }
+
+            break ;
+
+        case KEY_MAIN_SIGNAL:
+
+            parse_error_type(res->type,ENUM_KEY_SECTION_MAIN, idkey) ;
+
+            if (!parse_clean_line(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            int t = 0 ;
+            if (!sig0_scan(store, &t))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            res->execute.downsignal = (uint32_t)t ;
+
+            break ;
+
+        case KEY_MAIN_T_KILL:
+
+            parse_error_type(res->type,ENUM_KEY_SECTION_MAIN, idkey) ;
+
+            if (!uint320_scan(store, &res->execute.timeout.kill))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_MAIN_T_FINISH:
+
+            parse_error_type(res->type,ENUM_KEY_SECTION_MAIN, idkey) ;
+
+            if (!uint320_scan(store, &res->execute.timeout.finish))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_MAIN_T_UP:
+
+            parse_error_type(res->type,ENUM_KEY_SECTION_MAIN, idkey) ;
+
+            if (!uint320_scan(store, &res->execute.timeout.up))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_MAIN_T_DOWN:
+
+            parse_error_type(res->type,ENUM_KEY_SECTION_MAIN, idkey) ;
+
+            if (!uint320_scan(store, &res->execute.timeout.down))
+                parse_error_return(0, 3, idsec, idkey) ;
+
+            break ;
+
+        case KEY_MAIN_HIERCOPY:
+
+            if (res->type == TYPE_BUNDLE)
+                log_warn_return(LOG_EXIT_ONE,"key: ", get_key_by_enum(ENUM_KEY_SECTION_MAIN, idkey), ": is not valid for type ", get_key_by_enum(ENUM_TYPE, res->type), " -- ignoring it") ;
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+            {
+                size_t len = sa.len ;
+
+                char t[len + 1] ;
+
+                sastr_to_char(t, &sa) ;
+
+                sa.len = 0 ;
+                pos = 0 ;
+
+                for (; pos < len ; pos += strlen(t + pos) + 1) {
+                    if (!auto_stra(&sa, t + pos, " "))
+                            goto err ;
+                }
+            }
+            sa.len-- ;
+            if (!stralloc_0(&sa))
+                goto err ;
+
+            res->hiercopy = resolve_add_string(wres, sa.s) ;
+
+            break ;
+
+        case KEY_MAIN_OPTIONS:
+
+            if (res->type == TYPE_BUNDLE)
+                log_warn_return(LOG_EXIT_ONE,"key: ", get_key_by_enum(ENUM_KEY_SECTION_MAIN, idkey), ": is not valid for type ", get_key_by_enum(ENUM_TYPE, res->type), " -- ignoring it") ;
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+            {
+                pos = 0 ;
+                FOREACH_SASTR(&sa, pos) {
+
+                    uint8_t reverse = sa.s[pos] == '!' ? 1 : 0 ;
+
+                    r = get_enum_by_key(sa.s + pos + reverse) ;
+
+                    if (r == -1)
+                        parse_error_return(0, 0, idsec, idkey) ;
+
+                    /** do no set a logger by default */
+                    if (reverse && r == OPTS_LOGGER)
+                        res->logger.want = 0 ;
+
+                    if (r == OPTS_ENVIR)
+                        log_warn("options: env is deprecated -- simply set an [environment] section") ;
+                }
+            }
+
+            break ;
+
+        case KEY_MAIN_USER:
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            {
+                uid_t user[256] ;
+                memset(user, 0, 256*sizeof(uid_t)) ;
+
+                uid_t owner = MYUID ;
+                if (!owner) {
+
+                    if (sastr_find(&sa, "root") == -1)
+                        log_warnu_return(LOG_EXIT_ZERO, "use the service -- permission denied") ;
+                }
+                /** special case, we don't know which user want to use
+                 * the service, we need a general name to allow the current owner
+                 * of the process. The term "user" is took here to allow him */
+                ssize_t p = sastr_cmp(&sa, "user") ;
+                size_t len = sa.len ;
+                pos = 0 ;
+
+                char t[len + 1] ;
+
+                sastr_to_char(t, &sa) ;
+
+                sa.len = 0 ;
+
+                for (; pos < len ; pos += strlen(t + pos) + 1) {
+
+                    if (pos == (size_t)p) {
+
+                        struct passwd *pw = getpwuid(owner);
+                        if (!pw) {
+
+                            if (!errno) errno = ESRCH ;
+                            log_warnu_return(LOG_EXIT_ZERO,"get user name") ;
+                        }
+
+                        if (!scan_uidlist(pw->pw_name, user))
+                            parse_error_return(0, 0, idsec, idkey) ;
+
+                        if (!auto_stra(&sa, pw->pw_name, " "))
+                            log_warnu_return(LOG_EXIT_ZERO, "stralloc") ;
+
+                        continue ;
+                    }
+
+                    if (!scan_uidlist(t + pos, user))
+                        parse_error_return(0, 0, idsec, idkey) ;
+
+                    if (!auto_stra(&sa, t + pos, " "))
+                        log_warnu_return(LOG_EXIT_ZERO, "stralloc") ;
+
+                }
+                uid_t nb = user[0] ;
+                if (p == -1 && owner) {
+
+                    int e = 0 ;
+                    for (int i = 1; i < nb+1; i++) {
+                        if (user[i] == owner) {
+                            e = 1 ;
+                            break ;
+                        }
+                    }
+                    if (!e)
+                        log_warnu_return(LOG_EXIT_ZERO,"use the service -- permission denied") ;
+                }
+            }
+
+            res->user = resolve_add_string(wres, sa.s) ;
+
+            break ;
+
+        case KEY_MAIN_DEPENDS:
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->dependencies.depends = parse_compute_list(wres, &sa, &res->dependencies.ndepends, 0) ;
+
+            break ;
+
+        case KEY_MAIN_REQUIREDBY:
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->dependencies.requiredby = parse_compute_list(wres, &sa, &res->dependencies.nrequiredby, 0) ;
+
+            break ;
+
+        case KEY_MAIN_OPTSDEPS:
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->dependencies.optsdeps = parse_compute_list(wres, &sa, &res->dependencies.noptsdeps, 1) ;
+
+            break ;
+
+        case KEY_MAIN_INTREE:
+
+            if (!parse_clean_line(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->intree = resolve_add_string(wres, store) ;
+
+            break ;
+
+        default:
+            log_warn_return(LOG_EXIT_ZERO, "unknown key: ", get_key_by_key_all(idsec, idkey)) ;
+    }
+
+    e = 1 ;
+
+    err :
+        stralloc_free(&sa) ;
+        free(wres) ;
+        return e ;
+
+}
diff --git a/src/lib66/parse/parse_store_regex.c b/src/lib66/parse/parse_store_regex.c
new file mode 100644
index 00000000..253378c4
--- /dev/null
+++ b/src/lib66/parse/parse_store_regex.c
@@ -0,0 +1,78 @@
+/*
+ * parse_store_regex.c
+ *
+ * Copyright (c) 2018-2022 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 <stdlib.h> //free
+
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/enum.h>
+
+int parse_store_regex(resolve_service_t *res, char *store, int idsec, int idkey)
+{
+    log_flow() ;
+
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ;
+
+    switch(idkey) {
+
+        case KEY_REGEX_CONFIGURE:
+
+            if (!parse_clean_quotes(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->regex.configure = resolve_add_string(wres, store) ;
+
+            break ;
+
+        case KEY_REGEX_DIRECTORIES:
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->regex.directories = parse_compute_list(wres, &sa, &res->regex.ndirectories, 0) ;
+
+            break ;
+
+        case KEY_REGEX_FILES:
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->regex.files = parse_compute_list(wres, &sa, &res->regex.nfiles, 0) ;
+
+            break ;
+
+        case KEY_REGEX_INFILES:
+
+            if (!parse_clean_list(&sa, store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            res->regex.infiles = parse_compute_list(wres, &sa, &res->regex.ninfiles, 0) ;
+
+            break ;
+
+        default:
+            log_warn_return(LOG_EXIT_ZERO, "unknown key: ", get_key_by_key_all(idsec, idkey)) ;
+    }
+
+    stralloc_free(&sa) ;
+    free(wres) ;
+    return 1 ;
+}
diff --git a/src/lib66/parse/parse_store_start_stop.c b/src/lib66/parse/parse_store_start_stop.c
new file mode 100644
index 00000000..72d9cb9f
--- /dev/null
+++ b/src/lib66/parse/parse_store_start_stop.c
@@ -0,0 +1,105 @@
+/*
+ * parse_store_start_stop.c
+ *
+ * Copyright (c) 2018-2022 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 <stdlib.h> //free
+
+#include <oblibs/log.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/parser.h>
+#include <66/resolve.h>
+#include <66/service.h>
+#include <66/enum.h>
+
+int parse_store_start_stop(resolve_service_t *res, char *store, int idsec, int idkey)
+{
+    int e = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, res) ;
+
+    switch(idkey) {
+
+        case KEY_STARTSTOP_BUILD:
+
+            if (!parse_clean_line(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            if (idsec == SECTION_START)
+                res->execute.run.build = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_STOP)
+                res->execute.finish.build = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_LOG)
+                res->logger.execute.run.build = resolve_add_string(wres, store) ;
+
+            break ;
+
+        case KEY_STARTSTOP_RUNAS:
+
+            if (!parse_clean_line(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            if (!parse_clean_runas(store, idsec, idkey))
+                goto err ;
+
+            if (idsec == SECTION_START)
+                res->execute.run.runas = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_STOP)
+                res->execute.finish.runas = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_LOG)
+                res->logger.execute.run.runas = resolve_add_string(wres, store) ;
+
+            break ;
+
+        case KEY_STARTSTOP_SHEBANG:
+
+            log_1_warn("deprecated key @shebang -- define your complete shebang directly inside your @execute key field") ;
+
+            if (!parse_clean_quotes(store))
+                parse_error_return(0, 8, idsec, idkey) ;
+
+            if (store[0] != '/')
+                parse_error_return(0, 4, idsec, idkey) ;
+
+            if (idsec == SECTION_START)
+                res->execute.run.shebang = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_STOP)
+                res->execute.finish.shebang = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_LOG)
+                res->logger.execute.run.shebang = resolve_add_string(wres, store) ;
+
+            break ;
+
+        case KEY_STARTSTOP_EXEC:
+
+            if (idsec == SECTION_START)
+                res->execute.run.run_user = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_STOP)
+                res->execute.finish.run_user = resolve_add_string(wres, store) ;
+            else if (idsec == SECTION_LOG)
+                res->logger.execute.run.run_user = resolve_add_string(wres, store) ;
+
+            break ;
+
+        default:
+            log_warn_return(LOG_EXIT_ZERO, "unknown key: ", get_key_by_key_all(idsec, idkey)) ;
+    }
+
+    e = 1 ;
+
+    err :
+        stralloc_free(&sa) ;
+        free(wres) ;
+        return e ;
+}
-- 
GitLab