diff --git a/src/lib66/exec/ssexec_help.c b/src/lib66/exec/ssexec_help.c
index 7c6ec02a3783e952ebb2a6574c80c158b66af643..b770ab9531dccb41f8ab44d7d0e98015ffb3d191 100644
--- a/src/lib66/exec/ssexec_help.c
+++ b/src/lib66/exec/ssexec_help.c
@@ -248,13 +248,14 @@ char const *help_state =
 "   -h: print this help\n"
 ;
 
-char const *usage_remove = "66 remove [ -h ] service" ;
+char const *usage_remove = "66 remove [ -h ] [ -P ] service" ;
 
 char const *help_remove =
 "\nremove services and cleanup all files belong to it from the system\n"
 "\n"
 "options :\n"
 "   -h: print this help\n"
+"   -P: do not propagate signal to its dependencies at stop process\n"
 ;
 
 char const *usage_signal = "66 signal [ -h ] [ -wu | -wU | -wd | -wD | -wr | -wR ] [ -abqHkti12pcyodDuUxOr ] service..." ;
diff --git a/src/lib66/exec/ssexec_remove.c b/src/lib66/exec/ssexec_remove.c
index 6e152a66458b897ef05cd51261e8baa6084f4a47..44208157b3c7490bf3220358d7b300a0cf897f94 100644
--- a/src/lib66/exec/ssexec_remove.c
+++ b/src/lib66/exec/ssexec_remove.c
@@ -12,10 +12,220 @@
  * except according to the terms contained in the LICENSE file./
  */
 
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <oblibs/log.h>
+#include <oblibs/string.h>
+#include <oblibs/types.h>
+#include <oblibs/sastr.h>
+#include <oblibs/directory.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/sgetopt.h>
+
+#include <66/state.h>
+#include <66/enum.h>
 #include <66/ssexec.h>
+#include <66/resolve.h>
+#include <66/service.h>
+#include <66/tree.h>
+#include <66/config.h>
+#include <66/constants.h>
+
+static void auto_remove(char const *path)
+{
+    log_trace("remove directory: ", path) ;
+    if (!dir_rm_rf(path))
+        log_dieusys(LOG_EXIT_SYS, "remove directory: ", path) ;
+}
+
+static void remove_service(resolve_service_t *res, ssexec_t *info)
+{
+    int r ;
+    char *path = 0 ;
+    char sym[strlen(res->sa.s + res->path.home) + SS_SYSTEM_LEN + SS_RESOLVE_LEN + SS_SERVICE_LEN + 1 + SS_MAX_SERVICE_NAME + 1] ;
+
+    path = realpath(res->sa.s + res->path.servicedir, 0) ;
+    if (!path)
+        log_dieusys(LOG_EXIT_SYS, "retrieve real path of: ", res->sa.s + res->path.servicedir) ;
+
+    auto_remove(path) ;
+
+    free(path) ;
+
+    tree_service_remove(info->base.s, res->sa.s + res->treename, res->sa.s + res->name) ;
+
+    if (res->logger.want && res->type == TYPE_CLASSIC) {
+
+        resolve_service_t lres = RESOLVE_SERVICE_ZERO ;
+        resolve_wrapper_t_ref lwres = resolve_set_struct(DATA_SERVICE, &lres) ;
+
+        r = resolve_read_g(lwres, info->base.s, res->sa.s + res->logger.name) ;
+        if (r <= 0)
+            log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", res->sa.s + res->logger.name) ;
+
+        path = realpath(lres.sa.s + lres.path.servicedir, 0) ;
+        if (!path)
+            log_dieusys(LOG_EXIT_SYS, "retrieve real path of: ", lres.sa.s + lres.path.servicedir) ;
+
+        auto_remove(path) ;
+
+        free(path) ;
+
+        auto_remove(lres.sa.s + lres.logger.destination) ;
+
+        tree_service_remove(info->base.s, lres.sa.s + lres.treename, lres.sa.s + lres.name) ;
+
+        auto_strings(sym, lres.sa.s + lres.path.home, SS_SYSTEM, SS_RESOLVE, SS_SERVICE, "/", lres.sa.s + lres.name) ;
+
+        log_trace("remove symlink: ", sym) ;
+        unlink_void(sym) ;
+
+        log_info("removed successfully: ", lres.sa.s + lres.name) ;
+
+        resolve_free(lwres) ;
+    }
+
+    auto_strings(sym, res->sa.s + res->path.home, SS_SYSTEM, SS_RESOLVE, SS_SERVICE, "/", res->sa.s + res->name) ;
+
+    log_trace("remove symlink: ", sym) ;
+    unlink_void(sym) ;
+
+    log_info("removed successfully: ", res->sa.s + res->name) ;
+}
+
 
 int ssexec_remove(int argc, char const *const *argv, ssexec_t *info)
 {
+    log_flow() ;
+
+    int r ;
+    size_t pos = 0 ;
+    uint32_t flag = 0 ;
+    uint8_t siglen = 0 ;
+    unsigned int areslen = 0 ;
+    ss_state_t ste = STATE_ZERO ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_wrapper_t_ref wres = 0 ;
+
+    FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_ISSUPERVISED|STATE_FLAGS_TOUNSUPERVISE|STATE_FLAGS_WANTDOWN) ;
+
+    {
+        subgetopt l = SUBGETOPT_ZERO ;
+
+        for (;;) {
+
+            int opt = subgetopt_r(argc,argv, OPTS_START, &l) ;
+            if (opt == -1) break ;
+
+            switch (opt) {
+
+                case 'h' :
+
+                    info_help(info->help, info->usage) ;
+                    return 0 ;
+
+                case 'P' :
+
+                    FLAGS_CLEAR(flag, STATE_FLAGS_TOPROPAGATE) ;
+                    siglen++ ;
+                    break ;
+
+                default :
+
+                    log_usage(info->usage, "\n", info->help) ;
+            }
+        }
+        argc -= l.ind ; argv += l.ind ;
+    }
+
+    if (argc < 1)
+        log_usage(info->usage, "\n", info->help) ;
+
+    resolve_service_t ares[argc] ;
+
+    for(; pos < argc ; pos++) {
+
+        resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+        wres = resolve_set_struct(DATA_SERVICE, &res) ;
+
+        r = resolve_read_g(wres, info->base.s, argv[pos]) ;
+        if (r < 0)
+            log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", argv[pos]) ;
+
+        if (!r)
+            log_dieu(LOG_EXIT_USER, "find service: ", argv[pos], " -- did you parsed it ?") ;
+
+        if (!state_read(&ste, &res))
+            log_dieusys(LOG_EXIT_SYS, "read state file of: ", argv[pos], " -- please make a bug report") ;
+
+        if (service_is(&ste, STATE_FLAGS_ISSUPERVISED) == STATE_FLAGS_TRUE)
+            if (!sastr_add_string(&sa, argv[pos]))
+                log_dieusys(LOG_EXIT_SYS, "add service: ", argv[pos], " to selection") ;
+
+        ares[areslen++] = res ;
+    }
+
+    if (sa.len) {
+
+        pos = 0 ;
+        char const *prog = PROG ;
+        int nargc = 2 + siglen + sastr_nelement(&sa) ;
+        char const *newargv[nargc] ;
+        unsigned int m = 0 ;
+
+        newargv[m++] = "stop" ;
+        newargv[m++] = "-u" ;
+        if (siglen)
+            newargv[m++] = "-P" ;
+
+        FOREACH_SASTR(&sa, pos)
+            newargv[m++] = sa.s + pos ;
+
+        newargv[m] = 0 ;
+
+        PROG = "stop" ;
+        if (ssexec_stop(nargc, newargv, info))
+            log_dieu(LOG_EXIT_SYS, "stop service selection") ;
+        PROG = prog ;
+    }
+
+    for (pos = 0 ; pos < areslen ; pos++) {
+
+        remove_service(&ares[pos], info) ;
+
+        if (ares[pos].type == TYPE_MODULE) {
+
+            if (ares[pos].dependencies.ncontents) {
+
+                size_t pos = 0 ;
+                sa.len = 0 ;
+                resolve_service_t mres = RESOLVE_SERVICE_ZERO ;
+                resolve_wrapper_t_ref mwres = resolve_set_struct(DATA_SERVICE, &mres) ;
+
+                if (!sastr_clean_string(&sa, ares[pos].sa.s + ares[pos].dependencies.contents))
+                    log_dieu(LOG_EXIT_SYS, "clean string") ;
+
+                FOREACH_SASTR(&sa, pos) {
+
+                    r = resolve_read_g(mwres, info->base.s, sa.s + pos) ;
+                    if (r <= 0)
+                        log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", sa.s + pos) ;
+
+                    remove_service(&mres, info) ;
+                }
+
+                resolve_free(mwres) ;
+            }
+        }
+    }
 
+    stralloc_free(&sa) ;
+    service_resolve_array_free(ares, areslen) ;
+    free(wres) ;
 
+    return 0 ;
 }