Skip to content
Snippets Groups Projects
resolve.c 11.41 KiB
/*
 * resolve.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 <stdint.h>
#include <unistd.h>//close, fsync
#include <stdlib.h>//mkstemp, malloc, free
#include <sys/types.h>//ssize_t
#include <stdio.h>//rename

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

#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>
#include <skalibs/cdb.h>
#include <skalibs/djbunix.h>
#include <skalibs/cdbmake.h>
#include <skalibs/posixplz.h>//unlink
#include <skalibs/types.h>//uint##_pack

#include <66/resolve.h>
#include <66/service.h>
#include <66/tree.h>
#include <66/constants.h>
#include <66/graph.h>

/**
 *
 * MAIN API
 *
 * */

resolve_wrapper_t *resolve_set_struct(uint8_t type, void *s)
{
    log_flow() ;

    resolve_wrapper_t *wres = malloc(sizeof(resolve_wrapper_t)) ;

    wres->obj = s ;
    wres->type = type ;
    return wres ;
} ;


int resolve_init(resolve_wrapper_t *wres)
{
    log_flow() ;

    RESOLVE_SET_SAWRES(wres) ;

    sawres->len = 0 ;

    return resolve_add_string(wres,"") ;
}

int resolve_read(resolve_wrapper_t *wres, char const *src, char const *name)
{
    log_flow() ;

    size_t srclen = strlen(src) ;
    size_t namelen = strlen(name) ;

    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
    auto_strings(tmp,src,SS_RESOLVE,"/",name) ;

    if (!resolve_read_cdb(wres,tmp))
        return 0 ;

    return 1 ;
}

int resolve_write(resolve_wrapper_t *wres, char const *dst, char const *name)
{
    log_flow() ;

    size_t dstlen = strlen(dst) ;
    size_t namelen = strlen(name) ;

    char tmp[dstlen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
    auto_strings(tmp,dst,SS_RESOLVE,"/") ;

    if (!resolve_write_cdb(wres,tmp,name))
        return 0 ;

    return 1 ;
}

int resolve_check(char const *src, char const *name)
{
    log_flow() ;

    int r ;
    size_t srclen = strlen(src) ;
    size_t namelen = strlen(name) ;

    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen + 1] ;
    auto_strings(tmp, src, SS_RESOLVE, "/", name) ;

    r = scan_mode(tmp,S_IFREG) ;
    if (r <= 0)
        return 0 ;

    return 1 ;
}

int resolve_append(genalloc *ga, resolve_wrapper_t *wres)
{
    log_flow() ;

    int e = 0 ;

    if (wres->type == DATA_SERVICE) {

        resolve_service_t cp = RESOLVE_SERVICE_ZERO ;
        if (!service_resolve_copy(&cp, ((resolve_service_t *)wres->obj)))
            goto err ;

        if (!genalloc_append(resolve_service_t, ga, &cp))
            goto err ;

    } else if (wres->type == DATA_TREE) {

        resolve_tree_t cp = RESOLVE_TREE_ZERO ;
        if (!tree_resolve_copy(&cp, ((resolve_tree_t *)wres->obj)))
            goto err ;
        if (!genalloc_append(resolve_tree_t, ga, &cp))
            goto err ;

    }

    e = 1 ;
    err:
        return e ;
}

int resolve_search(genalloc *ga, char const *name, uint8_t type)
{
    log_flow() ;

    size_t len, pos = 0 ;

    if (type == DATA_SERVICE) {

        len = genalloc_len(resolve_service_t, ga) ;

        for (;pos < len ; pos++) {

            char *s = genalloc_s(resolve_service_t,ga)[pos].sa.s + genalloc_s(resolve_service_t,ga)[pos].name ;
            if (!strcmp(name,s))
                return pos ;
        }

    } else if (type == DATA_TREE) {

        len = genalloc_len(resolve_tree_t, ga) ;

        for (;pos < len ; pos++) {

            char *s = genalloc_s(resolve_tree_t,ga)[pos].sa.s + genalloc_s(resolve_tree_t,ga)[pos].name ;
            if (!strcmp(name,s))
                return pos ;
        }
    }

    return -1 ;
}

int resolve_cmp(genalloc *ga, char const *name, uint8_t type)
{
    log_flow() ;

    size_t len, pos = 0 ;

    if (type == DATA_SERVICE) {

        len = genalloc_len(resolve_service_t, ga) ;

        for (;pos < len ; pos++) {

            char *str = genalloc_s(resolve_service_t, ga)[pos].sa.s ;
            char *s = str + genalloc_s(resolve_service_t, ga)[pos].name ;
            if (!strcmp(name,s))
                return 1 ;
        }

    } else if (type == DATA_TREE) {

        len = genalloc_len(resolve_tree_t, ga) ;

        for (;pos < len ; pos++) {

            char *str = genalloc_s(resolve_tree_t, ga)[pos].sa.s ;
            char *s = str + genalloc_s(resolve_tree_t, ga)[pos].name ;
            if (!strcmp(name,s))
                return 1 ;
        }
    }

    return 0 ;
}

void resolve_rmfile(char const *src,char const *name)
{
    log_flow() ;

    size_t srclen = strlen(src) ;
    size_t namelen = strlen(name) ;

    char tmp[srclen + SS_RESOLVE_LEN + 1 + namelen +1] ;
    auto_strings(tmp, src, SS_RESOLVE, "/", name) ;

    unlink_void(tmp) ;
}

ssize_t resolve_add_string(resolve_wrapper_t *wres, char const *data)
{
    log_flow() ;

    RESOLVE_SET_SAWRES(wres) ;

    ssize_t baselen = sawres->len ;

    if (!data) {

        if (!stralloc_catb(sawres,"",1))
            log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;

        return baselen ;
    }

    size_t datalen = strlen(data) ;

    if (!stralloc_catb(sawres,data,datalen + 1))
        log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;

    return baselen ;
}

int resolve_modify_field(resolve_wrapper_t_ref wres, uint8_t field, char const *by)
{
    log_flow() ;

    int e = 0 ;

    resolve_wrapper_t_ref mwres = 0 ;

    if (wres->type == DATA_SERVICE) {

        resolve_service_t_ref res = (resolve_service_t *)wres->obj  ;
        mwres = resolve_set_struct(DATA_SERVICE, res) ;

        log_trace("modify field ", resolve_service_field_table[field].field," of service ", res->sa.s + res->name, " with value: ", by) ;

        if (!service_resolve_modify_field(res, field, by))
            goto err ;

    } else if (wres-> type == DATA_TREE) {

        resolve_tree_t_ref res = (resolve_tree_t *)wres->obj  ;
        mwres = resolve_set_struct(DATA_TREE, res) ;

        log_trace("modify field ", resolve_tree_field_table[field].field," of tree ", res->sa.s + res->name, " with value: ", by) ;

        if (!tree_resolve_modify_field(res, field, by))
            goto err ;

    }
    e = 1 ;
    err:
        free(mwres) ;
        return e ;
}

int resolve_modify_field_g(resolve_wrapper_t_ref wres, char const *base, char const *element, uint8_t field, char const *value)
{

    log_flow() ;

    size_t baselen = strlen(base), tot = 0, treelen = 0 ;
    char *treename = 0 ;

    if (wres->type == DATA_SERVICE) {

        treelen = strlen(((resolve_service_t *)wres->obj)->sa.s + ((resolve_service_t *)wres->obj)->treename) ;
        tot = baselen + SS_SYSTEM_LEN + 1 + treelen + SS_SVDIRS_LEN + 1 ;

    } else {

        tot = baselen + SS_SYSTEM_LEN + 1 ;
    }

    char solve[tot] ;

    if (wres->type == DATA_SERVICE) {

        treename = ((resolve_service_t *)wres->obj)->sa.s + ((resolve_service_t *)wres->obj)->treename ;
        auto_strings(solve, base, SS_SYSTEM, "/", treename, SS_SVDIRS) ;

    } else {

        auto_strings(solve, base, SS_SYSTEM) ;
    }

    if (!resolve_read(wres, solve, element))
        log_warnusys_return(LOG_EXIT_ZERO, "read resolve file of: ", solve, "/", element) ;

    if (!resolve_modify_field(wres, field, value))
        log_warnusys_return(LOG_EXIT_ZERO, "modify resolve file of: ", solve, "/", element) ;

    if (!resolve_write(wres, solve, element))
        log_warnusys_return(LOG_EXIT_ZERO, "write resolve file of :", solve, "/", element) ;

    return 1 ;

}

/**
 *
 * FREED
 *
 * */

void resolve_free(resolve_wrapper_t *wres)
{
    log_flow() ;

    RESOLVE_SET_SAWRES(wres) ;

    stralloc_free(sawres) ;

    free(wres) ;
}

void resolve_deep_free(uint8_t type, genalloc *g)
{
    log_flow() ;

    size_t pos = 0 ;

    if (type == DATA_SERVICE) {

        for (; pos < genalloc_len(resolve_service_t, g) ; pos++)
            stralloc_free(&genalloc_s(resolve_service_t, g)[pos].sa) ;

        genalloc_free(resolve_service_t, g) ;

    } else if (type == DATA_TREE) {

        for (; pos < genalloc_len(resolve_tree_t, g) ; pos++)
            stralloc_free(&genalloc_s(resolve_tree_t, g)[pos].sa) ;

         genalloc_free(resolve_tree_t, g) ;
    }

}

/**
 *
 * CDB
 *
 * */

int resolve_read_cdb(resolve_wrapper_t *wres, char const *name)
{
    log_flow() ;

    int fd, e = 0 ;
    cdb c = CDB_ZERO ;

    fd = open_readb(name) ;
    if (fd < 0) {
        log_warnusys("open: ",name) ;
        goto err_fd ;
    }

    if (!cdb_init_fromfd(&c, fd)) {
        log_warnusys("cdb_init: ", name) ;
        goto err ;
    }

    if (wres->type == DATA_SERVICE) {

        if (!service_read_cdb(&c, ((resolve_service_t *)wres->obj)))
            goto err ;

    } else if (wres->type == DATA_TREE){

        if (!tree_read_cdb(&c, ((resolve_tree_t *)wres->obj)))
            goto err ;

    }

    e = 1 ;

    err:
        close(fd) ;
    err_fd:
        cdb_free(&c) ;
        return e ;
}

int resolve_write_cdb(resolve_wrapper_t *wres, char const *dst, char const *name)
{
    log_flow() ;
    int fd ;
    size_t dstlen = strlen(dst), namelen = strlen(name);
    cdbmaker c = CDBMAKER_ZERO ;
    char tfile[dstlen + 1 + namelen + namelen + 9] ;
    char dfile[dstlen + 1 + namelen + 1] ;

    auto_strings(dfile,dst,"/",name) ;

    auto_strings(tfile,dst,"/",name,":",name,":","XXXXXX") ;

    fd = mkstemp(tfile) ;
    if (fd < 0 || ndelay_off(fd)) {
        log_warnusys("mkstemp: ", tfile) ;
        goto err_fd ;
    }

    if (!cdbmake_start(&c, fd)) {
        log_warnusys("cdbmake_start") ;
        goto err ;
    }

    if (wres->type == DATA_SERVICE) {

        if (!service_write_cdb(&c, ((resolve_service_t *)wres->obj)))
            goto err ;

    } else if (wres->type == DATA_TREE) {

        if (!tree_write_cdb(&c, ((resolve_tree_t *)wres->obj)))
            goto err ;

    }

    if (!cdbmake_finish(&c) || fsync(fd) < 0) {
        log_warnusys("write to: ", tfile) ;
        goto err ;
    }

    close(fd) ;

    if (rename(tfile, dfile) < 0) {
        log_warnusys("rename ", tfile, " to ", dfile) ;
        goto err_fd ;
    }

    return 1 ;

    err:
        close(fd) ;
    err_fd:
        unlink_void(tfile) ;
        return 0 ;
}

int resolve_add_cdb(cdbmaker *c, char const *key, char const *data)
{
    log_flow() ;

    size_t klen = strlen(key) ;
    size_t dlen = strlen(data) ;

    if (!cdbmake_add(c,key,klen,dlen ? data : 0,dlen))
        log_warnsys_return(LOG_EXIT_ZERO,"cdb_make_add: ",key) ;

    return 1 ;
}

int resolve_add_cdb_uint(cdbmaker *c, char const *key, uint32_t data)
{
    log_flow() ;

    char pack[4] ;
    size_t klen = strlen(key) ;

    uint32_pack_big(pack, data) ;
    if (!cdbmake_add(c,key,klen,pack,4))
        log_warnsys_return(LOG_EXIT_ZERO,"cdb_make_add: ",key) ;

    return 1 ;
}

int resolve_find_cdb(stralloc *result, cdb const *c, char const *key)
{
    log_flow() ;

    uint32_t x = 0 ;
    size_t klen = strlen(key) ;
    cdb_data cdata ;

    result->len = 0 ;

    int r = cdb_find(c, &cdata, key, klen) ;
    if (r == -1)
        log_warnusys_return(LOG_EXIT_LESSONE,"search on cdb key: ",key) ;

    if (!r)
        log_warn_return(LOG_EXIT_ZERO,"unknown cdb key: ",key) ;

    char pack[cdata.len + 1] ;
    memcpy(pack,cdata.s, cdata.len) ;
    pack[cdata.len] = 0 ;

    uint32_unpack_big(pack, &x) ;

    if (!auto_stra(result,pack))
        log_warnusys_return(LOG_EXIT_LESSONE,"stralloc") ;

    return x ;
}