diff --git a/package/deps.mak b/package/deps.mak
index 0de7f4f23fe7ee2c1352e3224bb4df6e30623717..315edf1fb3600cb4b74d007e62322bfbb282369e 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -38,6 +38,7 @@ src/66/66-tree.o src/66/66-tree.lo: src/66/66-tree.c src/include/66/config.h src
 src/66/66-update.o src/66/66-update.lo: src/66/66-update.c src/include/66/backup.h src/include/66/constants.h src/include/66/db.h src/include/66/parser.h src/include/66/resolve.h src/include/66/ssexec.h src/include/66/svc.h src/include/66/tree.h src/include/66/utils.h
 src/extra-tools/66-echo.o src/extra-tools/66-echo.lo: src/extra-tools/66-echo.c
 src/extra-tools/66-umountall.o src/extra-tools/66-umountall.lo: src/extra-tools/66-umountall.c src/include/66/config.h
+src/extra-tools/execl-envfile.o src/extra-tools/execl-envfile.lo: src/extra-tools/execl-envfile.c
 src/lib66/backup_cmd_switcher.o src/lib66/backup_cmd_switcher.lo: src/lib66/backup_cmd_switcher.c src/include/66/constants.h src/include/66/enum.h src/include/66/ssexec.h src/include/66/utils.h
 src/lib66/backup_make_new.o src/lib66/backup_make_new.lo: src/lib66/backup_make_new.c src/include/66/constants.h src/include/66/db.h src/include/66/enum.h src/include/66/tree.h src/include/66/utils.h
 src/lib66/backup_realpath_sym.o src/lib66/backup_realpath_sym.lo: src/lib66/backup_realpath_sym.c src/include/66/constants.h src/include/66/enum.h src/include/66/ssexec.h src/include/66/utils.h
@@ -68,7 +69,7 @@ src/lib66/ss_utils.o src/lib66/ss_utils.lo: src/lib66/ss_utils.c src/include/66/
 src/lib66/ssexec_dbctl.o src/lib66/ssexec_dbctl.lo: src/lib66/ssexec_dbctl.c src/include/66/constants.h src/include/66/db.h src/include/66/enum.h src/include/66/resolve.h src/include/66/ssexec.h src/include/66/state.h src/include/66/utils.h
 src/lib66/ssexec_disable.o src/lib66/ssexec_disable.lo: src/lib66/ssexec_disable.c src/include/66/constants.h src/include/66/db.h src/include/66/resolve.h src/include/66/state.h src/include/66/svc.h src/include/66/tree.h src/include/66/utils.h
 src/lib66/ssexec_enable.o src/lib66/ssexec_enable.lo: src/lib66/ssexec_enable.c src/include/66/constants.h src/include/66/db.h src/include/66/parser.h src/include/66/resolve.h src/include/66/ssexec.h src/include/66/svc.h src/include/66/tree.h src/include/66/utils.h
-src/lib66/ssexec_env.o src/lib66/ssexec_env.lo: src/lib66/ssexec_env.c src/include/66/config.h src/include/66/environ.h src/include/66/parser.h src/include/66/ssexec.h src/include/66/utils.h
+src/lib66/ssexec_env.o src/lib66/ssexec_env.lo: src/lib66/ssexec_env.c src/include/66/config.h src/include/66/constants.h src/include/66/environ.h src/include/66/parser.h src/include/66/ssexec.h src/include/66/utils.h
 src/lib66/ssexec_free.o src/lib66/ssexec_free.lo: src/lib66/ssexec_free.c src/include/66/ssexec.h
 src/lib66/ssexec_help.o src/lib66/ssexec_help.lo: src/lib66/ssexec_help.c src/include/66/ssexec.h
 src/lib66/ssexec_init.o src/lib66/ssexec_init.lo: src/lib66/ssexec_init.c src/include/66/constants.h src/include/66/db.h src/include/66/rc.h src/include/66/resolve.h src/include/66/ssexec.h src/include/66/state.h src/include/66/svc.h src/include/66/tree.h src/include/66/utils.h
@@ -140,6 +141,8 @@ src/lib66/tree_switch_current.o src/lib66/tree_switch_current.lo: src/lib66/tree
 66-echo: src/extra-tools/66-echo.o -loblibs -lskarnet 
 66-umountall: EXTRA_LIBS :=
 66-umountall: src/extra-tools/66-umountall.o -loblibs -lskarnet
+execl-envfile: EXTRA_LIBS :=
+execl-envfile: src/extra-tools/execl-envfile.o ${LIBEXECLINE} -loblibs -lexecline -lskarnet 
 ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
 lib66.a.xyzzy: src/lib66/backup_cmd_switcher.o src/lib66/backup_make_new.o src/lib66/backup_realpath_sym.o src/lib66/db_compile.o src/lib66/db_find_compiled_state.o src/lib66/db_ok.o src/lib66/db_switch_to.o src/lib66/db_update.o src/lib66/hpr_shutdown.o src/lib66/hpr_wall.o src/lib66/parser.o src/lib66/parser_enabled.o src/lib66/parser_module.o src/lib66/parser_utils.o src/lib66/parser_write.o src/lib66/rc_init.o src/lib66/rc_manage.o src/lib66/rc_send.o src/lib66/rc_unsupervise.o src/lib66/ss_environ.o src/lib66/ss_get_enum.o src/lib66/ss_info_utils.o src/lib66/ss_instance.o src/lib66/ss_resolve.o src/lib66/ss_resolve_graph.o src/lib66/ss_state.o src/lib66/ss_utils.o src/lib66/ssexec_dbctl.o src/lib66/ssexec_enable.o src/lib66/ssexec_env.o src/lib66/ssexec_disable.o src/lib66/ssexec_free.o src/lib66/ssexec_help.o src/lib66/ssexec_init.o src/lib66/ssexec_main.o src/lib66/ssexec_start.o src/lib66/ssexec_stop.o src/lib66/ssexec_svctl.o src/lib66/svc_init.o src/lib66/svc_init_pipe.o src/lib66/svc_send.o src/lib66/svc_switch_to.o src/lib66/svc_unsupervise.o src/lib66/tree_cmd_state.o src/lib66/tree_copy.o src/lib66/tree_copy_tmp.o src/lib66/tree_find_current.o src/lib66/tree_get_permissions.o src/lib66/tree_sethome.o src/lib66/tree_setname.o src/lib66/tree_switch_current.o
 else
diff --git a/package/modes b/package/modes
index 9193f0f48fd30d7981e3036dff9fee9be278219c..bbf8e5aef99a9d1e595863e094bf90f2132a7d93 100644
--- a/package/modes
+++ b/package/modes
@@ -22,6 +22,7 @@
 66-update		    0755
 66-umountall    	0755
 66-echo 			0755
+execl-envfile		0755
 halt    			0755
 init			    0755
 init.conf		    0644
diff --git a/package/targets.mak b/package/targets.mak
index 73289d8bd6f9af07ac3acfcf908b800b0d23005e..ff41fd8bacaa70b250aa4ea6e36fbf988d5ca911 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -22,6 +22,7 @@ BIN_TARGETS := \
 66-hpr \
 66-update \
 66-umountall \
-66-echo
+66-echo \
+execl-envfile
 
 LIB_DEFS := 66=66
diff --git a/src/extra-tools/deps-exe/execl-envfile b/src/extra-tools/deps-exe/execl-envfile
new file mode 100644
index 0000000000000000000000000000000000000000..6210896fcf83e97008e87edc603bb0ff0181e36c
--- /dev/null
+++ b/src/extra-tools/deps-exe/execl-envfile
@@ -0,0 +1,5 @@
+${LIBEXECLINE}
+-loblibs
+-lexecline
+-lskarnet
+
diff --git a/src/extra-tools/execl-envfile.c b/src/extra-tools/execl-envfile.c
new file mode 100644
index 0000000000000000000000000000000000000000..19d7532e379c724af1c839eee2d99f673d9ba815
--- /dev/null
+++ b/src/extra-tools/execl-envfile.c
@@ -0,0 +1,238 @@
+/* 
+ * execl-envfile.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 <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <oblibs/string.h>
+#include <oblibs/log.h>
+#include <oblibs/types.h>
+#include <oblibs/directory.h>
+#include <oblibs/files.h>
+#include <oblibs/environ.h>
+#include <oblibs/sastr.h>
+
+#include <skalibs/bytestr.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/env.h>
+#include <skalibs/sgetopt.h>
+
+#include <execline/execline.h>
+
+#define USAGE "execl-envfile [ -h ] [ -l ] src prog"
+
+static inline void info_help (void)
+{
+  static char const *help =
+"execl-envfile <options> src prog\n"
+"\n"
+"options :\n"
+"	-h: print this help\n" 
+"	-l: loose\n"
+;
+
+ if (buffer_putsflush(buffer_1, help) < 0)
+    log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+}
+
+void clean_n_unexport(stralloc *modifs, stralloc *dst, stralloc *src)
+{
+	if (!environ_clean_envfile(modifs,src)) log_dieu(LOG_EXIT_SYS,"prepare modified environment of: ",src->s) ;
+	if (!sastr_split_string_in_nline(modifs)) log_dieu(LOG_EXIT_SYS,"build environment line of: ",src->s) ;
+	if (!stralloc_cats(dst,src->s)) log_die_nomem("stralloc") ;
+}
+
+static int cmpnsort(stralloc *sa)
+{
+	size_t pos = 0 ;
+	if (!sa->len) return 0 ;
+	size_t salen = sa->len ;
+	size_t nel = sastr_len(sa), idx = 0, a = 0, b = 0 ;
+	char names[nel][MAXENV + 1] ;
+	char tmp[MAXENV + 1] ;
+
+	for (; pos < salen && idx < nel ; pos += strlen(sa->s + pos) + 1,idx++)
+	{
+		memcpy(names[idx],sa->s + pos,strlen(sa->s + pos)) ;
+		names[idx][strlen(sa->s+pos)] = 0 ;
+	}
+	for (; a < nel - 1 ; a++)
+	{
+		for (b = a + 1 ; b < idx ; b++)
+		{
+			if (strcmp(names[a],names[b]) > 0)
+			{
+				strcpy(tmp,names[a]) ;
+				strcpy(names[a],names[b]);
+				strcpy(names[b],tmp);
+			}
+		}
+	}
+	sa->len = 0 ;
+	for (a = 0 ; a < nel ; a++)
+	{
+		if (!sastr_add_string(sa,names[a])) return 0 ;
+	}
+	return 1 ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+	int r = 0, unexport = 0, insist = 1, nvar = 0 ;
+	size_t pos = 0 ;
+	char const *path = 0, *file = 0 ;
+	char tpath[MAXENV + 1], tfile[MAXENV+1] ;
+	stralloc src = STRALLOC_ZERO ;
+	stralloc modifs = STRALLOC_ZERO ;
+	stralloc dst = STRALLOC_ZERO ;
+	stralloc toparse = STRALLOC_ZERO ; 
+	stralloc key = STRALLOC_ZERO ; 
+	stralloc val = STRALLOC_ZERO ; 
+	
+	exlsn_t info = EXLSN_ZERO ;
+		
+	PROG = "execl-envfile" ;
+	{
+		subgetopt_t l = SUBGETOPT_ZERO ;
+
+		for (;;)
+		{
+			int opt = subgetopt_r(argc,argv, "hl", &l) ;
+			if (opt == -1) break ;
+			switch (opt)
+			{
+				case 'h' : 	info_help(); return 0 ;
+				case 'l' : 	insist = 0 ; break ;
+				default : 	log_usage(USAGE) ; 
+			}
+		}
+		argc -= l.ind ; argv += l.ind ;
+	}
+	if (argc < 2) log_usage(USAGE) ;
+	
+	path = *argv ;
+	argv++;
+	argc--;
+	
+	r = scan_mode(path,S_IFREG) ;
+	if (r > 0)
+	{
+		if (!ob_basename(tfile,path)) log_dieu(LOG_EXIT_SYS,"get file name of: ",path) ;
+		file = tfile ;
+		if (!ob_dirname(tpath,path)) log_dieu(LOG_EXIT_SYS,"get parent path of: ",path) ;
+		path = tpath ;
+	}
+		
+	if (path[0] == '.')
+	{
+		if (!dir_beabsolute(tpath,path) && insist) 
+			log_dieusys(LOG_EXIT_SYS,"find absolute path of: ",path) ;
+		path = tpath ;
+	}
+		
+	r = sastr_dir_get(&toparse,path,"",S_IFREG) ;
+	if (!r && insist) log_dieusys(LOG_EXIT_SYS,"get file from: ",path) ;
+	else if ((!r && !insist) || !toparse.len)
+	{
+		xpathexec_run(argv[0],argv,envp) ;
+	}
+	if (file)
+	{
+		ssize_t	r = sastr_cmp(&toparse,file) ;
+		if (r < 0) 
+		{
+			if (insist) log_dieu(LOG_EXIT_SYS,"find: ",path,file) ;
+			else
+			{
+				xpathexec_run(argv[0],argv,envp) ;
+			}
+		}
+		if (!file_readputsa(&src,path,file)) log_dieusys(LOG_EXIT_SYS,"read file: ",path,file) ;
+		clean_n_unexport(&modifs,&dst,&src) ;
+		nvar = environ_get_num_of_line(&src) ;
+		if (nvar == -1) log_dieusys(LOG_EXIT_SYS,"get number of line of:",path,toparse.s+pos) ;
+		if (nvar > MAXVAR) log_dieusys(LOG_EXIT_SYS,"to many variables in file: ",path,toparse.s+pos) ;
+	}
+	else
+	{
+		if (sastr_nelement(&toparse) > MAXFILE) log_die(LOG_EXIT_SYS,"to many file to parse in: ",path) ;
+		if (!cmpnsort(&toparse)) log_dieu(LOG_EXIT_SYS,"sort environment file list from: ",path) ;
+		for (;pos < toparse.len; pos += strlen(toparse.s + pos) + 1)
+		{
+			src.len = 0 ;
+			if (!file_readputsa(&src,path,toparse.s+pos)) log_dieusys(LOG_EXIT_SYS,"read file: ",path,toparse.s+pos) ;
+			clean_n_unexport(&modifs,&dst,&src) ;
+			nvar = environ_get_num_of_line(&src) ;
+			if (nvar == -1) log_dieusys(LOG_EXIT_SYS,"get number of line of:",path,toparse.s+pos) ;
+			if (nvar > MAXVAR) log_die(LOG_EXIT_SYS,"to many variables in file: ",path,toparse.s+pos) ;
+		}
+	}
+	stralloc_free(&src) ;
+	
+	/** be able to freed the stralloc before existing */
+	char tmp[modifs.len+1] ;
+	memcpy(tmp,modifs.s,modifs.len) ;
+	tmp[modifs.len] = 0 ;
+	
+	size_t n = env_len(envp) + 1 + byte_count(modifs.s,modifs.len,'\0') ;
+	if (n > MAXENV) log_die(LOG_EXIT_SYS,"environment string too long") ;
+	char const *newenv[n + 1] ;
+	if (!env_merge (newenv, n ,envp,env_len(envp),tmp, modifs.len)) log_dieusys(LOG_EXIT_SYS,"build environment") ;
+	
+	if (!sastr_split_string_in_nline(&dst)) log_dieusys(LOG_EXIT_SYS,"split line") ;
+	pos = 0 ;
+	
+	while (pos < dst.len)
+	{		
+		unexport = 0 ;
+		key.len = val.len = 0 ;
+		if (!stralloc_copy(&key,&dst) ||
+		!stralloc_copy(&val,&dst)) log_die_nomem("stralloc") ;
+		
+		if (!environ_get_key_nclean(&key,&pos)) log_dieusys(LOG_EXIT_SYS,"get key from line: ",key.s + pos) ;
+		pos-- ;// retrieve the '=' character
+		if (!environ_get_val(&val,&pos)) log_dieusys(LOG_EXIT_SYS,"get value from line: ",val.s + pos) ;
+		
+		char *uval = val.s ;
+		if (val.s[0] == VAR_UNEXPORT)
+		{
+			uval = val.s+1 ;
+			unexport = 1 ;
+		}
+		if(sastr_cmp(&info.vars,key.s) == -1)
+			if (!environ_substitute(key.s,uval,&info,newenv,unexport)) 
+				log_dieu(LOG_EXIT_SYS,"substitute value of: ",key.s," by: ",uval) ;
+	}
+	stralloc_free(&key) ;
+	stralloc_free(&val) ;
+	stralloc_free(&dst) ;
+	stralloc_free(&modifs) ;
+	
+	if (!env_string (&modifs, argv, (unsigned int) argc)) log_dieu(LOG_EXIT_SYS,"make environment string") ;
+	r = el_substitute (&dst, modifs.s, modifs.len, info.vars.s, info.values.s,
+		genalloc_s (elsubst_t const, &info.data),genalloc_len (elsubst_t const, &info.data)) ;
+	if (r < 0) log_dieusys(LOG_EXIT_SYS,"el_substitute") ;
+	else if (!r) _exit(0) ;
+
+	stralloc_free(&modifs) ;
+
+	char const *v[r + 1] ;
+	if (!env_make (v, r ,dst.s, dst.len)) log_dieusys(LOG_EXIT_SYS,"make environment") ;
+	v[r] = 0 ;
+	
+	pathexec_r (v, newenv, env_len(newenv),info.modifs.s,info.modifs.len) ;
+}