diff --git a/src/66/66-tree.c b/src/66/66-tree.c
index 84f5226ebd65d6308529db54e4e0e69ed839d1c5..4b7d9867dd2f39f9546e7f10d8ada122491c0a08 100644
--- a/src/66/66-tree.c
+++ b/src/66/66-tree.c
@@ -12,789 +12,21 @@
  * except according to the terms contained in the LICENSE file./
  */
 
-#include <66/tree.h>
-
-#include <string.h>
-#include <stdint.h>//uintx_t
-#include <sys/stat.h>
-#include <stdio.h>//rename
-
-#include <oblibs/obgetopt.h>
 #include <oblibs/log.h>
-#include <oblibs/types.h>
-#include <oblibs/directory.h>
-#include <oblibs/files.h>
-#include <oblibs/string.h>
-#include <oblibs/sastr.h>
-
-#include <skalibs/stralloc.h>
-#include <skalibs/djbunix.h>
-#include <skalibs/bytestr.h>//byte_count
-#include <skalibs/posixplz.h>//unlink_void
-
-#include <66/config.h>
-#include <66/utils.h>
-#include <66/constants.h>
-#include <66/db.h>
-#include <66/enum.h>
-#include <66/state.h>
-#include <66/resolve.h>
-
-#include <s6/supervise.h>
-#include <s6-rc/s6rc-servicedir.h>
-#include <s6-rc/s6rc-constants.h>
-
-#define USAGE "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -n|R ] [ -a|d ] [ -c ] [ -S after_tree ] [ -E|D ] [ -C clone ] tree"
-
-static char const *cleantree = 0 ;
-
-static inline void info_help (void)
-{
-    DEFAULT_MSG = 0 ;
-
-    static char const *help =
-"\n"
-"options :\n"
-"   -h: print this help\n"
-"   -z: use color\n"
-"   -v: increase/decrease verbosity\n"
-"   -n: create a new empty tree\n"
-"   -a: allow user(s) at tree\n"
-"   -d: deny user(s) at tree\n"
-"   -c: set tree as default\n"
-"   -S: start the tree after after_tree\n"
-"   -E: enable the tree\n"
-"   -D: disable the tree\n"
-"   -R: remove the tree\n"
-"   -C: clone the tree\n"
-;
-
-    log_info(USAGE,"\n",help) ;
-}
-
-static void cleanup(void)
-{
-    log_flow() ;
-
-    if (cleantree)
-    {
-        log_trace("removing: ",cleantree,"...") ;
-        rm_rf(cleantree) ;
-    }
-}
-
-static void auto_string(char *strings,char const *str,size_t baselen)
-{
-    log_flow() ;
-
-    size_t slen = strlen(str) ;
-    memcpy(strings + baselen,str,slen) ;
-    strings[baselen+slen] = 0 ;
-}
-
-static void auto_dir(char const *dst,mode_t mode)
-{
-    log_flow() ;
-
-    log_trace("create directory: ",dst) ;
-    if (!dir_create_parent(dst,mode))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create directory: ",dst) ;
-}
 
-static void auto_create(char *strings,char const *str,size_t baselen,mode_t mode)
-{
-    log_flow() ;
-
-    auto_string(strings,str,baselen) ;
-    auto_dir(strings,mode) ;
-}
-
-static void auto_check(char *dst,char const *str,size_t baselen,mode_t mode)
-{
-    log_flow() ;
-
-    auto_string(dst,str,baselen) ;
-    if (!scan_mode(dst,mode)) auto_dir(dst,0755) ;
-}
-
-static void auto_check_one(char *dst,mode_t mode)
-{
-    log_flow() ;
-
-    if (!scan_mode(dst,mode)) auto_dir(dst,0755) ;
-}
-
-static void inline auto_stralloc(stralloc *sa,char const *str)
-{
-    log_flow() ;
-
-    if (!stralloc_cats(sa,str)) log_die_nomem("stralloc") ;
-}
-
-static void inline auto_stralloc0(stralloc *sa)
-{
-    log_flow() ;
-
-    if (!stralloc_0(sa)) log_die_nomem("stralloc") ;
-    sa->len-- ;
-}
-
-static void inline auto_stralloc_0(stralloc *sa,char const *str)
-{
-    log_flow() ;
-
-    auto_stralloc(sa,str) ;
-    auto_stralloc0(sa) ;
-}
-
-int sanitize_tree(stralloc *dstree, char const *base, char const *tree,uid_t owner)
-{
-    log_flow() ;
-
-    ssize_t r ;
-    size_t baselen = strlen(base) ;
-    size_t treelen = strlen(tree) ;
-    char dst[baselen + SS_SYSTEM_LEN + 1 + treelen + 1] ;
-    auto_string(dst,base,0) ;
-
-    /** base is /var/lib/66 or $HOME/.66*/
-    /** this verification is made in case of
-     * first use of 66-*** tools */
-    auto_check(dst,SS_SYSTEM,baselen,0755) ;
-    /** create extra directory for service part */
-    if (!owner)
-    {
-        auto_check_one(SS_LOGGER_SYSDIR,0755) ;
-        auto_check_one(SS_SERVICE_SYSDIR,0755) ;
-        auto_check_one(SS_SERVICE_ADMDIR,0755) ;
-        auto_check_one(SS_SERVICE_ADMCONFDIR,0755) ;
-        auto_check_one(SS_MODULE_SYSDIR,0755) ;
-        auto_check_one(SS_MODULE_ADMDIR,0755) ;
-        auto_check_one(SS_SCRIPT_SYSDIR,0755) ;
-    }
-    else
-    {
-        size_t extralen ;
-        stralloc extra = STRALLOC_ZERO ;
-        if (!set_ownerhome(&extra,owner))
-            log_dieusys(LOG_EXIT_SYS,"set home directory") ;
-
-        extralen = extra.len ;
-        auto_stralloc(&extra,SS_USER_DIR) ;
-        auto_stralloc_0(&extra,SS_SYSTEM) ;
-        auto_check_one(extra.s,0755) ;
-        extra.len = extralen ;
-        auto_stralloc_0(&extra,SS_LOGGER_USERDIR) ;
-        auto_check_one(extra.s,0755) ;
-        extra.len = extralen ;
-        auto_stralloc_0(&extra,SS_SERVICE_USERDIR) ;
-        auto_check_one(extra.s,0755) ;
-        extra.len = extralen ;
-        auto_stralloc_0(&extra,SS_SERVICE_USERCONFDIR) ;
-        auto_check_one(extra.s,0755) ;
-        extra.len = extralen ;
-        auto_stralloc_0(&extra,SS_MODULE_USERDIR) ;
-        auto_check_one(extra.s,0755) ;
-        extra.len = extralen ;
-        auto_stralloc_0(&extra,SS_SCRIPT_USERDIR) ;
-        auto_check_one(extra.s,0755) ;
-        stralloc_free(&extra) ;
-    }
-
-    auto_check(dst,SS_TREE_CURRENT,baselen,0755) ;
-    auto_string(dst,SS_SYSTEM,baselen) ;
-    auto_check(dst,SS_BACKUP,baselen + SS_SYSTEM_LEN,0755) ;
-    auto_string(dst,SS_STATE,baselen + SS_SYSTEM_LEN) ;
-    if (!scan_mode(dst,S_IFREG))
-    {
-        auto_string(dst,SS_SYSTEM,baselen) ;
-        if(!file_create_empty(dst,SS_STATE + 1,0644))
-            log_dieusys(LOG_EXIT_SYS,"create ",dst,SS_STATE) ;
-    }
-    auto_string(dst,"/",baselen + SS_SYSTEM_LEN) ;
-    auto_string(dst,tree,baselen + SS_SYSTEM_LEN + 1) ;
-    r = scan_mode(dst,S_IFDIR) ;
-    if (r == -1) log_die(LOG_EXIT_SYS,"invalid directory: ",dst) ;
-    /** we have one, keep it*/
-    if (!stralloc_cats(dstree,dst)) log_die_nomem("stralloc") ;
-    if (!stralloc_0(dstree)) log_die_nomem("stralloc") ;
-
-    if (!r) return 0 ;
-
-    return 1 ;
-}
-
-void create_tree(char const *tree,char const *treename)
-{
-    log_flow() ;
-
-    size_t newlen = 0 ;
-    size_t treelen = strlen(tree) ;
-
-    char dst[treelen + SS_SVDIRS_LEN + SS_DB_LEN + SS_SRC_LEN + 16 + 1] ;
-    ss_resolve_t res = RESOLVE_ZERO ;
-    ss_resolve_init(&res) ;
-
-    memcpy(dst, tree, treelen) ;
-    newlen = treelen ;
-    dst[newlen] = 0 ;
-
-    res.name = ss_resolve_add_string(&res,SS_MASTER+1) ;
-    res.description = ss_resolve_add_string(&res,"inner bundle - do not use it") ;
-    res.tree = ss_resolve_add_string(&res,dst) ;
-    res.treename = ss_resolve_add_string(&res,treename) ;
-    res.type = TYPE_BUNDLE ;
-    res.disen = 1 ;
-
-    auto_create(dst,SS_SVDIRS,newlen,0755) ;
-    auto_create(dst,SS_RULES,newlen,0755) ;
-    auto_string(dst,SS_SVDIRS,newlen) ;
-    newlen = newlen + SS_SVDIRS_LEN ;
-    auto_create(dst,SS_DB,newlen,0755) ;
-    auto_create(dst,SS_SVC,newlen,0755) ;
-    auto_create(dst,SS_RESOLVE,newlen,0755) ;
-    dst[newlen] = 0 ;
-    log_trace("write resolve file of inner bundle") ;
-    if (!ss_resolve_write(&res,dst,SS_MASTER+1))
-    {
-        ss_resolve_free(&res) ;
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ;
-    }
-    ss_resolve_free(&res) ;
-
-    char sym[newlen + 1 + SS_SYM_SVC_LEN + 1] ;
-    char dstsym[newlen + SS_SVC_LEN + 1] ;
-
-    auto_string(sym,dst,0) ;
-    auto_string(sym,"/",newlen) ;
-    auto_string(sym,SS_SYM_SVC,newlen + 1) ;
-
-    auto_string(dstsym,dst,0) ;
-    auto_string(dstsym,SS_SVC,newlen) ;
-    log_trace("point symlink: ",sym," to ",dstsym) ;
-    if (symlink(dstsym,sym) < 0)
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ;
-
-    auto_string(sym,SS_SYM_DB,newlen + 1) ;
-    auto_string(dstsym,SS_DB,newlen) ;
-    log_trace("point symlink: ",sym," to ",dstsym) ;
-    if (symlink(dstsym,sym) < 0)
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ;
-
-    auto_string(dst,SS_DB,newlen) ;
-    newlen = newlen + SS_DB_LEN ;
-    auto_create(dst,SS_SRC,newlen,0755) ;
-    auto_string(dst,SS_SRC,newlen) ;
-    newlen = newlen + SS_SRC_LEN ;
-    auto_create(dst,SS_MASTER,newlen,0755) ;
-    auto_string(dst,SS_MASTER,newlen) ;
-    newlen = newlen + SS_MASTER_LEN ;
-    log_trace("create file: ",dst,"/contents") ;
-    if (!file_create_empty(dst,"contents",0644))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create: ",dst,"/contents") ;
-
-    auto_string(dst,"/type",newlen) ;
-    log_trace("create file: ",dst) ;
-    if(!openwritenclose_unsafe(dst,"bundle\n",7))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write: ",dst) ;
-
-
-}
-
-void create_backupdir(char const *base, char const *treename)
-{
-    log_flow() ;
-
-    int r ;
-
-    size_t baselen = strlen(base) - 1 ;//remove the last slash
-    size_t treenamelen = strlen(treename) ;
-
-    char treetmp[baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ;
-
-    auto_string(treetmp,base,0) ;
-    auto_string(treetmp,"/",baselen) ;
-    auto_string(treetmp,SS_SYSTEM,baselen + 1) ;
-    auto_string(treetmp,SS_BACKUP,baselen + 1 + SS_SYSTEM_LEN) ;
-    auto_string(treetmp,"/",baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN) ;
-    auto_string(treetmp,treename,baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1) ;
-
-    r = scan_mode(treetmp,S_IFDIR) ;
-    if (r || (r == -1))
-    {
-        log_trace("remove existing backup: ",treetmp) ;
-        if (rm_rf(treetmp) < 0)
-            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"remove: ",treetmp) ;
-    }
-    if (!r) auto_dir(treetmp,0755) ;
-}
-
-/** @what -> 0 deny
- * @what -> 1 allow */
-void set_rules(char const *tree,uid_t *uids, size_t uidn,uint8_t what)
-{
-    log_flow() ;
-
-    log_trace("set ", !what ? "denied" : "allowed"," user for tree: ",tree,"..." ) ;
-
-    int r ;
-    size_t treelen = strlen(tree) ;
-
-    char pack[256] ;
-    char tmp[treelen + SS_RULES_LEN + 1] ;
-
-    auto_string(tmp,tree,0) ;
-    auto_string(tmp,SS_RULES,treelen) ;
-
-    if (!uidn && what)
-    {
-        uids[0] = 1 ;
-        uids[1] = MYUID ;
-        uidn++ ;
-    }
-    if (what) //allow
-    {
-        for (size_t i = 0 ; i < uidn ; i++)
-        {
-            uint32_pack(pack,uids[i+1]) ;
-            pack[uint_fmt(pack,uids[i+1])] = 0 ;
-            log_trace("create file: ",pack," at ",tmp) ;
-            if(!file_create_empty(tmp,pack,0644) && errno != EEXIST)
-                log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ;
-
-            log_trace("user: ",pack," is allowed for tree: ",tree) ;
-        }
-        return ;
-    }
-    //else deny
-    for (size_t i = 0 ; i < uidn ; i++)
-    {
-        if (MYUID == uids[i+1]) continue ;
-        uint32_pack(pack,uids[i+1]) ;
-        pack[uint_fmt(pack,uids[i+1])] = 0 ;
-        char ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[i+1]) + 1] ;
-        memcpy(ut,tmp,treelen + SS_RULES_LEN) ;
-        memcpy(ut + treelen + SS_RULES_LEN,"/",1) ;
-        memcpy(ut + treelen + SS_RULES_LEN + 1,pack,uint_fmt(pack,uids[i+1])) ;
-        ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[i + 1])] = 0 ;
-        r = scan_mode(tmp,S_IFREG) ;
-        if (r == 1)
-        {
-            log_trace("unlink: ",ut) ;
-            r = unlink(ut) ;
-            if (r == -1)
-                log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ;
-        }
-        log_trace("user: ",pack," is denied for tree: ",tree) ;
-    }
-}
-
-/** @action -> 0 disable
- * @action -> 1 enable */
-void tree_enable_disable(char const *base, char const *dst, char const *tree,uint8_t action)
-{
-    log_flow() ;
-
-    int r ;
-    log_trace(!action ? "disable " : "enable ",dst,"...") ;
-    r  = tree_cmd_state(VERBOSITY,!action ? "-d" : "-a", tree) ;
-    if (!r) log_dieusys(LOG_EXIT_SYS,!action ? "disable: " : "enable: ",dst," at: ",base,SS_SYSTEM,SS_STATE) ;
-    else if (r == 1)
-    {
-        log_info(!action ? "Disabled" : "Enabled"," successfully tree: ",tree) ;
-    }
-    else log_info("Already ",!action ? "disabled" : "enabled"," tree: ",tree) ;
-
-}
-
-void tree_modify_resolve(ss_resolve_t *res,ss_resolve_enum_t field,char const *regex,char const *by)
-{
-    log_flow() ;
-
-    stralloc sa = STRALLOC_ZERO ;
-    ss_resolve_t modif = RESOLVE_ZERO ;
-
-    log_trace("modify field: ",ss_resolve_field_table[field].field," of service: ",res->sa.s + res->name) ;
-
-    if (!ss_resolve_copy(&modif,res))
-        log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ", res->sa.s + res->name) ;
-
-    if (!ss_resolve_put_field_to_sa(&sa,&modif, field))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get copy field: ",ss_resolve_field_table[field].field) ;
-
-    if (sa.len) {
-        if (!sastr_replace(&sa,regex,by))
-            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"replace field: ",ss_resolve_field_table[field].field) ;
-
-        if (!stralloc_0(&sa))
-            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"stralloc") ;
-
-        sa.len-- ;
-    }
-
-    if (!ss_resolve_modify_field(&modif,field,sa.s))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"modify field: ",ss_resolve_field_table[field].field) ;
-
-    if (!ss_resolve_copy(res,&modif))
-        log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ",res->sa.s + res->name) ;
-
-    stralloc_free(&sa) ;
-
-    ss_resolve_free(&modif) ;
-}
-
-void tree_remove(char const *base,char const *dst,char const *tree)
-{
-    log_flow() ;
-
-    log_trace("delete: ",dst,"..." ) ;
-
-    int r ;
-
-    if (rm_rf(dst) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ", dst) ;
-
-    size_t treelen = strlen(tree) ;
-    size_t baselen = strlen(base) ;
-    char treetmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treelen  + 1] ;
-    auto_string(treetmp,base,0) ;
-    auto_string(treetmp,SS_SYSTEM,baselen) ;
-    auto_string(treetmp,SS_BACKUP,baselen + SS_SYSTEM_LEN) ;
-    auto_string(treetmp,"/",baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN) ;
-    auto_string(treetmp,tree,baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1) ;
-
-    r = scan_mode(treetmp,S_IFDIR) ;
-    if (r || (r < 0))
-    {
-        log_trace("delete backup of tree: ",treetmp,"...") ;
-        if (rm_rf(treetmp) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ",treetmp) ;
-    }
-
-    tree_enable_disable(base,dst,tree,0) ;
-
-    log_info("Deleted successfully: ",tree) ;
-}
+#include <66/ssexec.h>
 
 int main(int argc, char const *const *argv,char const *const *envp)
 {
-    int r, current, create, allow, deny, enable, disable, remove, snap ;
-
-    uid_t owner ;
-
-    size_t auidn = 0 ;
-    uid_t auids[256] = { 0 } ;
-
-    size_t duidn = 0 ;
-    uid_t duids[256] = { 0 } ;
-
-    char const *tree = 0 ;
-    char const *after_tree = 0 ;
-
-    stralloc base = STRALLOC_ZERO ;
-    stralloc dstree = STRALLOC_ZERO ;
-    stralloc clone = STRALLOC_ZERO ;
-
-    log_color = &log_color_disable ;
-
-    current = create = allow = deny = enable = disable = remove = snap = 0 ;
-
     PROG = "66-tree" ;
-    {
-        subgetopt l = SUBGETOPT_ZERO ;
-
-        for (;;)
-        {
-            int opt = getopt_args(argc,argv, "hv:na:d:cS:EDRC:z", &l) ;
-            if (opt == -1) break ;
-            if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ;
-            switch (opt)
-            {
-                case 'h' :  info_help(); return 0 ;
-                case 'v' :  if (!uint0_scan(l.arg, &VERBOSITY)) log_usage(USAGE) ; break ;
-                case 'n' :  create = 1 ; break ;
-                case 'a' :  if (!scan_uidlist_wdelim(l.arg,auids,',')) log_usage(USAGE) ;
-                            auidn = auids[0] ;
-                            allow = 1 ;
-                            break ;
-                case 'd' :  if (!scan_uidlist_wdelim(l.arg,duids,',')) log_usage(USAGE) ;
-                            duidn = duids[0] ;
-                            deny = 1 ;
-                            break ;
-                case 'c' :  current = 1 ; break ;
-                case 'S' :  after_tree = l.arg ; break ;
-                case 'E' :  enable = 1 ; if (disable) log_usage(USAGE) ; break ;
-                case 'D' :  disable = 1 ; if (enable) log_usage (USAGE) ; break ;
-                case 'R' :  remove = 1 ; if (create) log_usage(USAGE) ; break ;
-                case 'C' :  if (remove) log_usage(USAGE) ;
-                            if (!stralloc_cats(&clone,l.arg)) log_die_nomem("stralloc") ;
-                            if (!stralloc_0(&clone)) log_die_nomem("stralloc") ;
-                            snap = 1 ;
-                            break ;
-                case 'z' :  log_color = !isatty(1) ? &log_color_disable : &log_color_enable ; break ;
-                default :   log_usage(USAGE) ;
-            }
-        }
-        argc -= l.ind ; argv += l.ind ;
-    }
-
-    if (argc != 1) log_usage(USAGE) ;
-
-    tree = argv[0] ;
-    owner = MYUID ;
-
-    if (!set_ownersysdir(&base, owner)) log_dieusys(LOG_EXIT_SYS,"set owner directory") ;
-
-    log_trace("sanitize ",tree,"..." ) ;
-    r = sanitize_tree(&dstree,base.s,tree,owner) ;
-
-    if(!r && create)
-    {
-        /** set cleanup */
-        cleantree = dstree.s ;
-        log_trace("creating: ",dstree.s,"..." ) ;
-        create_tree(dstree.s,tree) ;
-
-        log_trace("creating backup directory for: ", tree,"...") ;
-        create_backupdir(base.s,tree) ;
-        /** unset cleanup */
-        cleantree = 0 ;
-
-        log_trace("set permissions rules for: ",dstree.s,"..." ) ;
-            set_rules(dstree.s,auids,auidn,1) ;
-
-        size_t dblen = dstree.len - 1 ;
-        char newdb[dblen + SS_SVDIRS_LEN + 1] ;
-        auto_string(newdb,dstree.s,0) ;
-        auto_string(newdb,SS_SVDIRS,dblen) ;
-
-        log_trace("compile: ",newdb,"/db/",tree,"..." ) ;
-        if (!db_compile(newdb,dstree.s,tree,envp))
-            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"compile ",newdb,"/db/",tree) ;
-
-        r = 1 ;
-        create = 0 ;
-        log_info("Created successfully tree: ",tree) ;
-    }
-
-    if ((!r && !create) || (!r && enable)) log_dieusys(LOG_EXIT_SYS,"find tree: ",dstree.s) ;
-    if (r && create) log_dieu(LOG_EXIT_USER,"create: ",dstree.s,": already exist") ;
-
-    if (enable)
-        tree_enable_disable(base.s,dstree.s,tree,1) ;
-
-    if (disable)
-        tree_enable_disable(base.s,dstree.s,tree,0) ;
-
-    if (auidn)
-        set_rules(dstree.s,auids,auidn,1) ;
-
-    if (duidn)
-        set_rules(dstree.s,duids,duidn,0) ;
-
-    if(current)
-    {
-        log_trace("make: ",dstree.s," as default ..." ) ;
-        if (!tree_switch_current(base.s,tree)) log_dieusys(LOG_EXIT_SYS,"set: ",dstree.s," as default") ;
-        log_info("Set successfully: ",tree," as default") ;
-    }
-
-    if (remove)
-        tree_remove(base.s,dstree.s,tree) ;
-
-    if (snap)
-    {
-        stralloc salist = STRALLOC_ZERO ;
-        ss_resolve_t res = RESOLVE_ZERO ;
-
-        size_t syslen = base.len + SS_SYSTEM_LEN ;
-        size_t treelen = strlen(tree) ;
-        size_t pos = 0 ;
-
-        char system[syslen + 1] ;
-        auto_strings(system,base.s,SS_SYSTEM) ;
-
-        size_t clone_target_len = syslen + 1 + clone.len ;
-        char clone_target[clone_target_len + 1] ;
-        auto_strings(clone_target,system,"/",clone.s) ;
-
-        r = scan_mode(clone_target,S_IFDIR) ;
-        if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ;
-
-        // clone main directory
-        log_trace("clone: ",tree," as: ",clone.s,"..." ) ;
-        if (!hiercopy(dstree.s,clone_target))
-            log_dieusys(LOG_EXIT_SYS,"copy: ",dstree.s," to: ",clone_target) ;
-
-        // clone backup directory
-        size_t clone_backup_len = syslen + SS_BACKUP_LEN + 1 + clone.len ;
-        char clone_backup[clone_backup_len + 1] ;
-        auto_strings(clone_backup,system,SS_BACKUP,"/",clone.s) ;
-
-        char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ;
-        auto_strings(tree_backup,system,SS_BACKUP,"/",tree) ;
-
-        /* make cleantree pointing to the clone to be able to remove it
-         * in case of crach */
-        cleantree = clone_target ;
-
-        log_trace("clone backup of: ",tree," as: ",clone.s,"..." ) ;
-        if (!hiercopy(tree_backup,clone_backup))
-            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tree_backup," to: ",clone_backup) ;
-
-        // modify the resolve file to match the new name
-        // main directory first
-        char src_resolve[clone_target_len + SS_SVDIRS_LEN + SS_RESOLVE_LEN + 1] ;
-        auto_strings(src_resolve,clone_target,SS_SVDIRS,SS_RESOLVE) ;
-
-        if (!sastr_dir_get(&salist,src_resolve,"",S_IFREG))
-            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ;
-
-        char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ;
-        auto_strings(clone_res,clone_target,SS_SVDIRS) ;
-
-        for (;pos < salist.len ; pos += strlen(salist.s + pos) + 1)
-        {
-            char *name = salist.s + pos ;
-
-            if (!ss_resolve_read(&res,clone_res,name))
-                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ;
-
-            tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ;
-            tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ;
-            tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ;
-            tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ;
-
-            if (!ss_resolve_write(&res,clone_res,name))
-                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ;
-        }
-
-        // rename db
-        char clone_db_old[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + treelen + 1] ;
-        auto_strings(clone_db_old,clone_target,SS_SVDIRS,SS_DB,"/",tree) ;
-
-        char clone_db_new[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + clone.len + 1] ;
-        auto_strings(clone_db_new,clone_target,SS_SVDIRS,SS_DB,"/",clone.s) ;
-
-        log_trace("rename tree db: ",tree," as: ",clone.s,"..." ) ;
-        if (rename(clone_db_old,clone_db_new) == -1)
-            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_old," to: ",clone_db_new) ;
-
-        // backup directory
-        char src_resolve_backup[clone_backup_len + SS_RESOLVE_LEN + 1] ;
-        auto_strings(src_resolve_backup,clone_backup,SS_RESOLVE) ;
-
-        salist.len = 0 ;
-
-        /** main and backup can be different,so rebuild the list
-         * Also, a backup directory can be empty, check it first */
-        r = scan_mode(src_resolve_backup,S_IFDIR) ;
-        if (r == 1)
-        {
-            if (!sastr_dir_get(&salist,src_resolve_backup,"",S_IFREG))
-                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ;
-
-            for (pos = 0 ; pos < salist.len ; pos += strlen(salist.s + pos) + 1)
-            {
-                char *name = salist.s + pos ;
-
-                if (!ss_resolve_read(&res,clone_backup,name))
-                    log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ;
-
-                tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ;
-                tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ;
-                tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ;
-                tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ;
-
-                if (!ss_resolve_write(&res,clone_backup,name))
-                    log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ;
-            }
-            // rename db
-            char clone_db_backup_old[clone_backup_len + SS_DB_LEN + 1 + treelen + 1] ;
-            auto_strings(clone_db_backup_old,clone_backup,SS_DB,"/",tree) ;
-
-            char clone_db_backup_new[clone_backup_len + SS_DB_LEN + 1 + clone.len + 1] ;
-            auto_strings(clone_db_backup_new,clone_backup,SS_DB,"/",clone.s) ;
-
-            log_trace("rename tree backup db: ",tree," as: ",clone.s,"..." ) ;
-            if (rename(clone_db_backup_old,clone_db_backup_new) == -1)
-                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_backup_old," to: ",clone_db_backup_new) ;
-        }
-
-        stralloc_free(&salist) ;
-        ss_resolve_free(&res) ;
-
-        log_info("Cloned successfully: ",tree," to ",clone.s) ;
-    }
-
-    if (after_tree)
-    {
-        stralloc contents = STRALLOC_ZERO ;
-        stralloc tmp = STRALLOC_ZERO ;
-        int befirst = obstr_equal(tree,after_tree) ;
-        size_t baselen = base.len, pos = 0 ;
-        char ste[baselen + SS_SYSTEM_LEN + 1] ;
-        auto_strings(ste,base.s,SS_SYSTEM) ;
-
-        int enabled = tree_cmd_state(VERBOSITY,"-s",tree) ;
-        if (enabled != 1)
-            log_die(LOG_EXIT_USER,"tree: ",tree," is not enabled") ;
-
-        enabled = tree_cmd_state(VERBOSITY,"-s",after_tree) ;
-        if (enabled != 1)
-            log_die(LOG_EXIT_USER,"tree: ",after_tree," is not enabled") ;
-
-        r  = tree_cmd_state(VERBOSITY,"-d",tree) ;
-        if (!r) log_dieusys(LOG_EXIT_SYS,"disable: ",tree," at: ",ste,SS_STATE) ;
-
-        r = file_readputsa(&tmp,ste,SS_STATE + 1) ;
-        if(!r) log_dieusys(LOG_EXIT_SYS,"open: ", ste,SS_STATE) ;
-
-        /** if you have only one tree enabled, the state file will be
-         * empty because we disable it before reading the file(see line 803).
-         * This will make a crash at sastr_? call.
-         * So write directly the name of the tree at state file. */
-
-        if (tmp.len)
-        {
-            if (!sastr_rebuild_in_oneline(&tmp) ||
-            !sastr_clean_element(&tmp))
-                log_dieu(LOG_EXIT_SYS,"rebuild state list") ;
-
-            for (pos = 0 ;pos < tmp.len; pos += strlen(tmp.s + pos) + 1)
-            {
-                char *name = tmp.s + pos ;
-
-                /* e.g 66-tree -S root root -> meaning root need to
-                 * be the first to start */
-                if ((befirst) && (pos == 0))
-                {
-                    if (!auto_stra(&contents,tree,"\n"))
-                        log_dieusys(LOG_EXIT_SYS,"stralloc") ;
-                }
-                if (!auto_stra(&contents,name,"\n"))
-                    log_dieusys(LOG_EXIT_SYS,"stralloc") ;
-
-                if (obstr_equal(name,after_tree))
-                {
-                    if (!auto_stra(&contents,tree,"\n"))
-                        log_dieusys(LOG_EXIT_SYS,"stralloc") ;
-                }
-            }
-        }
-        else
-        {
-            if (!auto_stra(&contents,tree,"\n"))
-                log_dieusys(LOG_EXIT_SYS,"stralloc") ;
-        }
 
-        if (!file_write_unsafe(ste,SS_STATE + 1,contents.s,contents.len))
-            log_dieusys(LOG_EXIT_ZERO,"write: ",ste,SS_STATE) ;
+    ssexec_t info = SSEXEC_ZERO ;
 
-        log_info("Ordered successfully: ",tree," starts after tree: ",after_tree) ;
-    }
+    info.prog = PROG ;
+    info.help = help_tree ;
+    info.usage = usage_tree ;
 
-    stralloc_free(&base) ;
-    stralloc_free(&dstree) ;
-    stralloc_free(&clone) ;
+    info.skip_opt_tree = 1 ;
 
-    return 0 ;
+    return ssexec_main(argc,argv,envp,&ssexec_tree,&info) ;
 }
diff --git a/src/include/66/ssexec.h b/src/include/66/ssexec.h
index 0bb4c40139ded232eae578ebbda92e118096cf2f..41fd8e85f582f210c15113d3c3270c2eae763ce1 100644
--- a/src/include/66/ssexec.h
+++ b/src/include/66/ssexec.h
@@ -40,7 +40,7 @@ struct ssexec_s
     uint8_t opt_timeout ;
     uint8_t opt_color ;
     // skip option definition 0->no,1-yes
-    uint8_t skip_opt_tree ; // tree,treename, treeallow and the permissions for the tree will be not set
+    uint8_t skip_opt_tree ; // tree,treename, treeallow will not be set. Also, trees permissions is not checked.
 } ;
 
 #define SSEXEC_ZERO {   .base = STRALLOC_ZERO , \
@@ -78,6 +78,7 @@ extern ssexec_func_t ssexec_svctl ;
 extern ssexec_func_t ssexec_dbctl ;
 extern ssexec_func_t ssexec_env ;
 extern ssexec_func_t ssexec_all ;
+extern ssexec_func_t ssexec_tree ;
 
 extern char const *usage_enable ;
 extern char const *help_enable ;
@@ -97,6 +98,8 @@ extern char const *usage_env ;
 extern char const *help_env ;
 extern char const *usage_all ;
 extern char const *help_all ;
+extern char const *usage_tree ;
+extern char const *help_tree ;
 
 #define OPTS_INIT "cdb"
 #define OPTS_INIT_LEN (sizeof OPTS_INIT - 1)
@@ -116,7 +119,11 @@ extern char const *help_all ;
 #define OPTS_ENV_LEN (sizeof OPTS_ENV - 1)
 #define OPTS_ALL "f"
 #define OPTS_ALL_LEN (sizeof OPTS_ALL - 1)
+#define OPTS_TREE "na:d:cS:EDRC:"
+#define OPTS_TREE_LEN (sizeof OPTS_TREE - 1)
 
 extern int ssexec_main(int argc, char const *const *argv, char const *const *envp,ssexec_func_t *func,ssexec_t *info) ;
+extern void ssexec_set_info(ssexec_t *info) ;
+extern int ssexec_set_treeinfo(ssexec_t *info) ;
 
 #endif
diff --git a/src/lib66/ssexec_help.c b/src/lib66/ssexec_help.c
index 3cca0ddd4a80216cabc60dfa440455a62f681dc2..1b806111241e49ead453b438f1eaf8aa92eb22a0 100644
--- a/src/lib66/ssexec_help.c
+++ b/src/lib66/ssexec_help.c
@@ -154,3 +154,28 @@ char const *help_all =
 "   -t: tree to use\n"
 "   -f: fork the process\n"
 ;
+
+char const *usage_tree = "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -n|R ] [ -a|d ] [ -c ] [ -o depends=:requiredby= ] [ -E|D ] [ -C clone ] tree" ;
+
+char const *help_tree =
+"\n"
+"options :\n"
+"   -h: print this help\n"
+"   -z: use color\n"
+"   -v: increase/decrease verbosity\n"
+"   -n: create a new empty tree\n"
+"   -R: remove the tree\n"
+"   -a: allow user(s) at tree\n"
+"   -d: deny user(s) at tree\n"
+"   -c: set tree as default\n"
+"   -o: colon separated list of dependencies\n"
+"   -E: enable the tree\n"
+"   -D: disable the tree\n"
+"   -C: clone the tree\n"
+
+"\n"
+"valid fields for -o options are:\n"
+"\n"
+"   depends=: comma separated list of dependencies for tree\n"
+"   requiredby=: comma separated list of trees required by tree\n"
+;
diff --git a/src/lib66/ssexec_tree.c b/src/lib66/ssexec_tree.c
new file mode 100644
index 0000000000000000000000000000000000000000..07fe56e2dac7115d56c5b05ee5db75ef64167570
--- /dev/null
+++ b/src/lib66/ssexec_tree.c
@@ -0,0 +1,864 @@
+/*
+ * ssexec_tree.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 <66/tree.h>
+
+#include <string.h>
+#include <stdint.h>//uintx_t
+#include <sys/stat.h>
+#include <stdio.h>//rename
+#include <pwd.h>
+
+#include <oblibs/obgetopt.h>
+#include <oblibs/log.h>
+#include <oblibs/types.h>
+#include <oblibs/directory.h>
+#include <oblibs/files.h>
+#include <oblibs/string.h>
+#include <oblibs/sastr.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/bytestr.h>//byte_count
+#include <skalibs/posixplz.h>//unlink_void
+
+#include <66/config.h>
+#include <66/utils.h>
+#include <66/constants.h>
+#include <66/db.h>
+#include <66/enum.h>
+#include <66/state.h>
+#include <66/resolve.h>
+
+#include <s6/supervise.h>
+#include <s6-rc/s6rc-servicedir.h>
+#include <s6-rc/s6rc-constants.h>
+
+
+/**
+ *
+ *
+ *
+ *
+ * create > option by default
+ *
+ * -o depends=boot,system:requiredby=graphics
+ *
+ * depends/requiredby automatically enable the trees found at field except for boot
+ *
+ * -S options dissappear but it kept as it with a warn to user for the compatibility.
+ *
+ * -G for groups
+ *
+ *
+ * -a user,root. Actuellement user n'est pas compris.faire comme dans le parser_utils.
+ *
+ * */
+
+static char const *cleantree = 0 ;
+
+static void cleanup(void)
+{
+    log_flow() ;
+
+    if (cleantree) {
+
+        log_trace("removing: ",cleantree,"...") ;
+        rm_rf(cleantree) ;
+    }
+}
+
+static void auto_dir(char const *dst,mode_t mode)
+{
+    log_flow() ;
+
+    log_trace("create directory: ",dst) ;
+    if (!dir_create_parent(dst,mode))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create directory: ",dst) ;
+}
+
+static void auto_create(char *strings,char const *str, size_t len)
+{
+    log_flow() ;
+
+    auto_strings(strings + len, str) ;
+    auto_dir(strings,0755) ;
+}
+
+static void auto_check(char *dst)
+{
+    log_flow() ;
+
+    int r = scan_mode(dst,S_IFDIR) ;
+
+    if (r == -1)
+        log_diesys_nclean(LOG_EXIT_SYS, &cleanup, "conflicting format for: ", dst) ;
+
+    if (!r)
+        auto_dir(dst,0755) ;
+}
+
+static void inline auto_stralloc(stralloc *sa,char const *str)
+{
+    log_flow() ;
+
+    if (!auto_stra(sa,str))
+        log_die_nomem("stralloc") ;
+}
+
+//int sanitize_tree(stralloc *dstree, char const *base, char const *tree,uid_t owner)
+int sanitize_tree(ssexec_t *info, char const *tree)
+{
+    log_flow() ;
+
+    ssize_t r ;
+    size_t baselen = info->base.len ;
+    size_t treelen = strlen(tree) ;
+    uid_t log_uid ;
+    gid_t log_gid ;
+    char dst[baselen + SS_SYSTEM_LEN + 1 + treelen + 1] ;
+    auto_strings(dst,info->base.s, SS_SYSTEM) ;
+
+    /** base is /var/lib/66 or $HOME/.66*/
+    /** this verification is made in case of
+     * first use of 66-*** tools */
+    auto_check(dst) ;
+    /** create extra directory for service part */
+    if (!info->owner) {
+
+        auto_check(SS_LOGGER_SYSDIR) ;
+
+        if (!youruid(&log_uid,SS_LOGGER_RUNNER) ||
+        !yourgid(&log_gid,log_uid))
+            log_dieusys(LOG_EXIT_SYS,"get uid and gid of: ",SS_LOGGER_RUNNER) ;
+
+        if (chown(SS_LOGGER_SYSDIR,log_uid,log_gid) == -1)
+            log_dieusys(LOG_EXIT_SYS,"chown: ",SS_LOGGER_RUNNER) ;
+
+        auto_check(SS_SERVICE_SYSDIR) ;
+        auto_check(SS_SERVICE_ADMDIR) ;
+        auto_check(SS_SERVICE_ADMCONFDIR) ;
+        auto_check(SS_MODULE_SYSDIR) ;
+        auto_check(SS_MODULE_ADMDIR) ;
+        auto_check(SS_SCRIPT_SYSDIR) ;
+        auto_check(SS_SEED_ADMDIR) ;
+        auto_check(SS_SEED_SYSDIR) ;
+
+    } else {
+
+        size_t extralen ;
+        stralloc extra = STRALLOC_ZERO ;
+        if (!set_ownerhome(&extra,info->owner))
+            log_dieusys(LOG_EXIT_SYS,"set home directory") ;
+
+        extralen = extra.len ;
+        if (!auto_stra(&extra, SS_USER_DIR, SS_SYSTEM))
+            log_die_nomem("stralloc") ;
+        auto_check(extra.s) ;
+
+        extra.len = extralen ;
+        auto_stralloc(&extra,SS_LOGGER_USERDIR) ;
+        auto_check(extra.s) ;
+
+        extra.len = extralen ;
+        auto_stralloc(&extra,SS_SERVICE_USERDIR) ;
+        auto_check(extra.s) ;
+
+        extra.len = extralen ;
+        auto_stralloc(&extra,SS_SERVICE_USERCONFDIR) ;
+        auto_check(extra.s) ;
+
+        extra.len = extralen ;
+        auto_stralloc(&extra,SS_MODULE_USERDIR) ;
+        auto_check(extra.s) ;
+
+        extra.len = extralen ;
+        auto_stralloc(&extra,SS_SCRIPT_USERDIR) ;
+        auto_check(extra.s) ;
+
+        extra.len = extralen ;
+        auto_stralloc(&extra,SS_SEED_USERDIR) ;
+        auto_check(extra.s) ;
+
+        stralloc_free(&extra) ;
+    }
+
+    auto_strings(dst + baselen, SS_TREE_CURRENT) ;
+    auto_check(dst) ;
+    auto_strings(dst + baselen,SS_SYSTEM, SS_BACKUP) ;
+    auto_check(dst) ;
+    auto_strings(dst + baselen + SS_SYSTEM_LEN, SS_STATE) ;
+
+    if (!scan_mode(dst,S_IFREG)) {
+
+        auto_strings(dst + baselen,SS_SYSTEM) ;
+        if(!file_create_empty(dst,SS_STATE + 1,0644))
+            log_dieusys(LOG_EXIT_SYS,"create ",dst,SS_STATE) ;
+    }
+
+    auto_strings(dst + baselen + SS_SYSTEM_LEN,"/",tree) ;
+    r = scan_mode(dst,S_IFDIR) ;
+    if (r == -1) log_die(LOG_EXIT_SYS,"invalid directory: ",dst) ;
+    /** we have one, keep it*/
+    info->tree.len = 0 ;
+    if (!auto_stra(&info->tree,dst))
+        log_die_nomem("stralloc") ;
+
+    if (!r) return 0 ;
+
+    return 1 ;
+}
+
+void create_tree(ssexec_t *info)
+{
+    log_flow() ;
+
+    size_t newlen = 0 ;
+    size_t treelen = info->tree.len ;
+
+    char const *tree = info->tree.s, *treename = info->treename.s ;
+
+    char dst[treelen + SS_SVDIRS_LEN + SS_DB_LEN + SS_SRC_LEN + 16 + 1] ;
+    ss_resolve_t res = RESOLVE_ZERO ;
+    ss_resolve_init(&res) ;
+
+    auto_strings(dst, tree) ;
+    newlen = treelen ;
+
+    res.name = ss_resolve_add_string(&res,SS_MASTER+1) ;
+    res.description = ss_resolve_add_string(&res,"inner bundle - do not use it") ;
+    res.tree = ss_resolve_add_string(&res,dst) ;
+    res.treename = ss_resolve_add_string(&res,treename) ;
+    res.type = TYPE_BUNDLE ;
+    res.disen = 1 ;
+
+    auto_create(dst, SS_SVDIRS, newlen) ;
+    auto_create(dst, SS_RULES, newlen) ;
+    auto_strings(dst + newlen, SS_SVDIRS) ;
+    newlen = newlen + SS_SVDIRS_LEN ;
+    auto_create(dst, SS_DB, newlen) ;
+    auto_create(dst, SS_SVC, newlen) ;
+    auto_create(dst, SS_RESOLVE, newlen) ;
+    dst[newlen] = 0 ;
+    log_trace("write resolve file of inner bundle") ;
+    if (!ss_resolve_write(&res,dst,SS_MASTER+1)) {
+
+        ss_resolve_free(&res) ;
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ;
+    }
+    ss_resolve_free(&res) ;
+
+    char sym[newlen + 1 + SS_SYM_SVC_LEN + 1] ;
+    char dstsym[newlen + SS_SVC_LEN + 1] ;
+
+    auto_strings(sym,dst, "/", SS_SYM_SVC) ;
+    auto_strings(dstsym, dst, SS_SVC) ;
+
+    log_trace("point symlink: ",sym," to ",dstsym) ;
+    if (symlink(dstsym,sym) < 0)
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ;
+
+    auto_strings(sym + newlen + 1, SS_SYM_DB) ;
+    auto_strings(dstsym + newlen, SS_DB) ;
+
+    log_trace("point symlink: ",sym," to ",dstsym) ;
+    if (symlink(dstsym,sym) < 0)
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ;
+
+    auto_strings(dst + newlen, SS_DB) ;
+    newlen = newlen + SS_DB_LEN ;
+    auto_create(dst, SS_SRC, newlen) ;
+    auto_strings(dst + newlen, SS_SRC) ;
+    newlen = newlen + SS_SRC_LEN ;
+    auto_create(dst, SS_MASTER, newlen) ;
+    auto_strings(dst + newlen, SS_MASTER) ;
+    newlen = newlen + SS_MASTER_LEN ;
+
+    log_trace("create file: ",dst,"/contents") ;
+    if (!file_create_empty(dst,"contents",0644))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create: ",dst,"/contents") ;
+
+    auto_strings(dst + newlen,"/type") ;
+
+    log_trace("create file: ",dst) ;
+    if(!openwritenclose_unsafe(dst,"bundle\n",7))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write: ",dst) ;
+
+}
+
+void create_backupdir(ssexec_t *info)
+{
+    log_flow() ;
+
+    int r ;
+
+    size_t baselen = info->base.len ;
+    size_t treenamelen = info->treename.len ;
+
+    char const *base = info->base.s, *treename = info->treename.s ;
+
+    char treetmp[baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ;
+
+    auto_strings(treetmp, base, SS_SYSTEM, SS_BACKUP, "/", treename) ;
+
+    r = scan_mode(treetmp,S_IFDIR) ;
+    if (r || (r == -1)) {
+
+        log_trace("remove existing backup: ",treetmp) ;
+        if (rm_rf(treetmp) < 0)
+            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"remove: ",treetmp) ;
+    }
+
+    if (!r)
+        auto_dir(treetmp,0755) ;
+}
+
+void parse_uild_list(uid_t *uids, char const *str)
+{
+    size_t pos = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (!sastr_clean_string_wdelim(&sa, str, ','))
+        log_dieu(LOG_EXIT_SYS,"parse uid list") ;
+
+    uid_t owner = MYUID ;
+    /** special case, we don't know which user want to use
+     *  the service, we need a general name to allow all user
+     *  the term "user" is took here to allow the current user*/
+    ssize_t p = sastr_cmp(&sa,"user") ;
+
+    FOREACH_SASTR(&sa, pos) {
+
+        if (pos == (size_t)p) {
+
+            struct passwd *pw = getpwuid(owner);
+
+            if (!pw) {
+
+                if (!errno) errno = ESRCH ;
+                    log_dieu(LOG_EXIT_ZERO,"get user name") ;
+            }
+
+            if (!scan_uidlist(pw->pw_name, uids))
+                log_dieu(LOG_EXIT_USER,"scan account: ",pw->pw_name) ;
+
+            continue ;
+        }
+
+        if (!scan_uidlist(sa.s + pos, uids))
+            log_dieu(LOG_EXIT_USER,"scan account: ",sa.s + pos) ;
+
+    }
+}
+
+/** @what -> 0 deny
+ * @what -> 1 allow */
+void set_rules(char const *tree, uid_t *uids, uint8_t what)
+{
+    log_flow() ;
+
+    log_trace("set ", !what ? "denied" : "allowed"," user for tree: ",tree,"..." ) ;
+
+    int r ;
+    size_t treelen = strlen(tree), uidn = uids[0], pos = 0 ;
+    uid_t owner = MYUID ;
+    char pack[256] ;
+    char tmp[treelen + SS_RULES_LEN + 1] ;
+
+    auto_strings(tmp, tree, SS_RULES) ;
+
+    if (!uidn && what) {
+
+        uids[0] = 1 ;
+        uids[1] = owner ;
+        uidn++ ;
+    }
+
+    //allow
+    if (what) {
+
+        for (; pos < uidn ; pos++) {
+
+            uint32_pack(pack,uids[pos+1]) ;
+            pack[uint_fmt(pack,uids[pos+1])] = 0 ;
+            log_trace("create file: ",pack," at ",tmp) ;
+            if(!file_create_empty(tmp,pack,0644) && errno != EEXIST)
+                log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ;
+
+            log_trace("user: ",pack," is allowed for tree: ",tree) ;
+        }
+        goto announce ;
+    }
+    //else deny
+    for (pos = 0 ; pos < uidn ; pos++) {
+
+        if (owner == uids[pos+1]) continue ;
+        uint32_pack(pack,uids[pos+1]) ;
+        pack[uint_fmt(pack,uids[pos+1])] = 0 ;
+        char ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos+1]) + 1] ;
+        memcpy(ut,tmp,treelen + SS_RULES_LEN) ;
+        memcpy(ut + treelen + SS_RULES_LEN,"/",1) ;
+        memcpy(ut + treelen + SS_RULES_LEN + 1,pack,uint_fmt(pack,uids[pos+1])) ;
+        ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos + 1])] = 0 ;
+        r = scan_mode(ut,S_IFREG) ;
+        if (r == 1) {
+
+            log_trace("unlink: ",ut) ;
+            r = unlink(ut) ;
+            if (r == -1)
+                log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ;
+        }
+
+        log_trace("user: ",pack," is denied for tree: ",tree) ;
+    }
+    announce:
+    log_info("Permissions rules set successfully for tree: ",tree) ;
+}
+
+/** @action -> 0 disable
+ * @action -> 1 enable */
+void tree_enable_disable(ssexec_t *info, uint8_t action)
+{
+    log_flow() ;
+
+    int r ;
+    char const *base = info->base.s, *dst = info->tree.s , *tree = info->treename.s ;
+
+    log_trace(!action ? "disable " : "enable ",dst,"...") ;
+    r  = tree_cmd_state(VERBOSITY,!action ? "-d" : "-a", tree) ;
+    if (!r)
+
+        log_dieusys(LOG_EXIT_SYS,!action ? "disable: " : "enable: ",dst," at: ",base,SS_SYSTEM,SS_STATE) ;
+
+    else if (r == 1) {
+
+        log_info(!action ? "Disabled" : "Enabled"," successfully tree: ",tree) ;
+
+    }
+
+    else log_info("Already ",!action ? "disabled" : "enabled"," tree: ",tree) ;
+
+}
+
+void tree_modify_resolve(ss_resolve_t *res,ss_resolve_enum_t field,char const *regex,char const *by)
+{
+    log_flow() ;
+
+    stralloc sa = STRALLOC_ZERO ;
+    ss_resolve_t modif = RESOLVE_ZERO ;
+
+    log_trace("modify field: ",ss_resolve_field_table[field].field," of service: ",res->sa.s + res->name) ;
+
+    if (!ss_resolve_copy(&modif,res))
+        log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ", res->sa.s + res->name) ;
+
+    if (!ss_resolve_put_field_to_sa(&sa,&modif, field))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get copy of field: ",ss_resolve_field_table[field].field) ;
+
+    if (sa.len) {
+        if (!sastr_replace(&sa,regex,by))
+            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"replace field: ",ss_resolve_field_table[field].field) ;
+
+        if (!stralloc_0(&sa))
+            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"stralloc") ;
+
+        sa.len-- ;
+    }
+
+    if (!ss_resolve_modify_field(&modif,field,sa.s))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"modify field: ",ss_resolve_field_table[field].field) ;
+
+    if (!ss_resolve_copy(res,&modif))
+        log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ",res->sa.s + res->name) ;
+
+    stralloc_free(&sa) ;
+
+    ss_resolve_free(&modif) ;
+}
+
+void tree_remove(ssexec_t *info)
+{
+    log_flow() ;
+
+    char const *base = info->base.s, *dst = info->tree.s, *tree = info->treename.s ;
+    int r ;
+
+    log_trace("delete: ",dst,"..." ) ;
+
+    if (rm_rf(dst) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ", dst) ;
+
+    size_t treelen = strlen(tree) ;
+    size_t baselen = strlen(base) ;
+    char treetmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treelen  + 1] ;
+
+    auto_strings(treetmp, base, SS_SYSTEM, SS_BACKUP, "/", tree) ;
+
+    r = scan_mode(treetmp,S_IFDIR) ;
+    if (r || (r < 0)) {
+
+        log_trace("delete backup of tree: ",treetmp,"...") ;
+        if (rm_rf(treetmp) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ",treetmp) ;
+
+    }
+
+    tree_enable_disable(info,0) ;
+
+    log_info("Deleted successfully: ",tree) ;
+}
+
+
+#include <stdio.h>
+
+
+int ssexec_tree(int argc, char const *const *argv,char const *const *envp,ssexec_t *info)
+{
+    int r, current, create, allow, deny, enable, disable, remove, snap ;
+
+    uid_t auids[256] = { 0 }, duids[256] = { 0 } ;
+
+    char const *tree, *after_tree = 0 ;
+
+    stralloc clone = STRALLOC_ZERO ;
+
+    current = create = allow = deny = enable = disable = remove = snap = 0 ;
+
+    {
+        subgetopt l = SUBGETOPT_ZERO ;
+
+        for (;;)
+        {
+            int opt = getopt_args(argc,argv, ">" OPTS_TREE, &l) ;
+            if (opt == -1) break ;
+            if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ;
+            switch (opt)
+            {
+
+                case 'n' :  create = 1 ; break ;
+                case 'a' :  parse_uild_list(auids, l.arg) ;
+                            allow = 1 ;
+                            break ;
+                case 'd' :  parse_uild_list(duids, l.arg) ;
+                            deny = 1 ;
+                            break ;
+                case 'c' :  current = 1 ; break ;
+                case 'S' :  after_tree = l.arg ; break ;
+                case 'E' :  enable = 1 ; if (disable) log_usage(usage_tree) ; break ;
+                case 'D' :  disable = 1 ; if (enable) log_usage(usage_tree) ; break ;
+                case 'R' :  remove = 1 ; if (create) log_usage(usage_tree) ; break ;
+                case 'C' :  if (remove) log_usage(usage_tree) ;
+                            if (!auto_stra(&clone,l.arg)) log_die_nomem("stralloc") ;
+                            snap = 1 ;
+                            break ;
+                default :   log_usage(usage_tree) ;
+            }
+        }
+        argc -= l.ind ; argv += l.ind ;
+    }
+
+    if (argc < 1) log_usage(usage_tree) ;
+
+    // make create the default option
+    if (!current && !create && !allow && !deny && !enable && !disable && !remove && !snap)
+        create = 1 ;
+
+    info->treename.len = 0 ;
+    if (!auto_stra(&info->treename, argv[0]))
+        log_die_nomem("stralloc") ;
+
+    tree = info->treename.s ;
+
+    log_trace("sanitize ",tree,"..." ) ;
+    r = sanitize_tree(info,tree) ;
+
+    if(!r && create) {
+
+        ss_tree_seed_t seed = TREE_SEED_ZERO ;
+        /** set cleanup */
+        cleantree = info->tree.s ;
+        log_trace("checking seed file: ",tree,"..." ) ;
+
+        if (tree_seed_isvalid(tree)) {
+
+            if (!tree_seed_setseed(&seed, tree, 0))
+                log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "parse seed file: ", tree) ;
+
+            if (seed.enabled)
+                enable = 1 ;
+
+            if (seed.current)
+                current = 1 ;
+
+            if (seed.allow > 0) {
+
+                parse_uild_list(auids, saseed.s + seed.allow) ;
+
+                allow = 1 ;
+            }
+
+            if (seed.deny > 0) {
+
+                parse_uild_list(duids, saseed.s + seed.deny) ;
+
+                deny = 1 ;
+            }
+        }
+        tree_seed_free();
+
+        log_trace("creating: ",info->tree.s,"..." ) ;
+        create_tree(info) ;
+
+        log_trace("creating backup directory for: ", tree,"...") ;
+        create_backupdir(info) ;
+        /** unset cleanup */
+        cleantree = 0 ;
+
+        // set permissions
+        allow = 1 ;
+
+        size_t dblen = info->tree.len ;
+        char newdb[dblen + SS_SVDIRS_LEN + 1] ;
+        auto_strings(newdb, info->tree.s, SS_SVDIRS) ;
+
+        log_trace("compile: ",newdb,"/db/",tree,"..." ) ;
+        if (!db_compile(newdb,info->tree.s,tree,envp))
+            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"compile ",newdb,"/db/",tree) ;
+
+        r = 1 ;
+        create = 0 ;
+        log_info("Created successfully tree: ",tree) ;
+    }
+
+    if ((!r && !create) || (!r && enable)) log_dieusys(LOG_EXIT_SYS,"find tree: ",info->tree.s) ;
+    if (r && create) log_dieu(LOG_EXIT_USER,"create: ",info->tree.s,": already exist") ;
+
+    if (enable)
+        tree_enable_disable(info,1) ;
+
+    if (disable)
+        tree_enable_disable(info,0) ;
+
+    if (allow)
+        set_rules(info->tree.s,auids,1) ;
+
+    if (deny)
+        set_rules(info->tree.s,duids,0) ;
+
+    if(current) {
+
+        log_trace("make: ",info->tree.s," as default ..." ) ;
+        if (!tree_switch_current(info->base.s,tree)) log_dieusys(LOG_EXIT_SYS,"set: ",info->tree.s," as default") ;
+        log_info("Set successfully: ",tree," as default") ;
+    }
+
+    if (remove)
+        tree_remove(info) ;
+
+    if (snap) {
+
+        stralloc salist = STRALLOC_ZERO ;
+        ss_resolve_t res = RESOLVE_ZERO ;
+
+        size_t syslen = info->base.len + SS_SYSTEM_LEN ;
+        size_t treelen = info->treename.len ;
+        size_t pos = 0 ;
+
+        char system[syslen + 1] ;
+        auto_strings(system,info->base.s,SS_SYSTEM) ;
+
+        size_t clone_target_len = syslen + 1 + clone.len ;
+        char clone_target[clone_target_len + 1] ;
+        auto_strings(clone_target,system,"/",clone.s) ;
+
+        r = scan_mode(clone_target,S_IFDIR) ;
+        if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ;
+
+        // clone main directory
+        log_trace("clone: ",tree," as: ",clone.s,"..." ) ;
+        if (!hiercopy(info->tree.s,clone_target))
+            log_dieusys(LOG_EXIT_SYS,"copy: ",info->tree.s," to: ",clone_target) ;
+
+        // clone backup directory
+        size_t clone_backup_len = syslen + SS_BACKUP_LEN + 1 + clone.len ;
+        char clone_backup[clone_backup_len + 1] ;
+        auto_strings(clone_backup,system,SS_BACKUP,"/",clone.s) ;
+
+        char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ;
+        auto_strings(tree_backup,system,SS_BACKUP,"/",tree) ;
+
+        /* make cleantree pointing to the clone to be able to remove it
+         * in case of crach */
+        cleantree = clone_target ;
+
+        log_trace("clone backup of: ",tree," as: ",clone.s,"..." ) ;
+        if (!hiercopy(tree_backup,clone_backup))
+            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tree_backup," to: ",clone_backup) ;
+
+        // modify the resolve file to match the new name
+        // main directory first
+        char src_resolve[clone_target_len + SS_SVDIRS_LEN + SS_RESOLVE_LEN + 1] ;
+        auto_strings(src_resolve,clone_target,SS_SVDIRS,SS_RESOLVE) ;
+
+        if (!sastr_dir_get(&salist,src_resolve,"",S_IFREG))
+            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ;
+
+        char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ;
+        auto_strings(clone_res,clone_target,SS_SVDIRS) ;
+
+        FOREACH_SASTR(&salist, pos) {
+
+            char *name = salist.s + pos ;
+
+            if (!ss_resolve_read(&res,clone_res,name))
+                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ;
+
+            tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ;
+            tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ;
+            tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ;
+            tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ;
+
+            if (!ss_resolve_write(&res,clone_res,name))
+                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ;
+        }
+
+        // rename db
+        char clone_db_old[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + treelen + 1] ;
+        auto_strings(clone_db_old,clone_target,SS_SVDIRS,SS_DB,"/",tree) ;
+
+        char clone_db_new[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + clone.len + 1] ;
+        auto_strings(clone_db_new,clone_target,SS_SVDIRS,SS_DB,"/",clone.s) ;
+
+        log_trace("rename tree db: ",tree," as: ",clone.s,"..." ) ;
+        if (rename(clone_db_old,clone_db_new) == -1)
+            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_old," to: ",clone_db_new) ;
+
+        // backup directory
+        char src_resolve_backup[clone_backup_len + SS_RESOLVE_LEN + 1] ;
+        auto_strings(src_resolve_backup,clone_backup,SS_RESOLVE) ;
+
+        salist.len = 0 ;
+
+        /** main and backup can be different,so rebuild the list
+         * Also, a backup directory can be empty, check it first */
+        r = scan_mode(src_resolve_backup,S_IFDIR) ;
+        if (r == 1) {
+
+            if (!sastr_dir_get(&salist,src_resolve_backup,"",S_IFREG))
+                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ;
+
+            pos = 0 ;
+            FOREACH_SASTR(&salist, pos) {
+
+                char *name = salist.s + pos ;
+
+                if (!ss_resolve_read(&res,clone_backup,name))
+                    log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ;
+
+                tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ;
+                tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ;
+                tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ;
+                tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ;
+
+                if (!ss_resolve_write(&res,clone_backup,name))
+                    log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ;
+            }
+            // rename db
+            char clone_db_backup_old[clone_backup_len + SS_DB_LEN + 1 + treelen + 1] ;
+            auto_strings(clone_db_backup_old,clone_backup,SS_DB,"/",tree) ;
+
+            char clone_db_backup_new[clone_backup_len + SS_DB_LEN + 1 + clone.len + 1] ;
+            auto_strings(clone_db_backup_new,clone_backup,SS_DB,"/",clone.s) ;
+
+            log_trace("rename tree backup db: ",tree," as: ",clone.s,"..." ) ;
+            if (rename(clone_db_backup_old,clone_db_backup_new) == -1)
+                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_backup_old," to: ",clone_db_backup_new) ;
+        }
+
+        stralloc_free(&salist) ;
+        ss_resolve_free(&res) ;
+
+        log_info("Cloned successfully: ",tree," to ",clone.s) ;
+    }
+
+    if (after_tree) {
+
+        stralloc contents = STRALLOC_ZERO ;
+        stralloc tmp = STRALLOC_ZERO ;
+        int befirst = obstr_equal(tree,after_tree) ;
+        size_t baselen = info->base.len, pos = 0 ;
+        char ste[baselen + SS_SYSTEM_LEN + 1] ;
+        auto_strings(ste,info->base.s,SS_SYSTEM) ;
+
+        int enabled = tree_cmd_state(VERBOSITY,"-s",tree) ;
+        if (enabled != 1)
+            log_die(LOG_EXIT_USER,"tree: ",tree," is not enabled") ;
+
+        enabled = tree_cmd_state(VERBOSITY,"-s",after_tree) ;
+        if (enabled != 1)
+            log_die(LOG_EXIT_USER,"tree: ",after_tree," is not enabled") ;
+
+        r  = tree_cmd_state(VERBOSITY,"-d",tree) ;
+        if (!r) log_dieusys(LOG_EXIT_SYS,"disable: ",tree," at: ",ste,SS_STATE) ;
+
+        r = file_readputsa(&tmp,ste,SS_STATE + 1) ;
+        if(!r) log_dieusys(LOG_EXIT_SYS,"open: ", ste,SS_STATE) ;
+
+        /** if you have only one tree enabled, the state file will be
+         * empty because we disable it before reading the file(see line 803).
+         * This will make a crash at sastr_? call.
+         * So write directly the name of the tree at state file. */
+
+        if (tmp.len) {
+
+            if (!sastr_rebuild_in_oneline(&tmp) ||
+            !sastr_clean_element(&tmp))
+                log_dieu(LOG_EXIT_SYS,"rebuild state list") ;
+
+            pos = 0 ;
+            FOREACH_SASTR(&tmp, pos) {
+
+                char *name = tmp.s + pos ;
+
+                /* e.g 66-tree -S root root -> meaning root need to
+                 * be the first to start */
+                if ((befirst) && (pos == 0))
+                {
+                    if (!auto_stra(&contents,tree,"\n"))
+                        log_dieusys(LOG_EXIT_SYS,"stralloc") ;
+                }
+                if (!auto_stra(&contents,name,"\n"))
+                    log_dieusys(LOG_EXIT_SYS,"stralloc") ;
+
+                if (obstr_equal(name,after_tree))
+                {
+                    if (!auto_stra(&contents,tree,"\n"))
+                        log_dieusys(LOG_EXIT_SYS,"stralloc") ;
+                }
+            }
+
+        } else {
+
+            if (!auto_stra(&contents,tree,"\n"))
+                log_dieusys(LOG_EXIT_SYS,"stralloc") ;
+        }
+
+        if (!file_write_unsafe(ste,SS_STATE + 1,contents.s,contents.len))
+            log_dieusys(LOG_EXIT_ZERO,"write: ",ste,SS_STATE) ;
+
+        log_info("Ordered successfully: ",tree," starts after tree: ",after_tree) ;
+    }
+
+    stralloc_free(&clone) ;
+
+    return 0 ;
+}