diff --git a/src/lib66/ssexec_help.c b/src/lib66/ssexec_help.c
index c7625d96286f73182c7727dfc7af05bd0e9b4313..8ad754b0a44c4f241f7bf4ede1aeacbb4a92f44f 100644
--- a/src/lib66/ssexec_help.c
+++ b/src/lib66/ssexec_help.c
@@ -155,7 +155,7 @@ char const *help_all =
 "   -f: fork the process\n"
 ;
 
-char const *usage_tree = "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -n|R ] [ -a|d ] [ -c ] [ -o depends=:requiredby=:rename= ] [ -E|D ] [ -C clone ] tree" ;
+char const *usage_tree = "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -c ] [ -o depends=:... ] [ -E|D ] [ -R ] tree" ;
 
 char const *help_tree =
 "\n"
@@ -163,20 +163,20 @@ char const *help_tree =
 "   -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"
+"   -o: colon separated list of options\n"
 "   -E: enable the tree\n"
 "   -D: disable the tree\n"
-"   -C: clone the tree\n"
+"   -R: remove 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"
-"   rename=: rename tree with as rename\n"
+"   depends=: comma separated list of dependencies for tree or none\n"
+"   requiredby=: comma separated list of trees required by tree or none\n"
+"   groups=: add tree to the specified groups\n"
+"   allow=: comma separated list of account to allow at tree\n"
+"   deny=: comma separated list of account to deny at tree\n"
+"   clone=: make a clone of tree\n"
+"   noseed: do not use seed file to build the tree\n"
 ;
diff --git a/src/lib66/ssexec_tree.c b/src/lib66/ssexec_tree.c
index daa64a9c5ebcce56495392f798786a904ea069d4..ba21427ccbfa5063081fb5e1eb58f73b344304bd 100644
--- a/src/lib66/ssexec_tree.c
+++ b/src/lib66/ssexec_tree.c
@@ -19,6 +19,7 @@
 #include <sys/stat.h>
 #include <stdio.h>//rename
 #include <pwd.h>
+#include <stdlib.h>//free
 
 #include <oblibs/obgetopt.h>
 #include <oblibs/log.h>
@@ -42,34 +43,18 @@
 #include <66/state.h>
 #include <66/service.h>
 #include <66/resolve.h>
+#include <66/graph.h>
 
 #include <s6/supervise.h>
 #include <s6-rc/s6rc-servicedir.h>
 #include <s6-rc/s6rc-constants.h>
 
-
-/**
- *
- *
- *
- * -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
- *
- *
- * */
 #define TREE_COLON_DELIM ':'
 #define TREE_COMMA_DELIM ','
-#define TREE_MAXOPTS 4
+#define TREE_MAXOPTS 9
 #define tree_checkopts(n) if (n >= TREE_MAXOPTS) log_die(LOG_EXIT_USER, "too many -o options")
-stralloc TREE_SAOPTS = STRALLOC_ZERO ;
 
 static char const *cleantree = 0 ;
-static graph_t GRAPH = GRAPH_ZERO ;
 
 typedef struct tree_opts_map_s tree_opts_map_t ;
 struct tree_opts_map_s
@@ -84,25 +69,79 @@ enum enum_ns_opts_e
     TREE_OPTS_DEPENDS = 0,
     TREE_OPTS_REQUIREDBY,
     TREE_OPTS_RENAME,
+    TREE_OPTS_GROUPS,
+    TREE_OPTS_NOSEED,
+    TREE_OPTS_ALLOW,
+    TREE_OPTS_DENY,
+    TREE_OPTS_CLONE,
     TREE_OPTS_ENDOFKEY
 } ;
 
 tree_opts_map_t const tree_opts_table[] =
 {
-    { .str = "depends", .id = TREE_OPTS_DEPENDS },
-    { .str = "requiredby", .id = TREE_OPTS_REQUIREDBY },
-    { .str = "rename", .id = TREE_OPTS_RENAME },
+    { .str = "depends",     .id = TREE_OPTS_DEPENDS },
+    { .str = "requiredby",  .id = TREE_OPTS_REQUIREDBY },
+    { .str = "rename",      .id = TREE_OPTS_RENAME },
+    { .str = "groups",      .id = TREE_OPTS_GROUPS },
+    { .str = "noseed",      .id = TREE_OPTS_NOSEED },
+    { .str = "allow",       .id = TREE_OPTS_ALLOW },
+    { .str = "deny",        .id = TREE_OPTS_DENY },
+    { .str = "clone",       .id = TREE_OPTS_CLONE },
     { .str = 0 }
 } ;
 
-typedef struct tree_opts_s tree_opts_t, *tree_opts_t_ref ;
-struct tree_opts_s
+typedef struct tree_what_s tree_what_t, *tree_what_t_ref ;
+struct tree_what_s
 {
-    int depends ; //index of depends at TREE_SAOPTS
-    int requiredby ; //index of requiredby at TREE_SAOPTS
-    int rename ; //index of rename at TREE_SAOPTS
+    uint8_t create ;
+    uint8_t depends ;
+    uint8_t requiredby ;
+    uint8_t allow ;
+    uint8_t deny ;
+    uint8_t enable ;
+    uint8_t disable ;
+    uint8_t remove ;
+    uint8_t clone ;
+    uint8_t groups ;
+    uint8_t current ;
+    uint8_t rename ;
+    uint8_t noseed ;
+
+    char gr[6] ;
+    char sclone[100] ;
+    uid_t auids[256] ;
+    uid_t duids[256] ;
+    uint8_t ndepends ; // only used if the term none is passed as dependencies
+    uint8_t nrequiredby ; // only used if the term none is passed as dependencies
+
+    uint8_t nopts ;
 } ;
-#define TREE_OPTS_ZERO { -1, -1, -1 }
+#define TREE_WHAT_ZERO { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, { 0 }, { 0 }, { 0 }, 1, 1, 0 }
+
+tree_what_t what_init(void)
+{
+    log_flow() ;
+
+    tree_what_t what = TREE_WHAT_ZERO ;
+
+    memset(what.gr, 0, 6) ;
+    memset(what.auids, 0, 256 * sizeof(uid_t));
+    memset(what.duids, 0, 256 * sizeof(uid_t)) ;
+
+    return what ;
+}
+
+void visit_init(visit *v, size_t len)
+{
+    log_flow() ;
+
+    size_t pos = 0 ;
+    for (; pos < len; pos++)
+        v[pos] = SS_WHITE ;
+
+}
+
+void tree_enable_disable(graph_t *g, char const *base, char const *treename, uint8_t action) ;
 
 static void cleanup(void)
 {
@@ -111,10 +150,18 @@ static void cleanup(void)
     if (cleantree) {
 
         log_trace("removing: ",cleantree,"...") ;
-        rm_rf(cleantree) ;
+        if (!dir_rm_rf(cleantree))
+            log_dieusys(LOG_EXIT_SYS, "remove: ", cleantree) ;
     }
 }
 
+static void check_identifier(char const *name)
+{
+    if (!memcmp(name, SS_MASTER + 1, 6))
+        log_die(LOG_EXIT_USER,"tree name: ",name,": starts with reserved prefix Master") ;
+
+}
+
 static void auto_dir(char const *dst,mode_t mode)
 {
     log_flow() ;
@@ -171,16 +218,16 @@ static ssize_t tree_get_key(char *table,char const *str)
     return pos ;
 }
 
-int sanitize_tree(ssexec_t *info, char const *tree)
+void sanitize_system(ssexec_t *info)
 {
     log_flow() ;
 
-    ssize_t r ;
+    log_trace("sanitize system..." ) ;
+
     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 + SS_RESOLVE_LEN + 1 + treelen + 1] ;
+    char dst[baselen + SS_SYSTEM_LEN + SS_RESOLVE_LEN + SS_MASTER_LEN + 1] ;
     auto_strings(dst,info->base.s, SS_SYSTEM) ;
 
     /** base is /var/lib/66 or $HOME/.66*/
@@ -190,9 +237,6 @@ int sanitize_tree(ssexec_t *info, char const *tree)
     /** create extra directory for service part */
     if (!info->owner) {
 
-        auto_strings(dst,info->base.s, SS_SYSTEM, SS_RESOLVE) ;
-        auto_check(dst) ;
-
         auto_check(SS_LOGGER_SYSDIR) ;
 
         if (!youruid(&log_uid,SS_LOGGER_RUNNER) ||
@@ -253,150 +297,54 @@ int sanitize_tree(ssexec_t *info, char const *tree)
     auto_strings(dst,info->base.s, SS_SYSTEM, SS_RESOLVE) ;
     auto_check(dst) ;
 
+    auto_strings(dst + baselen + SS_SYSTEM_LEN + SS_RESOLVE_LEN, SS_MASTER) ;
+
+    if (!scan_mode(dst, S_IFREG))
+        if (!tree_resolve_create_master(info->base.s, info->owner))
+            log_dieu(LOG_EXIT_SYS, "write resolve file of inner tree") ;
+
     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)
+static void tree_parse_options_groups(char *store, char const *str)
 {
     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] ;
-    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
-    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
-    resolve_init(wres) ;
-
-    auto_strings(dst, tree) ;
-    newlen = treelen ;
-
-    res.name = resolve_add_string(wres,SS_MASTER+1) ;
-    res.description = resolve_add_string(wres,"inner bundle - do not use it") ;
-    res.tree = resolve_add_string(wres,dst) ;
-    res.treename = resolve_add_string(wres,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 (!resolve_write(wres,dst,SS_MASTER+1)) {
-
-        resolve_free(wres) ;
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ;
-    }
-    resolve_free(wres) ;
-
-    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 ;
+    uid_t uid = getuid() ;
 
-    log_trace("create file: ",dst,"/contents") ;
-    if (!file_create_empty(dst,"contents",0644))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create: ",dst,"/contents") ;
+    if (strcmp(str, TREE_GROUPS_BOOT) &&
+        strcmp(str, TREE_GROUPS_ADM) &&
+        strcmp(str, TREE_GROUPS_USER) &&
+        strcmp(str, "none"))
+        log_die(LOG_EXIT_SYS, "invalid group: ", str) ;
 
-    auto_strings(dst + newlen,"/type") ;
+    if (!uid && (!strcmp(str, TREE_GROUPS_USER)))
+        log_die(LOG_EXIT_SYS, "Only regular user can use this group") ;
 
-    log_trace("create file: ",dst) ;
-    if(!openwritenclose_unsafe(dst,"bundle\n",7))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write: ",dst) ;
+    else if (uid && (!strcmp(str, TREE_GROUPS_ADM) || !strcmp(str, TREE_GROUPS_BOOT)))
+        log_die(LOG_EXIT_SYS, "Only root user can use this group") ;
 
+    auto_strings(store, str) ;
 }
 
-void create_backupdir(ssexec_t *info)
+void tree_parse_uid_list(uid_t *uids, char const *str)
 {
     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_uid_list(uid_t *uids, char const *str)
-{
     size_t pos = 0 ;
     stralloc sa = STRALLOC_ZERO ;
 
-    if (!sastr_clean_string_wdelim(&sa, str, ','))
+    if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM))
         log_dieu(LOG_EXIT_SYS,"parse uid list") ;
 
-    uid_t owner = MYUID ;
+    uid_t owner = getuid() ;
     /** 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") ;
+     *  the tree, we need a general name to allow all users.
+     *  The term "user" is took here to allow the current user*/
+    ssize_t p = sastr_cmp(&sa, "user") ;
 
     FOREACH_SASTR(&sa, pos) {
 
@@ -407,7 +355,7 @@ void parse_uid_list(uid_t *uids, char const *str)
             if (!pw) {
 
                 if (!errno) errno = ESRCH ;
-                    log_dieu(LOG_EXIT_ZERO,"get user name") ;
+                    log_dieu(LOG_EXIT_SYS,"get user name") ;
             }
 
             if (!scan_uidlist(pw->pw_name, uids))
@@ -420,200 +368,111 @@ void parse_uid_list(uid_t *uids, char const *str)
             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) ;
+    stralloc_free(&sa) ;
 }
 
-/** @action -> 0 disable
- * @action -> 1 enable */
-void tree_enable_disable(ssexec_t *info, uint8_t action)
+static void tree_parse_options_depends(graph_t *g, ssexec_t *info, char const *str, uint8_t requiredby, tree_what_t *what)
 {
     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(resolve_service_t *res, resolve_service_enum_t field,char const *regex,char const *by)
-{
-    log_flow() ;
-
+    size_t pos = 0 ;
+    char *name = 0 ;
     stralloc sa = STRALLOC_ZERO ;
-    resolve_service_t modif = RESOLVE_SERVICE_ZERO ;
-    resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &modif) ;
-
-    log_trace("modify field: ", resolve_service_field_table[field].field," of service: ",res->sa.s + res->name) ;
 
-    if (!service_resolve_copy(&modif,res))
-        log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ", res->sa.s + res->name) ;
-
-    if (!service_resolve_field_to_sa(&sa,&modif, field))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get copy of field: ",resolve_service_field_table[field].field) ;
-
-    if (sa.len) {
-        if (!sastr_replace(&sa,regex,by))
-            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"replace field: ",resolve_service_field_table[field].field) ;
+    if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM))
+        log_dieu(LOG_EXIT_SYS,"clean sub options") ;
 
-        if (!stralloc_0(&sa))
-            log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"stralloc") ;
+    if (sastr_cmp(&sa, "none") >= 0) {
+        if (!requiredby)
+            what->ndepends = 0 ;
+        else
+            what->nrequiredby = 0 ;
 
-        sa.len-- ;
+        stralloc_free(&sa) ;
+        return ;
     }
 
-    if (!service_resolve_modify_field(&modif,field,sa.s))
-        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"modify field: ",resolve_service_field_table[field].field) ;
-
-    if (!service_resolve_copy(res,&modif))
-        log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ",res->sa.s + res->name) ;
-
-    stralloc_free(&sa) ;
+    FOREACH_SASTR(&sa, pos) {
 
-    resolve_free(wres) ;
-}
+        name = sa.s + pos ;
+
+        r = tree_isvalid(info->base.s, name) ;
+        if (r < 0)
+            log_diesys(LOG_EXIT_SYS, "invalid tree directory") ;
+        /** We only creates trees declared as dependency.
+         * TreeA depends on TreeB, we create TreeB
+         * if it doesn't exist yet */
+        if (!r && !requiredby) {
+
+            ssexec_t newinfo = SSEXEC_ZERO ;
+            if (!auto_stra(&newinfo.base, info->base.s) ||
+                !auto_stra(&newinfo.treename, name))
+                    log_die_nomem("stralloc") ;
+            newinfo.owner = info->owner ;
+            newinfo.prog = info->prog ;
+            newinfo.help = info->help ;
+            newinfo.usage = info->usage ;
+            newinfo.opt_color = info->opt_color ;
+            newinfo.skip_opt_tree = info->skip_opt_tree ;
+
+
+            int nwhat = what->noseed ? 2 : 0 ;
+            int nargc = 3 + nwhat ;
+            char const *newargv[nargc] ;
+            uint8_t m = 0 ;
+            newargv[m++] = "66-tree (child)" ;
+
+            if (nwhat) {
+                newargv[m++] = "-o" ;
+                newargv[m++] = "noseed" ;
+            }
 
-void tree_remove(ssexec_t *info)
-{
-    log_flow() ;
+            newargv[m++] = name ;
+            newargv[m++] = 0 ;
 
-    char const *base = info->base.s, *dst = info->tree.s, *tree = info->treename.s ;
-    int r ;
+            log_trace("launch 66-tree sub-process for tree: ", name) ;
 
-    log_trace("delete: ",dst,"..." ) ;
+            if (ssexec_tree(nargc, newargv, (char const *const *)environ, &newinfo))
+                log_dieusys(LOG_EXIT_SYS, "create tree: ", name) ;
 
-    if (rm_rf(dst) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ", dst) ;
+            ssexec_free(&newinfo) ;
 
-    size_t treelen = strlen(tree) ;
-    size_t baselen = strlen(base) ;
-    char treetmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treelen  + 1] ;
+            r = 1 ;
 
-    auto_strings(treetmp, base, SS_SYSTEM, SS_BACKUP, "/", tree) ;
+        }
 
-    r = scan_mode(treetmp,S_IFDIR) ;
-    if (r || (r < 0)) {
+        if (!requiredby) {
 
-        log_trace("delete backup of tree: ",treetmp,"...") ;
-        if (rm_rf(treetmp) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ",treetmp) ;
+            if (!graph_vertex_add_with_edge(g, info->treename.s, name))
+                log_die(LOG_EXIT_SYS,"add edge: ", name, " to vertex: ", info->treename.s) ;
 
+        } else if (r) {
+            /** if TreeA is requiredby TreeB, we don't want to create TreeB.
+             * We only manages it if it exist yet */
+            if (!graph_vertex_add_with_requiredby(g, info->treename.s, name))
+                log_die(LOG_EXIT_SYS,"add requiredby: ", name, " to: ", info->treename.s) ;
+        }
     }
 
-    tree_enable_disable(info,0) ;
-
-    log_info("Deleted successfully: ",tree) ;
-}
-
-#include <stdio.h>
-
-static void tree_parse_depends(char const *treename, char const *str)
-{
-    size_t pos = 0 ;
-    char *sv = 0 ;
-    stralloc sa = STRALLOC_ZERO ;
-
-    if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM))
-        log_dieu(LOG_EXIT_SYS,"clean sub options") ;
-
-    FOREACH_SASTR(&sa, pos) {
-
-        sv = sa.s + pos ;
-
-        if (!graph_vertex_add(&GRAPH, sv))
-            log_die(LOG_EXIT_SYS,"add vertex: ", sv) ;
-
-        if (!graph_edge_add_g(&GRAPH, treename, sv))
-            log_die(LOG_EXIT_SYS,"add edge: ", sv, " to vertex: ", treename) ;
-
-    }
     stralloc_free(&sa) ;
 }
 
-static void tree_parse_options(tree_opts_t *opts, char const *str)
+static void tree_parse_options(graph_t *g, char const *str, ssexec_t *info, tree_what_t *what)
 {
+    log_flow() ;
+
+    if (!str)
+        return ;
 
     size_t pos = 0, len = 0 ;
     ssize_t r ;
     char *line = 0, *key = 0, *val = 0 ;
-    tree_opts_map_t const *t ;
-
     stralloc sa = STRALLOC_ZERO ;
+    tree_opts_map_t const *t ;
 
-    if (!sastr_clean_string_wdelim(&sa,str,TREE_COLON_DELIM))
+    if (!sastr_clean_string_wdelim(&sa, str, TREE_COLON_DELIM))
         log_dieu(LOG_EXIT_SYS,"clean options") ;
 
     unsigned int n = sastr_len(&sa), nopts = 0 , old ;
@@ -632,38 +491,66 @@ static void tree_parse_options(tree_opts_t *opts, char const *str)
             char tmp[len + 1] ;
 
             r = tree_get_key(tmp,line) ;
-            if (r == -1)
+            if (r == -1 && strcmp(line, "noseed"))
                 log_die(LOG_EXIT_USER,"invalid key: ", line) ;
 
-            key = tmp ;
-            val = line + r ;
+            if (!strcmp(line, "noseed")) {
+                key = line ;
+            } else {
+                key = tmp ;
+                val = line + r ;
+            }
 
             if (!strcmp(key, t->str)) {
 
                 switch(t->id) {
 
                     case TREE_OPTS_DEPENDS :
+                        tree_parse_options_depends(g, info, val, 0, what) ;
+                        what->depends = 1 ;
+                        break ;
 
-                            opts->depends = TREE_SAOPTS.len ;
-                            if (!sastr_add_string(&TREE_SAOPTS, val))
-                                log_die_nomem("stralloc") ;
+                    case TREE_OPTS_REQUIREDBY :
 
-                            break ;
+                        tree_parse_options_depends(g, info, val, 1, what) ;
+                        what->requiredby = 1 ;
+                        break ;
 
-                    case TREE_OPTS_REQUIREDBY :
+                    case TREE_OPTS_RENAME:
+
+                        what->rename = 1 ;
+                        break ;
 
-                            opts->requiredby = TREE_SAOPTS.len ;
-                            if (!sastr_add_string(&TREE_SAOPTS, val))
-                                log_die_nomem("stralloc") ;
+                    case TREE_OPTS_GROUPS:
 
+                        tree_parse_options_groups(what->gr, val) ;
+                        what->groups = 1 ;
                         break ;
 
-                    case TREE_OPTS_RENAME:
+                    case TREE_OPTS_NOSEED:
 
-                            opts->rename = TREE_SAOPTS.len ;
-                            if (!sastr_add_string(&TREE_SAOPTS, val))
-                                log_die_nomem("stralloc") ;
+                        what->noseed = 1 ;
+                        break ;
+
+                    case TREE_OPTS_ALLOW:
+
+                        tree_parse_uid_list(what->auids, val) ;
+                        what->allow = 1 ;
+                        break ;
+
+                    case TREE_OPTS_DENY:
+
+                        tree_parse_uid_list(what->duids, val) ;
+                        what->deny = 1 ;
+                        break ;
+
+                   case TREE_OPTS_CLONE:
 
+                        if (strlen(val) > 99)
+                            log_die(LOG_EXIT_USER, "clone name cannot exceed 100 characters") ;
+
+                        auto_strings(what->sclone, val) ;
+                        what->clone = 1 ;
                         break ;
 
                     default :
@@ -677,407 +564,1070 @@ static void tree_parse_options(tree_opts_t *opts, char const *str)
         if (old == nopts)
             log_die(LOG_EXIT_SYS,"invalid option: ",line) ;
     }
+
     stralloc_free(&sa) ;
 }
 
-int ssexec_tree(int argc, char const *const *argv,char const *const *envp,ssexec_t *info)
+void tree_parse_seed(char const *treename, tree_seed_t *seed, tree_what_t *what)
 {
-    int r, current, create, allow, deny, enable, disable, remove, snap ;
+    log_flow() ;
 
-    uid_t auids[256] = { 0 }, duids[256] = { 0 } ;
+    log_trace("checking seed file: ", treename, "..." ) ;
 
-    char const *tree, *after_tree = 0 ;
+    if (tree_seed_isvalid(treename)) {
 
-    stralloc clone = STRALLOC_ZERO ;
-    tree_seed_t seed = TREE_SEED_ZERO ;
-    tree_opts_t opts = TREE_OPTS_ZERO ;
+        if (!tree_seed_setseed(seed, treename, 0))
+            log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "parse seed file: ", treename) ;
 
-    current = create = allow = deny = enable = disable = remove = snap = 0 ;
+        if (seed->depends)
+            what->depends = 1 ;
 
-    {
-        subgetopt l = SUBGETOPT_ZERO ;
+        if (seed->requiredby)
+            what->requiredby = 1 ;
 
-        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)
-            {
+        if (seed->disen)
+            what->enable = 1 ;
 
-                case 'n' :  create = 1 ; break ;
-                case 'a' :  parse_uid_list(auids, l.arg) ;
-                            allow = 1 ;
-                            break ;
-                case 'd' :  parse_uid_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 ;
-                case 'o' :  tree_parse_options(&opts, l.arg) ;
-                            break ;
-                default :   log_usage(usage_tree) ;
-            }
+        if (seed->allow > 0) {
+
+            tree_parse_uid_list(what->auids, seed->sa.s + seed->allow) ;
+            what->allow = 1 ;
         }
-        argc -= l.ind ; argv += l.ind ;
-    }
 
-    if (argc < 1) log_usage(usage_tree) ;
+        if (seed->deny > 0) {
 
-    // make create the default option
-    if (!current && !create && !allow && !deny && !enable && !disable && !remove && !snap && (opts.rename >= 0))
-        create = 1 ;
+            tree_parse_uid_list(what->duids, seed->sa.s + seed->deny) ;
+            what->deny = 1 ;
+        }
 
-    info->treename.len = 0 ;
-    if (!auto_stra(&info->treename, argv[0]))
-        log_die_nomem("stralloc") ;
+        if (seed->current)
+            what->current = 1 ;
 
-    tree = info->treename.s ;
+        if (seed->groups) {
 
-    log_trace("sanitize ",tree,"..." ) ;
-    r = sanitize_tree(info,tree) ;
+            tree_parse_options_groups(what->gr, seed->sa.s + seed->groups) ;
+            what->groups = 1 ;
+        }
+    }
+}
 
-    if (!graph_vertex_add(&GRAPH, tree))
-        log_dieu(LOG_EXIT_SYS,"add vertex: ",tree) ;
+void create_tree(ssexec_t *info)
+{
+    log_flow() ;
 
-    if (opts.depends >= 0)
-        tree_parse_depends(tree, TREE_SAOPTS.s + opts.depends) ;
+    size_t newlen = 0, treelen = info->tree.len ;
+    char const *tree = info->tree.s ;
+    char dst[treelen + SS_SVDIRS_LEN + SS_DB_LEN + SS_SRC_LEN + 16 + 1] ;
+    char sym[treelen + SS_SVDIRS_LEN + 1 + SS_SYM_SVC_LEN + 1] ;
+    char dstsym[treelen + SS_SVDIRS_LEN + SS_SVC_LEN + 1] ;
 
-    if(!r && create) {
+    auto_strings(dst, tree) ;
+    newlen = treelen ;
 
-        /** set cleanup */
-        cleantree = info->tree.s ;
-        log_trace("checking seed file: ",tree,"..." ) ;
+    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 ;
 
-        if (tree_seed_isvalid(tree)) {
+    if (!service_resolve_create_master(info->base.s, info->treename.s))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ;
 
-            if (!tree_seed_setseed(&seed, tree, 0))
-                log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "parse seed file: ", tree) ;
+    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) ;
 
-            if (seed.depends) {
+    auto_strings(sym + newlen + 1, SS_SYM_DB) ;
+    auto_strings(dstsym + newlen, SS_DB) ;
 
-                tree_parse_depends(tree, saseed.s + seed.depends) ;
+    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 ;
 
-            if (seed.requiredby) {
+    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") ;
 
-            if (seed.enabled)
-                enable = 1 ;
+    log_trace("create file: ", dst) ;
+    if(!openwritenclose_unsafe(dst, "bundle\n",7))
+        log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "write: ", dst) ;
 
-            if (seed.allow > 0) {
+}
 
-                parse_uid_list(auids, saseed.s + seed.allow) ;
+void tree_groups(char const *base, char const *treename, char const *value)
+{
+    log_flow() ;
 
-                allow = 1 ;
-            }
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
+    size_t nb = 0, baselen = strlen(base) ;
+    char pack[UINT_FMT] ;
+    char solve[baselen + SS_SYSTEM_LEN + 1] ;
+    char const *val ;
 
-            if (seed.deny > 0) {
+    auto_strings(solve, base, SS_SYSTEM) ;
 
-                parse_uid_list(duids, saseed.s + seed.deny) ;
+    log_trace("set: ", treename," to group ..." ) ;
 
-                deny = 1 ;
-            }
+    if (!strcmp(value, "none")) {
+        val = 0 ;
+        goto write ;
+    }
+
+    nb = 1 ;
+    val = value ;
+
+    write:
+
+    uint_pack(pack, nb) ;
+    pack[uint_fmt(pack, nb)] = 0 ;
+
+    if (!resolve_read(wres, solve, treename))
+        log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", solve, "/.resolve/", treename) ;
+
+    if (!resolve_modify_field(wres, TREE_ENUM_GROUPS, val) ||
+        !resolve_modify_field(wres, TREE_ENUM_NGROUPS, pack))
+            log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ;
+
+    if (!resolve_write(wres, solve, treename))
+        log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", solve, "/.resolve/", treename) ;
+
+    resolve_free(wres) ;
+
+    log_info("Set successfully: ", treename, " to group: ", value) ;
+}
+
+void create_backupdir(char const *base, char const *treename)
+{
+    log_flow() ;
+
+    int r ;
+    size_t baselen = strlen(base) ;
+    size_t treenamelen = strlen(treename) ;
+    char tmp[baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ;
+
+    auto_strings(tmp, base, SS_SYSTEM, SS_BACKUP, "/", treename) ;
+
+    r = scan_mode(tmp,S_IFDIR) ;
+    if (r || (r == -1)) {
+
+        log_trace("remove existing backup: ",tmp) ;
+        if (!dir_rm_rf(tmp))
+            log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "remove: ", tmp) ;
+    }
+
+    auto_dir(tmp,0755) ;
+}
+
+void tree_create(graph_t *g, ssexec_t *info, tree_what_t *what, char const *const *envp)
+{
+    log_flow() ;
+
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
+    tree_seed_t seed = TREE_SEED_ZERO ;
+    char solve[info->base.len + SS_SYSTEM_LEN + 1] ;
+
+    auto_strings(solve, info->base.s, SS_SYSTEM) ;
+
+    resolve_init(wres) ;
+
+    /** set cleanup */
+    cleantree = info->tree.s ;
+
+    /** check seed file */
+    if (!what->noseed)
+        tree_parse_seed(info->treename.s, &seed, what) ;
+
+    log_trace("creating: ", info->tree.s, "..." ) ;
+    create_tree(info) ;
+
+    log_trace("creating backup directory of tree: ", info->treename.s, "...") ;
+    create_backupdir(info->base.s, info->treename.s) ;
+
+    /** unset cleanup */
+    cleantree = 0 ;
+
+    // set permissions
+    what->allow = 1 ;
+
+    // compilation of the db
+    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/", info->treename.s, "..." ) ;
+    if (!db_compile(newdb, info->tree.s, info->treename.s, envp))
+        log_dieu_nclean(LOG_EXIT_SYS,&cleanup, "compile ", newdb, "/db/", info->treename.s) ;
+
+    tres.name = resolve_add_string(wres, info->treename.s) ;
+    tres.groups = resolve_add_string(wres, info->owner ? TREE_GROUPS_USER : TREE_GROUPS_ADM) ;
+    tres.ngroups = 1 ;
+
+    log_trace("write resolve file of: ", info->treename.s) ;
+    if (!resolve_write(wres, solve, info->treename.s))
+        log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "write resolve file: ", solve, SS_RESOLVE, "/", info->treename.s) ;
+
+    if (what->depends)
+        tree_parse_options_depends(g, info, seed.sa.s + seed.depends, 0, what) ;
+
+    if (what->requiredby)
+        tree_parse_options_depends(g, info, seed.sa.s + seed.requiredby, 1, what) ;
+
+    resolve_free(wres) ;
+    tree_seed_free(&seed) ;
+
+    log_info("Created successfully tree: ", info->treename.s) ;
+}
+
+/**
+ *
+ * WARNING: The order of the trees are not sorted by dependencies order
+ *
+ *
+ * !action -> disable
+ * action -> disable */
+void tree_master_enable_disable(char const *base, char const *treename, uint8_t action)
+{
+    log_flow() ;
+
+    size_t pos = 0, nb = 0, baselen = strlen(base), len = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
+    char solve[baselen + SS_SYSTEM_LEN + 1] ;
+
+    log_trace(!action ? "disable" : "enable"," tree: ", treename, " from: ", SS_MASTER + 1) ;
+
+    auto_strings(solve, base, SS_SYSTEM) ;
+
+    if (!resolve_read(wres, solve, SS_MASTER))
+        log_dieusys(LOG_EXIT_SYS, "read resolve file of inner tree") ;
+
+    if (!tres.nenabled && action) {
+        if (!resolve_modify_field(wres, TREE_ENUM_ENABLED, treename))
+            log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", SS_MASTER + 1) ;
 
-            if (seed.current)
-                current = 1 ;
+        tres.nenabled = 1 ;
+        goto write ;
+    }
+
+    if (tres.nenabled) {
+
+        if (!sastr_clean_string(&sa, tres.sa.s + tres.enabled))
+            log_dieu(LOG_EXIT_SYS, "clean string") ;
+
+        len = sa.len ;
+
+        char t[len + 1] ;
+
+        sastr_to_char(t, &sa) ;
 
-            if (seed.group) {
+        sa.len = 0 ;
+
+        for (; pos < len ; pos += strlen(t + pos) + 1) {
+
+            char *name = t + pos ;
+
+            if (!strcmp(name, treename))
+                continue ;
+
+            if (!auto_stra(&sa, name, " "))
+                log_die_nomem("stralloc") ;
+
+            nb++ ;
+        }
 
+        if (action) {
+            if (!auto_stra(&sa, treename))
+                log_die_nomem("stralloc") ;
+            nb++ ;
+        }
+
+        if (!action && sa.len)
+            sa.len-- ; //remove last " "
+
+        if (!stralloc_0(&sa))
+            log_die_nomem("stralloc") ;
+
+        if (!resolve_modify_field(wres, TREE_ENUM_ENABLED, sa.s))
+            log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", SS_MASTER + 1) ;
+
+        tres.nenabled = nb ;
+    }
+
+    write:
+        if (!resolve_write(wres, solve, SS_MASTER + 1))
+            log_dieusys(LOG_EXIT_SYS, "read resolve file of inner tree") ;
+
+        resolve_free(wres) ;
+        stralloc_free(&sa) ;
+}
+
+void tree_enable_disable_deps(graph_t *g,char const *base, char const *treename, uint8_t action)
+{
+    log_flow() ;
+
+    size_t pos = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (graph_matrix_get_edge_g(&sa, g, treename, action ? 0 : 1) < 0)
+        log_dieu(LOG_EXIT_SYS, "get ", action ? "dependencies" : "required by" ," of: ", treename) ;
+
+    size_t len = sastr_nelement(&sa) ;
+    visit v[len] ;
+
+    visit_init(v, len) ;
+
+    if (sa.len) {
+
+        FOREACH_SASTR(&sa, pos) {
+
+            if (v[pos] == SS_WHITE) {
+
+                char *name = sa.s + pos ;
+
+                tree_enable_disable(g, base, name, action) ;
+
+                v[pos] = SS_GRAY ;
             }
+        }
+    }
+
+    stralloc_free(&sa) ;
+}
+
+/** @action -> 0 disable
+ * @action -> 1 enable */
+void tree_enable_disable(graph_t *g, char const *base, char const *treename, uint8_t action)
+{
+    log_flow() ;
+
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
+    size_t baselen = strlen(base) ;
+
+    char solve[baselen + SS_SYSTEM_LEN + 1] ;
+
+    uint8_t disen = tree_isenabled(base, treename) ;
+    if (disen < 0)
+        log_dieu(LOG_EXIT_SYS, "read resolve file of: ", treename) ;
 
-            //if (seed.services)
+    if ((disen && !action) || (!disen && action)){
+
+        log_trace(!action ? "disable " : "enable ", base, SS_SYSTEM, "/" , treename, "...") ;
+
+        if (tree_ongroups(base, treename, TREE_GROUPS_BOOT) && action) {
+            log_1_warn(treename," is a part of group ", TREE_GROUPS_BOOT," -- ignoring enable request") ;
+            return ;
         }
 
+        auto_strings(solve, base, SS_SYSTEM) ;
 
-        log_trace("creating: ",info->tree.s,"..." ) ;
-        create_tree(info) ;
+        if (!resolve_read(wres, solve, treename))
+            log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", solve, "/", treename) ;
 
-        log_trace("creating backup directory for: ", tree,"...") ;
-        create_backupdir(info) ;
-        /** unset cleanup */
-        cleantree = 0 ;
+        if (!resolve_modify_field_g(wres, base, treename, TREE_ENUM_DISEN, !action ? "0" : "1"))
+            log_dieu(LOG_EXIT_SYS, "modify field: ", resolve_tree_field_table[TREE_ENUM_DISEN].field," of tree: ", treename, " with value: ", !action ? "0" : "1") ;
 
-        // set permissions
-        allow = 1 ;
+        tree_enable_disable_deps(g, base, treename, action) ;
+        tree_master_enable_disable(base, treename, action) ;
 
-        size_t dblen = info->tree.len ;
-        char newdb[dblen + SS_SVDIRS_LEN + 1] ;
-        auto_strings(newdb, info->tree.s, SS_SVDIRS) ;
+        log_info(!action ? "Disabled" : "Enabled"," successfully tree: ", treename) ;
 
-        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) ;
+    } else {
 
-        r = 1 ;
-        create = 0 ;
-        log_info("Created successfully tree: ",tree) ;
+        log_info("Already ",!action ? "disabled" : "enabled"," tree: ",treename) ;
     }
 
-    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") ;
+    resolve_free(wres) ;
+}
 
+/* !deps -> add
+ * deps -> remove */
+void tree_depends_requiredby(graph_t *g, char const *base, char const *treename, uint8_t requiredby, uint8_t none, char const *deps)
+{
+    log_flow() ;
+
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
+    size_t pos = 0, len = 0, nb = 0, baselen = strlen(base) ;
+    uint8_t ewhat = !requiredby ? TREE_ENUM_DEPENDS : TREE_ENUM_REQUIREDBY ;
+    uint8_t nwhat = !requiredby ? TREE_ENUM_NDEPENDS : TREE_ENUM_NREQUIREDBY ;
+    stralloc sa = STRALLOC_ZERO ;
+    char pack[UINT_FMT] ;
+    char solve[baselen + SS_SYSTEM_LEN + 1] ;
+
+    log_trace("manage ", !requiredby ? "dependencies" : "required by", " for tree: ", treename, "..." ) ;
+
+    auto_strings(solve, base, SS_SYSTEM) ;
+
+    if (graph_matrix_get_edge_g_sorted(&sa, g, treename, requiredby) < 0)
+        log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", treename) ;
+
+    size_t vlen = sastr_nelement(&sa) ;
+    visit v[vlen] ;
+
+    visit_init(v, vlen) ;
+
+    len = sa.len ;
+    {
+        char t[len + 1] ;
+
+        sastr_to_char(t, &sa) ;
+
+        sa.len = 0 ;
 
+        for(; pos < len ; pos += strlen(t + pos) + 1) {
 
-    if (enable) {
-        /**
-         *
-         *
-         * Also, check if depends of the tree are enabled.
-         *
-         *
-         *
-         * */
+            if (v[pos] == SS_WHITE) {
 
+                char *name = t + pos ;
 
-        if (!graph_matrix_build(&GRAPH))
-            log_dieu(LOG_EXIT_SYS,"build the graph") ;
+                if (!none) {
 
-        if (!graph_matrix_analyze_cycle(&GRAPH))
-            log_die(LOG_EXIT_SYS,"found cycle") ;
+                    if (!graph_edge_remove_g(g, treename, name))
+                       log_dieu(LOG_EXIT_SYS,"remove edge: ", name, " from vertex: ", treename);
 
-        if (!graph_matrix_sort(&GRAPH))
-            log_dieu(LOG_EXIT_SYS,"sort the graph") ;
+                } else {
 
-        graph_show_matrix(&GRAPH) ;
+                    if (deps) {
+                        if (!strcmp(name, deps)) {
+                            v[pos] = SS_GRAY ;
+                            continue ;
+                        }
+                    }
 
-        for (unsigned int i = 0 ; i < GRAPH.sort_count ; i++)
-            printf("%s\n",GRAPH.data.s + genalloc_s(graph_hash_t,&GRAPH.hash)[GRAPH.sort[i]].vertex) ;
-        tree_enable_disable(info,1) ;
+                    if (!auto_stra(&sa, name, " "))
+                        log_die_nomem("stralloc") ;
 
+                    nb++ ;
+                }
+
+                v[pos] = SS_GRAY ;
+            }
+        }
     }
+    if (sa.len)
+        sa.len-- ; //remove last " "
+
+    if (!stralloc_0(&sa))
+        log_die_nomem("stralloc") ;
 
-    if (disable)
-        tree_enable_disable(info,0) ;
+    uint_pack(pack, nb) ;
+    pack[uint_fmt(pack, nb)] = 0 ;
 
-    if (allow)
-        set_rules(info->tree.s,auids,1) ;
+    if (!resolve_read(wres, solve, treename))
+        log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", solve, "/.resolve/", treename) ;
 
-    if (deny)
-        set_rules(info->tree.s,duids,0) ;
+    if (!resolve_modify_field(wres, ewhat, sa.s) ||
+        !resolve_modify_field(wres, nwhat, pack))
+            log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ;
 
-    if(current) {
+    if (!resolve_write(wres, solve, treename))
+        log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", solve, "/.resolve/", treename) ;
 
-        log_trace("make: ",info->tree.s," as default ..." ) ;
+    if (!none) {
 
-        if (!tree_switch_current(info->base.s,tree))
-            log_dieusys(LOG_EXIT_SYS,"set: ",info->tree.s," as default") ;
+        graph_free_matrix(g) ;
+        graph_free_sort(g) ;
+
+        if (!graph_matrix_build(g))
+            log_die(LOG_EXIT_SYS, "build the graph") ;
+
+        if (!graph_matrix_analyze_cycle(g))
+            log_die(LOG_EXIT_SYS, "found cycle") ;
+
+        if (!graph_matrix_sort(g))
+            log_die(LOG_EXIT_SYS, "sort the graph") ;
 
-        log_info("Set successfully: ",tree," as default") ;
     }
 
-    if (remove)
-        tree_remove(info) ;
+    stralloc_free(&sa) ;
+    resolve_free(wres) ;
 
-    if (snap) {
+    log_info(requiredby ? "Required by " : "Dependencies ", "successfully managed for tree: ", treename) ;
+}
 
-        stralloc salist = STRALLOC_ZERO ;
-        resolve_service_t res = RESOLVE_SERVICE_ZERO ;
-        resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ;
-        char const *exclude[1] = { 0 } ;
+void tree_depends_requiredby_deps(graph_t *g, char const *base, char const *treename, uint8_t requiredby, uint8_t none, char const *deps)
+{
+    log_flow() ;
 
-        size_t syslen = info->base.len + SS_SYSTEM_LEN ;
-        size_t treelen = info->treename.len ;
-        size_t pos = 0 ;
+    size_t baselen = strlen(base), pos = 0, len = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+    char solve[baselen + SS_SYSTEM_LEN + 1] ;
 
-        char system[syslen + 1] ;
-        auto_strings(system,info->base.s,SS_SYSTEM) ;
+    if (graph_matrix_get_edge_g_sorted(&sa, g, treename, requiredby) < 0)
+        log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", treename) ;
 
-        size_t clone_target_len = syslen + 1 + clone.len ;
-        char clone_target[clone_target_len + 1] ;
-        auto_strings(clone_target,system,"/",clone.s) ;
+    size_t vlen = sastr_nelement(&sa) ;
+    visit v[vlen] ;
 
-        r = scan_mode(clone_target,S_IFDIR) ;
-        if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ;
+    visit_init(v, vlen) ;
 
-        // 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) ;
+    auto_strings(solve, base, SS_SYSTEM) ;
 
-        // 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) ;
+    len = sa.len ;
+    char t[len + 1] ;
 
-        char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ;
-        auto_strings(tree_backup,system,SS_BACKUP,"/",tree) ;
+    sastr_to_char(t, &sa) ;
 
-        /* make cleantree pointing to the clone to be able to remove it
-         * in case of crach */
-        cleantree = clone_target ;
+    for(; pos < len ; pos += strlen(t + pos) + 1) {
 
-        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) ;
+        if (v[pos] == SS_WHITE) {
 
-        // 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) ;
+            char *name = t + pos ;
 
-        if (!sastr_dir_get(&salist,src_resolve,exclude,S_IFREG))
-            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ;
+            tree_depends_requiredby(g, base, name, !requiredby, none, deps) ;
 
-        char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ;
-        auto_strings(clone_res,clone_target,SS_SVDIRS) ;
+            v[pos] = SS_GRAY ;
+        }
+    }
 
-        FOREACH_SASTR(&salist, pos) {
+    stralloc_free(&sa) ;
+}
 
-            char *name = salist.s + pos ;
+/** @what -> 0 deny
+ * @what -> 1 allow */
+void tree_rules(char const *base, char const *treename, uid_t *uids, uint8_t what)
+{
+    log_flow() ;
 
-            if (!resolve_read(wres,clone_res,name))
-                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ;
+    int r ;
+    size_t baselen = strlen(base), treenamelen = strlen(treename), uidn = uids[0], pos = 0, len = 0 ;
+    uid_t owner = MYUID ;
+    char pack[256] ;
+    char tmp[baselen + SS_SYSTEM_LEN + 1 + treenamelen + SS_RULES_LEN + 1] ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
 
-            tree_modify_resolve(&res,SERVICE_ENUM_RUNAT,tree,clone.s) ;
-            tree_modify_resolve(&res,SERVICE_ENUM_TREENAME,tree,clone.s) ;
-            tree_modify_resolve(&res,SERVICE_ENUM_TREE,tree,clone.s) ;
-            tree_modify_resolve(&res,SERVICE_ENUM_STATE,tree,clone.s) ;
+    log_trace("set ", !what ? "denied" : "allowed", " user for tree: ", treename, "..." ) ;
 
-            if (!resolve_write(wres,clone_res,name))
-                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ;
+    auto_strings(tmp, base, SS_SYSTEM) ;
+
+    if (!resolve_read(wres, tmp, treename))
+        log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", tmp, "/.resolve/", treename) ;
+
+    if (tres.nallow)
+        if (!sastr_clean_string(&sa, tres.sa.s + tres.allow))
+            log_dieu(LOG_EXIT_SYS, "clean string") ;
+
+    /** fresh creation of the tree */
+    if (!tres.nallow) {
+
+        if (!uids[0]) {
+
+            uids[0] = 1 ;
+            uids[1] = owner ;
+
+        } else {
+            /** command can be 66-tree -a <account> <tree>
+             * where <tree> doesn't exist yet.
+             * Keep the -a option value and append the owner
+             * of the process at the end of the list. */
+            uids[0]++ ;
+            uids[uidn + 1] = owner ;
         }
 
-        // 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) ;
+        uidn++ ;
+
+    }
+
+    //allow
+    if (what) {
 
-        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) ;
+        auto_strings(tmp, base, SS_SYSTEM, "/", treename, SS_RULES) ;
 
-        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) ;
+        for (; pos < uidn ; pos++) {
 
-        // backup directory
-        char src_resolve_backup[clone_backup_len + SS_RESOLVE_LEN + 1] ;
-        auto_strings(src_resolve_backup,clone_backup,SS_RESOLVE) ;
+            uint32_pack(pack,uids[pos+1]) ;
+            pack[uint_fmt(pack,uids[pos+1])] = 0 ;
 
-        salist.len = 0 ;
+            log_trace("create file: ",tmp,"/", pack) ;
 
-        /** 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(!file_create_empty(tmp,pack,0644) && errno != EEXIST)
+                log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ;
 
-            if (!sastr_dir_get(&salist,src_resolve_backup,exclude,S_IFREG))
-                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ;
+            /** avoid double entry of the owner of the tree */
+            if (sastr_cmp(&sa, pack) < 0) {
 
-            pos = 0 ;
-            FOREACH_SASTR(&salist, pos) {
+                if (!sastr_add_string(&sa, pack))
+                    log_die_nomem("stralloc") ;
 
-                char *name = salist.s + pos ;
+                tres.nallow++ ;
+            }
 
-                if (!resolve_read(wres,clone_backup,name))
-                    log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ;
+            log_trace("user: ", pack, " is allowed for tree: ", treename) ;
+        }
 
-                tree_modify_resolve(&res,SERVICE_ENUM_RUNAT,tree,clone.s) ;
-                tree_modify_resolve(&res,SERVICE_ENUM_TREENAME,tree,clone.s) ;
-                tree_modify_resolve(&res,SERVICE_ENUM_TREE,tree,clone.s) ;
-                tree_modify_resolve(&res,SERVICE_ENUM_STATE,tree,clone.s) ;
+    } else {
+        //deny
+        for (; pos < uidn ; pos++) {
 
-                if (!resolve_write(wres,clone_backup,name))
-                    log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ;
+            /** Keep at least the current owner of the process
+             *  of the tree */
+            if (owner == uids[pos+1]) {
+                log_1_warn("you can not deny yourself -- ignoring request") ;
+                continue ;
             }
-            // 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) ;
+            uint32_pack(pack,uids[pos+1]) ;
+            pack[uint_fmt(pack,uids[pos+1])] = 0 ;
+            char ut[baselen + SS_SYSTEM_LEN + 1 + treenamelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos+1]) + 1] ;
+
+            auto_strings(ut, base, SS_SYSTEM, "/", treename, SS_RULES,  "/", pack) ;
+
+            r = scan_mode(ut,S_IFREG) ;
+            if (r == 1) {
+
+                if (!sastr_remove_element(&sa, pack))
+                    log_dieu(LOG_EXIT_SYS, "remove: ", pack, " from list") ;
+
+                for (size_t poss = 0 ; poss < len ; poss += strlen(sa.s + pos) + 1)
+                    printf("    name::%s\n",sa.s + poss) ;
+                tres.nallow-- ;
+
+                log_trace("unlink: ",ut) ;
+                r = unlink(ut) ;
+                if (r == -1)
+                    log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ;
+            }
 
-            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) ;
+            log_trace("user: ", pack, " is denied for tree: ", treename) ;
         }
+    }
 
-        stralloc_free(&salist) ;
-        resolve_free(wres) ;
+    tmp[baselen + SS_SYSTEM_LEN] = 0 ;
+    len = sa.len ;
+
+    char t[len + 1] ;
+
+    sastr_to_char(t, &sa) ;
+
+    sa.len = 0 ;
+
+    for (pos = 0 ; pos < len ; pos += strlen(t + pos) + 1)
+        if (!auto_stra(&sa, t + pos, " "))
+            log_die_nomem("stralloc") ;
+
+    if (sa.len)
+        sa.len-- ;
+
+    if (!stralloc_0(&sa))
+        log_die_nomem("stralloc") ;
+
+    if (!resolve_modify_field(wres, TREE_ENUM_ALLOW, sa.s))
+        log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ;
+
+    if (!resolve_write(wres, tmp, treename))
+        log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", treename) ;
+
+    stralloc_free(&sa) ;
+    resolve_free(wres) ;
+
+    log_info("Permissions rules set successfully for tree: ", treename) ;
+}
+
+void tree_remove(graph_t *g, char const *base, char const *treename)
+{
+    log_flow() ;
+
+    int r ;
+    size_t baselen = strlen(base), treenamelen = strlen(treename) ;
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
+
+    char tree[baselen + SS_SYSTEM_LEN + 1 + treenamelen + 1] ;
+
+    auto_strings(tree, base, SS_SYSTEM, "/", treename) ;
+
+    log_trace("delete: ", tree, "..." ) ;
+
+    if (!dir_rm_rf(tree))
+        log_dieusys(LOG_EXIT_SYS,"delete: ", tree) ;
+
+    char tmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen  + 1] ;
+
+    auto_strings(tmp, base, SS_SYSTEM) ;
+
+    if (!resolve_read(wres, tmp, treename))
+        log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", tmp, "/.resolve/", treename) ;
+
+    tree_enable_disable(g, base, treename, 0) ;
+
+    /** depends */
+    tree_depends_requiredby_deps(g, base, treename, 0, 1, treename) ;
+
+    /** requiredby */
+    tree_depends_requiredby_deps(g, base, treename, 1, 1, treename) ;
+
+    log_trace("remove resolve file of tree: ", treename) ;
+
+    resolve_rmfile(tmp, treename) ;
+
+    auto_strings(tmp + baselen + SS_SYSTEM_LEN, SS_BACKUP, "/", treename) ;
+
+    r = scan_mode(tmp,S_IFDIR) ;
+    if (r || (r < 0)) {
+
+        log_trace("delete backup of tree: ", tmp, "...") ;
+        if (!dir_rm_rf(tmp))
+            log_dieusys(LOG_EXIT_SYS, "delete: ", tmp) ;
 
-        log_info("Cloned successfully: ",tree," to ",clone.s) ;
     }
 
-    if (after_tree) {
+    resolve_free(wres) ;
+
+    log_info("Deleted successfully: ", treename) ;
+}
+
+void tree_current(ssexec_t *info)
+{
+    log_trace("mark: ", info->treename.s," as default ..." ) ;
+
+    if (!tree_switch_current(info->base.s, info->treename.s))
+        log_dieusys(LOG_EXIT_SYS,"set: ", info->treename.s, " as default") ;
+
+    log_info("Set successfully: ", info->treename.s," as default") ;
+
+}
+
+void tree_clone(char const *clone, ssexec_t *info)
+{
+    log_flow() ;
+
+    int r ;
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
+    stralloc sa = STRALLOC_ZERO ;
+    char const *exclude[1] = { 0 } ;
+
+    size_t syslen = info->base.len + SS_SYSTEM_LEN ;
+    size_t treelen = info->treename.len, clonelen = strlen(clone) ;
+    size_t pos = 0 ;
 
-        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) ;
+    char system[syslen + 1] ;
+    auto_strings(system,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") ;
+    size_t clone_target_len = syslen + 1 + clonelen ;
+    char clone_target[clone_target_len + 1] ;
+    auto_strings(clone_target,system,"/",clone) ;
 
-        enabled = tree_cmd_state(VERBOSITY,"-s",after_tree) ;
-        if (enabled != 1)
-            log_die(LOG_EXIT_USER,"tree: ",after_tree," is not enabled") ;
+    r = scan_mode(clone_target,S_IFDIR) ;
+    if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ;
 
-        r  = tree_cmd_state(VERBOSITY,"-d",tree) ;
-        if (!r) log_dieusys(LOG_EXIT_SYS,"disable: ",tree," at: ",ste,SS_STATE) ;
+    // clone main directory
+    log_trace("clone: ",info->treename.s," as: ",clone,"..." ) ;
+    if (!hiercopy(info->tree.s,clone_target))
+        log_dieusys(LOG_EXIT_SYS,"copy: ",info->tree.s," to: ",clone_target) ;
 
-        r = file_readputsa(&tmp,ste,SS_STATE + 1) ;
-        if(!r) log_dieusys(LOG_EXIT_SYS,"open: ", ste,SS_STATE) ;
+    // clone backup directory
+    size_t clone_backup_len = syslen + SS_BACKUP_LEN + 1 + clonelen ;
+    char clone_backup[clone_backup_len + 1] ;
+    auto_strings(clone_backup,system,SS_BACKUP,"/",clone) ;
 
-        /** 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. */
+    char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ;
+    auto_strings(tree_backup,system,SS_BACKUP,"/",info->treename.s) ;
 
-        if (tmp.len) {
+    /* make cleantree pointing to the clone to be able to remove it
+     * in case of crach */
+    cleantree = clone_target ;
 
-            if (!sastr_rebuild_in_oneline(&tmp) ||
-            !sastr_clean_element(&tmp))
-                log_dieu(LOG_EXIT_SYS,"rebuild state list") ;
+    log_trace("clone backup of: ",info->treename.s," as: ",clone,"..." ) ;
+    if (!hiercopy(tree_backup,clone_backup))
+        log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tree_backup," to: ",clone_backup) ;
 
-            pos = 0 ;
-            FOREACH_SASTR(&tmp, pos) {
+    // 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) ;
 
-                char *name = tmp.s + pos ;
+    if (!sastr_dir_get(&sa,src_resolve,exclude,S_IFREG))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ;
 
-                /* 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") ;
+    char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ;
+    auto_strings(clone_res,clone_target,SS_SVDIRS) ;
 
-                if (obstr_equal(name,after_tree))
-                {
-                    if (!auto_stra(&contents,tree,"\n"))
-                        log_dieusys(LOG_EXIT_SYS,"stralloc") ;
-                }
+    FOREACH_SASTR(&sa, pos) {
+
+        char *name = sa.s + pos ;
+
+        if (!resolve_read(wres,clone_res,name))
+            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ;
+
+        if (!resolve_modify_field(wres, SERVICE_ENUM_RUNAT, clone)  ||
+            !resolve_modify_field(wres, SERVICE_ENUM_TREENAME, clone) ||
+            !resolve_modify_field(wres, SERVICE_ENUM_TREE, clone) ||
+            !resolve_modify_field(wres, SERVICE_ENUM_STATE, clone))
+                log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "modify resolve file of: ", name) ;
+
+        if (!resolve_write(wres,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,"/",info->treename.s) ;
+
+    char clone_db_new[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + clonelen + 1] ;
+    auto_strings(clone_db_new,clone_target,SS_SVDIRS,SS_DB,"/",clone) ;
+
+    log_trace("rename tree db: ",info->treename.s," as: ",clone,"..." ) ;
+    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) ;
+
+    sa.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(&sa,src_resolve_backup,exclude,S_IFREG))
+            log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ;
+
+        pos = 0 ;
+        FOREACH_SASTR(&sa, pos) {
+
+            char *name = sa.s + pos ;
+
+            if (!resolve_read(wres,clone_backup,name))
+                log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ;
+
+            if (!resolve_modify_field(wres, SERVICE_ENUM_RUNAT, clone) ||
+                !resolve_modify_field(wres, SERVICE_ENUM_TREENAME, clone) ||
+                !resolve_modify_field(wres, SERVICE_ENUM_TREE, clone) ||
+                !resolve_modify_field(wres, SERVICE_ENUM_STATE, clone))
+                    log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "modify resolve file of: ", name) ;
+
+            if (!resolve_write(wres,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,"/",info->treename.s) ;
+
+        char clone_db_backup_new[clone_backup_len + SS_DB_LEN + 1 + clonelen + 1] ;
+        auto_strings(clone_db_backup_new,clone_backup,SS_DB,"/",clone) ;
+
+        log_trace("rename tree backup db: ",info->treename.s," as: ",clone,"..." ) ;
+        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) ;
+    }
+    /** tree resolve file */
+
+    resolve_free(wres) ;
+
+    wres = resolve_set_struct(DATA_TREE, &tres) ;
+
+    if (!resolve_read(wres, system, info->treename.s))
+        log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ", system, "/", info->treename.s) ;
+
+    if (!resolve_modify_field(wres, TREE_ENUM_ENABLED, 0) ||
+        !resolve_modify_field(wres, TREE_ENUM_NAME, clone))
+            log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", clone) ;
+
+    tres.disen = 0 ;
+
+    if (!resolve_write(wres, system, clone))
+        log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "write resolve file of: ", system, "/", clone) ;
+
+    resolve_free(wres) ;
+
+    log_info("Cloned successfully: ", info->treename.s, " to: ", clone) ;
+}
+
+int ssexec_tree(int argc, char const *const *argv, char const *const *envp, ssexec_t *info)
+{
+    int r ;
+
+    stralloc sa = STRALLOC_ZERO ;
+    graph_t graph = GRAPH_ZERO ;
+
+    tree_what_t what = what_init() ;
+
+    {
+        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 'c' :
+
+                    what.current = 1 ;
+                    what.nopts++ ;
+                    break ;
+
+               case 'o' :
+
+                    if (!auto_stra(&sa, l.arg))
+                        log_die_nomem("stralloc") ;
+                    what.nopts++ ;
+                    break ;
+
+                case 'E' :
+
+                    what.enable = 1 ;
+                    what.nopts++ ;
+                    break ;
+
+                case 'D' :
+
+                    what.disable = 1 ;
+                    what.nopts++ ;
+                    break ;
+
+                case 'R' :
+
+                    what.remove = 1 ;
+                    what.create = 0 ;
+                    what.nopts++ ;
+                    break ;
+
+                case 'n':
+
+                    log_1_warn("deprecated option -n -- creation of a tree is the default option") ;
+                    break ;
+
+                case 'a' :
+
+                    log_1_warn("deprecated option -a -- see allow field at -o options") ;
+                    break ;
+
+                case 'd' :
+
+                    log_1_warn("deprecated option -d -- see allow field at -o options") ;
+                    break ;
+
+                case 'C' :
+
+                    log_1_warn("deprecated option -C -- see clone field at -o options") ;
+                    break ;
+
+                case 'S' :
+
+                    log_1_warn("deprecated option -S -- see depends/requiredb fields at -o options") ;
+                    break ;
+
+                default :
+
+                    log_usage(usage_tree) ;
             }
+        }
+        argc -= l.ind ; argv += l.ind ;
+    }
 
-        } else {
+    if (argc < 1) log_usage(usage_tree) ;
+
+    check_identifier(argv[0]) ;
+
+    info->treename.len = 0 ;
+    if (!auto_stra(&info->treename, argv[0]))
+        log_die_nomem("stralloc") ;
+
+    sanitize_system(info) ;
 
-            if (!auto_stra(&contents,tree,"\n"))
-                log_dieusys(LOG_EXIT_SYS,"stralloc") ;
+    r = tree_isvalid(info->base.s, info->treename.s) ;
+    if (r < 0)
+        log_diesys(LOG_EXIT_SYS, "invalid tree directory") ;
+
+    info->tree.len = 0 ;
+    if (!auto_stra(&info->tree, info->base.s, SS_SYSTEM, "/", info->treename.s))
+        log_die_nomem("stralloc") ;
+
+    tree_parse_options(&graph, sa.s, info, &what) ;
+
+    /** create is the option by default
+     * mark it false if the tree already exist */
+    if (r) {
+        if (!what.nopts) {
+            log_1_warn(info->treename.s, ": already exist") ;
+            goto freed ;
         }
+        what.create = 0 ;
+    }
 
-        if (!file_write_unsafe(ste,SS_STATE + 1,contents.s,contents.len))
-            log_dieusys(LOG_EXIT_ZERO,"write: ",ste,SS_STATE) ;
+    if(!r && what.create)
+        tree_create(&graph, info, &what, envp) ;
 
-        log_info("Ordered successfully: ",tree," starts after tree: ",after_tree) ;
+    if (!r && what.remove)
+        log_dieusys(LOG_EXIT_SYS,"find tree: ", info->treename.s) ;
+
+    if (!graph_build(&graph, info->base.s, info->treename.s, DATA_TREE))
+        log_dieu(LOG_EXIT_SYS,"build the graph") ;
+
+    if (what.remove) {
+        tree_remove(&graph, info->base.s, info->treename.s) ;
+        goto freed ;
     }
 
-    stralloc_free(&clone) ;
-    stralloc_free(&TREE_SAOPTS) ;
-    graph_free_all(&GRAPH) ;
-    tree_seed_free();
+    /** groups influence on enable. Apply it first */
+    if (what.groups)
+        tree_groups(info->base.s, info->treename.s, what.gr) ;
+
+    if (what.depends) {
+
+        tree_depends_requiredby(&graph, info->base.s, info->treename.s, 0, what.ndepends, 0) ;
+
+        tree_depends_requiredby_deps(&graph, info->base.s, info->treename.s, 0, what.ndepends, 0) ;
+    }
+
+    if (what.requiredby) {
+
+        tree_depends_requiredby(&graph, info->base.s, info->treename.s, 1, what.nrequiredby, 0) ;
+
+        tree_depends_requiredby_deps(&graph, info->base.s, info->treename.s, 1, what.nrequiredby, 0) ;
+    }
+
+    if (what.enable)
+        tree_enable_disable(&graph, info->base.s, info->treename.s, 1) ;
+
+    if (what.disable)
+        tree_enable_disable(&graph, info->base.s, info->treename.s, 0) ;
+
+    if (what.allow)
+        tree_rules(info->base.s, info->treename.s, what.auids, 1) ;
+
+    if (what.deny)
+        tree_rules(info->base.s, info->treename.s, what.duids, 0) ;
+
+    if (what.current)
+        tree_current(info) ;
+
+    if (what.clone)
+        tree_clone(what.sclone, info) ;
+
+    freed:
+        stralloc_free(&sa) ;
+        graph_free_all(&graph) ;
 
     return 0 ;
 }