diff --git a/src/lib66/info/deps-lib/deps b/src/lib66/info/deps-lib/deps
index 9ea1cba14c6f67c5291713457def0ce645c689e2..3d2fa79fe588a494ebc20c99b1160029430a4484 100644
--- a/src/lib66/info/deps-lib/deps
+++ b/src/lib66/info/deps-lib/deps
@@ -1,4 +1,14 @@
-info_utils.o
+info_display_field_name.o
+info_display_list.o
+info_display_nline.o
+info_field_align.o
+info_getcols_fd.o
+info_graph_display.o
+info_graph_display_service.o
+info_graph_display_tree.o
+info_graph_init.o
+info_length_from_wchar.o
+info_walk.o
 -ls6rc
 -ls6
 -loblibs
diff --git a/src/lib66/info/info_display_field_name.c b/src/lib66/info/info_display_field_name.c
new file mode 100644
index 0000000000000000000000000000000000000000..e9bef987a24c568543a02fcdabc4be897ad5f563
--- /dev/null
+++ b/src/lib66/info/info_display_field_name.c
@@ -0,0 +1,34 @@
+/*
+ * info_display_field_name.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 <stddef.h>
+
+#include <oblibs/log.h>
+
+#include <skalibs/lolstdio.h>
+
+#include <66/info.h>
+
+size_t info_display_field_name(char const *field)
+{
+    log_flow() ;
+
+    size_t len = 0 ;
+    if(field)
+    {
+        len = info_length_from_wchar(field) + 1 ;
+        if (!bprintf(buffer_1,"%s%s%s ", log_color->info, field, log_color->off)) log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
+    }
+    return len ;
+}
diff --git a/src/lib66/info/info_display_list.c b/src/lib66/info/info_display_list.c
new file mode 100644
index 0000000000000000000000000000000000000000..85a9acda8b175d6ec06e335edf531f11aa5cb7c7
--- /dev/null
+++ b/src/lib66/info/info_display_list.c
@@ -0,0 +1,61 @@
+/*
+ * info_display_list.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 <stddef.h>
+
+#include <oblibs/log.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/lolstdio.h>
+
+#include <66/info.h>
+
+void info_display_list(char const *field, stralloc *list)
+{
+    log_flow() ;
+
+    size_t a = 0 , b, cols, padding = 0, slen = 0 ;
+
+    unsigned short maxcols = info_getcols_fd(1) ;
+
+    padding = info_length_from_wchar(field) + 1 ;
+
+    cols = padding ;
+
+    for (; a < list->len ; a += strlen(list->s + a) + 1)
+    {
+        char const *str = list->s + a ;
+        slen = info_length_from_wchar(str) ;
+        if((maxcols > padding) && (cols + slen + 2 >= maxcols))
+        {
+            cols = padding ;
+            if (buffer_puts(buffer_1,"\n") == -1) goto err ;
+            for(b = 1 ; b <= padding ; b++)
+                if (buffer_puts(buffer_1," ") == -1) goto err ;
+        }
+        else if (cols != padding)
+        {
+            if (buffer_puts(buffer_1," ") == -1) goto err ;
+            cols += 2 ;
+        }
+        if (!bprintf(buffer_1,"%s",str)) goto err ;
+        cols += slen ;
+    }
+    if (buffer_puts(buffer_1,"\n") == -1) goto err ;
+
+    return ;
+    err:
+        log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
+}
diff --git a/src/lib66/info/info_display_nline.c b/src/lib66/info/info_display_nline.c
new file mode 100644
index 0000000000000000000000000000000000000000..855d4761ae5d33a920d81ce5eee5576b4169c7da
--- /dev/null
+++ b/src/lib66/info/info_display_nline.c
@@ -0,0 +1,60 @@
+/*
+ * info_display_nline.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 <oblibs/sastr.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/lolstdio.h>
+
+#include <66/info.h>
+
+void info_display_nline(char const *field,char const *str)
+{
+    log_flow() ;
+
+    size_t pos = 0, padding = info_length_from_wchar(field) + 1, len ;
+
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (!auto_stra(&sa, str))
+        log_die_nomem("stralloc") ;
+
+    if (!sastr_split_string_in_nline(&sa))
+        log_dieu(LOG_EXIT_SYS,"split string in nline") ;
+
+    len = sa.len ;
+    char tmp[sa.len + 1] ;
+    sastr_to_char(tmp, &sa) ;
+
+    for (;pos < len ; pos += strlen(tmp + pos) + 1) {
+
+        sa.len = 0 ;
+
+        if (!auto_stra(&sa,tmp + pos))
+            log_die_nomem("stralloc") ;
+
+        if (field) {
+            if (pos) {
+                if (!bprintf(buffer_1,"%*s",padding,""))
+                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
+            }
+        }
+        info_display_list(field,&sa) ;
+    }
+    stralloc_free(&sa) ;
+}
diff --git a/src/lib66/info/info_field_align.c b/src/lib66/info/info_field_align.c
new file mode 100644
index 0000000000000000000000000000000000000000..3519785c906f945141b258365bab1b0aaa122618
--- /dev/null
+++ b/src/lib66/info/info_field_align.c
@@ -0,0 +1,54 @@
+/*
+ * info_field_align.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 <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <66/info.h>
+
+void info_field_align (char buf[][INFO_FIELD_MAXLEN],char fields[][INFO_FIELD_MAXLEN],wchar_t const field_suffix[],size_t buflen)
+{
+    log_flow() ;
+
+    size_t a = 0, b = 0, maxlen = 0, wlen[buflen], len = INFO_FIELD_MAXLEN+nb_el(field_suffix) ;
+
+    int maxcol = 0, wcol[buflen] ;
+
+    wchar_t wbuf[buflen][len] ;
+
+    for(a = 0; a < buflen; a++)
+        for (b = 0; b < len; b++)
+            wbuf[a][b] = 0 ;
+
+    for(a = 0; a < buflen; a++)
+    {
+        wlen[a] = mbstowcs(wbuf[a], buf[a], strlen(buf[a]) + 1) ;
+        wcol[a] = wcswidth(wbuf[a], wlen[a]) ;
+        if(wcol[a] > maxcol) {
+            maxcol = wcol[a] ;
+        }
+        if(wlen[a] > maxlen) {
+            maxlen = wlen[a] ;
+        }
+    }
+
+    for(a = 0; a < buflen; a++)
+    {
+        size_t padlen = maxcol - wcol[a] ;
+        wmemset(wbuf[a] + wlen[a], L' ', padlen) ;
+        wmemcpy(wbuf[a] + wlen[a] + padlen, field_suffix, nb_el(field_suffix)) ;
+        wcstombs(fields[a], wbuf[a], sizeof(wbuf[a])) ;
+    }
+}
diff --git a/src/lib66/info/info_getcols_fd.c b/src/lib66/info/info_getcols_fd.c
new file mode 100644
index 0000000000000000000000000000000000000000..59b33945705aef5ad0b64a471b905bd7ec8d3170
--- /dev/null
+++ b/src/lib66/info/info_getcols_fd.c
@@ -0,0 +1,41 @@
+/*
+ * info_getcols_fd.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 <unistd.h>
+#include <sys/ioctl.h>
+#include <wchar.h>
+
+#include <66/info.h>
+
+int info_getcols_fd(int fd)
+{
+    int width = -1;
+
+    if(!isatty(fd)) return 0;
+
+#if defined(TIOCGSIZE)
+    struct ttysize win;
+    if(ioctl(fd, TIOCGSIZE, &win) == 0)
+        width = win.ts_cols;
+#elif defined(TIOCGWINSZ)
+    struct winsize win;
+    if(ioctl(fd, TIOCGWINSZ, &win) == 0)
+        width = win.ws_col;
+#endif
+
+    // return abitrary value
+    if(width <= 0) return 100 ;
+
+    return width;
+}
diff --git a/src/lib66/info/info_graph_display.c b/src/lib66/info/info_graph_display.c
new file mode 100644
index 0000000000000000000000000000000000000000..c7ff2ad0766ae08d08a2679970a7776e405dec0e
--- /dev/null
+++ b/src/lib66/info/info_graph_display.c
@@ -0,0 +1,55 @@
+/*
+ * info_graph_display.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 <skalibs/buffer.h>
+#include <skalibs/lolstdio.h>
+
+#include <66/info.h>
+
+int info_graph_display(char const *name, char const *obj, info_graph_func *func, depth_t *depth, int last, int padding, info_graph_style *style)
+{
+    log_flow() ;
+
+    int level = 1 ;
+
+    const char *tip = "" ;
+
+    tip = last ? style->last : style->tip ;
+
+    while(depth->prev)
+        depth = depth->prev ;
+
+    while(depth->next)
+    {
+        if (!bprintf(buffer_1,"%*s%-*s",style->indent * (depth->level - level) + (level == 1 ? padding : 0), "", style->indent, style->limb))
+            return 0 ;
+
+        level = depth->level + 1 ;
+        depth = depth->next ;
+    }
+
+    if (!bprintf(buffer_1,"%*s%*s%s", \
+                level == 1 ? padding : 0,"", \
+                style->indent * (depth->level - level), "", \
+                tip)) return 0 ;
+
+    int r = (*func)(name, obj) ;
+    if (!r) return 0 ;
+    if (buffer_putsflush(buffer_1,"\n") < 0)
+        return 0 ;
+
+    return 1 ;
+}
diff --git a/src/lib66/info/info_graph_display_service.c b/src/lib66/info/info_graph_display_service.c
new file mode 100644
index 0000000000000000000000000000000000000000..859ce0f29a7bdc88c9dbbeeeff23d60aad70c1ab
--- /dev/null
+++ b/src/lib66/info/info_graph_display_service.c
@@ -0,0 +1,126 @@
+/*
+ * info_graph_display_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 <stdint.h>
+
+#include <oblibs/log.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/lolstdio.h>
+#include <skalibs/buffer.h>
+
+#include <66/info.h>
+#include <66/service.h>
+#include <66/tree.h>
+#include <66/state.h>
+#include <66/enum.h>
+
+#include <s6/supervise.h>
+
+int info_graph_display_service(char const *name, char const *obj)
+{
+    log_flow() ;
+
+    stralloc tree = STRALLOC_ZERO ;
+    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
+
+    int r = service_intree(&tree, name, obj), err = 0 ;
+
+    if (r != 2) {
+        if (r == 1)
+            log_warnu("find: ", name, " at tree: ", !obj ? tree.s : obj) ;
+        if (r > 2)
+            log_1_warn(name, " is set on different tree -- please use -t options") ;
+
+        goto freed ;
+    }
+
+    if (!resolve_check(tree.s, name))
+        goto freed ;
+
+    if (!resolve_read(wres, tree.s, name))
+        goto freed ;
+
+    char str_pid[UINT_FMT] ;
+    uint8_t pid_color = 0 ;
+    char *ppid ;
+    ss_state_t sta = STATE_ZERO ;
+    s6_svstatus_t status = S6_SVSTATUS_ZERO ;
+
+    if (res.type == TYPE_CLASSIC || res.type == TYPE_LONGRUN) {
+
+        s6_svstatus_read(res.sa.s + res.runat ,&status) ;
+        pid_color = !status.pid ? 1 : 2 ;
+        str_pid[uint_fmt(str_pid, status.pid)] = 0 ;
+        ppid = &str_pid[0] ;
+
+    } else {
+
+        char *ste = res.sa.s + res.state ;
+        char *name = res.sa.s + res.name ;
+        if (!state_check(ste,name)) {
+
+            ppid = "unitialized" ;
+            goto dis ;
+        }
+
+        if (!state_read(&sta,ste,name)) {
+
+            log_warnu("read state of: ",name) ;
+            goto freed ;
+        }
+        if (sta.init) {
+
+            ppid = "unitialized" ;
+            goto dis ;
+
+        } else if (!sta.state) {
+
+            ppid = "down" ;
+            pid_color = 1 ;
+
+        } else if (sta.state) {
+
+            ppid = "up" ;
+            pid_color = 2 ;
+        }
+    }
+
+    dis:
+
+    if (!bprintf(buffer_1,"(%s%s%s,%s%s%s,%s) %s", \
+
+                pid_color > 1 ? log_color->valid : pid_color ? log_color->error : log_color->warning, \
+                ppid, \
+                log_color->off, \
+
+                res.disen ? log_color->off : log_color->error, \
+                res.disen ? "Enabled" : "Disabled", \
+                log_color->off, \
+
+                get_key_by_enum(ENUM_TYPE,res.type), \
+
+                name))
+                    goto freed ;
+
+    err = 1 ;
+
+    freed:
+        resolve_free(wres) ;
+        stralloc_free(&tree) ;
+
+    return err ;
+
+}
diff --git a/src/lib66/info/info_graph_display_tree.c b/src/lib66/info/info_graph_display_tree.c
new file mode 100644
index 0000000000000000000000000000000000000000..401c782063f2073e145df51bc2c6c904037f7ab9
--- /dev/null
+++ b/src/lib66/info/info_graph_display_tree.c
@@ -0,0 +1,101 @@
+/*
+ * info_graph_display_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 <unistd.h>
+#include <sys/types.h>
+
+#include <oblibs/log.h>
+#include <oblibs/string.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/lolstdio.h>
+#include <skalibs/buffer.h>
+
+#include <66/tree.h>
+#include <66/resolve.h>
+#include <66/utils.h>
+#include <66/constants.h>
+#include <66/info.h>
+
+int info_graph_display_tree(char const *name, char const *obj)
+{
+    log_flow() ;
+
+    int err = 0 ;
+    stralloc sa = STRALLOC_ZERO ;
+    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
+    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
+
+    uid_t owner = getuid() ;
+
+    if (!set_ownersysdir(&sa, owner)) {
+        log_warnusys("set owner directory") ;
+        resolve_free(wres) ;
+        stralloc_free(&sa) ;
+        return err ;
+    }
+
+    char base[sa.len + 1] ;
+    auto_strings(base, sa.s) ;
+
+    if (tree_isvalid(sa.s, name) <= 0) {
+        log_warn("invalide tree: ", name) ;
+        goto freed ;
+    }
+
+    if (!auto_stra(&sa, SS_SYSTEM))
+        goto freed ;
+
+    if (!resolve_check(sa.s, name))
+        goto freed ;
+
+    if (!resolve_read(wres, sa.s, name))
+        goto freed ;
+
+    sa.len = 0 ;
+
+    int r = set_livedir(&sa) ;
+    if (r <= 0)
+        goto freed ;
+
+    int init = tres.init ;
+    if (init < 0)
+        goto freed ;
+
+    int enabled = tree_isenabled(base, name) ;
+    if (enabled < 0)
+        goto freed ;
+
+    if (!bprintf(buffer_1,"(%s%s%s,%s%s%s) %s", \
+
+                init ? log_color->valid : log_color->warning, \
+                init ? "Initialized" : "Unitialized", \
+                log_color->off, \
+
+                enabled ? log_color->valid : log_color->error, \
+                enabled ? "Enabled" : "Disabled", \
+                log_color->off, \
+
+                name))
+                    goto freed ;
+
+    err = 1 ;
+
+    freed:
+        resolve_free(wres) ;
+        stralloc_free(&sa) ;
+
+    return err ;
+
+}
diff --git a/src/lib66/info/info_graph_init.c b/src/lib66/info/info_graph_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..116dbccee82c8f0ab237df14b90d19caf4f5850d
--- /dev/null
+++ b/src/lib66/info/info_graph_init.c
@@ -0,0 +1,46 @@
+/*
+ * info_graph_init.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 <66/info.h>
+
+unsigned int MAXDEPTH = 1 ;
+
+info_graph_style graph_utf8 = {
+    UTF_VR UTF_H,
+    UTF_UR UTF_H,
+    UTF_V " ",
+    2
+} ;
+
+info_graph_style graph_default = {
+    "|-",
+    "`-",
+    "|",
+    2
+} ;
+
+depth_t info_graph_init(void)
+{
+    log_flow() ;
+
+    depth_t d = {
+        NULL,
+        NULL,
+        1
+    } ;
+
+    return d ;
+}
diff --git a/src/lib66/info/info_length_from_wchar.c b/src/lib66/info/info_length_from_wchar.c
new file mode 100644
index 0000000000000000000000000000000000000000..b1ec09f2bf035a09ffc5d37615a8ccd9a11b734f
--- /dev/null
+++ b/src/lib66/info/info_length_from_wchar.c
@@ -0,0 +1,38 @@
+/*
+ * info_length_from_wchar.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 <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <oblibs/log.h>
+
+#include <66/info.h>
+
+size_t info_length_from_wchar(char const *str)
+{
+    log_flow() ;
+
+    ssize_t len ;
+    wchar_t *wcstr ;
+    if(!str || !str[0]) return 0 ;
+
+    len = strlen(str) + 1 ;
+    wcstr = calloc(len, sizeof(wchar_t)) ;
+    len = mbstowcs(wcstr, str, len) ;
+    len = wcswidth(wcstr, len) ;
+    free(wcstr) ;
+
+    return len == -1 ? 0 : (size_t)len  ;
+}
diff --git a/src/lib66/info/info_utils.c b/src/lib66/info/info_utils.c
deleted file mode 100644
index 8b50e9856cfd35a4730fe9ef498abc103c1a25ed..0000000000000000000000000000000000000000
--- a/src/lib66/info/info_utils.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * info_utils.c
- *
- * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org>
- *
- * All rights reserved.
- *
- * This file is part of Obarun. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution.
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file./
- * */
-
-#include <66/info.h>
-
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-#include <wchar.h>
-
-#include <string.h>
-#include <sys/types.h> //ssize_t
-
-#include <oblibs/sastr.h>
-#include <oblibs/log.h>
-#include <oblibs/graph.h>
-
-#include <skalibs/buffer.h>
-#include <skalibs/lolstdio.h>
-
-#include <s6/supervise.h>
-
-#include <66/resolve.h>
-#include <66/tree.h>
-#include <66/state.h>
-#include <66/utils.h>
-#include <66/constants.h>
-
-unsigned int MAXDEPTH = 1 ;
-
-info_graph_style graph_utf8 = {
-    UTF_VR UTF_H,
-    UTF_UR UTF_H,
-    UTF_V " ",
-    2
-} ;
-
-info_graph_style graph_default = {
-    "|-",
-    "`-",
-    "|",
-    2
-} ;
-
-int info_getcols_fd(int fd)
-{
-    int width = -1;
-
-    if(!isatty(fd)) return 0;
-
-#if defined(TIOCGSIZE)
-    struct ttysize win;
-    if(ioctl(fd, TIOCGSIZE, &win) == 0)
-        width = win.ts_cols;
-#elif defined(TIOCGWINSZ)
-    struct winsize win;
-    if(ioctl(fd, TIOCGWINSZ, &win) == 0)
-        width = win.ws_col;
-#endif
-
-    // return abitrary value
-    if(width <= 0) return 100 ;
-
-    return width;
-}
-
-void info_field_align (char buf[][INFO_FIELD_MAXLEN],char fields[][INFO_FIELD_MAXLEN],wchar_t const field_suffix[],size_t buflen)
-{
-    log_flow() ;
-
-    size_t a = 0, b = 0, maxlen = 0, wlen[buflen], len = INFO_FIELD_MAXLEN+nb_el(field_suffix) ;
-
-    int maxcol = 0, wcol[buflen] ;
-
-    wchar_t wbuf[buflen][len] ;
-
-    for(a = 0; a < buflen; a++)
-        for (b = 0; b < len; b++)
-            wbuf[a][b] = 0 ;
-
-    for(a = 0; a < buflen; a++)
-    {
-        wlen[a] = mbstowcs(wbuf[a], buf[a], strlen(buf[a]) + 1) ;
-        wcol[a] = wcswidth(wbuf[a], wlen[a]) ;
-        if(wcol[a] > maxcol) {
-            maxcol = wcol[a] ;
-        }
-        if(wlen[a] > maxlen) {
-            maxlen = wlen[a] ;
-        }
-    }
-
-    for(a = 0; a < buflen; a++)
-    {
-        size_t padlen = maxcol - wcol[a] ;
-        wmemset(wbuf[a] + wlen[a], L' ', padlen) ;
-        wmemcpy(wbuf[a] + wlen[a] + padlen, field_suffix, nb_el(field_suffix)) ;
-        wcstombs(fields[a], wbuf[a], sizeof(wbuf[a])) ;
-    }
-}
-
-size_t info_length_from_wchar(char const *str)
-{
-    log_flow() ;
-
-    ssize_t len ;
-    wchar_t *wcstr ;
-    if(!str || !str[0]) return 0 ;
-
-    len = strlen(str) + 1 ;
-    wcstr = calloc(len, sizeof(wchar_t)) ;
-    len = mbstowcs(wcstr, str, len) ;
-    len = wcswidth(wcstr, len) ;
-    free(wcstr) ;
-
-    return len == -1 ? 0 : (size_t)len  ;
-}
-
-size_t info_display_field_name(char const *field)
-{
-    log_flow() ;
-
-    size_t len = 0 ;
-    if(field)
-    {
-        len = info_length_from_wchar(field) + 1 ;
-        if (!bprintf(buffer_1,"%s%s%s ", log_color->info, field, log_color->off)) log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
-    }
-    return len ;
-}
-
-void info_display_list(char const *field, stralloc *list)
-{
-    log_flow() ;
-
-    size_t a = 0 , b, cols, padding = 0, slen = 0 ;
-
-    unsigned short maxcols = info_getcols_fd(1) ;
-
-    padding = info_length_from_wchar(field) + 1 ;
-
-    cols = padding ;
-
-    for (; a < list->len ; a += strlen(list->s + a) + 1)
-    {
-        char const *str = list->s + a ;
-        slen = info_length_from_wchar(str) ;
-        if((maxcols > padding) && (cols + slen + 2 >= maxcols))
-        {
-            cols = padding ;
-            if (buffer_puts(buffer_1,"\n") == -1) goto err ;
-            for(b = 1 ; b <= padding ; b++)
-                if (buffer_puts(buffer_1," ") == -1) goto err ;
-        }
-        else if (cols != padding)
-        {
-            if (buffer_puts(buffer_1," ") == -1) goto err ;
-            cols += 2 ;
-        }
-        if (!bprintf(buffer_1,"%s",str)) goto err ;
-        cols += slen ;
-    }
-    if (buffer_puts(buffer_1,"\n") == -1) goto err ;
-
-    return ;
-    err:
-        log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
-}
-
-void info_display_nline(char const *field,char const *str)
-{
-    log_flow() ;
-
-    size_t pos = 0, padding = info_length_from_wchar(field) + 1, len ;
-
-    stralloc sa = STRALLOC_ZERO ;
-
-    if (!auto_stra(&sa, str))
-        log_die_nomem("stralloc") ;
-
-    if (!sastr_split_string_in_nline(&sa))
-        log_dieu(LOG_EXIT_SYS,"split string in nline") ;
-
-    len = sa.len ;
-    char tmp[sa.len + 1] ;
-    sastr_to_char(tmp, &sa) ;
-
-    for (;pos < len ; pos += strlen(tmp + pos) + 1) {
-
-        sa.len = 0 ;
-
-        if (!auto_stra(&sa,tmp + pos))
-            log_die_nomem("stralloc") ;
-
-        if (field) {
-            if (pos) {
-                if (!bprintf(buffer_1,"%*s",padding,""))
-                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
-            }
-        }
-        info_display_list(field,&sa) ;
-    }
-    stralloc_free(&sa) ;
-}
-
-depth_t info_graph_init(void)
-{
-    log_flow() ;
-
-    depth_t d = {
-        NULL,
-        NULL,
-        1
-    } ;
-
-    return d ;
-}
-
-int info_graph_display_tree(char const *name, char const *obj)
-{
-    log_flow() ;
-
-    int err = 0 ;
-    stralloc sa = STRALLOC_ZERO ;
-    resolve_tree_t tres = RESOLVE_TREE_ZERO ;
-    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
-
-    uid_t owner = getuid() ;
-
-    if (!set_ownersysdir(&sa, owner)) {
-        log_warnusys("set owner directory") ;
-        resolve_free(wres) ;
-        stralloc_free(&sa) ;
-        return err ;
-    }
-
-    char base[sa.len + 1] ;
-    auto_strings(base, sa.s) ;
-
-    if (tree_isvalid(sa.s, name) <= 0) {
-        log_warn("invalide tree: ", name) ;
-        goto freed ;
-    }
-
-    if (!auto_stra(&sa, SS_SYSTEM))
-        goto freed ;
-
-    if (!resolve_check(sa.s, name))
-        goto freed ;
-
-    if (!resolve_read(wres, sa.s, name))
-        goto freed ;
-
-    sa.len = 0 ;
-
-    int r = set_livedir(&sa) ;
-    if (r <= 0)
-        goto freed ;
-
-    int init = tres.init ;
-    if (init < 0)
-        goto freed ;
-
-    int enabled = tree_isenabled(base, name) ;
-    if (enabled < 0)
-        goto freed ;
-
-    if (!bprintf(buffer_1,"(%s%s%s,%s%s%s) %s", \
-
-                init ? log_color->valid : log_color->warning, \
-                init ? "Initialized" : "Unitialized", \
-                log_color->off, \
-
-                enabled ? log_color->valid : log_color->error, \
-                enabled ? "Enabled" : "Disabled", \
-                log_color->off, \
-
-                name))
-                    goto freed ;
-
-    err = 1 ;
-
-    freed:
-        resolve_free(wres) ;
-        stralloc_free(&sa) ;
-
-    return err ;
-
-}
-
-int info_graph_display_service(char const *name, char const *obj)
-{
-    log_flow() ;
-
-    stralloc tree = STRALLOC_ZERO ;
-    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
-    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
-
-    int r = service_intree(&tree, name, obj), err = 0 ;
-
-    if (r != 2) {
-        if (r == 1)
-            log_warnu("find: ", name, " at tree: ", !obj ? tree.s : obj) ;
-        if (r > 2)
-            log_1_warn(name, " is set on different tree -- please use -t options") ;
-
-        goto freed ;
-    }
-
-    if (!resolve_check(tree.s, name))
-        goto freed ;
-
-    if (!resolve_read(wres, tree.s, name))
-        goto freed ;
-
-    char str_pid[UINT_FMT] ;
-    uint8_t pid_color = 0 ;
-    char *ppid ;
-    ss_state_t sta = STATE_ZERO ;
-    s6_svstatus_t status = S6_SVSTATUS_ZERO ;
-
-    if (res.type == TYPE_CLASSIC || res.type == TYPE_LONGRUN) {
-
-        s6_svstatus_read(res.sa.s + res.runat ,&status) ;
-        pid_color = !status.pid ? 1 : 2 ;
-        str_pid[uint_fmt(str_pid, status.pid)] = 0 ;
-        ppid = &str_pid[0] ;
-
-    } else {
-
-        char *ste = res.sa.s + res.state ;
-        char *name = res.sa.s + res.name ;
-        if (!state_check(ste,name)) {
-
-            ppid = "unitialized" ;
-            goto dis ;
-        }
-
-        if (!state_read(&sta,ste,name)) {
-
-            log_warnu("read state of: ",name) ;
-            goto freed ;
-        }
-        if (sta.init) {
-
-            ppid = "unitialized" ;
-            goto dis ;
-
-        } else if (!sta.state) {
-
-            ppid = "down" ;
-            pid_color = 1 ;
-
-        } else if (sta.state) {
-
-            ppid = "up" ;
-            pid_color = 2 ;
-        }
-    }
-
-    dis:
-
-    if (!bprintf(buffer_1,"(%s%s%s,%s%s%s,%s) %s", \
-
-                pid_color > 1 ? log_color->valid : pid_color ? log_color->error : log_color->warning, \
-                ppid, \
-                log_color->off, \
-
-                res.disen ? log_color->off : log_color->error, \
-                res.disen ? "Enabled" : "Disabled", \
-                log_color->off, \
-
-                get_key_by_enum(ENUM_TYPE,res.type), \
-
-                name))
-                    goto freed ;
-
-    err = 1 ;
-
-    freed:
-        resolve_free(wres) ;
-        stralloc_free(&tree) ;
-
-    return err ;
-
-}
-
-int info_graph_display(char const *name, char const *obj, info_graph_func *func, depth_t *depth, int last, int padding, info_graph_style *style)
-{
-    log_flow() ;
-
-    int level = 1 ;
-
-    const char *tip = "" ;
-
-    tip = last ? style->last : style->tip ;
-
-    while(depth->prev)
-        depth = depth->prev ;
-
-    while(depth->next)
-    {
-        if (!bprintf(buffer_1,"%*s%-*s",style->indent * (depth->level - level) + (level == 1 ? padding : 0), "", style->indent, style->limb))
-            return 0 ;
-
-        level = depth->level + 1 ;
-        depth = depth->next ;
-    }
-
-    if (!bprintf(buffer_1,"%*s%*s%s", \
-                level == 1 ? padding : 0,"", \
-                style->indent * (depth->level - level), "", \
-                tip)) return 0 ;
-
-    int r = (*func)(name, obj) ;
-    if (!r) return 0 ;
-    if (buffer_putsflush(buffer_1,"\n") < 0)
-        return 0 ;
-
-    return 1 ;
-}
-
-int info_walk(graph_t *g, char const *name, char const *obj, info_graph_func *func, uint8_t requiredby, uint8_t reverse, depth_t *depth, int padding, info_graph_style *style)
-{
-    log_flow() ;
-
-    int e = 0, idx = 0, count ;
-    size_t pos = 0, len ;
-
-    if ((unsigned int) depth->level > MAXDEPTH)
-        return 1 ;
-
-    stralloc sa = STRALLOC_ZERO ;
-
-    if (!name) {
-        if (!graph_matrix_sort_tosa(&sa, g)) {
-            stralloc_free(&sa) ;
-            return e ;
-        }
-        count = sastr_len(&sa) ;
-
-    } else {
-
-        count = graph_matrix_get_edge_g_sorted_sa(&sa, g, name, requiredby) ;
-
-        if (count == -1) {
-            stralloc_free(&sa) ;
-            return e ;
-        }
-    }
-
-    len = sa.len ;
-    char vertex[len + 1] ;
-
-    if (!sa.len)
-        goto freed ;
-
-    if (reverse)
-        if (!sastr_reverse(&sa))
-            goto err ;
-
-    sastr_to_char(vertex, &sa) ;
-
-    for (; pos < len ; pos += strlen(vertex + pos) + 1, idx++ ) {
-
-        sa.len = 0 ;
-        int last =  idx + 1 < count  ? 0 : 1 ;
-        char *name = vertex + pos ;
-
-        if (!info_graph_display(name, obj, func, depth, last, padding, style))
-            goto err ;
-
-        if (graph_matrix_get_edge_g_sorted_sa(&sa, g, name, requiredby) == -1)
-            goto err ;
-
-        if (sa.len)
-        {
-            depth_t d =
-            {
-                depth,
-                NULL,
-                depth->level + 1
-            } ;
-            depth->next = &d;
-
-            if(last)
-            {
-                if(depth->prev)
-                {
-                    depth->prev->next = &d;
-                    d.prev = depth->prev;
-                    depth = &d;
-
-                }
-                else
-                    d.prev = NULL;
-            }
-            if (!info_walk(g, name, obj, func, requiredby, reverse, &d, padding, style))
-                goto err ;
-            depth->next = NULL ;
-        }
-    }
-
-    freed:
-        e = 1 ;
-
-    err:
-        stralloc_free(&sa) ;
-
-    return e ;
-
-}
-
diff --git a/src/lib66/info/info_walk.c b/src/lib66/info/info_walk.c
new file mode 100644
index 0000000000000000000000000000000000000000..7753eaa4ffdd89826018ab70abe430270b3706b9
--- /dev/null
+++ b/src/lib66/info/info_walk.c
@@ -0,0 +1,115 @@
+/*
+ * info_walk.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 <stdint.h>
+#include <string.h>
+
+#include <oblibs/log.h>
+#include <oblibs/sastr.h>
+
+#include <skalibs/stralloc.h>
+
+#include <66/info.h>
+#include <66/graph.h>
+
+int info_walk(graph_t *g, char const *name, char const *obj, info_graph_func *func, uint8_t requiredby, uint8_t reverse, depth_t *depth, int padding, info_graph_style *style)
+{
+    log_flow() ;
+
+    int e = 0, idx = 0, count ;
+    size_t pos = 0, len ;
+
+    if ((unsigned int) depth->level > MAXDEPTH)
+        return 1 ;
+
+    stralloc sa = STRALLOC_ZERO ;
+
+    if (!name) {
+        if (!graph_matrix_sort_tosa(&sa, g)) {
+            stralloc_free(&sa) ;
+            return e ;
+        }
+        count = sastr_len(&sa) ;
+
+    } else {
+
+        count = graph_matrix_get_edge_g_sorted_sa(&sa, g, name, requiredby) ;
+
+        if (count == -1) {
+            stralloc_free(&sa) ;
+            return e ;
+        }
+    }
+
+    len = sa.len ;
+    char vertex[len + 1] ;
+
+    if (!sa.len)
+        goto freed ;
+
+    if (reverse)
+        if (!sastr_reverse(&sa))
+            goto err ;
+
+    sastr_to_char(vertex, &sa) ;
+
+    for (; pos < len ; pos += strlen(vertex + pos) + 1, idx++ ) {
+
+        sa.len = 0 ;
+        int last =  idx + 1 < count  ? 0 : 1 ;
+        char *name = vertex + pos ;
+
+        if (!info_graph_display(name, obj, func, depth, last, padding, style))
+            goto err ;
+
+        if (graph_matrix_get_edge_g_sorted_sa(&sa, g, name, requiredby) == -1)
+            goto err ;
+
+        if (sa.len)
+        {
+            depth_t d =
+            {
+                depth,
+                NULL,
+                depth->level + 1
+            } ;
+            depth->next = &d;
+
+            if(last)
+            {
+                if(depth->prev)
+                {
+                    depth->prev->next = &d;
+                    d.prev = depth->prev;
+                    depth = &d;
+
+                }
+                else
+                    d.prev = NULL;
+            }
+            if (!info_walk(g, name, obj, func, requiredby, reverse, &d, padding, style))
+                goto err ;
+            depth->next = NULL ;
+        }
+    }
+
+    freed:
+        e = 1 ;
+
+    err:
+        stralloc_free(&sa) ;
+
+    return e ;
+
+}