Skip to content
Snippets Groups Projects
ssexec_tree_status.c 16.5 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * ssexec_tree_status.c
    
    Eric Vidal's avatar
    Eric Vidal committed
     * Copyright (c) 2018-2024 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 <locale.h>
    #include <langinfo.h>
    #include <sys/types.h>
    #include <wchar.h>
    #include <unistd.h>//access
    
    #include <oblibs/sastr.h>
    
    #include <oblibs/log.h>
    
    #include <oblibs/types.h>
    #include <oblibs/string.h>
    
    #include <oblibs/files.h>
    
    Eric Vidal's avatar
    Eric Vidal committed
    #include <oblibs/lexer.h>
    
    #include <oblibs/stack.h>
    
    Eric Vidal's avatar
    Eric Vidal committed
    #include <skalibs/sgetopt.h>
    
    #include <skalibs/genalloc.h>
    #include <skalibs/lolstdio.h>
    #include <skalibs/bytestr.h>
    #include <skalibs/buffer.h>
    
    #include <66/info.h>
    #include <66/constants.h>
    #include <66/tree.h>
    #include <66/enum.h>
    #include <66/resolve.h>
    
    #include <66/service.h>
    
    #include <66/graph.h>
    
    Eric Vidal's avatar
    Eric Vidal committed
    #include <66/ssexec.h>
    
    #include <66/hash.h>
    
    
    static unsigned int REVERSE = 0 ;
    
    static unsigned int NOFIELD = 1 ;
    
    static unsigned int GRAPH = 0 ;
    
    static wchar_t const field_suffix[] = L" :" ;
    
    static char fields[INFO_NKEY][INFO_FIELD_MAXLEN] = {{ 0 }} ;
    
    static void info_display_name(char const *field,char const *treename) ;
    static void info_display_current(char const *field,char const *treename) ;
    
    static void info_display_enabled(char const *field,char const *treename) ;
    
    //static void info_display_init(char const *field,char const *treename) ;
    
    static void info_display_depends(char const *field,char const *treename) ;
    static void info_display_requiredby(char const *field,char const *treename) ;
    
    static void info_display_allow(char const *field,char const *treename) ;
    
    Eric Vidal's avatar
    Eric Vidal committed
    static void info_display_contents(char const *field,char const *treename) ;
    
    static void info_display_groups(char const *field,char const *treename) ;
    
    Eric Vidal's avatar
    Eric Vidal committed
    static info_graph_style *T_STYLE = &graph_default ;
    
    static ssexec_t_ref pinfo = 0 ;
    
    
    info_opts_map_t const opts_tree_table[] =
    {
    
        { .str = "name", .func = &info_display_name, .id = 0 },
    
        { .str = "current", .func = &info_display_current, .id = 1 },
    
        { .str = "enabled", .func = &info_display_enabled, .id = 2 },
    
    //    { .str = "init", .func = &info_display_init, .id = 3 },
        { .str = "allowed", .func = &info_display_allow, .id = 3 },
        { .str = "groups", .func = &info_display_groups, .id = 4 },
        { .str = "depends", .func = &info_display_depends, .id = 5 },
        { .str = "requiredby", .func = &info_display_requiredby, .id = 6 },
        { .str = "contents", .func = &info_display_contents, .id = 7 },
    
        { .str = 0, .func = 0, .id = -1 }
    
    #define MAXOPTS 9
    
    Eric Vidal's avatar
    Eric Vidal committed
    #define checkopts(n) if (n >= MAXOPTS) log_die(LOG_EXIT_USER, "too many options")
    
    #define DELIM ','
    
    static void info_display_name(char const *field, char const *treename)
    {
    
        if (NOFIELD) info_display_field_name(field) ;
        if (!bprintf(buffer_1,"%s",treename))
            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_current(char const *field,char const *treename)
    
        int current = tree_iscurrent(pinfo->base.s, treename) ;
        if (current < 0)
    
            log_dieu(LOG_EXIT_SYS, "read resolve file of: ", treename) ;
    
    
        if (NOFIELD) info_display_field_name(field) ;
    
    Eric Vidal's avatar
    Eric Vidal committed
        if (!bprintf(buffer_1,"%s%s%s", current ? log_color->valid : log_color->warning, current ? "yes":"no",log_color->off))
    
            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_enabled(char const *field,char const *treename)
    
        int enabled = tree_isenabled(pinfo->base.s, treename) ;
        if (enabled < 0)
    
            log_dieu(LOG_EXIT_SYS, "read resolve file of: ", treename) ;
    
    
        if (NOFIELD) info_display_field_name(field) ;
    
        if (!bprintf(buffer_1,"%s%s%s",enabled ? log_color->valid : log_color->warning, enabled ? "yes":"no",log_color->off))
    
            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_init(char const *field,char const *treename)
    
         it not possible to write the resolve file of a tree at boot
    
           if the filesystem is ro. So consider tree as never initiated.
           ssexec_{start,stop,free,...} will deal with the live state of
           the services anyway.
    
        unsigned int init = tree_isinitialized(pinfo->base.s, treename) ;
        if (init == -1) log_dieu(LOG_EXIT_SYS, "resolve file of tree: ", treename) ;
    
        if (NOFIELD) info_display_field_name(field) ;
    
        if (!bprintf(buffer_1,"%s%s%s",init ? log_color->valid : log_color->warning, init ? "yes":"no",log_color->off))
    
            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_allow(char const *field, char const *treename)
    {
    
        stralloc sa = STRALLOC_ZERO ;
        resolve_tree_t tres = RESOLVE_TREE_ZERO ;
        resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
    
    
        if (resolve_read_g(wres, pinfo->base.s, treename) <= 0)
    
            log_dieusys(LOG_EXIT_SYS,"read resolve file of tree: ", treename) ;
    
        if (NOFIELD)
            info_display_field_name(field) ;
    
        if (tres.nallow) {
    
            if (!sastr_clean_string(&sa, tres.sa.s + tres.allow))
                log_dieu(LOG_EXIT_SYS,"clean groups string") ;
    
            if (!sa.len)
                goto empty ;
    
            size_t len = sa.len, pos = 0 ;
            char t[len + 1] ;
    
            sastr_to_char(t, &sa) ;
    
            sa.len = 0 ;
    
            for (; pos < len ; pos += strlen(t + pos) + 1) {
    
                char *suid = t + pos ;
                uid_t uid = 0 ;
                if (!uid0_scan(suid, &uid))
                    log_dieusys(LOG_EXIT_SYS,"get uid of: ",suid) ;
                if (pos)
                    if (!stralloc_cats(&sa," ")) log_die_nomem("stralloc") ;
                if (!get_namebyuid(uid,&sa))
                    log_dieusys(LOG_EXIT_SYS, "get name of uid: ", suid) ;
            }
    
            if (!stralloc_0(&sa)) log_die_nomem("stralloc") ;
            if (!sastr_rebuild_in_oneline(&sa)) log_dieu(LOG_EXIT_SYS,"rebuild list") ;
    
            if (!stralloc_0(&sa)) log_die_nomem("stralloc") ;
    
            info_display_list(field,&sa) ;
    
        } else {
    
            empty:
            if (!bprintf(buffer_1,"%s%s%s\n",log_color->warning,"None",log_color->off))
                log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
        }
    
        resolve_free(wres) ;
        stralloc_free(&sa) ;
    
    }
    
    static void info_display_groups(char const *field, char const *treename)
    {
        stralloc sa = STRALLOC_ZERO ;
        resolve_tree_t tres = RESOLVE_TREE_ZERO ;
        resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
    
    
        if (resolve_read_g(wres, pinfo->base.s, treename) <= 0)
    
            log_dieusys(LOG_EXIT_SYS,"read resolve file of: ", treename) ;
    
        if (NOFIELD)
            info_display_field_name(field) ;
    
        if (tres.ngroups) {
    
            if (!sastr_clean_string(&sa, tres.sa.s + tres.groups))
                log_dieu(LOG_EXIT_SYS,"clean groups string") ;
    
            info_display_list(field,&sa) ;
    
        } else {
    
            if (!bprintf(buffer_1,"%s%s%s\n",log_color->warning,"None",log_color->off))
                log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
        }
    
        resolve_free(wres) ;
        stralloc_free(&sa) ;
    
    
    static void info_display_depends(char const *field, char const *treename)
    
        size_t padding = 1 ;
        graph_t graph = GRAPH_ZERO ;
        stralloc sa = STRALLOC_ZERO ;
    
        struct resolve_hash_tree_s *htres = NULL ;
    
    
        if (NOFIELD) padding = info_display_field_name(field) ;
        else { field = 0 ; padding = 0 ; }
    
        graph_build_tree(&graph, &htres, pinfo->base.s, E_RESOLVE_TREE_MASTER_CONTENTS) ;
    
    Eric Vidal's avatar
    Eric Vidal committed
        r = graph_matrix_get_edge_g_sorted_sa(&sa, &graph, treename, 0, 0) ;
    
        if (r < 0)
            log_dieu(LOG_EXIT_SYS, "get the dependencies list") ;
    
        if (!r || !sa.len)
            goto empty ;
    
        if (GRAPH) {
    
            if (!bprintf(buffer_1,"%s\n","\\"))
    
                log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
    
            if (!info_walk(&graph, treename, 0, &info_graph_display_tree, 0, REVERSE, &d, padding, T_STYLE))
    
                log_dieu(LOG_EXIT_SYS,"display the graph dependencies") ;
    
            goto freed ;
    
        } else {
    
            if (REVERSE)
                if (!sastr_reverse(&sa))
                    log_dieu(LOG_EXIT_SYS,"reverse the dependencies list") ;
    
            info_display_list(field,&sa) ;
    
            goto freed ;
        }
        empty:
            if (GRAPH) {
    
    
                if (!bprintf(buffer_1,"%s\n","\\"))
    
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
    
    Eric Vidal's avatar
    Eric Vidal committed
                if (!bprintf(buffer_1,"%*s%s%s%s%s\n",padding, "", T_STYLE->last, log_color->warning,"None",log_color->off))
    
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
            } else {
    
                if (!bprintf(buffer_1,"%s%s%s\n",log_color->warning,"None",log_color->off))
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
            }
    
        freed:
            graph_free_all(&graph) ;
            stralloc_free(&sa) ;
    
            hash_free_tree(&htres) ;
    
    }
    
    static void info_display_requiredby(char const *field, char const *treename)
    {
        int r ;
        size_t padding = 1 ;
        graph_t graph = GRAPH_ZERO ;
        stralloc sa = STRALLOC_ZERO ;
    
        struct resolve_hash_tree_s *htres = NULL ;
    
    
        if (NOFIELD) padding = info_display_field_name(field) ;
        else { field = 0 ; padding = 0 ; }
    
    
        graph_build_tree(&graph, &htres, pinfo->base.s, E_RESOLVE_TREE_MASTER_CONTENTS) ;
    
    Eric Vidal's avatar
    Eric Vidal committed
        r = graph_matrix_get_edge_g_sorted_sa(&sa, &graph, treename, 1, 0) ;
    
        if (r < 0)
            log_dieu(LOG_EXIT_SYS, "get the dependencies list") ;
    
        if (!r || !sa.len)
            goto empty ;
    
        if (GRAPH) {
    
    
            if (!bprintf(buffer_1,"%s\n","\\"))
    
                log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
            if (!info_walk(&graph, treename, 0, &info_graph_display_tree, 1, REVERSE, &d, padding, T_STYLE))
    
                log_dieu(LOG_EXIT_SYS,"display the graph dependencies") ;
    
            goto freed ;
    
        } else {
    
            if (REVERSE)
                if (!sastr_reverse(&sa))
                    log_dieu(LOG_EXIT_SYS,"reverse the dependencies list") ;
    
            info_display_list(field,&sa) ;
    
            goto freed ;
    
                if (!bprintf(buffer_1,"%s\n","\\"))
    
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
    
    Eric Vidal's avatar
    Eric Vidal committed
                if (!bprintf(buffer_1,"%*s%s%s%s%s\n",padding, "", T_STYLE->last, log_color->warning,"None",log_color->off))
    
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
            } else {
    
                if (!bprintf(buffer_1,"%s%s%s\n",log_color->warning,"None",log_color->off))
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
            }
    
        freed:
            graph_free_all(&graph) ;
            stralloc_free(&sa) ;
    
            hash_free_tree(&htres) ;
    
    Eric Vidal's avatar
    Eric Vidal committed
    static void info_display_contents(char const *field, char const *treename)
    
        size_t padding = 1 ;
    
        graph_t graph = GRAPH_ZERO ;
    
        stralloc sa = STRALLOC_ZERO ;
    
        struct resolve_hash_s *hres = NULL ;
    
        if (NOFIELD) padding = info_display_field_name(field) ;
        else { field = 0 ; padding = 0 ; }
    
    
        if (!resolve_get_field_tosa_g(&sa, pinfo->base.s, treename, DATA_TREE, E_RESOLVE_TREE_CONTENTS))
            log_dieu(LOG_EXIT_SYS, "get field contents of tree: ", treename) ;
    
        if (!sa.len)
            goto empty ;
    
    
        service_graph_g(sa.s, sa.len, &graph, &hres, pinfo, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ;
    
        if (!HASH_COUNT(hres))
    
    Eric Vidal's avatar
    Eric Vidal committed
            goto empty ;
    
        if (GRAPH) {
    
            if (!bprintf(buffer_1,"%s\n","\\"))
    
                log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
    
            depth_t d = info_graph_init() ;
    
    
            if (!info_walk(&graph, 0, 0, &info_graph_display_service, 0, REVERSE, &d, padding, T_STYLE))
    
                log_dieu(LOG_EXIT_SYS,"display the graph dependencies") ;
    
    
            goto freed ;
    
            if (REVERSE)
    
                if (!sastr_reverse(&sa))
    
                    log_dieu(LOG_EXIT_SYS,"reverse the dependencies list") ;
    
    
            info_display_list(field,&sa) ;
    
            goto freed ;
        }
    
    
            if (GRAPH) {
    
                if (!bprintf(buffer_1,"%s\n","\\"))
    
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
    Eric Vidal's avatar
    Eric Vidal committed
                if (!bprintf(buffer_1,"%*s%s%s%s%s\n",padding, "", T_STYLE->last, log_color->warning,"None",log_color->off))
    
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
                if (!bprintf(buffer_1,"%s%s%s\n",log_color->warning,"None",log_color->off))
    
                    log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
            }
    
            graph_free_all(&graph) ;
    
            hash_free(&hres) ;
    
            stralloc_free(&sa) ;
    
    static void info_display_all(char const *treename,int *what)
    {
    
    
        unsigned int i = 0 ;
    
        for (; what[i] >= 0 ; i++) {
    
    
            unsigned int idx = what[i] ;
            (*opts_tree_table[idx].func)(fields[opts_tree_table[idx].id],treename) ;
        }
    
    
    }
    
    static void info_parse_options(char const *str,int *what)
    {
    
        size_t pos = 0 ;
    
    Eric Vidal's avatar
    Eric Vidal committed
        _alloc_stk_(stk, strlen(str) + 1) ;
    
        if (!lexer_trim_with_delim(&stk, str, DELIM))
            log_dieu(LOG_EXIT_SYS,"parse options") ;
    
    Eric Vidal's avatar
    Eric Vidal committed
        unsigned int nopts = 0 , old ;
        checkopts(stk.count) ;
    
        info_opts_map_t const *t ;
    
    
    Eric Vidal's avatar
    Eric Vidal committed
        FOREACH_STK(&stk, pos) {
    
    Eric Vidal's avatar
    Eric Vidal committed
            char *o = stk.s + pos ;
    
            t = opts_tree_table ;
            old = nopts ;
    
    Eric Vidal's avatar
    Eric Vidal committed
                if (!strcmp(o,t->str))
    
    
            if (old == nopts)
                log_die(LOG_EXIT_SYS,"invalid option: ",o) ;
    
    int ssexec_tree_status(int argc, char const *const *argv, ssexec_t *info)
    
    Eric Vidal's avatar
    Eric Vidal committed
        log_flow() ;
    
    
        unsigned int legacy = 1 ;
    
    
        size_t pos = 0 ;
    
        int what[MAXOPTS] = { 0 } ;
    
        stralloc sa = STRALLOC_ZERO ;
    
        struct resolve_hash_tree_s *htres = NULL ;
    
    
        char const *treename = 0 ;
    
        for (int i = 0 ; i < MAXOPTS ; i++)
            what[i] = -1 ;
    
    
        char buf[MAXOPTS][INFO_FIELD_MAXLEN] = {
            "Name",
            "Current",
    
            //"Initialized",
    
            "Allowed",
    
            subgetopt l = SUBGETOPT_ZERO ;
    
                int opt = subgetopt_r(argc, argv, OPTS_TREE_STATUS, &l) ;
    
                if (opt == -1) break ;
    
                switch (opt)
                {
                    case 'n' :  NOFIELD = 0 ; break ;
                    case 'o' :  legacy = 0 ; info_parse_options(l.arg,what) ; break ;
                    case 'g' :  GRAPH = 1 ; break ;
                    case 'r' :  REVERSE = 1 ; break ;
    
    Eric Vidal's avatar
    Eric Vidal committed
                    case 'd' :  if (!uint0_scan(l.arg, &MAXDEPTH)) log_usage(info->usage, "\n", info->help) ; break ;
                    default :   log_usage(info->usage, "\n", info->help) ;
    
                }
            }
            argc -= l.ind ; argv += l.ind ;
        }
    
        if (argv[0]) treename = argv[0] ;
    
    
            unsigned int i = 0 ;
            for (; i < MAXOPTS - 1 ; i++)
                what[i] = i ;
    
            what[i] = -1 ;
        }
    
    
        info_field_align(buf,fields,field_suffix,MAXOPTS) ;
    
        setlocale(LC_ALL, "");
    
    
        if(!str_diff(nl_langinfo(CODESET), "UTF-8"))
    
    Eric Vidal's avatar
    Eric Vidal committed
            T_STYLE = &graph_utf8;
    
            /** should never happens as long as we have
             * a default created */
            char src[info->base.len + SS_SYSTEM_LEN + 1] ;
    
            auto_strings(src, info->base.s, SS_SYSTEM) ;
    
            if (!scan_mode(src, S_IFDIR)) {
    
    Eric Vidal's avatar
    Eric Vidal committed
                log_info("No tree exist yet") ;
    
        if (treename) {
    
            if (!tree_isvalid(info->base.s, treename))
                log_dieusys(LOG_EXIT_SYS, "find tree: ", treename) ;
    
            info_display_all(treename, what) ;
    
            graph_t graph = GRAPH_ZERO ;
    
            graph_build_tree(&graph, &htres, pinfo->base.s, E_RESOLVE_TREE_MASTER_CONTENTS) ;
    
            if (!graph_matrix_sort_tosa(&sa, &graph))
                log_dieu(LOG_EXIT_SYS, "get the sorted list of trees") ;
    
            graph_free_all(&graph) ;
    
            if (sa.len) {
    
                FOREACH_SASTR(&sa, pos) {
    
                    info_display_all(sa.s + pos, what) ;
    
                    if (buffer_puts(buffer_1,"\n") == -1)
                        log_dieusys(LOG_EXIT_SYS,"write to stdout") ;
    
    Eric Vidal's avatar
    Eric Vidal committed
                log_info("No tree exist yet") ;
    
                goto freed ;
            }
        }
    
        if (buffer_flush(buffer_1) == -1)
            log_dieusys(LOG_EXIT_SYS, "write to stdout") ;
    
    
        freed:
    
    
        stralloc_free(&sa) ;
    
        hash_free_tree(&htres) ;
    
        return 0 ;