From b023e886b6931798e1cd86a9145bf3dbd6ee006b Mon Sep 17 00:00:00 2001
From: obarun <eric@obarun.org>
Date: Sat, 11 Mar 2023 19:22:50 +1100
Subject: [PATCH] merge 66 scanctl and 66 scandir in one tool

---
 src/66/66-shutdownd.c                         |   7 +-
 src/66/66.c                                   |  21 +-
 src/include/66/ssexec.h                       |  56 ++--
 src/lib66/exec/deps-lib/deps                  |   6 +-
 src/lib66/exec/ssexec_boot.c                  |  11 +-
 src/lib66/exec/ssexec_help.c                  | 148 +++++++++--
 ...exec_scandir.c => ssexec_scandir_create.c} | 179 +++----------
 src/lib66/exec/ssexec_scandir_remove.c        |  63 +++++
 ...exec_scanctl.c => ssexec_scandir_signal.c} | 209 ++++++++-------
 src/lib66/exec/ssexec_scandir_wrapper.c       | 239 ++++++++++++++++++
 10 files changed, 628 insertions(+), 311 deletions(-)
 rename src/lib66/exec/{ssexec_scandir.c => ssexec_scandir_create.c} (82%)
 create mode 100644 src/lib66/exec/ssexec_scandir_remove.c
 rename src/lib66/exec/{ssexec_scanctl.c => ssexec_scandir_signal.c} (58%)
 create mode 100644 src/lib66/exec/ssexec_scandir_wrapper.c

diff --git a/src/66/66-shutdownd.c b/src/66/66-shutdownd.c
index 68e35109..b0f5fce5 100644
--- a/src/66/66-shutdownd.c
+++ b/src/66/66-shutdownd.c
@@ -251,7 +251,7 @@ static inline void prepare_stage4 (char what)
     unlink_void(STAGE4_FILE ".new") ;
     fd = open_excl(STAGE4_FILE ".new") ;
     if (fd == -1) log_dieusys(LOG_EXIT_SYS, "open ", STAGE4_FILE ".new", " for writing") ;
-    buffer_init(&b, &buffer_write, fd, buf, 512) ;
+    buffer_init(&b, &buffer_write, fd, buf, 516) ;
 
     if (inns)
     {
@@ -267,10 +267,9 @@ static inline void prepare_stage4 (char what)
             || buffer_puts(&b,live) < 0
             || buffer_puts(&b,SS_BOOT_LOG " }\n  ") < 0)
 
-            || buffer_puts(&b, S6_EXTBINPREFIX "66-scanctl ") < 0
-            || buffer_puts(&b, "-l ") < 0
+            || buffer_puts(&b, S6_EXTBINPREFIX "66 -l ") < 0
             || buffer_puts(&b, live) < 0
-            || buffer_putsflush(&b, " b\n}\n") < 0)
+            || buffer_puts(&b, " scandir abort\n}\n") < 0)
             log_dieusys(LOG_EXIT_SYS, "write to ", STAGE4_FILE ".new") ;
     }
     else
diff --git a/src/66/66.c b/src/66/66.c
index 683f1b89..4058bf95 100644
--- a/src/66/66.c
+++ b/src/66/66.c
@@ -263,9 +263,9 @@ int main(int argc, char const *const *argv)
         info.usage = usage_stop ;
         func = &ssexec_stop ;
 
-    } else if (!strcmp(argv[0], "env")) {
+    } else if (!strcmp(argv[0], "environ")) {
 
-        PROG = "env" ;
+        PROG = "environ" ;
         nargv[n++] = PROG ;
         info.prog = PROG ;
         info.help = help_env ;
@@ -329,7 +329,7 @@ int main(int argc, char const *const *argv)
 
     } else if (!strcmp(argv[0], "signal")) {
 
-        PROG = "svctl" ;
+        PROG = "signal" ;
         nargv[n++] = PROG ;
         info.prog = PROG ;
         info.help = help_service_signal ;
@@ -348,23 +348,14 @@ int main(int argc, char const *const *argv)
         nargv[n++] = PROG ;
         func = &ssexec_service_wrapper ;
 
-    } else if (!strcmp(argv[0], "scanctl")) {
-
-        PROG = "scanctl" ;
-        nargv[n++] = PROG ;
-        info.prog = PROG ;
-        info.help = help_scanctl ;
-        info.usage = usage_scanctl ;
-        func = &ssexec_scanctl ;
-
     } else if (!strcmp(argv[0], "scandir")) {
 
         PROG = "scandir" ;
         nargv[n++] = PROG ;
         info.prog = PROG ;
-        info.help = help_scandir ;
-        info.usage = usage_scandir ;
-        func = &ssexec_scandir ;
+        info.help = help_scandir_wrapper ;
+        info.usage = usage_scandir_wrapper ;
+        func = &ssexec_scandir_wrapper ;
 
     } else {
 
diff --git a/src/include/66/ssexec.h b/src/include/66/ssexec.h
index fa9f2162..e9d0897e 100644
--- a/src/include/66/ssexec.h
+++ b/src/include/66/ssexec.h
@@ -45,12 +45,6 @@ struct ssexec_s
     //char treename[SS_MAX_SERVICE] ;
     //size_t treenamelen ;
 
-    /**
-     *
-     * verifier pour les cast entre int et uint8_t
-     * a son call
-     *
-     * */
     uint8_t treeallow ; //1 yes , 0 no
     uid_t owner ;
     char ownerstr[UID_FMT] ;
@@ -96,6 +90,7 @@ extern void ssexec_copy(ssexec_t *dest, ssexec_t *src) ;
 extern ssexec_t const ssexec_zero ;
 extern void set_treeinfo(ssexec_t *info) ;
 
+/** main */
 extern ssexec_func_t ssexec_parse ;
 extern ssexec_func_t ssexec_init ;
 extern ssexec_func_t ssexec_enable ;
@@ -106,11 +101,14 @@ extern ssexec_func_t ssexec_env ;
 extern ssexec_func_t ssexec_reconfigure ;
 extern ssexec_func_t ssexec_reload ;
 extern ssexec_func_t ssexec_restart ;
+
 /** PID1 and supervision */
 extern ssexec_func_t ssexec_boot ;
-extern ssexec_func_t ssexec_scanctl ;
-extern ssexec_func_t ssexec_scandir ;
-//extern ssexec_func_t ssexec_inresolve ;
+extern ssexec_func_t ssexec_scandir_wrapper ;
+extern ssexec_func_t ssexec_scandir_create ;
+extern ssexec_func_t ssexec_scandir_remove ;
+extern ssexec_func_t ssexec_scandir_signal ;
+
 /** service */
 extern ssexec_func_t ssexec_service_resolve ;
 extern ssexec_func_t ssexec_service_state ;
@@ -118,6 +116,7 @@ extern ssexec_func_t ssexec_service_status ;
 extern ssexec_func_t ssexec_service_wrapper ;
 extern ssexec_func_t ssexec_service_admin ;
 extern ssexec_func_t ssexec_service_signal ;
+
 /** tree */
 extern ssexec_func_t ssexec_tree_wrapper ;
 extern ssexec_func_t ssexec_tree_signal ;
@@ -205,16 +204,39 @@ extern char const *help_service_remove ;
 extern char const *usage_service_signal ;
 extern char const *help_service_signal ;
 
-extern char const *usage_scanctl ;
-extern char const *help_scanctl ;
-
-extern char const *usage_scandir ;
-extern char const *help_scandir ;
+extern char const *usage_scandir_wrapper ;
+extern char const *help_scandir_wrapper ;
+extern char const *usage_scandir_create ;
+extern char const *help_scandir_create ;
+extern char const *usage_scandir_remove ;
+extern char const *help_scandir_remove ;
+extern char const *usage_scandir_start ;
+extern char const *help_scandir_start ;
+extern char const *usage_scandir_stop ;
+extern char const *help_scandir_stop ;
+extern char const *usage_scandir_reconfigure ;
+extern char const *help_scandir_reconfigure ;
+extern char const *usage_scandir_rescan ;
+extern char const *help_scandir_rescan ;
+extern char const *usage_scandir_quit ;
+extern char const *help_scandir_quit ;
+extern char const *usage_scandir_halt ;
+extern char const *help_scandir_halt ;
+extern char const *usage_scandir_abort ;
+extern char const *help_scandir_abort ;
+extern char const *usage_scandir_nuke ;
+extern char const *help_scandir_nuke ;
+extern char const *usage_scandir_annihilate ;
+extern char const *help_scandir_annihilate ;
+extern char const *usage_scandir_zombies ;
+extern char const *help_scandir_zombies ;
 
 #define OPTS_SUBSTART "hP"
 #define OPTS_SUBSTART_LEN (sizeof OPTS_SUBSTART - 1)
 #define OPTS_PARSE "hfFcmCI"
 #define OPTS_PARSE_LEN (sizeof OPTS_PARSE - 1)
+#define OPTS_INIT "h"
+#define OPTS_INIT_LEN (sizeof OPTS_INIT - 1)
 #define OPTS_ENABLE "hfFSI"
 #define OPTS_ENABLE_LEN (sizeof OPTS_ENABLE - 1)
 #define OPTS_DISABLE "hS"
@@ -239,8 +261,10 @@ extern char const *help_scandir ;
 #define OPTS_BOOT_LEN (sizeof OPTS_BOOT - 1)
 #define OPTS_SCANCTL "ho:d:t:e:"
 #define OPTS_SCANCTL_LEN (sizeof OPTS_SCANCTL - 1)
-#define OPTS_SCANDIR "hbl:s:o:L:cB"
-#define OPTS_SCANDIR_LEN (sizeof OPTS_SCANDIR - 1)
+#define OPTS_SCANDIR_WRAPPER "ho:"
+#define OPTS_SCANCTL_WRAPPER_LEN (sizeof OPTS_SCANDIR_WRAPPER - 1)
+#define OPTS_SCANDIR_CREATE "bBs:cL:"
+#define OPTS_SCANDIR_CREATE_LEN (sizeof OPTS_SCANDIR_CREATE - 1)
 
 #define OPTS_SERVICE_WRAPPER ""
 #define OPTS_SERVICE_WRAPPER_LEN (sizeof OPTS_SERVICE_WRAPPER - 1)
diff --git a/src/lib66/exec/deps-lib/deps b/src/lib66/exec/deps-lib/deps
index 329b6cfa..803650c5 100644
--- a/src/lib66/exec/deps-lib/deps
+++ b/src/lib66/exec/deps-lib/deps
@@ -10,8 +10,10 @@ ssexec_parse.o
 ssexec_reconfigure.o
 ssexec_reload.o
 ssexec_restart.o
-ssexec_scanctl.o
-ssexec_scandir.o
+ssexec_scandir_create.o
+ssexec_scandir_remove.o
+ssexec_scandir_signal.o
+ssexec_scandir_wrapper.o
 ssexec_service_admin.o
 ssexec_service_resolve.o
 ssexec_service_signal.o
diff --git a/src/lib66/exec/ssexec_boot.c b/src/lib66/exec/ssexec_boot.c
index 05d787bb..6c6d1cfd 100644
--- a/src/lib66/exec/ssexec_boot.c
+++ b/src/lib66/exec/ssexec_boot.c
@@ -409,11 +409,11 @@ static inline void make_cmdline(char const *prog,char const **add,int len,char c
     char const *newargv[m] ;
 
     newargv[n++] = "66" ;
-    newargv[n++] = prog ;
     newargv[n++] = "-v" ;
     newargv[n++] = cver ;
     newargv[n++] = "-l" ;
     newargv[n++] = live ;
+    newargv[n++] = prog ;
 
     for (;i<len;i++)
         newargv[n++] = add[i] ;
@@ -591,6 +591,7 @@ int ssexec_boot(int argc, char const *const *argv, ssexec_t *info)
 
         char const *t[nargc] ;
 
+        t[m++] = "create" ;
         if (container) {
             t[m++] = "-B" ;
         } else {
@@ -604,7 +605,7 @@ int ssexec_boot(int argc, char const *const *argv, ssexec_t *info)
         t[m++] = skel ;
         t[m++] = "-L" ;
         t[m++] = log_user ;
-        t[m++] = "create" ;
+
         log_info("Create live scandir at: ",live) ;
 
         make_cmdline("scandir", t, nargc, "create live scandir at: ", live, genv) ;
@@ -641,13 +642,13 @@ int ssexec_boot(int argc, char const *const *argv, ssexec_t *info)
         size_t m = 0 ;
         static char const *newargv[8] ;
         newargv[m++] = "66" ;
-        newargv[m++] = "scanctl" ;
         newargv[m++] = "-v0" ;
-        if (!catch_log)
-            newargv[m++] = fmtfd ;
         newargv[m++] = "-l" ;
         newargv[m++] = live ;
+        newargv[m++] = "scandir" ;
         newargv[m++] = "start" ;
+        if (!catch_log)
+            newargv[m++] = fmtfd ;
         newargv[m++] = 0 ;
 
         memcpy(pathvar, "PATH=", 5) ;
diff --git a/src/lib66/exec/ssexec_help.c b/src/lib66/exec/ssexec_help.c
index 8be48597..86c8ec4d 100644
--- a/src/lib66/exec/ssexec_help.c
+++ b/src/lib66/exec/ssexec_help.c
@@ -23,7 +23,7 @@ inline void info_help (char const *help,char const *usage)
 }
 
 
-char const *usage_66 = "66 [ -h ] [ -z ] [ -v verbosity ] [ -l live ] [ -T timeout ] start|stop|reload|restart|unsupervise|reconfigure|enable|disable|env|service|tree|init|parse|signal|scanctl|scandir|boot|version [<command options>] service...|tree" ;
+char const *usage_66 = "66 [ -h ] [ -z ] [ -v verbosity ] [ -l live ] [ -T timeout ] [ -t tree ] start|stop|reload|restart|unsupervise|reconfigure|enable|disable|environ|service|tree|init|parse|signal|scandir|boot|version [<command options>] service...|tree" ;
 
 char const *help_66 =
 "\nmain tool to init a system, control and manage services\n"
@@ -34,6 +34,7 @@ char const *help_66 =
 "   -v: increase/decrease verbosity\n"
 "   -l: live directory\n"
 "   -T: timeout\n"
+"   -t: name of the tree to use\n"
 "\n"
 "command:\n"
 "   start: bring up service\n"
@@ -44,13 +45,12 @@ char const *help_66 =
 "   reconfigure: bring down, unsupervise, parse it again and bring up service\n"
 "   enable: activate service for the next boot\n"
 "   disable: deactivate service for the next boot\n"
-"   env: manage service environment variable\n"
+"   environ: manage service environment variable\n"
 "   service: manage/see service information\n"
 "   tree: manage/see tree information\n"
 "   init: initiate to scandir all services marked enabled at tree\n"
 "   parse: parse the service frontend file\n"
 "   signal: send signal to service\n"
-"   scanctl: send signal to scandir\n"
 "   scandir: manage scandir\n"
 "   boot: boot the system with 66\n"
 "   version: display 66 version\n"
@@ -116,7 +116,7 @@ char const *help_stop =
 "   -P: do not propagate signal to its requiredby\n"
 ;
 
-char const *usage_env = "66 env [ -h ] [ -c version ] [ -s version ] [ -V|L ] [ -r key=value ] [ -i src,dst ] [ -e editor ] service" ;
+char const *usage_env = "66 environ [ -h ] [ -c version ] [ -s version ] [ -V|L ] [ -r key=value ] [ -i src,dst ] [ -e editor ] service" ;
 
 char const *help_env =
 "\nmanage environment service files and its contents\n"
@@ -479,30 +479,146 @@ char const *help_service_remove =
 "   -h: print this help\n"
 ;
 
-char const *usage_scanctl = "66 scanctl [ -d notif ] [ -t rescan ] [ -e environment ] [ -o owner ] start|stop|reload|quit|nuke|zombies or any s6-svscanctl options" ;
+char const *usage_scandir_wrapper = "66 scandir [ -h ] [ -o owner ] create|remove|start|stop|reconfigure|rescan|quit|halt|abort|nuke|annihilate|zombies [<command options>]" ;
 
-char const *help_scanctl =
-"\nsend signal to scandir\n"
+char const *help_scandir_wrapper =
+"\nmain sub tools to manage scandir\n"
 "\n"
 "options :\n"
 "   -h: print this help\n"
-"   -d: notify readiness on file descriptor\n"
-"   -t: rescan scandir every milliseconds\n"
-"   -e: environment directory\n"
 "   -o: handles scandir of owner\n"
+"\n"
+"command:\n"
+"   create: create a scandir\n"
+"   remove: remove a scandir\n"
+"   start: start a scandir\n"
+"   stop: stop a running scandir\n"
+"   reconfigure: reconfigure a running scandir\n"
+"   rescan: rescan a running scandir\n"
+"   quit: quit a running scandir\n"
+"   halt: halt a running scandir\n"
+"   abort: abort a running scandir\n"
+"   nuke: nuke a running scandir\n"
+"   annihilate: annihilate a running scandir\n"
+"   zombies: destroy zombies from a running scandir\n"
+"\n"
+"Use '66 scandir <command> -h' to see command options\n"
 ;
 
-char const *usage_scandir = "66 scandir [ -h ] [ -b|B ] [ -c ] [ -L log_user ] [ -s skel ] [ -o owner ] create|remove" ;
+char const *usage_scandir_create = "66 scandir create [ -h ] [ -b|B ] [ -c ] [ -L log_user ] [ -s skel ]" ;
 
-char const *help_scandir =
-"\nmanage a scandir\n"
+char const *help_scandir_create =
+"\ncreate a scandir\n"
 "\n"
 "options:\n"
 "   -h: print this help\n"
 "   -b: create scandir for a boot process\n"
 "   -B: create scandir for a boot process inside a container\n"
-"   -c: do not catch log\n"
+"   -c: do not catch logs\n"
 "   -L: run catch-all logger as log_user user\n"
-"   -s: skeleton directory\n"
-"   -o: handles owner scandir\n"
+"   -s: use skel as skeleton directory\n"
+;
+
+char const *usage_scandir_remove = "66 scandir remove [ -h ]" ;
+
+char const *help_scandir_remove =
+"\nremove a existing scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_start = "66 scandir start [ -h ] [ -d notif ] [ -s rescan ] [ -e environment ]" ;
+
+char const *help_scandir_start =
+"\nstart a scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+"   -d: notify readiness on file descriptor\n"
+"   -s: scan scandir every milliseconds\n"
+"   -e: use environment as environment directory\n"
+;
+
+char const *usage_scandir_stop = "66 scandir stop [ -h ]" ;
+
+char const *help_scandir_stop =
+"\nstop a running scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_reconfigure = "66 scandir reconfigure [ -h ]" ;
+
+char const *help_scandir_reconfigure =
+"\nperform a scan and destroy inactive service of scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_rescan = "66 scandir rescan [ -h ]" ;
+
+char const *help_scandir_rescan =
+"\nrescan a running scandir to integrate new services\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+"   -o: handles scandir of owner\n"
 ;
+
+char const *usage_scandir_quit = "66 scandir quit [ -h ]" ;
+
+char const *help_scandir_quit =
+"\nquit a running scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_halt = "66 scandir halt [ -h ]" ;
+
+char const *help_scandir_halt =
+"\nhalt a running scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_abort = "66 scandir abort [ -h ]" ;
+
+char const *help_scandir_abort =
+"\nabort a running scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_nuke = "66 scandir nuke [ -h ]" ;
+
+char const *help_scandir_nuke =
+"\nnuke a running scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_annihilate = "66 scandir annihilate [ -h ]" ;
+
+char const *help_scandir_annihilate =
+"\nannihilate a running scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
+char const *usage_scandir_zombies = "66 scandir zombies [ -h ]" ;
+
+char const *help_scandir_zombies =
+"\ndestroy zombies from a running scandir\n"
+"\n"
+"options:\n"
+"   -h: print this help\n"
+;
+
diff --git a/src/lib66/exec/ssexec_scandir.c b/src/lib66/exec/ssexec_scandir_create.c
similarity index 82%
rename from src/lib66/exec/ssexec_scandir.c
rename to src/lib66/exec/ssexec_scandir_create.c
index 24713c72..150a0166 100644
--- a/src/lib66/exec/ssexec_scandir.c
+++ b/src/lib66/exec/ssexec_scandir_create.c
@@ -1,5 +1,5 @@
 /*
- * ssexec_scandir.c
+ * ssexec_scandir_create.c
  *
  * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
  *
@@ -13,37 +13,30 @@
  */
 
 #include <string.h>
-#include <errno.h>
-#include <sys/stat.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
 #include <sys/stat.h>
 #include <stdarg.h>
 
+#include <oblibs/string.h>
 #include <oblibs/log.h>
 #include <oblibs/directory.h>
 #include <oblibs/types.h>
 #include <oblibs/files.h>
-#include <oblibs/string.h>
-#include <oblibs/environ.h>
 
-#include <skalibs/stralloc.h>
-#include <skalibs/sgetopt.h>
 #include <skalibs/djbunix.h>
-#include <skalibs/types.h>
-#include <skalibs/env.h>
-#include <skalibs/bytestr.h>//byte_count
-#include <skalibs/exec.h>
 #include <skalibs/buffer.h>
+#include <skalibs/sgetopt.h>
 
-#include <s6/config.h>
-#include <execline/config.h>
-
+#include <66/constants.h>
+#include <66/utils.h>
 #include <66/config.h>
 #include <66/ssexec.h>
-#include <66/svc.h>
-#include <66/utils.h>
 #include <66/enum.h>
-#include <66/constants.h>
+
+#include <execline/config.h>
+#include <s6/config.h>
 
 #define CRASH 0
 #define FINISH 1
@@ -60,7 +53,7 @@
 #define PERM1777 S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO
 
 static uid_t OWNER ;
-static char OWNERSTR[UID_FMT] ;
+static char *OWNERSTR ;
 static gid_t GIDOWNER ;
 static char GIDSTR[GID_FMT] ;
 
@@ -73,31 +66,6 @@ static size_t compute_buf_size(char const *str,...) ;
 static size_t CONFIG_STR_LEN = 0 ;
 static int BUF_FD ; // general buffer fd
 
-#define USAGE "66-scandir [ -h ] [ -z ] [ -v verbosity ] [ -l live ] [ -b|B ] [ -c ] [ -L log_user ] [ -s skel ] [ -o owner ] create|remove"
-
-static inline unsigned int lookup (char const *const *table, char const *signal)
-{
-    log_flow() ;
-
-    unsigned int i = 0 ;
-    for (; table[i] ; i++) if (!strcmp(signal, table[i])) break ;
-    return i ;
-}
-
-static inline unsigned int parse_command (char const *command)
-{
-    log_flow() ;
-
-    static char const *const command_table[] =
-    {
-        "create",
-        "remove",
-        0
-    } ;
-  unsigned int i = lookup(command_table, command) ;
-  if (!command_table[i]) i = 3 ;
-  return i ;
-}
 
 static void inline auto_chown(char const *str)
 {
@@ -173,7 +141,7 @@ static void inline auto_rm(char const *str)
     if (r > 0)
     {
         log_info("removing: ",str,"...") ;
-        if (rm_rf(str) < 0) log_dieusys(LOG_EXIT_SYS,"remove: ",str) ;
+        if (!dir_rm_rf(str)) log_dieusys(LOG_EXIT_SYS,"remove: ",str) ;
     }
 }
 
@@ -500,14 +468,14 @@ void write_control(char const *scandir,char const *live, char const *filename, i
             break ;
         case TERM:
             if (!BOOT)
-                if (!auto_buf(&b, SS_BINPREFIX "66 -l ",live," scanctl stop\n"))
+                if (!auto_buf(&b, SS_BINPREFIX "66 -l ",live," scandir stop\n"))
                     log_die_nomem("buffer") ;
 
             break ;
         case QUIT:
 
             if (!BOOT)
-                if (!auto_buf(&b, SS_BINPREFIX "66 -l ",live," scanctl quit\n"))
+                if (!auto_buf(&b, SS_BINPREFIX "66 -l ",live," scandir quit\n"))
                     log_die_nomem("buffer") ;
 
             break ;
@@ -742,34 +710,24 @@ void sanitize_live(char const *live)
     auto_check(tmp,0755,PERM1777,AUTO_CRTE_CHW_CHM) ;
 }
 
-int ssexec_scandir(int argc, char const *const *argv, ssexec_t *info)
+int ssexec_scandir_create(int argc, char const *const *argv, ssexec_t *info)
 {
     int r ;
-    unsigned int cmd, create, remove ;
-
-    stralloc live = STRALLOC_ZERO ;
-    stralloc scandir = STRALLOC_ZERO ;
 
     CONFIG_STR_LEN = compute_buf_size(SS_BINPREFIX, SS_EXTBINPREFIX, SS_EXTLIBEXECPREFIX, SS_LIBEXECPREFIX, SS_EXECLINE_SHEBANGPREFIX, 0) ;
 
-    cmd = create = remove = 0 ;
-
-    OWNER = MYUID ;
+    OWNER = info->owner ;
+    OWNERSTR = info->ownerstr ;
 
     {
         subgetopt l = SUBGETOPT_ZERO ;
 
         for (;;)
         {
-            int opt = subgetopt_r(argc, argv, OPTS_SCANDIR, &l) ;
+            int opt = subgetopt_r(argc, argv, OPTS_SCANDIR_CREATE, &l) ;
             if (opt == -1) break ;
 
-            switch (opt)
-            {
-                 case 'h' :
-
-                    info_help(info->help, info->usage) ;
-                    return 0 ;
+            switch (opt) {
 
                 case 'b' :
 
@@ -782,27 +740,11 @@ int ssexec_scandir(int argc, char const *const *argv, ssexec_t *info)
                     BOOT = 1 ;
                     break ;
 
-                case 'l' :
-
-                    if (!stralloc_cats(&live,l.arg) ||
-                    !stralloc_0(&live))
-                        log_die_nomem("stralloc") ;
-
-                    break ;
-
                 case 's' :
 
                     skel = l.arg ;
                     break ;
 
-                case 'o' :
-
-                    if (MYUID)
-                        log_die(LOG_EXIT_USER, "only root can use -o option") ;
-
-                    if (!youruid(&OWNER,l.arg))
-                        log_dieusys(LOG_EXIT_SYS,"get uid of: ",l.arg) ;
-
                 case 'c' :
 
                     CATCH_LOG = 0 ;
@@ -821,87 +763,28 @@ int ssexec_scandir(int argc, char const *const *argv, ssexec_t *info)
         argc -= l.ind ; argv += l.ind ;
     }
 
-    if (!argc)
-        log_usage(info->usage, "\n", info->help) ;
-
-    cmd = parse_command(argv[0]) ;
-
-    if (cmd == 3) {
-        log_usage(usage_scandir) ;
-    } else if (!cmd) {
-        create = 1 ;
-    } else  {
-        remove = 1 ;
-    }
-
     if (BOOT && OWNER && !CONTAINER)
-        log_die(LOG_EXIT_USER,"-b options can be set only with root") ;
-
-    OWNERSTR[uid_fmt(OWNERSTR,OWNER)] = 0 ;
+        log_die(LOG_EXIT_USER, "-b options can be set only with root") ;
 
     if (!yourgid(&GIDOWNER,OWNER))
-        log_dieusys(LOG_EXIT_SYS,"set gid of: ",OWNERSTR) ;
+        log_dieusys(LOG_EXIT_SYS, "set gid of: ", OWNERSTR) ;
 
     GIDSTR[gid_fmt(GIDSTR,GIDOWNER)] = 0 ;
 
-    /** live -> /run/66/ */
-    r = set_livedir(&live) ;
-    if (r < 0) log_die(LOG_EXIT_USER,"live: ",live.s," must be an absolute path") ;
-    if (!r) log_dieusys(LOG_EXIT_SYS,"set live directory") ;
-
-    if (!stralloc_copy(&scandir,&live)) log_die_nomem("stralloc") ;
-
-    /** scandir -> /run/66/scandir/ */
-    r = set_livescan(&scandir,OWNER) ;
-    if (r < 0) log_die(LOG_EXIT_USER,"scandir: ", scandir.s, " must be an absolute path") ;
-    if (!r) log_dieusys(LOG_EXIT_SYS,"set scandir directory") ;
-
     if (BOOT && skel[0] != '/')
-        log_die(LOG_EXIT_USER, "rc.shutdown: ",skel," must be an absolute path") ;
-
-    r = scan_mode(scandir.s, S_IFDIR) ;
-    if (r < 0) log_die(LOG_EXIT_SYS,"scandir: ",scandir.s," exist with unkown mode") ;
-    if (!r && !create && !remove) log_die(LOG_EXIT_USER,"scandir: ",scandir.s," doesn't exist") ;
-    if (!r && create)
-    {
-        log_trace("sanitize ",live.s," ...") ;
-        sanitize_live(live.s) ;
-        log_info ("create scandir ",scandir.s," ...") ;
-        create_scandir(live.s, scandir.s) ;
-    }
-
-    if (r && create)
-    {
-        log_info("scandir: ",scandir.s," already exist, keep it") ;
-        goto end ;
-    }
+        log_die(LOG_EXIT_USER, "rc.shutdown: ", skel, " must be an absolute path") ;
 
-    r = svc_scandir_ok(scandir.s) ;
-    if (r < 0) log_dieusys(LOG_EXIT_SYS, "check: ", scandir.s) ;
-    if (r && remove) log_dieu(LOG_EXIT_USER,"remove: ",scandir.s,": is running")  ;
-    if (remove)
-    {
-        /** /run/66/scandir/0 */
-        auto_rm(scandir.s) ;
+    r = scan_mode(info->scandir.s, S_IFDIR) ;
+    if (r < 0) log_die(LOG_EXIT_SYS, "scandir: ", info->scandir.s, " exist with unkown mode") ;
+    if (!r) {
 
-        if (CONTAINER) {
-            /** /run/66/scandir/container */
-            if (!stralloc_copy(&scandir,&live)) log_die_nomem("stralloc") ;
-            if (!auto_stra(&scandir,SS_BOOT_CONTAINER_DIR,"/",OWNERSTR))
-                log_die_nomem("stralloc") ;
-            auto_rm(scandir.s) ;
-        }
-
-        /** run/66/state/uid */
-        if (!stralloc_copy(&scandir,&live)) log_die_nomem("stralloc") ;
-        r = set_livestate(&scandir,OWNER) ;
-        if (!r) log_dieusys(LOG_EXIT_SYS,"set livestate directory") ;
-        auto_rm(scandir.s) ;
-    }
+        log_trace("sanitize ", info->live.s, " ...") ;
+        sanitize_live(info->live.s) ;
+        log_info ("create scandir ", info->scandir.s, " ...") ;
+        create_scandir(info->live.s, info->scandir.s) ;
 
-    end:
-    stralloc_free(&scandir) ;
-    stralloc_free(&live) ;
+    } else
+        log_info("scandir: ", info->scandir.s, " already exist, keep it") ;
 
     return 0 ;
 }
diff --git a/src/lib66/exec/ssexec_scandir_remove.c b/src/lib66/exec/ssexec_scandir_remove.c
new file mode 100644
index 00000000..983feb19
--- /dev/null
+++ b/src/lib66/exec/ssexec_scandir_remove.c
@@ -0,0 +1,63 @@
+/*
+ * ssexec_scandir_remove.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 <oblibs/log.h>
+#include <oblibs/types.h>
+#include <oblibs/directory.h>
+#include <oblibs/string.h>
+
+#include <66/ssexec.h>
+#include <66/svc.h>
+#include <66/constants.h>
+
+static void inline auto_rm(char const *str)
+{
+    log_flow() ;
+
+    int r ;
+    r = scan_mode(str, S_IFDIR) ;
+    if (r > 0) {
+        log_info("removing: ", str, "...") ;
+        if (!dir_rm_rf(str))
+            log_dieusys(LOG_EXIT_SYS, "remove: ", str) ;
+    }
+}
+
+int ssexec_scandir_remove(int argc, char const *const *argv, ssexec_t *info)
+{
+    int r ;
+
+    r = svc_scandir_ok(info->scandir.s) ;
+    if (r < 0)
+        log_dieusys(LOG_EXIT_SYS, "check: ", info->scandir.s) ;
+    if (r)
+        log_dieu(LOG_EXIT_USER, "remove: ", info->scandir.s, ": is running")  ;
+
+    /** /run/66/scandir/0 */
+    auto_rm(info->scandir.s) ;
+
+    /** /run/66/scandir/container */
+    info->scandir.len = 0 ;
+    if (!auto_stra(&info->scandir, info->live.s, SS_BOOT_CONTAINER_DIR, "/", info->ownerstr))
+        log_die_nomem("stralloc") ;
+    auto_rm(info->scandir.s) ;
+
+    /** run/66/state/uid */
+    info->scandir.len = 0 ;
+    if (!auto_stra(&info->scandir, info->live.s, SS_STATE, "/", info->ownerstr))
+        log_die_nomem("stralloc") ;
+    auto_rm(info->scandir.s) ;
+
+    return 0 ;
+}
diff --git a/src/lib66/exec/ssexec_scanctl.c b/src/lib66/exec/ssexec_scandir_signal.c
similarity index 58%
rename from src/lib66/exec/ssexec_scanctl.c
rename to src/lib66/exec/ssexec_scandir_signal.c
index 76c69201..42b75b28 100644
--- a/src/lib66/exec/ssexec_scanctl.c
+++ b/src/lib66/exec/ssexec_scandir_signal.c
@@ -1,5 +1,5 @@
 /*
- * ssexec_scanctl.c
+ * ssexec_scandir_signal.c
  *
  * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
  *
@@ -19,19 +19,17 @@
 #include <oblibs/string.h>
 #include <oblibs/environ.h>
 
+#include <skalibs/types.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/env.h>
 #include <skalibs/sgetopt.h>
 #include <skalibs/stralloc.h>
-#include <skalibs/types.h>
-#include <skalibs/djbunix.h>
 #include <skalibs/exec.h>
-#include <skalibs/env.h>
-#include <skalibs/bytestr.h>
 
-#include <s6/config.h>
-
-#include <66/svc.h>
-#include <66/utils.h>
 #include <66/ssexec.h>
+#include <66/svc.h>
+
+#include <s6/config.h>
 
 static char TMPENV[MAXENV + 1] ;
 
@@ -51,16 +49,20 @@ static inline unsigned int parse_signal (char const *signal)
     static char const *const signal_table[] =
     {
         "start",
-        "stop",
-        "reload",
-        "quit",
-        "nuke",
-        "zombies",
+        "stop", // -t
+        "reconfigure", // -h or -an
+        "rescan", // -a
+        "quit", // -q
+        "halt", // -qb
+        "abort", // -b
+        "nuke", // -n
+        "annihilate", // -N
+        "zombies", // -z
         0
     } ;
-  unsigned int i = lookup(signal_table, signal) ;
-  if (!signal_table[i]) i = 6 ;
-  return i ;
+    unsigned int i = lookup(signal_table, signal) ;
+    if (!signal_table[i]) i = 10 ;
+    return i ;
 }
 
 static int send_signal(char const *scandir, char const *signal)
@@ -68,53 +70,73 @@ static int send_signal(char const *scandir, char const *signal)
     log_flow() ;
 
     unsigned int sig = 0 ;
-    size_t siglen = strlen(signal) ;
-    char csig[siglen + 1] ;
+    char csig[3] ;
     sig = parse_signal(signal) ;
-    if (sig < 6)
-    {
-        switch(sig)
-        {
-            /** start signal, should never happens */
-            case 0:
 
-                return 1 ;
+    switch(sig) {
 
-            case 1:
+        /** start signal, should never happens */
+        case 0:
 
-                csig[0] = 't' ;
-                csig[1] = 0 ;
-                break ;
+            return 1 ;
 
-            case 2:
+        case 1: // stop
 
-                csig[0] = 'h' ;
-                csig[1] = 0 ;
-                break ;
+            csig[0] = 't' ;
+            csig[1] = 0 ;
+            break ;
 
-            case 3:
+        case 2: // reconfigure
 
-                csig[0] = 'q' ;
-                csig[1] = 0 ;
-                break ;
+            csig[0] = 'h' ;
+            csig[1] = 0 ;
+            break ;
 
-            case 4:
+        case 3: // rescan
 
-                csig[0] = 'n' ;
-                csig[1] = 0 ;
-                break ;
+            csig[0] = 'a' ;
+            csig[1] = 0 ;
+            break ;
 
-            case 5:
+        case 4: // quit
 
-                csig[0] = 'z' ;
-                csig[1] = 0 ;
-                break ;
+            csig[0] = 'q' ;
+            csig[1] = 0 ;
+            break ;
 
-            default: break ;
-        }
-    }
-    else {
-        auto_strings(csig,signal) ;
+        case 5: // halt
+
+            csig[0] = 'q' ;
+            csig[1] = 'b' ;
+            csig[2] = 0 ;
+            break ;
+
+        case 6: // abort
+
+            csig[0] = 'b' ;
+            csig[1] = 0 ;
+            break ;
+
+        case 7: // nuke
+
+            csig[0] = 'n' ;
+            csig[1] = 0 ;
+            break ;
+
+        case 8: // annihilate
+
+            csig[0] = 'N' ;
+            csig[1] = 0 ;
+            break ;
+
+        case 9: // zombies
+
+            csig[0] = 'z' ;
+            csig[1] = 0 ;
+            break ;
+
+        default:
+            log_die(LOG_EXIT_SYS, "unknown signal: ", signal) ;
     }
 
     return svc_scandir_send(scandir,csig) ;
@@ -122,15 +144,6 @@ static int send_signal(char const *scandir, char const *signal)
 
 static void scandir_up(char const *scandir, unsigned int timeout, unsigned int notif, char const *const *envp)
 {
-    int r ;
-    r = svc_scandir_ok(scandir) ;
-    if (r < 0) log_dieusys(LOG_EXIT_SYS, "check: ", scandir) ;
-    if (r)
-    {
-        log_trace("scandir: ",scandir," already running") ;
-        return ;
-    }
-
     unsigned int no = notif ? 2 : 0 ;
     char const *newup[6 + no] ;
     unsigned int m = 0 ;
@@ -153,10 +166,10 @@ static void scandir_up(char const *scandir, unsigned int timeout, unsigned int n
     xexec_ae(newup[0], newup, envp) ;
 }
 
-int ssexec_scanctl(int argc, char const *const *argv, ssexec_t *info)
+int ssexec_scandir_signal(int argc, char const *const *argv, ssexec_t *info)
 {
     int r ;
-    uid_t owner = MYUID ;
+
     unsigned int timeout = 0, notif = 0, sig = 0 ;
 
     char const *newenv[MAXENV+1] ;
@@ -164,7 +177,6 @@ int ssexec_scanctl(int argc, char const *const *argv, ssexec_t *info)
     char const *const *genvp = (char const *const *)environ ;
     char const *signal ;
 
-    stralloc scandir = STRALLOC_ZERO ;
     stralloc envdir = STRALLOC_ZERO ;
 
     {
@@ -177,25 +189,10 @@ int ssexec_scanctl(int argc, char const *const *argv, ssexec_t *info)
 
             switch (opt) {
 
-                 case 'h' :
-
-                    info_help(info->help, info->usage) ;
-                    return 0 ;
-
-                case 'o' :
-
-                    if (MYUID)
-                        log_die(LOG_EXIT_USER, "only root can use -o option") ;
-
-                    if (!youruid(&owner,l.arg))
-                        log_dieusys(LOG_EXIT_SYS,"get uid of: ",l.arg) ;
-
-                    break ;
-
                 case 'd' :
 
                     if (!uint0_scan(l.arg, &notif))
-                        log_usage(usage_scanctl) ;
+                        log_usage(info->usage, "\n", info->help) ;
 
                     if (notif < 3)
                         log_die(LOG_EXIT_USER, "notification fd must be 3 or more") ;
@@ -205,10 +202,10 @@ int ssexec_scanctl(int argc, char const *const *argv, ssexec_t *info)
 
                     break ;
 
-                case 't' :
+                case 's' :
 
                     if (!uint0_scan(l.arg, &timeout))
-                        log_usage(usage_scanctl) ;
+                        log_usage(info->usage, "\n", info->help) ;
 
                     break ;
 
@@ -227,17 +224,13 @@ int ssexec_scanctl(int argc, char const *const *argv, ssexec_t *info)
         argc -= l.ind ; argv += l.ind ;
     }
 
-    if (argc < 1) log_usage(info->usage, "\n", info->help) ;
+    if (argc < 1)
+        log_usage(info->usage, "\n", info->help) ;
+
     signal = argv[0] ;
-    r = set_livedir(&scandir) ;
-    if (r < 0) log_die(LOG_EXIT_USER,"live: ",scandir.s," must be an absolute path") ;
-    if (!r) log_dieusys(LOG_EXIT_SYS,"set live directory") ;
-    r = set_livescan(&scandir,owner) ;
-    if (r < 0) log_die(LOG_EXIT_USER,"scandir: ", scandir.s, " must be an absolute path") ;
-    if (!r) log_dieusys(LOG_EXIT_SYS,"set scandir directory") ;
-
-    if (envdir.len)
-    {
+
+    if (envdir.len) {
+
         stralloc modifs = STRALLOC_ZERO ;
         if (envdir.s[0] != '/')
             log_die(LOG_EXIT_USER,"environment: ",envdir.s," must be an absolute path") ;
@@ -245,7 +238,6 @@ int ssexec_scanctl(int argc, char const *const *argv, ssexec_t *info)
         if (!environ_clean_envfile_unexport(&modifs,envdir.s))
             log_dieu(LOG_EXIT_SYS,"clean environment file of: ",envdir.s) ;
 
-
         size_t envlen = env_len(genvp) ;
         size_t n = env_len(genvp) + 1 + byte_count(modifs.s,modifs.len,'\0') ;
         size_t mlen = modifs.len ;
@@ -265,28 +257,35 @@ int ssexec_scanctl(int argc, char const *const *argv, ssexec_t *info)
 
     if (!sig) {
 
-        char scan[scandir.len + 1] ;
-        auto_strings(scan,scandir.s) ;
+        char scandir[info->scandir.len + 1] ;
+        auto_strings(scandir, info->scandir.s) ;
+
+        int r ;
+        r = svc_scandir_ok(scandir) ;
+        if (r < 0)
+            log_dieusys(LOG_EXIT_SYS, "check: ", scandir) ;
+        if (r) {
+            log_trace("scandir: ", scandir, " already running") ;
+            return 0 ;
+        }
 
         stralloc_free(&envdir) ;
-        stralloc_free(&scandir) ;
+        ssexec_free(info) ;
 
-        scandir_up(scan,timeout,notif,genv) ;
-        /** if already running, scandir_up() return */
+        scandir_up(scandir, timeout, notif, genv) ;
         return 0 ;
     }
 
-    r = svc_scandir_ok(scandir.s) ;
-    if (!r) log_diesys(LOG_EXIT_SYS,"scandir: ",scandir.s," is not running") ;
-    else if (r < 0) log_dieusys(LOG_EXIT_SYS, "check: ", scandir.s) ;
+    r = svc_scandir_ok(info->scandir.s) ;
+    if (r < 0)
+        log_dieusys(LOG_EXIT_SYS, "check: ", info->scandir.s) ;
+    else if (!r)
+        log_diesys(LOG_EXIT_SYS, "scandir: ", info->scandir.s, " is not running") ;
 
-    if (send_signal(scandir.s,signal) <= 0) goto err ;
+    if (send_signal(info->scandir.s,signal) <= 0)
+        log_dieu(LOG_EXIT_SYS, "send signal to scandir: ", info->scandir.s) ;
 
-    stralloc_free(&scandir) ;
     return 0 ;
-    err:
-        stralloc_free(&scandir) ;
-        return 111 ;
 }
 
 
diff --git a/src/lib66/exec/ssexec_scandir_wrapper.c b/src/lib66/exec/ssexec_scandir_wrapper.c
new file mode 100644
index 00000000..ba6dac36
--- /dev/null
+++ b/src/lib66/exec/ssexec_scandir_wrapper.c
@@ -0,0 +1,239 @@
+/*
+ * ssexec_scandir_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 <oblibs/string.h>
+
+#include <skalibs/sgetopt.h>
+
+#include <66/ssexec.h>
+#include <66/constants.h>
+#include <66/config.h>
+#include <66/utils.h>
+
+int ssexec_scandir_wrapper(int argc, char const *const *argv, ssexec_t *info)
+{
+    log_flow() ;
+
+    if (!argv[1]) {
+        PROG = "scandir" ;
+        log_usage(usage_scandir_wrapper, "\n", help_scandir_wrapper) ;
+    }
+
+    int r, n = 0, i = 0 ;
+    uid_t owner = -1 ;
+    ssexec_func_t_ref func = 0 ;
+    char const *nargv[argc + 1] ;
+
+    if (!strcmp(argv[1], "create")) {
+
+        nargv[n++] = PROG ;
+        info->prog = PROG ;
+        info->help = help_scandir_create ;
+        info->usage = usage_scandir_create ;
+        func = &ssexec_scandir_create ;
+
+    } else if (!strcmp(argv[1], "remove")) {
+
+        nargv[n++] = PROG ;
+        info->prog = PROG ;
+        info->help = help_scandir_remove ;
+        info->usage = usage_scandir_remove ;
+        func = &ssexec_scandir_remove ;
+
+    } else if (!strcmp(argv[1], "start")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_start ;
+        info->usage = usage_scandir_start ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "stop")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_stop ;
+        info->usage = usage_scandir_stop ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "reconfigure")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_reconfigure ;
+        info->usage = usage_scandir_reconfigure ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "rescan")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_rescan ;
+        info->usage = usage_scandir_rescan ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "quit")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_quit ;
+        info->usage = usage_scandir_quit ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "halt")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_halt ;
+        info->usage = usage_scandir_halt ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "abort")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_abort ;
+        info->usage = usage_scandir_abort ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "nuke")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_nuke ;
+        info->usage = usage_scandir_nuke ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "annihilate")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_annihilate ;
+        info->usage = usage_scandir_annihilate ;
+        func = &ssexec_scandir_signal ;
+
+    } else if (!strcmp(argv[1], "zombies")) {
+
+        nargv[n++] = PROG ;
+        nargv[n++] = argv[1] ;
+        info->prog = PROG ;
+        info->help = help_scandir_zombies ;
+        info->usage = usage_scandir_zombies ;
+        func = &ssexec_scandir_signal ;
+
+    } else {
+
+        if (!strcmp(argv[1], "-h")) {
+            info_help(help_scandir_wrapper, usage_scandir_wrapper) ;
+            return 0 ;
+        }
+
+        log_usage(usage_scandir_wrapper, "\n", help_scandir_wrapper) ;
+    }
+
+    argc-- ;
+    argv++ ;
+
+    {
+        subgetopt l = SUBGETOPT_ZERO ;
+
+        int f = 0 ;
+        for (;;) {
+
+            int opt = subgetopt_r(argc, argv, OPTS_SCANDIR_WRAPPER, &l) ;
+            if (opt == -1) break ;
+            switch (opt) {
+
+                case 'h' :
+
+                    info_help(info->help, info->usage) ;
+                    return 0 ;
+
+                case 'o' :
+
+                    if (MYUID)
+                        log_die(LOG_EXIT_USER, "only root can use -o option") ;
+
+                    if (!youruid(&owner,l.arg))
+                        log_dieusys(LOG_EXIT_SYS, "get uid of: ", l.arg) ;
+
+                    info->owner = owner ;
+                    info->ownerlen = uid_fmt(info->ownerstr, info->owner) ;
+                    info->ownerstr[info->ownerlen] = 0 ;
+
+                    info->scandir.len = 0 ;
+                    if (!auto_stra(&info->scandir, info->live.s, SS_SCANDIR, "/", info->ownerstr))
+                        log_die_nomem("stralloc") ;
+
+                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 ;
+
+    r = (*func)(n, nargv, info) ;
+
+    return r ;
+}
-- 
GitLab