diff --git a/src/include/66/parser.h b/src/include/66/parser.h
index 73519ebd930da37639ec67c73699773bb4899a37..ed511f0dbe393bd0baed84202639d2a11de9357f 100644
--- a/src/include/66/parser.h
+++ b/src/include/66/parser.h
@@ -55,7 +55,6 @@ struct sv_execlog_s
 	int destination ;
 	uint32_t backup ;
 	uint32_t maxsize ;
-	/**timestamp=50->tai,timestamp=51->iso,52->none*/
 	int timestamp ;
 	int idga ; //pos in stralloc deps
 	unsigned int nga ; //number of deps in stralloc deps
@@ -285,9 +284,9 @@ extern void freed_parser(void) ;
 extern void start_parser(stralloc *list,ssexec_t *info, unsigned int *nbsv,uint8_t FORCE) ;
 extern int parser(sv_alltype *service,stralloc *src,char const *svname,int svtype) ;
 extern int parse_service_check_enabled(char const *tree_directory, char const *svname,uint8_t force,uint8_t *exist) ;
-extern int parse_service_before(ssexec_t *info, stralloc *parsed_list, stralloc *opts_deps_list, char const *sv,unsigned int *nbsv, stralloc *sasv,uint8_t force) ;
-extern int parse_service_deps(ssexec_t *info,stralloc *parsed_list, stralloc *opts_deps_list, sv_alltype *sv_before, char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force) ;
-extern int parse_service_opts_deps(ssexec_t *info,stralloc *parsed_list,stralloc *opts_deps_list,sv_alltype *sv_before,char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force,uint8_t mandatory) ;
+extern int parse_service_before(ssexec_t *info, stralloc *parsed_list, stralloc *opts_deps_list, char const *sv,unsigned int *nbsv, stralloc *sasv,uint8_t force,uint8_t conf) ;
+extern int parse_service_deps(ssexec_t *info,stralloc *parsed_list, stralloc *opts_deps_list, sv_alltype *sv_before, char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force,uint8_t conf) ;
+extern int parse_service_opts_deps(ssexec_t *info,stralloc *parsed_list,stralloc *opts_deps_list,sv_alltype *sv_before,char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force,uint8_t conf,uint8_t mandatory) ;
 extern int parse_add_service(stralloc *parsed_list,sv_alltype *sv_before,char const *service,unsigned int *nbsv,uid_t owner) ;
 extern int get_svtype(sv_alltype *sv_before, char const *contents) ;
 /** split */
@@ -319,7 +318,7 @@ extern int write_dependencies(unsigned int nga,unsigned int idga,char const *dst
 extern int write_env(char const *name,stralloc *sa,char const *dst) ;
 extern int write_oneshot_logger(stralloc *destlog, sv_alltype *sv) ;
 /** module */
-extern int parse_module(sv_alltype *sv_before,char const *svname,uid_t owner,uint8_t force) ;
+extern int parse_module(stralloc *svclassic,sv_alltype *sv_before,char const *svname,uid_t owner,uint8_t force,uint8_t conf) ;
 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) ;
diff --git a/src/lib66/deps-lib/66 b/src/lib66/deps-lib/66
index bbea3507f79d0005d4b9fe9f8d9ded14028cd66a..de7b216a102c3cc886565cfa7203033f614e207b 100644
--- a/src/lib66/deps-lib/66
+++ b/src/lib66/deps-lib/66
@@ -15,6 +15,7 @@ hpr_wall.o
 instance.o
 parser.o
 parser_enabled.o
+parser_module.o
 parser_utils.o
 parser_write.o
 rc_init.o
diff --git a/src/lib66/parser_enabled.c b/src/lib66/parser_enabled.c
index 8b5bf3917eb58237751573f4a66d9e32599a5be7..45d074ce8b589a67de747c8d0642c7cbb86847f0 100644
--- a/src/lib66/parser_enabled.c
+++ b/src/lib66/parser_enabled.c
@@ -30,18 +30,20 @@
 #include <skalibs/direntry.h>
 #include <skalibs/djbunix.h>
 #include <skalibs/env.h>
+#include <skalibs/bytestr.h>//byte_count
 
 #include <66/resolve.h>
 #include <66/utils.h>
 #include <66/constants.h>
 #include <66/environ.h>
 
-int parse_service_before(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list, char const *sv,unsigned int *nbsv, stralloc *sasv,uint8_t force)
+int parse_service_before(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list, char const *sv,unsigned int *nbsv, stralloc *sasv,uint8_t force,uint8_t conf)
 {
 	log_trace("start parse process of service: ",sv) ;
 	int insta ;
 	uint8_t exist = 0 ;
 	size_t svlen = strlen(sv), svsrclen, svnamelen ;
+	stralloc svclassic = STRALLOC_ZERO ;
 	char svname[svlen + 1], svsrc[svlen + 1] ; 
 	if (!ob_basename(svname,sv)) log_warnu_return(LOG_EXIT_ZERO,"get basename of: ",sv) ;
 	if (!ob_dirname(svsrc,sv)) log_warnu_return(LOG_EXIT_ZERO,"get dirname of: ",sv) ;
@@ -131,9 +133,11 @@ int parse_service_before(ssexec_t *info,stralloc *parsed_list,stralloc *tree_lis
 		if (!stralloc_catb(&keep,svname,svnamelen + 1)) return 0 ;
 	}
 	add:
+	
 	if (sv_before.cname.itype == TYPE_MODULE)
 	{
-		r = parse_module(&sv_before,svname,info->owner,force) ;
+		svclassic.len = 0 ;
+		r = parse_module(&svclassic,&sv_before,svname,info->owner,force,conf) ;
 		if (!r) return 0 ;
 		else if (r == 2)
 		{
@@ -141,213 +145,43 @@ int parse_service_before(ssexec_t *info,stralloc *parsed_list,stralloc *tree_lis
 			sv_alltype_free(&sv_before) ;
 			goto deps ;
 		}
-		if (force > 1)
+		if (force > 1 && exist)
 		{
-			int wstat ;
-			pid_t pid ;
-			int color = log_color == &log_color_enable ? 1 : 0 ; 
-			char const *newargv[9 + color + 1] ;
+			char const *newargv[4] ;
 			unsigned int m = 0 ;
-			char fmt[UINT_FMT] ;
-			fmt[uint_fmt(fmt,VERBOSITY)] = 0 ;
-
-			newargv[m++] = SS_BINPREFIX "66-disable" ;
-			newargv[m++] = "-v" ;
-			newargv[m++] = fmt ;
-			if (color)
-				newargv[m++] = "-z" ;
-			newargv[m++] = "-l" ;
-			newargv[m++] = info->live.s ;
-			newargv[m++] = "-t" ;
-			newargv[m++] = info->treename.s ;
+			
+			newargv[m++] = "fake_name" ;
 			newargv[m++] = svname ;
 			newargv[m++] = 0 ;
-			
-			pid = child_spawn0(newargv[0],newargv,(const char *const *)environ) ;
-			if (waitpid_nointr(pid,&wstat, 0) < 0)
-				log_warnusys_return (LOG_EXIT_ZERO,"wait for: 66-disable") ;
-			/** may not be enabled yet, don't crash if it's the case */
-			if (wstat && WEXITSTATUS(wstat) != LOG_EXIT_USER) log_warnu_return(LOG_EXIT_ZERO,"disable module: ",svname) ;
-		}
-	}
-	deps:
-	if (!parse_add_service(parsed_list,&sv_before,svpath,nbsv,info->owner)) return 0 ;
-	
-	if ((sv_before.cname.itype > TYPE_CLASSIC && force > 1) || !exist)
-	{
-		if (!parse_service_deps(info,parsed_list,tree_list,&sv_before,sv,nbsv,sasv,force)) return 0 ;
-		if (!parse_service_opts_deps(info,parsed_list,tree_list,&sv_before,sv,nbsv,sasv,force,KEY_MAIN_EXTDEPS)) return 0 ;
-		if (!parse_service_opts_deps(info,parsed_list,tree_list,&sv_before,sv,nbsv,sasv,force,KEY_MAIN_OPTSDEPS)) return 0 ;
-	}
-	freed:
-	return 1 ;
-}
-
-/** return 1 if all good
- * return 0 on crash
- * return 2 on already enabled */
-int parse_module(sv_alltype *sv_before,char const *svname,uid_t owner,uint8_t force)
-{
-	log_trace("start parse process of module: ",svname) ;
-	int r, insta, err = 1 ;
-	size_t in = 0 , pos = 0, len = 0 ;
-	stralloc mdir = STRALLOC_ZERO ; // module dir
-	stralloc sdir = STRALLOC_ZERO ; // service dir
-	stralloc list = STRALLOC_ZERO ;
-	stralloc tmp = STRALLOC_ZERO ;
-	stralloc sainsta = STRALLOC_ZERO ; // SS_INSTANCE_NAME
-	
-	if (!ss_resolve_module_path(&sdir,&mdir,svname,owner)) return 0 ;
-	
-	/** keep instance name */
-	insta = instance_check(svname) ;
-	if (!instance_splitname(&sainsta,svname,insta,SS_INSTANCE_NAME))
-		log_warnu_return(LOG_EXIT_ZERO,"get instance name") ;
-	
-	r = scan_mode(sdir.s,S_IFDIR) ;
-	if (r < 0) { errno = EEXIST ; log_warnusys_return(LOG_EXIT_ZERO,"conflicting format of: ",sdir.s) ; }
-	else if (!r)
-	{
-		if (!hiercopy(mdir.s,sdir.s))
-			log_warnusys_return(LOG_EXIT_ZERO,"copy: ",mdir.s," to: ",sdir.s) ;
-	}
-	else
-	{
-		if (force < 2)
-		{
-			log_warn("Ignoring module: ",svname," -- already configured") ;
-			err = 2 ;
-			goto make_deps ;
+			if (ssexec_disable(m,newargv,(const char *const *)environ,info)) 
+				log_warnu_return(LOG_EXIT_ZERO,"disable module: ",svname) ;	
 		}
-		
-		if (rm_rf(sdir.s) < 0)
-			log_warnusys_return (LOG_EXIT_ZERO,"remove: ",sdir.s) ;
-				
-		if (!hiercopy(mdir.s,sdir.s))
-			log_warnusys_return(LOG_EXIT_ZERO,"copy: ",mdir.s," to: ",sdir.s) ;
-	}
-	
-	/** regex file content */
-	if (!sastr_dir_get_recursive(&list,sdir.s,"",S_IFREG)) 
-		log_warnusys_return(LOG_EXIT_ZERO,"get file(s) of module: ",svname) ;
-	
-	pos = sv_before->type.module.start_infiles, len = sv_before->type.module.end_infiles ;
-	for (;pos < len; pos += strlen(keep.s + pos) + 1)
-	{
-		int all = 0 ; int fpos = 0 ;
-		char filename[512] = { 0 } ;
-		char replace[512] = { 0 } ;
-		char regex[512] = { 0 } ;
-		char const *line = keep.s + pos ;
-	
-		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") ;
-			
-		fpos = regex_get_file_name(filename,line) ;
-
-		if (fpos == -1)  log_warnu_return(LOG_EXIT_ZERO,"file name of line: ",line) ;
-		else if (fpos < 3) all = 1 ;
-		
-		if (!regex_get_replace(replace,line+fpos)) log_warnu_return(LOG_EXIT_ZERO,"replace string of line: ",line) ;
-
-		if (!regex_get_regex(regex,line+fpos)) log_warnu_return(LOG_EXIT_ZERO,"regex string of line: ",line) ;
-
-		for (in = 0 ; in < list.len; in += strlen(list.s + in) + 1)
+		deps:
+		if (svclassic.len)
 		{
-			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 (obstr_equal(bname,filename) || all)
+			size_t pos = 0 ;
+			for (; pos < svclassic.len ; pos += strlen(svclassic.s + pos) + 1)
 			{
-				if (!ob_dirname(dname,str)) log_warnu_return(LOG_EXIT_ZERO,"get dirname of: ",str) ;
-				if (!read_svfile(&tmp,bname,dname)) log_warnusys_return(LOG_EXIT_ZERO,"read file: ",str) ;
-				if (!sastr_replace_all(&tmp,replace,regex)) log_warnu_return(LOG_EXIT_ZERO,"replace: ",replace," by: ", regex," in file: ",str) ;
-				if (!file_write_unsafe(dname,bname,tmp.s,tmp.len))
-					log_warnusys_return(LOG_EXIT_ZERO,"write: ",dname,"/","filename") ;
+				char *sv = svclassic.s + pos ;
+				if (!parse_service_before(info,parsed_list,tree_list,sv,nbsv,sasv,force,conf)) return 0 ;
 			}
 		}
 	}
-	/* regex directories name */
-	if (!regex_replace(sv_before->type.module.iddir,sv_before->type.module.ndir,sdir.s,S_IFDIR)) return 0 ;
-	/* regex files name */
-	if (!regex_replace(sv_before->type.module.idfiles,sv_before->type.module.nfiles,sdir.s,S_IFREG)) return 0 ;
-	/*  configure script */
-	tmp.len = 0 ;
-	if (!auto_stra(&tmp,sdir.s,"/.configure/configure")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-
-	r = scan_mode(tmp.s,S_IFREG) ;
-	if (r > 0)
-	{
-		int wstat ;
-		pid_t pid ;
-		size_t clen = sv_before->type.module.configure > 0 ? 1 : 0 ;
-		char const *newargv[2 + clen] ;
-		unsigned int m = 0 ;
-		char pwd[sdir.len + 12] ;
-		auto_strings(pwd,sdir.s,"/.configure") ;
-		if (chdir(pwd) < 0) log_warnusys_return(LOG_EXIT_ZERO,"chdir to: ",pwd) ;
-
-		newargv[m++] = tmp.s ;
-		if (sv_before->type.module.configure > 0)
-			newargv[m++] = keep.s + sv_before->type.module.configure ;
-		newargv[m++] = 0 ;
-
-		pid = child_spawn0(newargv[0],newargv,(const char *const *)environ) ;
-		if (waitpid_nointr(pid,&wstat, 0) < 0)
-			log_warnusys_return(LOG_EXIT_ZERO,"wait for: ",sdir.s) ;
 
-		if (wstat) log_warnu_return(LOG_EXIT_ZERO,"run: ",sdir.s) ;
-		tmp.len = 0 ;
-		if (!auto_stra(&tmp,sdir.s,"/.configure")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-		if (rm_rf(tmp.s) < 0)
-			log_warnusys_return(LOG_EXIT_ZERO,"remove: ",tmp.s) ;
-	}
-	make_deps:
-	/** get all services */
-	list.len = 0 ;
-	if (!sastr_dir_get_recursive(&list,sdir.s,".configure",S_IFREG)) 
-		log_warnusys_return(LOG_EXIT_ZERO,"get file(s) of module: ",svname) ;
-	
-	/** remake the deps field */
-	size_t id = sv_before->cname.idga, nid = sv_before->cname.nga ;
-	sv_before->cname.idga = deps.len ;
-	sv_before->cname.nga = 0 ;
-	for (;nid; id += strlen(deps.s + id) + 1, nid--)
-	{
-		char *name = deps.s + id ;
-		if (!stralloc_catb(&deps,name,strlen(deps.s + id) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; ;
-		sv_before->cname.nga++ ;
-	}
+	if (!parse_add_service(parsed_list,&sv_before,svpath,nbsv,info->owner)) return 0 ;
 	
-	for (pos = 0 ; pos < list.len ; pos += strlen(list.s + pos) + 1)
+	if ((sv_before.cname.itype > TYPE_CLASSIC && force > 1) || !exist)
 	{
-		char *name = list.s + pos ;
-		char bname[len + sainsta.len + 1] ;
-		if (!ob_basename(bname,name)) log_warnu_return(LOG_EXIT_ZERO,"get basename of: ",name) ;
-		insta = get_len_until(bname,'@') ;
-		insta++ ; // keep '@'
-		if (insta > 0)
-		{
-			auto_string_from(bname,insta,sainsta.s) ;
-		}
-		if (!stralloc_catb(&deps,bname,strlen(bname) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
-		sv_before->cname.nga++ ;
+		if (!parse_service_deps(info,parsed_list,tree_list,&sv_before,sv,nbsv,sasv,force,conf)) return 0 ;
+		if (!parse_service_opts_deps(info,parsed_list,tree_list,&sv_before,sv,nbsv,sasv,force,conf,KEY_MAIN_EXTDEPS)) return 0 ;
+		if (!parse_service_opts_deps(info,parsed_list,tree_list,&sv_before,sv,nbsv,sasv,force,conf,KEY_MAIN_OPTSDEPS)) return 0 ;
 	}
-	
-	stralloc_free(&mdir) ;
-	stralloc_free(&sdir) ;
-	stralloc_free(&list) ;
-	stralloc_free(&tmp) ;
-	stralloc_free(&sainsta) ;
-	
-	return err ;
+	freed:
+		stralloc_free(&svclassic) ;
+	return 1 ;
 }
 
-int parse_service_deps(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list, sv_alltype *sv_before, char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force)
+int parse_service_deps(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list, sv_alltype *sv_before, char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force,uint8_t conf)
 {
 	int r ;
 	char *dname = 0 ;
@@ -367,7 +201,7 @@ int parse_service_deps(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list,
 			r = ss_resolve_src_path(&newsv,dname,info->owner) ;
 			if (r < 1) goto err ;//don't warn here, the ss_revolve_src_path already warn user
 
-			if (!parse_service_before(info,parsed_list,tree_list,newsv.s,nbsv,sasv,force)) goto err ;
+			if (!parse_service_before(info,parsed_list,tree_list,newsv.s,nbsv,sasv,force,conf)) goto err ;
 		}
 	}
 	else log_trace(sv,": haven't dependencies") ;
@@ -378,7 +212,7 @@ int parse_service_deps(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list,
 		return 0 ;
 }
 
-int parse_service_opts_deps(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list,sv_alltype *sv_before,char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force, uint8_t mandatory)
+int parse_service_opts_deps(ssexec_t *info,stralloc *parsed_list,stralloc *tree_list,sv_alltype *sv_before,char const *sv,unsigned int *nbsv,stralloc *sasv,uint8_t force,uint8_t conf, uint8_t mandatory)
 {
 	int r ;
 	stralloc newsv = STRALLOC_ZERO ;
@@ -441,7 +275,7 @@ int parse_service_opts_deps(ssexec_t *info,stralloc *parsed_list,stralloc *tree_
 					}
 					// be paranoid with the else if
 					else if (r == 1) {
-						if (!parse_service_before(info,parsed_list,tree_list,newsv.s,nbsv,sasv,force))
+						if (!parse_service_before(info,parsed_list,tree_list,newsv.s,nbsv,sasv,force,conf))
 							goto err ;
 						// we only keep the first found on optsdepends
 						if (!ext) break ;
@@ -486,7 +320,6 @@ int parse_service_check_enabled(char const *tree,char const *svname,uint8_t forc
 		return 0 ;
 }
 
-
 int parse_add_service(stralloc *parsed_list,sv_alltype *sv_before,char const *service,unsigned int *nbsv,uid_t owner)
 {
 	stralloc conf = STRALLOC_ZERO ;
@@ -511,99 +344,3 @@ int parse_add_service(stralloc *parsed_list,sv_alltype *sv_before,char const *se
 		stralloc_free(&conf) ;
 		return 0 ;
 }
-
-/* module helper */
-
-/* 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)
-{
-	int r ;
-	size_t pos = 0 ;
-	stralloc kp = STRALLOC_ZERO ;
-
-	parse_mill_t MILL_GET_COLON = { 
-	.open = ':', .close = ':',
-	.skip = " \t\r", .skiplen = 3,
-	.forceclose = 1,
-	.inner.debug = "get_colon" } ;
-	
-	r = mill_element(&kp,str,&MILL_GET_COLON,&pos) ;
-	if (r == -1) goto err ;
-	
-	auto_strings(filename,kp.s) ;
-	
-	stralloc_free(&kp) ;
-	return pos ;
-	err:
-		stralloc_free(&kp) ;
-		return -1 ;
-}
-
-int regex_get_replace(char *replace, char const *str)
-{
-	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 regex_get_regex(char *regex, char const *str)
-{
-	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 ;
-}
-
-int regex_replace(int id,unsigned int nid, char const *sdir,mode_t mode)
-{
-	stralloc list = STRALLOC_ZERO ;
-	stralloc tmp = STRALLOC_ZERO ;
-	size_t pos = id, len = nid, in ;
-	if (!sastr_dir_get_recursive(&list,sdir,"",mode)) 
-		log_warnusys_return(LOG_EXIT_ZERO,"get content of: ",sdir) ;
-		
-	pos = id, len = nid ;
-	
-	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) ;
-			
-		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) ;
-		
-			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") ;
-			
-			if (!sastr_replace(&tmp,replace,regex)) log_warnu_return(LOG_EXIT_ZERO,"replace: ",replace," by: ", regex," in file: ",str) ;
-			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))
-				if (rename(str,new) < 0) 
-					log_warnusys_return(LOG_EXIT_ZERO,"rename: ",str," by: ",new) ;
-		}
-	}
-	stralloc_free(&tmp) ;
-	stralloc_free(&list) ;
-	return 1 ;
-}
diff --git a/src/lib66/parser_module.c b/src/lib66/parser_module.c
new file mode 100644
index 0000000000000000000000000000000000000000..5d160831eb37aecf34e55655699829af035d1cd0
--- /dev/null
+++ b/src/lib66/parser_module.c
@@ -0,0 +1,363 @@
+/* 
+ * parser.c
+ * 
+ * Copyright (c) 2018-2020 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 <66/parser.h>
+
+#include <string.h>
+#include <stdio.h> //rename
+#include <unistd.h> //chdir
+
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+#include <oblibs/environ.h>
+#include <oblibs/files.h>
+#include <oblibs/mill.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/env.h>
+#include <skalibs/bytestr.h>//byte_count
+#include <skalibs/genalloc.h>
+
+#include <66/resolve.h>
+#include <66/utils.h>
+#include <66/constants.h>
+#include <66/environ.h>
+
+/** return 1 if all good
+ * return 0 on crash
+ * return 2 on already enabled */
+int parse_module(stralloc *svclassic,sv_alltype *sv_before,char const *svname,uid_t owner,uint8_t force,uint8_t conf)
+{
+	log_trace("start parse process of module: ",svname) ;
+	int r, insta, err = 1 ;
+	size_t in = 0 , pos = 0, inlen = 0 ;
+	stralloc sdir = STRALLOC_ZERO ; // service dir
+	stralloc list = STRALLOC_ZERO ;
+	stralloc tmp = STRALLOC_ZERO ;
+	stralloc sainsta = STRALLOC_ZERO ; // SS_INSTANCE_NAME
+	stralloc satype = STRALLOC_ZERO ; // keep information of module service
+	genalloc galist = GENALLOC_ZERO ; // module_type_t
+		
+	if (!ss_resolve_module_path(&sdir,&tmp,svname,owner)) return 0 ;
+	
+	/** keep instance name */
+	insta = instance_check(svname) ;
+	if (!instance_splitname(&sainsta,svname,insta,SS_INSTANCE_NAME))
+		log_warnu_return(LOG_EXIT_ZERO,"get instance name") ;
+	
+	r = scan_mode(sdir.s,S_IFDIR) ;
+	if (r < 0) { errno = EEXIST ; log_warnusys_return(LOG_EXIT_ZERO,"conflicting format of: ",sdir.s) ; }
+	else if (!r)
+	{
+		if (!hiercopy(tmp.s,sdir.s))
+			log_warnusys_return(LOG_EXIT_ZERO,"copy: ",tmp.s," to: ",sdir.s) ;
+	}
+	else
+	{
+		/** Must reconfigure all services of the module */
+		if (force < 2)
+		{
+			log_warn("Ignoring module: ",svname," -- already configured") ;
+			err = 2 ;
+			goto make_deps ;
+		}
+		
+		if (rm_rf(sdir.s) < 0)
+			log_warnusys_return (LOG_EXIT_ZERO,"remove: ",sdir.s) ;
+				
+		if (!hiercopy(tmp.s,sdir.s))
+			log_warnusys_return(LOG_EXIT_ZERO,"copy: ",tmp.s," to: ",sdir.s) ;
+	}
+	
+	/** regex file content */
+	if (!sastr_dir_get_recursive(&list,sdir.s,".configure",S_IFREG)) 
+		log_warnusys_return(LOG_EXIT_ZERO,"get file(s) of module: ",svname) ;
+	
+	for (in = 0 ; in < list.len; in += strlen(list.s + in) + 1)
+	{
+		tmp.len = 0 ;
+		sv_alltype m_type = SV_ALLTYPE_ZERO ;
+		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) ;
+		
+		if (!read_svfile(&tmp,bname,dname)) log_warnusys_return(LOG_EXIT_ZERO,"read file: ",str) ;
+
+		pos = sv_before->type.module.start_infiles, inlen = sv_before->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 (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") ;
+				
+			fpos = regex_get_file_name(filename,line) ;
+
+			if (fpos == -1)  log_warnu_return(LOG_EXIT_ZERO,"get filename of line: ",line) ;
+			else if (fpos < 3) all = 1 ;
+			
+			if (!regex_get_replace(replace,line+fpos)) log_warnu_return(LOG_EXIT_ZERO,"replace string of line: ",line) ;
+
+			if (!regex_get_regex(regex,line+fpos)) log_warnu_return(LOG_EXIT_ZERO,"regex string of line: ",line) ;
+			
+			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) ;
+				if (!file_write_unsafe(dname,bname,tmp.s,tmp.len))
+					log_warnusys_return(LOG_EXIT_ZERO,"write: ",dname,"/","filename") ;
+			}
+		}
+	
+		/** keep information of the service */
+		m_type.cname.name = satype.len ;
+		if (!stralloc_catb(&satype,bname,strlen(bname) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
+		m_type.src = satype.len ;
+		if (!stralloc_catb(&satype,dname,strlen(dname) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
+		if (!get_svtype(&m_type,tmp.s))
+			log_warn_return (LOG_EXIT_ZERO,"invalid value for key: ",get_key_by_enum(ENUM_KEY_SECTION_MAIN,KEY_MAIN_TYPE)," in service file: ",dname,"/",bname) ;
+				
+		if (!genalloc_append(sv_alltype,&galist,&m_type))
+			log_warnsys_return(LOG_EXIT_ZERO,"genalloc") ;
+	}
+	
+	/* regex directories name */
+	if (!regex_replace(sv_before->type.module.iddir,sv_before->type.module.ndir,sdir.s,S_IFDIR)) return 0 ;
+	/* regex files name */
+	if (!regex_replace(sv_before->type.module.idfiles,sv_before->type.module.nfiles,sdir.s,S_IFREG)) return 0 ;
+	/*  configure script */
+	tmp.len = 0 ;
+	if (!auto_stra(&tmp,sdir.s,"/.configure/configure")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
+
+	r = scan_mode(tmp.s,S_IFREG) ;
+	if (r > 0)
+	{
+		stralloc oenv = STRALLOC_ZERO ;
+		stralloc env = STRALLOC_ZERO ;
+		/** environment is not mandatory */
+		if (sv_before->opts[2] > 0)
+		{
+			/** sv_before->srconf is not set yet
+			* we don't care, env_compute will find it.
+			* env_compute return 2 in case of need to write */
+			r = env_compute(&oenv,sv_before,conf) ;
+			if (!r) log_warnu_return(LOG_EXIT_ZERO,"compute environment") ;
+			if (!stralloc_0(&oenv)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;	
+			/** prepare for the environment merge */
+				
+			if (!environ_clean_envfile(&env,&oenv))
+				log_warnu_return(LOG_EXIT_ZERO,"prepare environment") ;
+			if (!stralloc_0(&oenv)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;	
+					
+			if (!sastr_split_string_in_nline(&env))
+				log_warnu_return(LOG_EXIT_ZERO,"rebuild environment") ;
+		}
+		size_t n = env_len((const char *const *)environ) + 1 + byte_count(env.s,env.len,'\0') ;
+		char const *newenv[n + 1] ;
+		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") ;
+		
+		int wstat ;
+		pid_t pid ;
+		size_t clen = sv_before->type.module.configure > 0 ? 1 : 0 ;
+		char const *newargv[2 + clen] ;
+		unsigned int m = 0 ;
+		char pwd[sdir.len + 12] ;
+		auto_strings(pwd,sdir.s,"/.configure") ;
+		if (chdir(pwd) < 0) log_warnusys_return(LOG_EXIT_ZERO,"chdir to: ",pwd) ;
+		
+		newargv[m++] = tmp.s ;
+		if (sv_before->type.module.configure > 0)
+			newargv[m++] = keep.s + sv_before->type.module.configure ;
+		newargv[m++] = 0 ;
+		log_trace("launch script configure of module: ",svname) ;
+		pid = child_spawn0(newargv[0],newargv,newenv) ;
+		if (waitpid_nointr(pid,&wstat, 0) < 0)
+			log_warnusys_return(LOG_EXIT_ZERO,"wait for: ",tmp.s) ;
+
+		if (wstat) log_warnu_return(LOG_EXIT_ZERO,"run: ",tmp.s) ;
+		tmp.len = 0 ;
+		if (!auto_stra(&tmp,sdir.s,"/.configure")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
+		if (rm_rf(tmp.s) < 0)
+			log_warnusys_return(LOG_EXIT_ZERO,"remove: ",tmp.s) ;
+		
+		stralloc_free(&oenv) ;
+		stralloc_free(&env) ;
+	}
+	make_deps:
+	/** get all services */
+	list.len = 0 ;
+	if (!sastr_dir_get_recursive(&list,sdir.s,".configure",S_IFREG)) 
+		log_warnusys_return(LOG_EXIT_ZERO,"get file(s) of module: ",svname) ;
+
+	/** remake the deps field */
+	size_t id = sv_before->cname.idga, nid = sv_before->cname.nga ;
+	sv_before->cname.idga = deps.len ;
+	sv_before->cname.nga = 0 ;
+	for (;nid; id += strlen(deps.s + id) + 1, nid--)
+	{
+		char *name = deps.s + id ;
+		if (!stralloc_catb(&deps,name,strlen(deps.s + id) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; ;
+		sv_before->cname.nga++ ;
+	}
+	/*** change name for instantiated service
+	 * remove classic service from the list 
+	 * and add service to the stralloc deps.
+	 * The genalloc was built before the configure script.
+	 * Some services was removed. So we need to compare with
+	 * the effective @list to match exactly our needs */
+	for (size_t i = 0; i < genalloc_len(sv_alltype,&galist); i++)
+	{
+		sv_alltype_ref sv = &genalloc_s(sv_alltype,&galist)[i] ;
+		char *name = satype.s + sv->cname.name ;
+		char *src = satype.s + sv->src ;
+		size_t namelen = strlen(name), srclen = strlen(src) ;
+		char tmp[namelen + srclen + 1] ;
+		auto_strings(tmp,src,name) ;
+		if (sv->cname.itype == TYPE_CLASSIC)
+		{
+			if (!sastr_add_string(svclassic,tmp))
+				log_warnu_return(LOG_EXIT_ZERO,"store classic service: ",tmp) ;
+			continue ;
+		}
+		
+		if (sastr_find(&list,name) < 0) continue ;
+
+		insta = get_len_until(name,'@') ;
+		if (insta > 0)
+		{
+			insta++ ; // keep '@'
+			auto_string_from(name,insta,sainsta.s) ;
+		}
+		if (!stralloc_catb(&deps,name,strlen(name) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ;
+		sv_before->cname.nga++ ;
+	}
+	
+	stralloc_free(&sdir) ;
+	stralloc_free(&list) ;
+	stralloc_free(&tmp) ;
+	stralloc_free(&sainsta) ;
+	
+	for (size_t i = 0 ; i < genalloc_len(sv_alltype,&galist) ; i++)
+		sv_alltype_free(&genalloc_s(sv_alltype,&galist)[i]) ;
+	genalloc_free(sv_alltype,&galist) ;
+	
+	return err ;
+}
+
+/* helper */
+
+/* 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)
+{
+	int r ;
+	size_t pos = 0 ;
+	stralloc kp = STRALLOC_ZERO ;
+
+	parse_mill_t MILL_GET_COLON = { 
+	.open = ':', .close = ':',
+	.skip = " \t\r", .skiplen = 3,
+	.forceclose = 1,
+	.inner.debug = "get_colon" } ;
+	
+	r = mill_element(&kp,str,&MILL_GET_COLON,&pos) ;
+	if (r == -1) goto err ;
+	
+	auto_strings(filename,kp.s) ;
+	
+	stralloc_free(&kp) ;
+	return pos ;
+	err:
+		stralloc_free(&kp) ;
+		return -1 ;
+}
+
+int regex_get_replace(char *replace, char const *str)
+{
+	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 regex_get_regex(char *regex, char const *str)
+{
+	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 ;
+}
+
+int regex_replace(int id,unsigned int nid, char const *sdir,mode_t mode)
+{
+	stralloc list = STRALLOC_ZERO ;
+	stralloc tmp = STRALLOC_ZERO ;
+	size_t pos = id, len = nid, in ;
+	if (!sastr_dir_get_recursive(&list,sdir,"",mode)) 
+		log_warnusys_return(LOG_EXIT_ZERO,"get content of: ",sdir) ;
+		
+	pos = id, len = nid ;
+	
+	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) ;
+			
+		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) ;
+		
+			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") ;
+			
+			if (!sastr_replace(&tmp,replace,regex)) log_warnu_return(LOG_EXIT_ZERO,"replace: ",replace," by: ", regex," in file: ",str) ;
+			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))
+				if (rename(str,new) < 0) 
+					log_warnusys_return(LOG_EXIT_ZERO,"rename: ",str," by: ",new) ;
+		}
+	}
+	stralloc_free(&tmp) ;
+	stralloc_free(&list) ;
+	return 1 ;
+}