Skip to content
Snippets Groups Projects
ssexec_stop.c 8.52 KiB
/*
 * ssexec_stop.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/obgetopt.h>
#include <oblibs/log.h>
#include <oblibs/string.h>

#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>

#include <66/utils.h>
#include <66/constants.h>
#include <66/db.h>
#include <66/svc.h>
#include <66/rc.h>
#include <66/ssexec.h>
#include <66/resolve.h>
#include <66/service.h>
#include <66/state.h>

static unsigned int DEADLINE = 0 ;
static unsigned int UNSUP = 0 ;
static char *SIG = "-d" ;

static ss_resolve_graph_t graph_unsup_cl = RESOLVE_GRAPH_ZERO ;
static ss_resolve_graph_t graph_cl = RESOLVE_GRAPH_ZERO ;
static ss_resolve_graph_t graph_unsup_rc = RESOLVE_GRAPH_ZERO ;
static ss_resolve_graph_t graph_rc = RESOLVE_GRAPH_ZERO ;

int svc_down(ssexec_t *info, char const *const *envp)
{
    log_flow() ;

    unsigned int reverse = 1 ;
    int r ;

    if (genalloc_len(resolve_service_t,&graph_unsup_cl.name))
    {
        UNSUP = 1 ;
        r = ss_resolve_graph_publish(&graph_unsup_cl,reverse) ;
        if (r < 0 || !r)
        {
            log_warnusys("publish service graph") ;
            goto err ;
        }
        if (!svc_unsupervise(info,&graph_unsup_cl.sorted,SIG,envp)) goto err ;
    }
    else
    {
        r = ss_resolve_graph_publish(&graph_cl,reverse) ;
        if (r < 0 || !r)
        {
            log_warnusys("publish service graph") ;
            goto err ;
        }
        if (!svc_send(info,&graph_cl.sorted,SIG,envp)) goto err ;
    }
    ss_resolve_graph_free(&graph_unsup_cl) ;
    ss_resolve_graph_free(&graph_cl) ;
    return 1 ;
    err:
        ss_resolve_graph_free(&graph_unsup_cl) ;
        ss_resolve_graph_free(&graph_cl) ;
        return 0 ;
}

int rc_down(ssexec_t *info, char const *const *envp)
{
    log_flow() ;

    unsigned int reverse = 1 ;
    int r ;

    if (genalloc_len(resolve_service_t,&graph_unsup_rc.name))
    {
        UNSUP = 1 ;
        r = ss_resolve_graph_publish(&graph_unsup_rc,reverse) ;
        if (r < 0 || !r)
        {
            log_warnusys("publish service graph") ;
            goto err ;
        }
        if (!rc_unsupervise(info,&graph_unsup_rc.sorted,"-d",envp)) goto err ;
    }
    else
    {
        r = ss_resolve_graph_publish(&graph_rc,reverse) ;
        if (r < 0 || !r)
        {
            log_warnusys("publish service graph") ;
            goto err ;
        }
        if (!rc_send(info,&graph_rc.sorted,"-d",envp)) goto err ;
    }

    ss_resolve_graph_free(&graph_unsup_rc) ;
    ss_resolve_graph_free(&graph_rc) ;
    return 1 ;
    err:
        ss_resolve_graph_free(&graph_unsup_rc) ;
        ss_resolve_graph_free(&graph_rc) ;
        return 0 ;
}

int ssexec_stop(int argc, char const *const *argv,char const *const *envp,ssexec_t *info)
{
    // be sure that the global var are set correctly
    DEADLINE = 0 ;
    UNSUP = 0 ;
    SIG = "-d" ;

    if (info->timeout) DEADLINE = info->timeout ;

    int cl, rc, sigopt ;
    stralloc sares = STRALLOC_ZERO ;
    genalloc gares = GENALLOC_ZERO ; //resolve_service_t
    resolve_service_t_ref pres ;
    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
    ss_state_t sta = STATE_ZERO ;

    cl = rc = sigopt = 0 ;

    {
        subgetopt l = SUBGETOPT_ZERO ;

        for (;;)
        {
            int opt = getopt_args(argc,argv, ">" OPTS_STOP, &l) ;
            if (opt == -1) break ;
            if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ;

            switch (opt)
            {
                case 'u' :  UNSUP = 1 ; break ;
                case 'X' :  if (sigopt) log_usage(usage_stop) ; sigopt = 1 ; SIG = "-X" ; break ;
                case 'K' :  if (sigopt) log_usage(usage_stop) ; sigopt = 1 ; SIG = "-K" ; break ;
                default :   log_usage(usage_stop) ;
            }
        }
        argc -= l.ind ; argv += l.ind ;
    }

    if (argc < 1) log_usage(usage_stop) ;

    if ((scandir_ok(info->scandir.s)) !=1 ) log_diesys(LOG_EXIT_SYS,"scandir: ", info->scandir.s," is not running") ;

    if (!sa_pointo(&sares,info,SS_NOTYPE,SS_RESOLVE_SRC)) log_dieusys(LOG_EXIT_SYS,"set revolve pointer to source") ;

    for (;*argv;argv++)
    {
        char const *name = *argv ;
        if (!resolve_check(sares.s,name)) log_info_return(LOG_EXIT_ZERO,name," is not enabled") ;
        if (!resolve_read(wres,sares.s,name)) log_dieusys(LOG_EXIT_SYS,"read resolve file of: ",name) ;
        if (res.type == TYPE_MODULE)
        {
            if (!module_in_cmdline(&gares,&res,sares.s))
                log_dieu(LOG_EXIT_SYS,"add dependencies of module: ",name) ;
        }
        else
        {
            if (!resolve_append(&gares,wres))
                log_dieusys(LOG_EXIT_SYS,"append resolve file of: ",name) ;
        }
    }

    for (unsigned int i = 0 ; i < genalloc_len(resolve_service_t,&gares) ; i++)
    {
        int unsup = 0 , reverse = 1 ;
        pres = &genalloc_s(resolve_service_t,&gares)[i] ;
        char const *string = pres->sa.s ;
        char const *name = string + pres->name ;
        char const *state = string + pres->state ;

        if (!state_check(state,name)) log_die(LOG_EXIT_USER,name," : is not initialized") ;
        else if (!state_read(&sta,state,name)) log_dieusys(LOG_EXIT_SYS,"read state file of: ",name) ;

        int logname = get_rstrlen_until(name,SS_LOG_SUFFIX) ;

        if (obstr_equal(name,SS_MASTER + 1))
        {
            if (pres->ndepends) goto append ;
            else continue ;
        }

        /** logger cannot be unsupervised alone */
        if (logname > 0 && (!resolve_cmp(&gares,string + pres->logassoc, DATA_SERVICE)))
        {
            if (UNSUP) log_die(LOG_EXIT_SYS,"logger detected - unsupervise request is not allowed") ;
        }
        if (UNSUP) unsup = 1 ;
        if (sta.unsupervise) unsup = 1 ;
        append:
        if (pres->type == TYPE_CLASSIC)
        {
            if (unsup)
            {
                if (!ss_resolve_graph_build(&graph_unsup_cl,&genalloc_s(resolve_service_t,&gares)[i],sares.s,reverse))
                    log_dieusys(LOG_EXIT_SYS,"build services graph") ;
                if (!service_resolve_add_logger(&graph_unsup_cl.name,sares.s))
                    log_dieusys(LOG_EXIT_SYS,"append service selection with logger") ;
            }
            if (!ss_resolve_graph_build(&graph_cl,&genalloc_s(resolve_service_t,&gares)[i],sares.s,reverse))
                log_dieusys(LOG_EXIT_SYS,"build services graph") ;
            cl++ ;
        }
        else
        {
            if (unsup)
            {
                if (!ss_resolve_graph_build(&graph_unsup_rc,&genalloc_s(resolve_service_t,&gares)[i],sares.s,reverse))
                    log_dieusys(LOG_EXIT_SYS,"build services graph") ;
                if (!service_resolve_add_logger(&graph_unsup_rc.name,sares.s))
                    log_dieusys(LOG_EXIT_SYS,"append service selection with logger") ;
            }
            if (!ss_resolve_graph_build(&graph_rc,&genalloc_s(resolve_service_t,&gares)[i],sares.s,reverse))
                log_dieusys(LOG_EXIT_SYS,"build services graph") ;
            rc++;
        }
    }

    /** rc work */
    if (rc)
    {
        log_trace("stop atomic services ...") ;
        if (!rc_down(info,envp))
            log_dieu(LOG_EXIT_SYS,"stop atomic services") ;
        log_trace("switch atomic services of: ",info->treename.s," to source") ;
        if (!db_switch_to(info,envp,SS_SWSRC))
            log_dieu(LOG_EXIT_SYS,"switch",info->livetree.s,"/",info->treename.s," to source") ;

    }

    /** svc work */
    if (cl)
    {
        log_trace("stop classic services ...") ;
        if (!svc_down(info,envp))
            log_dieu(LOG_EXIT_SYS,"stop classic services") ;
        log_trace("switch classic services of: ",info->treename.s," to source") ;
        if (!svc_switch_to(info,SS_SWSRC))
            log_dieu(LOG_EXIT_SYS,"switch classic service of: ",info->treename.s," to source") ;
    }

    if (UNSUP)
    {
        log_trace("send signal -an to scandir: ",info->scandir.s) ;
        if (scandir_send_signal(info->scandir.s,"h") <= 0)
            log_dieu(LOG_EXIT_SYS,"send signal to scandir: ", info->scandir.s) ;
    }
    stralloc_free(&sares) ;
    resolve_free(wres) ;
    resolve_deep_free(DATA_SERVICE, &gares) ;

    return 0 ;
}