Skip to content
Snippets Groups Projects
rc_init.c 5.85 KiB
/*
 * rc_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 <66/rc.h>

#include <string.h>
#include <stdlib.h>
#include <sys/types.h>

#include <oblibs/log.h>
#include <oblibs/string.h>
#include <oblibs/types.h>
#include <oblibs/directory.h>
#include <oblibs/sastr.h>

#include <skalibs/genalloc.h>
#include <skalibs/djbunix.h>
#include <skalibs/types.h>

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

#include <s6-rc/config.h>

/**@Return 1 on success
 * @Return 2 on empty database
 * @Return 0 on fail */
int rc_init(ssexec_t *info, char const *const *envp)
{
    log_flow() ;

    int r, wstat, empty = 0, e = 0 ;
    pid_t pid ;
    size_t pos = 0 ;

    ss_state_t sta = STATE_ZERO ;
    stralloc sares = STRALLOC_ZERO ;
    resolve_service_t res = RESOLVE_SERVICE_ZERO ;
    resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
    stralloc sasvc = STRALLOC_ZERO ;
    genalloc gares = GENALLOC_ZERO ; //resolve_service_t type

    char svdir[info->tree.len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + info->treename.len + 1] ;
    char ltree[info->livetree.len + 1 + info->treename.len + 1] ;
    char prefix[info->treename.len + 1 + 1] ;
    char tt[UINT32_FMT] ;
    char const *newargv[12] ;
    unsigned int m = 0 ;

    gid_t gidowner ;
    if (!yourgid(&gidowner,info->owner)){ log_warnusys("set gid") ; goto err ; }

    r = scan_mode(info->livetree.s,S_IFDIR) ;
    if (r == -1) { errno = EEXIST ; log_warnsys("conflicting format of: ",info->livetree.s) ; goto err ; }
    if (!r)
    {
        log_trace("create directory: ",info->livetree.s) ;
        r = dir_create(info->livetree.s,0700) ;
        if (!r){ log_warnusys("create directory: ",info->livetree.s) ; goto err ; }
        log_trace("chown directory: ",info->livetree.s) ;
        if (chown(info->livetree.s,info->owner,gidowner) < 0){ log_warnusys("chown directory: ",info->livetree.s) ; goto err ; }
    }

    if (!sa_pointo(&sares,info,SS_NOTYPE,SS_RESOLVE_SRC))
        { log_warnu("set revolve pointer to source") ; goto err ; }

    if (!resolve_check(sares.s,SS_MASTER +1)) { log_warnu("find inner bundle -- please make a bug report") ; goto err ; }
    if (!resolve_read(wres,sares.s,SS_MASTER + 1)) { log_warnusys("read resolve file of inner bundle") ; goto err ; }
    if (!res.ndepends)
    {
        log_info("Initialization: no atomic services into tree: ",info->treename.s) ;
        empty = 1 ;
        goto end ;
    }
    if (!create_live(info)) { log_warnusys("create live state") ; goto err ; }

    memcpy(svdir,info->tree.s,info->tree.len) ;
    memcpy(svdir + info->tree.len ,SS_SVDIRS ,SS_SVDIRS_LEN) ;
    memcpy(svdir + info->tree.len + SS_SVDIRS_LEN,SS_DB,SS_DB_LEN) ;
    memcpy(svdir + info->tree.len + SS_SVDIRS_LEN + SS_DB_LEN, "/", 1) ;
    memcpy(svdir + info->tree.len + SS_SVDIRS_LEN + SS_DB_LEN + 1, info->treename.s,info->treename.len) ;
    svdir[info->tree.len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + info->treename.len] = 0 ;

    memcpy(ltree,info->livetree.s,info->livetree.len) ;
    ltree[info->livetree.len] = '/' ;
    memcpy(ltree + info->livetree.len + 1, info->treename.s, info->treename.len) ;
    ltree[info->livetree.len + 1 + info->treename.len] = 0 ;

    memcpy(prefix,info->treename.s,info->treename.len) ;
    memcpy(prefix + info->treename.len, "-",1) ;
    prefix[info->treename.len + 1] = 0 ;

    tt[uint32_fmt(tt,info->timeout)] = 0 ;

    newargv[m++] = S6RC_BINPREFIX "s6-rc-init" ;
    newargv[m++] = "-l" ;
    newargv[m++] = ltree ;
    newargv[m++] = "-c" ;
    newargv[m++] = svdir ;
    newargv[m++] = "-p" ;
    newargv[m++] = prefix ;
    newargv[m++] = "-t" ;
    newargv[m++] = tt ;
    newargv[m++] = "--" ;
    newargv[m++] = info->scandir.s ;
    newargv[m++] = 0 ;

    log_trace("initiate db of tree: ",info->treename.s," ...") ;

    pid = child_spawn0(newargv[0],newargv,envp) ;
    if (waitpid_nointr(pid,&wstat, 0) < 0)
        { log_warnusys("wait for ",newargv[0]) ; goto err ; }

    if (wstat) { log_warnu("init db of tree: ",info->treename.s) ; goto err ; }

    if (!sastr_clean_string(&sasvc,res.sa.s + res.depends)) { log_warnusys("clean dependencies of inner bundle") ; goto err ; }

    for (; pos < sasvc.len ; pos += strlen(sasvc.s + pos) +1)
    {
        char *name = sasvc.s + pos ;
        resolve_service_t tmp = RESOLVE_SERVICE_ZERO ;
        resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &tmp) ;
        if (!resolve_check(sares.s,name)){ log_warnsys("unknown service: ",name) ; goto err ; }
        if (!resolve_read(wres,sares.s,name)) { log_warnusys("read resolve file of: ",name) ; goto err ; }
        if (!service_resolve_add_deps(&gares,&tmp,sares.s)) { log_warnusys("resolve dependencies of: ",name) ; goto err ; }
        resolve_free(wres) ;
    }

    for (pos = 0 ; pos < genalloc_len(resolve_service_t,&gares) ; pos++)
    {
        char const *string = genalloc_s(resolve_service_t,&gares)[pos].sa.s ;
        char const *name = string + genalloc_s(resolve_service_t,&gares)[pos].name  ;
        char const *state = string + genalloc_s(resolve_service_t,&gares)[pos].state  ;

        log_trace("Write state file of: ",name) ;
        if (!state_write(&sta,state,name))
        {
            log_warnusys("write state file of: ",name) ;
            goto err ;
        }
        log_info("Initialized successfully: ",name) ;
    }

    end:

    e = empty ? 2 : 1 ;

    err:
        resolve_deep_free(DATA_SERVICE, &gares) ;
        stralloc_free(&sasvc) ;
        resolve_free(wres) ;
        stralloc_free(&sares) ;
        return e ;
}