diff --git a/src/include/66/ssexec.h b/src/include/66/ssexec.h
index 6691708288e62cd1b28344bbd8d69168af622d7a..696dfaafa7444d34c4ee68ec0854293d17b947ef 100644
--- a/src/include/66/ssexec.h
+++ b/src/include/66/ssexec.h
@@ -116,6 +116,8 @@ extern ssexec_func_t ssexec_reconfigure ;
 extern ssexec_func_t ssexec_reload ;
 extern ssexec_func_t ssexec_restart ;
 extern ssexec_func_t ssexec_inresolve ;
+extern ssexec_func_t ssexec_resolve_service ;
+extern ssexec_func_t ssexec_resolve_tree ;
 extern ssexec_func_t ssexec_instate ;
 extern ssexec_func_t ssexec_intree ;
 extern ssexec_func_t ssexec_inservice ;
@@ -123,6 +125,8 @@ extern ssexec_func_t ssexec_boot ;
 extern ssexec_func_t ssexec_scanctl ;
 extern ssexec_func_t ssexec_scandir ;
 extern ssexec_func_t ssexec_tree_wrapper ;
+extern ssexec_func_t ssexec_service_wrapper ;
+extern ssexec_func_t ssexec_service_admin ;
 
 extern char const *usage_parse ;
 extern char const *help_parse ;
@@ -166,6 +170,10 @@ extern char const *usage_scanctl ;
 extern char const *help_scanctl ;
 extern char const *usage_scandir ;
 extern char const *help_scandir ;
+extern char const *usage_service_wrapper ;
+extern char const *help_service_wrapper ;
+extern char const *usage_service_admin ;
+extern char const *help_service_admin ;
 extern char const *usage_66 ;
 
 #define OPTS_SUBSTART "P"
@@ -176,7 +184,7 @@ extern char const *usage_66 ;
 #define OPTS_INIT_LEN (sizeof OPTS_INIT - 1)
 #define OPTS_ENABLE "fFSI"
 #define OPTS_ENABLE_LEN (sizeof OPTS_ENABLE - 1)
-#define OPTS_DISABLE "SFR"
+#define OPTS_DISABLE "S"
 #define OPTS_DISABLE_LEN (sizeof OPTS_DISABLE - 1)
 #define OPTS_START "P"
 #define OPTS_START_LEN (sizeof OPTS_START - 1)
@@ -204,6 +212,10 @@ extern char const *usage_66 ;
 #define OPTS_SCANCTL_LEN (sizeof OPTS_SCANCTL - 1)
 #define OPTS_SCANDIR "bl:s:o:L:cB"
 #define OPTS_SCANDIR_LEN (sizeof OPTS_SCANDIR - 1)
+#define OPTS_SERVICE_WRAPPER ""
+#define OPTS_SERVICE_WRAPPER_LEN (sizeof OPTS_SERVICE_WRAPPER - 1)
+#define OPTS_SERVICE_ADMIN ""
+#define OPTS_SERVICE_ADMIN_LEN (sizeof OPTS_SERVICE_ADMIN - 1)
 
 
 
diff --git a/src/lib66/exec/deps-lib/deps b/src/lib66/exec/deps-lib/deps
index 5570d296e1a0480df8ecd80215431cefa62e6fff..96614ae633152379f058168675a162816b0622e0 100644
--- a/src/lib66/exec/deps-lib/deps
+++ b/src/lib66/exec/deps-lib/deps
@@ -6,21 +6,24 @@ ssexec_env.o
 ssexec_free.o
 ssexec_help.o
 ssexec_init.o
-ssexec_inresolve.o
 ssexec_inservice.o
 ssexec_instate.o
 ssexec_intree.o
 ssexec_parse.o
 ssexec_reconfigure.o
 ssexec_reload.o
+ssexec_resolve_service.o
+ssexec_resolve_tree.o
 ssexec_restart.o
 ssexec_scanctl.o
 ssexec_scandir.o
+ssexec_service_wrapper.o
 ssexec_start.o
 ssexec_stop.o
 ssexec_svctl.o
 ssexec_tree.o
 ssexec_treectl.o
+ssexec_service_admin.o
 ssexec_tree_wrapper.o
 -ls6
 -loblibs
diff --git a/src/lib66/exec/ssexec_help.c b/src/lib66/exec/ssexec_help.c
index 0ee7956f310f4cf7989980971d1f2d828b61f35b..5f8de4de75b63d0ab84db71e1ce2cb781388436c 100644
--- a/src/lib66/exec/ssexec_help.c
+++ b/src/lib66/exec/ssexec_help.c
@@ -43,7 +43,7 @@ char const *help_enable =
 "   -S: enable and start the service\n"
 ;
 
-char const *usage_disable = "66 disable [ -h ] [ -z ] [ -v verbosity ] [ - l live ] [ -t tree ] [ -S ] [ -F ] [ -R ] service(s)" ;
+char const *usage_disable = "66 disable [ -h ] [ -z ] [ -v verbosity ] [ - l live ] [ -t tree ] [ -S ] service(s)" ;
 
 char const *help_disable =
 "\n"
@@ -53,9 +53,7 @@ char const *help_disable =
 "   -v: increase/decrease verbosity\n"
 "   -l: live directory\n"
 "   -t: name of the tree to use\n"
-"   -S: disable and stop the service\n"
-"   -F: forces to disable the service\n"
-"   -R: disable the service and remove its configuration and logger files\n"
+"   -S: disable and stop/unsupervice the service if needed\n"
 ;
 
 char const *usage_init = "66 init [ -h ] [ -z ] [ -v verbosity ] [ -l live ] tree" ;
@@ -311,6 +309,60 @@ char const *help_inservice =
 "   logfile: displays the contents of the log file\n"
 ;
 
+/**
+ *
+ * pass -g as default
+ * -d -g -p become -o depth=,graph=none,reverse=,nline=
+ *
+ *
+ * */
+char const *usage_service_wrapper = "66 service [ -h ] [ -z ] [ -v verbosity ] [ -t tree ] status|resolve|state|remove [ -n ] [ -o name,intree,status,... ] [ -g ] [ -d depth ] [ -r ]  [ -p nline ] service" ;
+
+char const *help_service_wrapper =
+"\n"
+"options :\n"
+"   -h: print this help\n"
+"   -z: use color\n"
+"   -v: increase/decrease verbosity\n"
+"   -n: do not display the field name\n"
+"   -o: comma separated list of field to display\n"
+"   -g: displays the contents field as graph\n"
+"   -d: limit the depth of the contents field recursion\n"
+"   -r: reverse the contents field\n"
+"   -t: only search service at the specified tree\n"
+"   -p: print n last lines of the log file\n"
+"\n"
+"valid fields for -o options are:\n"
+"\n"
+"   name: displays the name\n"
+"   version: displays the version of the service\n"
+"   intree: displays the service's tree name\n"
+"   status: displays the status\n"
+"   type: displays the service type\n"
+"   description: displays the description\n"
+"   source: displays the source of the service's frontend file\n"
+"   live: displays the service's live directory\n"
+"   depends: displays the service's dependencies\n"
+"   requiredby: displays the service(s) which depends on service\n"
+"   extdepends: displays the service's external dependencies\n"
+"   optsdepends: displays the service's optional dependencies\n"
+"   start: displays the service's start script\n"
+"   stop: displays the service's stop script\n"
+"   envat: displays the source of the environment file\n"
+"   envfile: displays the contents of the environment file\n"
+"   logname: displays the logger's name\n"
+"   logdst: displays the logger's destination\n"
+"   logfile: displays the contents of the log file\n"
+;
+
+char const *usage_service_admin = "66 service remove [ -h ] service" ;
+
+char const *help_service_admin =
+"\n"
+"options :\n"
+"   -h: print this help\n"
+;
+
 char const *usage_boot = "66 boot [ -h ] [ -z ] [ -m ] [ -s skel ] [ -l log_user ] [ -e environment ] [ -d dev ] [ -b banner ]" ;
 
 char const *help_boot =
@@ -358,4 +410,4 @@ char const *help_scandir =
 "   -o: handles owner scandir\n"
 ;
 
-char const *usage_66 = "66 start|stop|unsupervise|enable|disable|init|env|parse|svctl|tree|reconfigure|reload|restart|scanctl|scandir|boot service(s)|tree" ;
+char const *usage_66 = "66 start|stop|reload|restart|unsupervise|reconfigure|enable|disable|env|service|tree|init|parse|svctl|scanctl|scandir|boot|version service(s)|tree" ;
diff --git a/src/lib66/exec/ssexec_inresolve.c b/src/lib66/exec/ssexec_inresolve.c
deleted file mode 100644
index 2ae548c905e0d50bc397d5f6f8050cfa4a59f1ff..0000000000000000000000000000000000000000
--- a/src/lib66/exec/ssexec_inresolve.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * ssexec_inresolve.c
- *
- * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
- *
- * All rights reserved.
- *
- * This file is part of Obarun. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution.
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file./
- */
-
-#include <string.h>
-#include <wchar.h>
-
-#include <oblibs/log.h>
-#include <oblibs/sastr.h>
-#include <oblibs/string.h>
-#include <oblibs/types.h>
-
-#include <skalibs/types.h>
-#include <skalibs/stralloc.h>
-#include <skalibs/lolstdio.h>
-#include <skalibs/buffer.h>
-
-#include <66/resolve.h>
-#include <66/ssexec.h>
-#include <66/tree.h>
-#include <66/service.h>
-#include <66/info.h>
-#include <66/utils.h>
-#include <66/constants.h>
-#include <66/config.h>
-#include <66/state.h>
-
-#define MAXOPTS 84
-
-static wchar_t const field_suffix[] = L" :" ;
-static char fields[INFO_NKEY][INFO_FIELD_MAXLEN] = {{ 0 }} ;
-
-static inline unsigned int lookup (char const *const *table, char const *data)
-{
-    log_flow() ;
-
-    unsigned int i = 0 ;
-    for (; table[i] ; i++) if (!strcmp(data, table[i])) break ;
-    return i ;
-}
-
-static inline unsigned int parse_what (char const *str)
-{
-    log_flow() ;
-
-    static char const *const table[] =
-    {
-        "service",
-        "tree",
-        0
-    } ;
-  unsigned int i = lookup(table, str) ;
-  if (!table[i]) i = 2 ;
-  return i ;
-}
-
-static void info_display_string(char const *field, char const *str, uint32_t element, uint8_t check)
-{
-    info_display_field_name(field) ;
-
-    if (check && !element) {
-
-        if (!bprintf(buffer_1,"%s%s", log_color->warning, "None"))
-            log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
-
-    } else {
-
-        if (!buffer_puts(buffer_1, str + element))
-            log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
-    }
-
-    if (buffer_putsflush(buffer_1, "\n") == -1)
-        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
-
-
-}
-
-static void info_display_int(char const *field, uint32_t element)
-{
-    info_display_field_name(field) ;
-
-    char ui[UINT_FMT] ;
-    ui[uint_fmt(ui, element)] = 0 ;
-
-    if (!buffer_puts(buffer_1, ui))
-        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
-
-    if (buffer_putsflush(buffer_1, "\n") == -1)
-        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
-}
-
-static void info_display_service_field(resolve_service_t *res)
-{
-    info_display_string(fields[0], res->sa.s, res->name, 0) ;
-    info_display_string(fields[1], res->sa.s, res->description, 1) ;
-    info_display_string(fields[2], res->sa.s, res->version, 1) ;
-    info_display_int(fields[3], res->type) ;
-    info_display_int(fields[4], res->notify) ;
-    info_display_int(fields[5], res->maxdeath) ;
-    info_display_int(fields[6], res->earlier) ;
-    info_display_string(fields[7], res->sa.s, res->hiercopy, 1) ;
-    info_display_string(fields[8], res->sa.s, res->intree, 1) ;
-    info_display_string(fields[9], res->sa.s, res->ownerstr, 1) ;
-    info_display_int(fields[10], res->owner) ;
-    info_display_string(fields[11], res->sa.s, res->treename, 1) ;
-    info_display_string(fields[12], res->sa.s, res->user, 1) ;
-    info_display_string(fields[13], res->sa.s, res->inmodule, 1) ;
-
-    info_display_string(fields[14], res->sa.s, res->path.home, 1) ;
-    info_display_string(fields[15], res->sa.s, res->path.frontend, 1) ;
-    info_display_string(fields[16], res->sa.s, res->path.tree, 1) ;
-    info_display_string(fields[17], res->sa.s, res->path.status, 1) ;
-
-    info_display_string(fields[18], res->sa.s, res->dependencies.depends, 1) ;
-    info_display_string(fields[19], res->sa.s, res->dependencies.requiredby, 1) ;
-    info_display_string(fields[20], res->sa.s, res->dependencies.optsdeps, 1) ;
-    info_display_int(fields[21], res->dependencies.ndepends) ;
-    info_display_int(fields[22], res->dependencies.nrequiredby) ;
-    info_display_int(fields[23], res->dependencies.noptsdeps) ;
-
-    info_display_string(fields[24], res->sa.s, res->execute.run.run, 1) ;
-    info_display_string(fields[25], res->sa.s, res->execute.run.run_user, 1) ;
-    info_display_string(fields[26], res->sa.s, res->execute.run.build, 1) ;
-    info_display_string(fields[27], res->sa.s, res->execute.run.shebang, 1) ;
-    info_display_string(fields[28], res->sa.s, res->execute.run.runas, 1) ;
-    info_display_string(fields[29], res->sa.s, res->execute.finish.run, 1) ;
-    info_display_string(fields[30], res->sa.s, res->execute.finish.run_user, 1) ;
-    info_display_string(fields[31], res->sa.s, res->execute.finish.build, 1) ;
-    info_display_string(fields[32], res->sa.s, res->execute.finish.shebang, 1) ;
-    info_display_string(fields[33], res->sa.s, res->execute.finish.runas, 1) ;
-    info_display_int(fields[34], res->execute.timeout.kill) ;
-    info_display_int(fields[35], res->execute.timeout.finish) ;
-    info_display_int(fields[36], res->execute.timeout.up) ;
-    info_display_int(fields[37], res->execute.timeout.down) ;
-    info_display_int(fields[38], res->execute.down) ;
-    info_display_int(fields[39], res->execute.downsignal) ;
-
-    info_display_string(fields[40], res->sa.s, res->live.livedir, 1) ;
-    info_display_string(fields[41], res->sa.s, res->live.scandir, 1) ;
-    info_display_string(fields[42], res->sa.s, res->live.statedir, 1) ;
-    info_display_string(fields[43], res->sa.s, res->live.eventdir, 1) ;
-    info_display_string(fields[44], res->sa.s, res->live.notifdir, 1) ;
-    info_display_string(fields[45], res->sa.s, res->live.supervisedir, 1) ;
-    info_display_string(fields[46], res->sa.s, res->live.fdholderdir, 1) ;
-    info_display_string(fields[47], res->sa.s, res->live.oneshotddir, 1) ;
-
-    info_display_string(fields[48], res->sa.s, res->logger.name, 1) ;
-    info_display_string(fields[49], res->sa.s, res->logger.destination, 1) ;
-    info_display_int(fields[50], res->logger.backup) ;
-    info_display_int(fields[51], res->logger.maxsize) ;
-    info_display_int(fields[52], res->logger.timestamp) ;
-    info_display_string(fields[53], res->sa.s, res->logger.execute.run.run, 1) ;
-    info_display_string(fields[54], res->sa.s, res->logger.execute.run.run_user, 1) ;
-    info_display_string(fields[55], res->sa.s, res->logger.execute.run.build, 1) ;
-    info_display_string(fields[56], res->sa.s, res->logger.execute.run.shebang, 1) ;
-    info_display_string(fields[57], res->sa.s, res->logger.execute.run.runas, 1) ;
-    info_display_int(fields[58], res->logger.execute.timeout.kill) ;
-    info_display_int(fields[59], res->logger.execute.timeout.finish) ;
-
-    info_display_string(fields[60], res->sa.s, res->environ.env, 1) ;
-    info_display_string(fields[61], res->sa.s, res->environ.envdir, 1) ;
-    info_display_int(fields[62], res->environ.env_overwrite) ;
-
-    info_display_string(fields[63], res->sa.s, res->regex.configure, 1) ;
-    info_display_string(fields[64], res->sa.s, res->regex.directories, 1) ;
-    info_display_string(fields[65], res->sa.s, res->regex.files, 1) ;
-    info_display_string(fields[66], res->sa.s, res->regex.infiles, 1) ;
-    info_display_int(fields[67], res->regex.ndirectories) ;
-    info_display_int(fields[68], res->regex.nfiles) ;
-    info_display_int(fields[69], res->regex.ninfiles) ;
-
-}
-
-int ssexec_inresolve(int argc, char const *const *argv, ssexec_t *info)
-{
-    int found = 0, what = 0 ;
-    uint8_t master = 0 ;
-
-    char const *svname = 0 ;
-    char const *treename = info->treename.s ;
-    char atree[SS_MAX_TREENAME + 1] ;
-
-    argc-- ;
-    argv++ ;
-
-    if (argc < 2) log_usage(usage_inresolve) ;
-
-    what = parse_what(*argv) ;
-    if (what == 2)
-        log_usage(usage_inresolve) ;
-
-    argv++;
-    argc--;
-    svname = *argv ;
-
-    if (!what) {
-
-        char service_buf[MAXOPTS][INFO_FIELD_MAXLEN] = {
-            "name",
-            "description" ,
-            "version",
-            "type",
-            "notify",
-            "maxdeath",
-            "earlier",
-            "hiercopy",
-            "intree",
-            "ownerstr",
-            "owner",
-            "treename",
-            "user" ,
-            "inmodule", // 14
-
-            "home",
-            "frontend",
-            "tree",
-            "status", //18
-
-            "depends",
-            "requiredby",
-            "optsdeps",
-            "ndepends",
-            "nrequiredby",
-            "noptsdeps", // 24
-
-            "run",
-            "run_user",
-            "run_build",
-            "run_shebang",
-            "run_runas",
-            "finish",
-            "finish_user",
-            "finish_build",
-            "finish_shebang",
-            "finish_runas",
-            "timeoutkill",
-            "timeoutfinish",
-            "timeoutup",
-            "timeoutdown",
-            "down",
-            "downsignal", // 40
-
-            "livedir",
-            "scandir",
-            "statedir",
-            "eventdir",
-            "notifdir",
-            "supervisedir",
-            "fdholderdir",
-            "oneshotddir", //48
-
-            "logname" ,
-            "logdestination" ,
-            "logbackup" ,
-            "logmaxsize" ,
-            "logtimestamp" ,
-            "logrun" ,
-            "logrun_user" ,
-            "logrun_build" ,
-            "logrun_shebang" ,
-            "logrun_runas" ,
-            "logtimeoutkill",
-            "logtimeoutfinish", // 60
-
-            "env",
-            "envdir",
-            "env_overwrite", // 63
-
-            "configure",
-            "directories",
-            "files",
-            "infiles",
-            "ndirectories",
-            "nfiles",
-            "ninfiles", // 70
-
-            "classic",
-            "bundle",
-            "oneshot",
-            "module",
-            "enabled",
-            "disabled",
-            "contents",
-            "nclassic",
-            "nbundle",
-            "noneshot",
-            "nmodule",
-            "nenabled",
-            "ndisabled",
-            "ncontents" // 84
-        } ;
-
-        resolve_wrapper_t_ref wres = 0 ;
-        resolve_service_t res = RESOLVE_SERVICE_ZERO ;
-        resolve_service_master_t mres = RESOLVE_SERVICE_MASTER_ZERO ;
-
-        if (!strcmp(svname, SS_MASTER + 1)) {
-
-            master = 1 ;
-            wres = resolve_set_struct(DATA_SERVICE_MASTER, &mres) ;
-
-        } else {
-
-            wres = resolve_set_struct(DATA_SERVICE, &res) ;
-        }
-
-        if (!master) {
-
-            found = service_is_g(atree, svname, STATE_FLAGS_ISPARSED) ;
-            if (found == -1)
-                log_dieu(LOG_EXIT_SYS, "get information of service: ", svname, " -- please a bug report") ;
-            else if (!found)
-                log_die(LOG_EXIT_USER, svname, " is not parsed -- try to parse it first") ;
-
-            if (!resolve_read_g(wres, info->base.s, svname))
-                log_dieusys(LOG_EXIT_SYS,"read resolve file") ;
-
-        } else {
-
-            char solve[info->base.len + SS_SYSTEM_LEN + 1 + strlen(treename) + SS_SVDIRS_LEN + 1] ;
-            auto_strings(solve, info->base.s, SS_SYSTEM, "/", treename, SS_SVDIRS) ;
-
-            if (!resolve_read(wres, solve, SS_MASTER + 1))
-                log_dieusys(LOG_EXIT_SYS,"read resolve file") ;
-        }
-
-        info_field_align(service_buf, fields, field_suffix,MAXOPTS) ;
-
-        if (!master) {
-
-            info_display_service_field(&res) ;
-
-        } else {
-
-                info_display_string(fields[0], mres.sa.s, mres.name, 0) ;
-                info_display_string(fields[70], mres.sa.s, mres.classic, 1) ;
-                info_display_string(fields[71], mres.sa.s, mres.bundle, 1) ;
-                info_display_string(fields[72], mres.sa.s, mres.oneshot, 1) ;
-                info_display_string(fields[73], mres.sa.s, mres.module, 1) ;
-                info_display_string(fields[74], mres.sa.s, mres.enabled, 1) ;
-                info_display_string(fields[75], mres.sa.s, mres.disabled, 1) ;
-                info_display_string(fields[76], mres.sa.s, mres.contents, 1) ;
-
-                info_display_int(fields[77], mres.nclassic) ;
-                info_display_int(fields[78], mres.nbundle) ;
-                info_display_int(fields[79], mres.noneshot) ;
-                info_display_int(fields[80], mres.nmodule) ;
-                info_display_int(fields[81], mres.nenabled) ;
-                info_display_int(fields[82], mres.ndisabled) ;
-                info_display_int(fields[83], mres.ncontents) ;
-        }
-
-        resolve_free(wres) ;
-
-    } else {
-
-        char tree_buf[MAXOPTS][INFO_FIELD_MAXLEN] = {
-            "name",
-            "depends" ,
-            "requiredby",
-            "allow",
-            "groups",
-            "contents",
-            "ndepends",
-            "nrequiredby",
-            "nallow",
-            "ngroups",
-            "ncontents",
-            "init" ,
-            "supervised",
-            "disen", // 14
-            // Master
-            "enabled",
-            "current",
-            "contents",
-            "nenabled",
-            "ncontents" // 19
-        } ;
-
-        resolve_wrapper_t_ref wres = 0 ;
-        resolve_tree_t tres = RESOLVE_TREE_ZERO ;
-        resolve_tree_master_t mres = RESOLVE_TREE_MASTER_ZERO ;
-
-        if (!strcmp(argv[0], SS_MASTER + 1)) {
-
-            master = 1 ;
-            wres = resolve_set_struct(DATA_TREE_MASTER, &mres) ;
-
-        } else {
-
-            wres = resolve_set_struct(DATA_TREE, &tres) ;
-        }
-
-        found = tree_isvalid(info->base.s, svname) ;
-        if (found < 0)
-            log_diesys(LOG_EXIT_SYS, "invalid tree directory") ;
-
-        if (!found)
-            log_dieusys(LOG_EXIT_SYS, "find tree: ", svname) ;
-
-        if (!resolve_read_g(wres, info->base.s, svname))
-            log_dieusys(LOG_EXIT_SYS, "read resolve file") ;
-
-        info_field_align(tree_buf, fields, field_suffix,MAXOPTS) ;
-
-        if (!master) {
-
-            info_display_string(fields[0], tres.sa.s, tres.name, 0) ;
-            info_display_string(fields[1], tres.sa.s, tres.depends, 1) ;
-            info_display_string(fields[2], tres.sa.s, tres.requiredby, 1) ;
-            info_display_string(fields[3], tres.sa.s, tres.allow, 1) ;
-            info_display_string(fields[4], tres.sa.s, tres.groups, 1) ;
-            info_display_string(fields[5], tres.sa.s, tres.contents, 1) ;
-            info_display_int(fields[6], tres.ndepends) ;
-            info_display_int(fields[7], tres.nrequiredby) ;
-            info_display_int(fields[8], tres.nallow) ;
-            info_display_int(fields[9], tres.ngroups) ;
-            info_display_int(fields[10], tres.ncontents) ;
-            info_display_int(fields[11], tres.init) ;
-            info_display_int(fields[12], tres.supervised) ;
-            info_display_int(fields[13], tres.disen) ;
-
-        } else {
-
-            info_display_string(fields[0], mres.sa.s, mres.name, 1) ;
-            info_display_string(fields[3], mres.sa.s, mres.allow, 1) ;
-            info_display_string(fields[14], mres.sa.s, mres.enabled, 1) ;
-            info_display_string(fields[15], mres.sa.s, mres.current, 1) ;
-            info_display_string(fields[16], mres.sa.s, mres.contents, 1) ;
-            info_display_int(fields[17], mres.nenabled) ;
-            info_display_int(fields[18], mres.ncontents) ;
-        }
-
-        resolve_free(wres) ;
-    }
-
-    return 0 ;
-}
diff --git a/src/lib66/exec/ssexec_resolve_service.c b/src/lib66/exec/ssexec_resolve_service.c
new file mode 100644
index 0000000000000000000000000000000000000000..adec8d4acb4f21ffd524489db92e69810d848b2b
--- /dev/null
+++ b/src/lib66/exec/ssexec_resolve_service.c
@@ -0,0 +1,275 @@
+/*
+ * ssexec_resolve_service.c
+ *
+ * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
+ *
+ * All rights reserved.
+ *
+ * This file is part of Obarun. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution.
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file./
+ */
+
+#include <string.h>
+#include <wchar.h>
+
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+
+#include <skalibs/types.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/lolstdio.h>
+#include <skalibs/buffer.h>
+
+#include <66/resolve.h>
+#include <66/ssexec.h>
+#include <66/service.h>
+#include <66/info.h>
+#include <66/utils.h>
+#include <66/constants.h>
+#include <66/config.h>
+#include <66/state.h>
+
+#define MAXOPTS 70
+
+static wchar_t const field_suffix[] = L" :" ;
+static char fields[INFO_NKEY][INFO_FIELD_MAXLEN] = {{ 0 }} ;
+
+static void info_display_string(char const *field, char const *str, uint32_t element, uint8_t check)
+{
+    info_display_field_name(field) ;
+
+    if (check && !element) {
+
+        if (!bprintf(buffer_1,"%s%s", log_color->warning, "None"))
+            log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+
+    } else {
+
+        if (!buffer_puts(buffer_1, str + element))
+            log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+    }
+
+    if (buffer_putsflush(buffer_1, "\n") == -1)
+        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+
+
+}
+
+static void info_display_int(char const *field, uint32_t element)
+{
+    info_display_field_name(field) ;
+
+    char ui[UINT_FMT] ;
+    ui[uint_fmt(ui, element)] = 0 ;
+
+    if (!buffer_puts(buffer_1, ui))
+        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+
+    if (buffer_putsflush(buffer_1, "\n") == -1)
+        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+}
+
+static void info_display_service_field(resolve_service_t *res)
+{
+    info_display_string(fields[0], res->sa.s, res->name, 0) ;
+    info_display_string(fields[1], res->sa.s, res->description, 1) ;
+    info_display_string(fields[2], res->sa.s, res->version, 1) ;
+    info_display_int(fields[3], res->type) ;
+    info_display_int(fields[4], res->notify) ;
+    info_display_int(fields[5], res->maxdeath) ;
+    info_display_int(fields[6], res->earlier) ;
+    info_display_string(fields[7], res->sa.s, res->hiercopy, 1) ;
+    info_display_string(fields[8], res->sa.s, res->intree, 1) ;
+    info_display_string(fields[9], res->sa.s, res->ownerstr, 1) ;
+    info_display_int(fields[10], res->owner) ;
+    info_display_string(fields[11], res->sa.s, res->treename, 1) ;
+    info_display_string(fields[12], res->sa.s, res->user, 1) ;
+    info_display_string(fields[13], res->sa.s, res->inmodule, 1) ;
+
+    info_display_string(fields[14], res->sa.s, res->path.home, 1) ;
+    info_display_string(fields[15], res->sa.s, res->path.frontend, 1) ;
+    info_display_string(fields[16], res->sa.s, res->path.tree, 1) ;
+    info_display_string(fields[17], res->sa.s, res->path.status, 1) ;
+
+    info_display_string(fields[18], res->sa.s, res->dependencies.depends, 1) ;
+    info_display_string(fields[19], res->sa.s, res->dependencies.requiredby, 1) ;
+    info_display_string(fields[20], res->sa.s, res->dependencies.optsdeps, 1) ;
+    info_display_int(fields[21], res->dependencies.ndepends) ;
+    info_display_int(fields[22], res->dependencies.nrequiredby) ;
+    info_display_int(fields[23], res->dependencies.noptsdeps) ;
+
+    info_display_string(fields[24], res->sa.s, res->execute.run.run, 1) ;
+    info_display_string(fields[25], res->sa.s, res->execute.run.run_user, 1) ;
+    info_display_string(fields[26], res->sa.s, res->execute.run.build, 1) ;
+    info_display_string(fields[27], res->sa.s, res->execute.run.shebang, 1) ;
+    info_display_string(fields[28], res->sa.s, res->execute.run.runas, 1) ;
+    info_display_string(fields[29], res->sa.s, res->execute.finish.run, 1) ;
+    info_display_string(fields[30], res->sa.s, res->execute.finish.run_user, 1) ;
+    info_display_string(fields[31], res->sa.s, res->execute.finish.build, 1) ;
+    info_display_string(fields[32], res->sa.s, res->execute.finish.shebang, 1) ;
+    info_display_string(fields[33], res->sa.s, res->execute.finish.runas, 1) ;
+    info_display_int(fields[34], res->execute.timeout.kill) ;
+    info_display_int(fields[35], res->execute.timeout.finish) ;
+    info_display_int(fields[36], res->execute.timeout.up) ;
+    info_display_int(fields[37], res->execute.timeout.down) ;
+    info_display_int(fields[38], res->execute.down) ;
+    info_display_int(fields[39], res->execute.downsignal) ;
+
+    info_display_string(fields[40], res->sa.s, res->live.livedir, 1) ;
+    info_display_string(fields[41], res->sa.s, res->live.scandir, 1) ;
+    info_display_string(fields[42], res->sa.s, res->live.statedir, 1) ;
+    info_display_string(fields[43], res->sa.s, res->live.eventdir, 1) ;
+    info_display_string(fields[44], res->sa.s, res->live.notifdir, 1) ;
+    info_display_string(fields[45], res->sa.s, res->live.supervisedir, 1) ;
+    info_display_string(fields[46], res->sa.s, res->live.fdholderdir, 1) ;
+    info_display_string(fields[47], res->sa.s, res->live.oneshotddir, 1) ;
+
+    info_display_string(fields[48], res->sa.s, res->logger.name, 1) ;
+    info_display_string(fields[49], res->sa.s, res->logger.destination, 1) ;
+    info_display_int(fields[50], res->logger.backup) ;
+    info_display_int(fields[51], res->logger.maxsize) ;
+    info_display_int(fields[52], res->logger.timestamp) ;
+    info_display_string(fields[53], res->sa.s, res->logger.execute.run.run, 1) ;
+    info_display_string(fields[54], res->sa.s, res->logger.execute.run.run_user, 1) ;
+    info_display_string(fields[55], res->sa.s, res->logger.execute.run.build, 1) ;
+    info_display_string(fields[56], res->sa.s, res->logger.execute.run.shebang, 1) ;
+    info_display_string(fields[57], res->sa.s, res->logger.execute.run.runas, 1) ;
+    info_display_int(fields[58], res->logger.execute.timeout.kill) ;
+    info_display_int(fields[59], res->logger.execute.timeout.finish) ;
+
+    info_display_string(fields[60], res->sa.s, res->environ.env, 1) ;
+    info_display_string(fields[61], res->sa.s, res->environ.envdir, 1) ;
+    info_display_int(fields[62], res->environ.env_overwrite) ;
+
+    info_display_string(fields[63], res->sa.s, res->regex.configure, 1) ;
+    info_display_string(fields[64], res->sa.s, res->regex.directories, 1) ;
+    info_display_string(fields[65], res->sa.s, res->regex.files, 1) ;
+    info_display_string(fields[66], res->sa.s, res->regex.infiles, 1) ;
+    info_display_int(fields[67], res->regex.ndirectories) ;
+    info_display_int(fields[68], res->regex.nfiles) ;
+    info_display_int(fields[69], res->regex.ninfiles) ;
+
+}
+
+int ssexec_resolve_service(int argc, char const *const *argv, ssexec_t *info)
+{
+    int r = 0 ;
+
+    char const *svname = 0 ;
+    char atree[SS_MAX_TREENAME + 1] ;
+
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
+
+    argc-- ;
+    argv++ ;
+
+    if (argc < 1)
+        log_usage(usage_inresolve) ;
+
+    svname = *argv ;
+
+    char service_buf[MAXOPTS][INFO_FIELD_MAXLEN] = {
+        "name",
+        "description" ,
+        "version",
+        "type",
+        "notify",
+        "maxdeath",
+        "earlier",
+        "hiercopy",
+        "intree",
+        "ownerstr",
+        "owner",
+        "treename",
+        "user" ,
+        "inmodule", // 14
+
+        "home",
+        "frontend",
+        "tree",
+        "status", //18
+
+        "depends",
+        "requiredby",
+        "optsdeps",
+        "ndepends",
+        "nrequiredby",
+        "noptsdeps", // 24
+
+        "run",
+        "run_user",
+        "run_build",
+        "run_shebang",
+        "run_runas",
+        "finish",
+        "finish_user",
+        "finish_build",
+        "finish_shebang",
+        "finish_runas",
+        "timeoutkill",
+        "timeoutfinish",
+        "timeoutup",
+        "timeoutdown",
+        "down",
+        "downsignal", // 40
+
+        "livedir",
+        "scandir",
+        "statedir",
+        "eventdir",
+        "notifdir",
+        "supervisedir",
+        "fdholderdir",
+        "oneshotddir", //48
+
+        "logname" ,
+        "logdestination" ,
+        "logbackup" ,
+        "logmaxsize" ,
+        "logtimestamp" ,
+        "logrun" ,
+        "logrun_user" ,
+        "logrun_build" ,
+        "logrun_shebang" ,
+        "logrun_runas" ,
+        "logtimeoutkill",
+        "logtimeoutfinish", // 60
+
+        "env",
+        "envdir",
+        "env_overwrite", // 63
+
+        "configure",
+        "directories",
+        "files",
+        "infiles",
+        "ndirectories",
+        "nfiles",
+        "ninfiles" // 70
+
+    } ;
+
+
+    r = service_is_g(atree, svname, STATE_FLAGS_ISPARSED) ;
+    if (r == -1)
+        log_dieu(LOG_EXIT_SYS, "get information of service: ", svname, " -- please a bug report") ;
+    else if (!r)
+        log_die(LOG_EXIT_USER, svname, " is not parsed -- try to parse it first") ;
+
+    if (!resolve_read_g(wres, info->base.s, svname))
+        log_dieusys(LOG_EXIT_SYS, "read resolve file") ;
+
+    info_field_align(service_buf, fields, field_suffix,MAXOPTS) ;
+
+    info_display_service_field(&res) ;
+
+    resolve_free(wres) ;
+
+    return 0 ;
+}
diff --git a/src/lib66/exec/ssexec_resolve_tree.c b/src/lib66/exec/ssexec_resolve_tree.c
new file mode 100644
index 0000000000000000000000000000000000000000..3298d7129174b83a5d1cad670eeb52a5e54fd8d3
--- /dev/null
+++ b/src/lib66/exec/ssexec_resolve_tree.c
@@ -0,0 +1,173 @@
+/*
+ * ssexec_resolve_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 <string.h>
+#include <wchar.h>
+
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+
+#include <skalibs/types.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/lolstdio.h>
+#include <skalibs/buffer.h>
+
+#include <66/resolve.h>
+#include <66/ssexec.h>
+#include <66/tree.h>
+#include <66/info.h>
+#include <66/utils.h>
+#include <66/constants.h>
+#include <66/config.h>
+#include <66/state.h>
+
+#define MAXOPTS 19
+
+static wchar_t const field_suffix[] = L" :" ;
+static char fields[INFO_NKEY][INFO_FIELD_MAXLEN] = {{ 0 }} ;
+
+static void info_display_string(char const *field, char const *str, uint32_t element, uint8_t check)
+{
+    info_display_field_name(field) ;
+
+    if (check && !element) {
+
+        if (!bprintf(buffer_1,"%s%s", log_color->warning, "None"))
+            log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+
+    } else {
+
+        if (!buffer_puts(buffer_1, str + element))
+            log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+    }
+
+    if (buffer_putsflush(buffer_1, "\n") == -1)
+        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+
+
+}
+
+static void info_display_int(char const *field, uint32_t element)
+{
+    info_display_field_name(field) ;
+
+    char ui[UINT_FMT] ;
+    ui[uint_fmt(ui, element)] = 0 ;
+
+    if (!buffer_puts(buffer_1, ui))
+        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+
+    if (buffer_putsflush(buffer_1, "\n") == -1)
+        log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
+}
+
+int ssexec_resolve_tree(int argc, char const *const *argv, ssexec_t *info)
+{
+    int r = 0 ;
+    uint8_t master = 0 ;
+
+    char const *svname = 0 ;
+    char const *treename = info->treename.s ;
+
+    resolve_wrapper_t_ref wres = 0 ;
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_tree_master_t mres = RESOLVE_TREE_MASTER_ZERO ;
+
+    argc-- ;
+    argv++ ;
+
+    if (argc < 1)
+        log_usage(usage_inresolve) ;
+
+    svname = *argv ;
+
+    char tree_buf[MAXOPTS][INFO_FIELD_MAXLEN] = {
+        "name",
+        "depends" ,
+        "requiredby",
+        "allow",
+        "groups",
+        "contents",
+        "ndepends",
+        "nrequiredby",
+        "nallow",
+        "ngroups",
+        "ncontents",
+        "init" ,
+        "supervised",
+        "disen", // 14
+        // Master
+        "enabled",
+        "current",
+        "contents",
+        "nenabled",
+        "ncontents" // 19
+    } ;
+
+    if (!strcmp(argv[0], SS_MASTER + 1)) {
+
+        master = 1 ;
+        wres = resolve_set_struct(DATA_TREE_MASTER, &mres) ;
+
+    } else {
+
+        wres = resolve_set_struct(DATA_TREE, &tres) ;
+    }
+
+    r = tree_isvalid(info->base.s, svname) ;
+    if (r < 0)
+        log_diesys(LOG_EXIT_SYS, "invalid tree directory") ;
+
+    if (!r)
+        log_dieusys(LOG_EXIT_SYS, "find tree: ", svname) ;
+
+    if (!resolve_read_g(wres, info->base.s, svname))
+        log_dieusys(LOG_EXIT_SYS, "read resolve file") ;
+
+    info_field_align(tree_buf, fields, field_suffix,MAXOPTS) ;
+
+    if (!master) {
+
+        info_display_string(fields[0], tres.sa.s, tres.name, 0) ;
+        info_display_string(fields[1], tres.sa.s, tres.depends, 1) ;
+        info_display_string(fields[2], tres.sa.s, tres.requiredby, 1) ;
+        info_display_string(fields[3], tres.sa.s, tres.allow, 1) ;
+        info_display_string(fields[4], tres.sa.s, tres.groups, 1) ;
+        info_display_string(fields[5], tres.sa.s, tres.contents, 1) ;
+        info_display_int(fields[6], tres.ndepends) ;
+        info_display_int(fields[7], tres.nrequiredby) ;
+        info_display_int(fields[8], tres.nallow) ;
+        info_display_int(fields[9], tres.ngroups) ;
+        info_display_int(fields[10], tres.ncontents) ;
+        info_display_int(fields[11], tres.init) ;
+        info_display_int(fields[12], tres.supervised) ;
+        info_display_int(fields[13], tres.disen) ;
+
+    } else {
+
+        info_display_string(fields[0], mres.sa.s, mres.name, 1) ;
+        info_display_string(fields[3], mres.sa.s, mres.allow, 1) ;
+        info_display_string(fields[14], mres.sa.s, mres.enabled, 1) ;
+        info_display_string(fields[15], mres.sa.s, mres.current, 1) ;
+        info_display_string(fields[16], mres.sa.s, mres.contents, 1) ;
+        info_display_int(fields[17], mres.nenabled) ;
+        info_display_int(fields[18], mres.ncontents) ;
+    }
+
+    resolve_free(wres) ;
+
+    return 0 ;
+}
diff --git a/src/lib66/exec/ssexec_service_admin.c b/src/lib66/exec/ssexec_service_admin.c
new file mode 100644
index 0000000000000000000000000000000000000000..4e6dadb084c6b7c763c6b806d752cbcbaba851c6
--- /dev/null
+++ b/src/lib66/exec/ssexec_service_admin.c
@@ -0,0 +1,184 @@
+/*
+ * ssexec_service_admin.c
+ *
+ * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
+ *
+ * All rights reserved.
+ *
+ * This file is part of Obarun. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution.
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file./
+ */
+
+#include <string.h>
+
+#include <oblibs/log.h>
+
+#include <skalibs/sgetopt.h>
+
+#include <66/ssexec.h>
+#include <66/config.h>
+
+static inline void info_help (char const *help,char const *usage)
+{
+    log_flow() ;
+
+    DEFAULT_MSG = 0 ;
+
+    log_info(usage,"\n", help) ;
+}
+
+int ssexec_service_admin(int argc, char const *const *argv, ssexec_t *info)
+{
+    log_flow() ;
+
+    if (!argv[1]) {
+        PROG = "service" ;
+        log_usage(usage_service_wrapper) ;
+    }
+
+    int r, n = 0, i = 0 ;
+    uint8_t ctl = 0 ;
+    ssexec_func_t_ref func = 0 ;
+    char const *nargv[argc + 1] ;
+
+    if (!strcmp(argv[1], "status")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_inservice ;
+        info->usage = usage_inservice ;
+        func = &ssexec_inservice ;
+
+        argc-- ;
+        argv++ ;
+
+    } else if (!strcmp(argv[1], "resolve")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_inresolve ;
+        info->usage = usage_inresolve ;
+        func = &ssexec_resolve_service ;
+
+        argc-- ;
+        argv++ ;
+
+    } else if (!strcmp(argv[1], "state")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_instate ;
+        info->usage = usage_instate ;
+        func = &ssexec_instate ;
+
+        argc-- ;
+        argv++ ;
+
+    } else if (!strcmp(argv[1], "remove")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_instate ;
+        info->usage = usage_instate ;
+        func = &ssexec_service_admin ;
+
+        argc-- ;
+        argv++ ;
+
+    } else {
+
+        log_usage(usage_tree) ;
+    }
+
+    {
+        subgetopt l = SUBGETOPT_ZERO ;
+
+        int f = 0 ;
+        for (;;) {
+
+            int opt = subgetopt_r(argc, argv, "-h", &l) ;
+            if (opt == -1) break ;
+            switch (opt) {
+
+                case 'h' :
+
+                    info_help(info->help, info->usage) ;
+                    return 0 ;
+
+                default:
+
+                    for (i = 0 ; i < n ; i++) {
+
+                        if (!argv[l.ind])
+                            log_usage(info->usage) ;
+
+                        if (l.arg) {
+
+                            if (!strcmp(nargv[i],argv[l.ind - 2]) || !strcmp(nargv[i],l.arg))
+                                f = 1 ;
+
+                        } else {
+
+                            if (!strcmp(nargv[i],argv[l.ind]))
+                                f = 1 ;
+                        }
+                    }
+
+                    if (!f) {
+
+                        if (l.arg) {
+                            // distinction between e.g -enano and -e nano
+                            if (argv[l.ind - 1][0] != '-')
+                                nargv[n++] = argv[l.ind - 2] ;
+
+                            nargv[n++] = argv[l.ind - 1] ;
+
+                        } else {
+
+                            nargv[n++] = argv[l.ind] ;
+                        }
+                    }
+                    f = 0 ;
+                    break ;
+            }
+        }
+        argc -= l.ind ; argv += l.ind ;
+    }
+
+    for (i = 0 ; i < argc ; i++ , argv++)
+        nargv[n++] = *argv ;
+
+    nargv[n] = 0 ;
+
+    if (ctl) {
+        /* swap the command and options e.g.
+         * down -f <treename> <-> -f down <treename> */
+        if (n > 2) {
+            /* swap the command and options e.g.
+             * down -f <-> -f down */
+            nargv[n] = nargv[n-1] ;
+            nargv[n-1] = nargv[0] ;
+            nargv[++n] = 0 ;
+
+        } else if (nargv[n-1][0] == '-') {
+            nargv[n++] = nargv[0] ;
+            nargv[n] = 0 ;
+        } else {
+            nargv[n] = nargv[n-1] ;
+            nargv[n-1] = nargv[0] ;
+            nargv[++n] = 0 ;
+        }
+
+    }
+
+    r = (*func)(n, nargv, info) ;
+
+    return r ;
+}
diff --git a/src/lib66/exec/ssexec_service_wrapper.c b/src/lib66/exec/ssexec_service_wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..26e8407dd44fdeec09bd9bbb774dfb77082a8266
--- /dev/null
+++ b/src/lib66/exec/ssexec_service_wrapper.c
@@ -0,0 +1,184 @@
+/*
+ * ssexec_service_wrapper.c
+ *
+ * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
+ *
+ * All rights reserved.
+ *
+ * This file is part of Obarun. It is subject to the license terms in
+ * the LICENSE file found in the top-level directory of this
+ * distribution.
+ * This file may not be copied, modified, propagated, or distributed
+ * except according to the terms contained in the LICENSE file./
+ */
+
+#include <string.h>
+
+#include <oblibs/log.h>
+
+#include <skalibs/sgetopt.h>
+
+#include <66/ssexec.h>
+#include <66/config.h>
+
+static inline void info_help (char const *help,char const *usage)
+{
+    log_flow() ;
+
+    DEFAULT_MSG = 0 ;
+
+    log_info(usage,"\n", help) ;
+}
+
+int ssexec_service_wrapper(int argc, char const *const *argv, ssexec_t *info)
+{
+    log_flow() ;
+
+    if (!argv[1]) {
+        PROG = "service" ;
+        log_usage(usage_service_wrapper) ;
+    }
+
+    int r, n = 0, i = 0 ;
+    uint8_t ctl = 0 ;
+    ssexec_func_t_ref func = 0 ;
+    char const *nargv[argc + 1] ;
+
+    if (!strcmp(argv[1], "status")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_inservice ;
+        info->usage = usage_inservice ;
+        func = &ssexec_inservice ;
+
+        argc-- ;
+        argv++ ;
+
+    } else if (!strcmp(argv[1], "resolve")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_inresolve ;
+        info->usage = usage_inresolve ;
+        func = &ssexec_resolve_service ;
+
+        argc-- ;
+        argv++ ;
+
+    } else if (!strcmp(argv[1], "state")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_instate ;
+        info->usage = usage_instate ;
+        func = &ssexec_instate ;
+
+        argc-- ;
+        argv++ ;
+
+    } else if (!strcmp(argv[1], "remove")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_instate ;
+        info->usage = usage_instate ;
+        func = &ssexec_service_admin ;
+
+        argc-- ;
+        argv++ ;
+
+    } else {
+
+        log_usage(usage_tree) ;
+    }
+
+    {
+        subgetopt l = SUBGETOPT_ZERO ;
+
+        int f = 0 ;
+        for (;;) {
+
+            int opt = subgetopt_r(argc, argv, "-h", &l) ;
+            if (opt == -1) break ;
+            switch (opt) {
+
+                case 'h' :
+
+                    info_help(info->help, info->usage) ;
+                    return 0 ;
+
+                default:
+
+                    for (i = 0 ; i < n ; i++) {
+
+                        if (!argv[l.ind])
+                            log_usage(info->usage) ;
+
+                        if (l.arg) {
+
+                            if (!strcmp(nargv[i],argv[l.ind - 2]) || !strcmp(nargv[i],l.arg))
+                                f = 1 ;
+
+                        } else {
+
+                            if (!strcmp(nargv[i],argv[l.ind]))
+                                f = 1 ;
+                        }
+                    }
+
+                    if (!f) {
+
+                        if (l.arg) {
+                            // distinction between e.g -enano and -e nano
+                            if (argv[l.ind - 1][0] != '-')
+                                nargv[n++] = argv[l.ind - 2] ;
+
+                            nargv[n++] = argv[l.ind - 1] ;
+
+                        } else {
+
+                            nargv[n++] = argv[l.ind] ;
+                        }
+                    }
+                    f = 0 ;
+                    break ;
+            }
+        }
+        argc -= l.ind ; argv += l.ind ;
+    }
+
+    for (i = 0 ; i < argc ; i++ , argv++)
+        nargv[n++] = *argv ;
+
+    nargv[n] = 0 ;
+
+    if (ctl) {
+        /* swap the command and options e.g.
+         * down -f <treename> <-> -f down <treename> */
+        if (n > 2) {
+            /* swap the command and options e.g.
+             * down -f <-> -f down */
+            nargv[n] = nargv[n-1] ;
+            nargv[n-1] = nargv[0] ;
+            nargv[++n] = 0 ;
+
+        } else if (nargv[n-1][0] == '-') {
+            nargv[n++] = nargv[0] ;
+            nargv[n] = 0 ;
+        } else {
+            nargv[n] = nargv[n-1] ;
+            nargv[n-1] = nargv[0] ;
+            nargv[++n] = 0 ;
+        }
+
+    }
+
+    r = (*func)(n, nargv, info) ;
+
+    return r ;
+}
diff --git a/src/lib66/exec/ssexec_tree_wrapper.c b/src/lib66/exec/ssexec_tree_wrapper.c
index e0f80ec56cd24aed0821466f899964d15792639e..bc3235244af0bf226e4ba433ef4523972f1ea450 100644
--- a/src/lib66/exec/ssexec_tree_wrapper.c
+++ b/src/lib66/exec/ssexec_tree_wrapper.c
@@ -1,5 +1,5 @@
 /*
- * ssexec_reload.c
+ * ssexec_tree_wrapper.c
  *
  * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
  *
@@ -21,6 +21,15 @@
 #include <66/ssexec.h>
 #include <66/config.h>
 
+static inline void info_help (char const *help,char const *usage)
+{
+    log_flow() ;
+
+    DEFAULT_MSG = 0 ;
+
+    log_info(usage,"\n", help) ;
+}
+
 int ssexec_tree_wrapper(int argc, char const *const *argv, ssexec_t *info)
 {
     log_flow() ;
@@ -113,6 +122,32 @@ int ssexec_tree_wrapper(int argc, char const *const *argv, ssexec_t *info)
         argc-- ;
         argv++ ;
 
+    } else if (!strcmp(argv[1], "resolve")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_inresolve ;
+        info->usage = usage_inresolve ;
+
+        func = &ssexec_resolve_tree ;
+
+        argc-- ;
+        argv++ ;
+
+    } else if (!strcmp(argv[1], "status")) {
+
+        nargv[n++] = PROG ;
+
+        info->prog = PROG ;
+        info->help = help_intree ;
+        info->usage = usage_intree ;
+
+        func = &ssexec_intree ;
+
+        argc-- ;
+        argv++ ;
+
     } else if (!strcmp(argv[1], "up")) {
 
         info->prog = PROG ;
@@ -148,41 +183,51 @@ int ssexec_tree_wrapper(int argc, char const *const *argv, ssexec_t *info)
         int f = 0 ;
         for (;;) {
 
-            int opt = subgetopt_r(argc, argv, "", &l) ;
+            int opt = subgetopt_r(argc, argv, "-h", &l) ;
             if (opt == -1) break ;
+            switch (opt) {
 
-            for (i = 0 ; i < n ; i++) {
+                case 'h' :
 
-                if (!argv[l.ind])
-                    log_usage(info->usage) ;
+                    info_help(info->help, info->usage) ;
+                    return 0 ;
 
-                if (l.arg) {
+                default:
 
-                    if (!strcmp(nargv[i],argv[l.ind - 2]) || !strcmp(nargv[i],l.arg))
-                        f = 1 ;
+                    for (i = 0 ; i < n ; i++) {
 
-                } else {
+                        if (!argv[l.ind])
+                            log_usage(info->usage) ;
 
-                    if (!strcmp(nargv[i],argv[l.ind]))
-                        f = 1 ;
-                }
-            }
+                        if (l.arg) {
+
+                            if (!strcmp(nargv[i],argv[l.ind - 2]) || !strcmp(nargv[i],l.arg))
+                                f = 1 ;
+
+                        } else {
+
+                            if (!strcmp(nargv[i],argv[l.ind]))
+                                f = 1 ;
+                        }
+                    }
 
-            if (!f) {
+                    if (!f) {
 
-                if (l.arg) {
-                    // distinction between e.g -enano and -e nano
-                    if (argv[l.ind - 1][0] != '-')
-                        nargv[n++] = argv[l.ind - 2] ;
+                        if (l.arg) {
+                            // distinction between e.g -enano and -e nano
+                            if (argv[l.ind - 1][0] != '-')
+                                nargv[n++] = argv[l.ind - 2] ;
 
-                    nargv[n++] = argv[l.ind - 1] ;
+                            nargv[n++] = argv[l.ind - 1] ;
 
-                } else {
+                        } else {
 
-                    nargv[n++] = argv[l.ind] ;
-                }
+                            nargv[n++] = argv[l.ind] ;
+                        }
+                    }
+                    f = 0 ;
+                    break ;
             }
-            f = 0 ;
         }
         argc -= l.ind ; argv += l.ind ;
     }