-
Eric Vidal authoredEric Vidal authored
parse_service.c 11.52 KiB
/*
* parse_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 <66/parser.h>
#include <stdint.h>
#include <string.h>
#include <oblibs/log.h>
#include <oblibs/sastr.h>
#include <oblibs/string.h>
#include <oblibs/types.h>
#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>
#include <66/utils.h>
#include <66/constants.h>
#include <66/ssexec.h>
#include <66/service.h>
#include <66/tree.h>
static void parse_service_instance(stralloc *frontend, char const *svsrc, char const *sv, int insta)
{
log_flow() ;
stralloc sa = STRALLOC_ZERO ;
if (!instance_splitname(&sa, sv, insta, SS_INSTANCE_TEMPLATE))
log_die(LOG_EXIT_SYS, "split instance service: ", sv) ;
log_trace("read frontend service of: ", svsrc, sa.s) ;
if (read_svfile(frontend, sa.s, svsrc) <= 0)
log_dieusys(LOG_EXIT_SYS, "read frontend service of: ", svsrc, sa.s) ;
stralloc_free(&sa) ;
if (!instance_create(frontend, sv, SS_INSTANCE_REGEX, insta))
log_die(LOG_EXIT_SYS, "create instance service: ", sv) ;
/** ensure that we have an empty line at the end of the string*/
if (!auto_stra(frontend, "\n"))
log_die_nomem("stralloc") ;
}
static int parse_add_service(stralloc *parsed_list, sv_alltype *alltype, char const *service, uint8_t conf)
{
log_flow() ;
log_trace("add service: ", service) ;
// keep overwrite_conf
alltype->overwrite_conf = conf ;
// keep source of the frontend file
alltype->src = keep.len ;
if (!sastr_add_string(&keep, service))
return 0 ;
// keep service on current list
if (!sastr_add_string(parsed_list, service))
return 0 ;
if (!genalloc_append(sv_alltype, &gasv, alltype))
return 0 ;
return 1 ;
}
static void set_info(ssexec_t *info)
{
log_flow() ;
info->tree.len = 0 ;
int r = ssexec_set_treeinfo(info) ;
if (r == -4) log_die(LOG_EXIT_USER,"You're not allowed to use the tree: ",info->tree.s) ;
if (r == -3) log_dieu(LOG_EXIT_USER,"find the current tree. You must use the -t options") ;
if (r == -2) log_dieu(LOG_EXIT_USER,"set the tree name") ;
if (r == -1) log_dieu(LOG_EXIT_USER,"parse seed file") ;
if (!r) log_dieusys(LOG_EXIT_SYS,"find tree: ", info->treename.s) ;
}
#include <stdio.h>
/* @sv -> name of the service to parse with
* the path of the frontend file source
* @Return 0 on fail
* @Return 1 on success
* @Return 2 -> already parsed */
int parse_service(char const *sv, stralloc *parsed_list, ssexec_t *info, uint8_t force, uint8_t conf)
{
log_flow() ;
if (sastr_cmp(parsed_list, sv) >= 0) {
log_warn("ignoring: ", sv, " service -- already parsed") ;
return 2 ;
}
log_trace("parse service: ", sv) ;
int insta, r ;
size_t svlen = strlen(sv) ;
char svname[svlen + 1], svsrc[svlen + 1] ;
sv_alltype alltype = SV_ALLTYPE_ZERO ;
stralloc frontend = STRALLOC_ZERO ;
stralloc satree = STRALLOC_ZERO ;
if (!ob_basename(svname, sv))
log_dieu(LOG_EXIT_SYS, "get basename of: ", sv) ;
if (!ob_dirname(svsrc, sv))
log_dieu(LOG_EXIT_SYS, "get dirname of: ", sv) ;
insta = instance_check(svname) ;
if (!insta) {
log_die(LOG_EXIT_SYS, "invalid instance name: ", svname) ;
} else if (insta > 0) {
parse_service_instance(&frontend, svsrc, svname, insta) ;
} else {
log_trace("read frontend service of: ", sv) ;
if (read_svfile(&frontend, svname, svsrc) <= 0)
log_dieusys(LOG_EXIT_SYS, "read frontend service of: ", sv) ;
}
r = service_isenabledat(&satree, svname) ;
if (r < -1)
log_dieu(LOG_EXIT_SYS, "check already enabled services") ;
if (r > 0) {
if (force) {
/* -t option was used */
if (!info->skip_opt_tree) {
if (strcmp(info->treename.s, satree.s))
log_die(LOG_EXIT_SYS,"you can not force to enable again a service on different tree -- current: ", satree.s, " asked: ", info->treename.s, ". Try first to disable it") ;
} else {
if (!auto_stra(&info->treename, satree.s))
log_die_nomem("stralloc") ;
}
goto set ;
} else {
log_info("ignoring service: ", sv, " -- already enabled at tree: ", satree.s) ;
/** we don't care about the use of the -t option. The define of the
* info->tree and info->treename is just made to avoid segmentation fault
* at the rest of the process. The service is not parsed or enable again anyway. */
info->treename.len = 0 ;
if (!auto_stra(&info->treename, satree.s))
log_die_nomem("stralloc") ;
set_info(info) ;
sv_alltype_free(&alltype) ;
stralloc_free(&frontend) ;
stralloc_free(&satree) ;
return 2 ;
}
}
if (info->skip_opt_tree) {
/** first try to find the @intree key at the frontend file*/
if (!get_svintree(&alltype,frontend.s))
log_die(LOG_EXIT_USER, "invalid value for key: ",get_key_by_enum(ENUM_KEY_SECTION_MAIN,KEY_MAIN_INTREE)," in service file: ", sv) ;
if (alltype.cname.intree >= 0) {
info->treename.len = 0 ;
if (!auto_stra(&info->treename, keep.s + alltype.cname.intree))
log_die_nomem("stralloc") ;
}
}
set:
set_info(info) ;
if (!get_svtype(&alltype, frontend.s))
log_die(LOG_EXIT_USER, "invalid value for key: ", get_key_by_enum(ENUM_KEY_SECTION_MAIN, KEY_MAIN_TYPE), " at frontend service: ", sv) ;
/** contents of directory should be listed by service_frontend_path
* except for module type */
if (scan_mode(sv,S_IFDIR) == 1 && alltype.cname.itype != TYPE_MODULE)
goto freed ;
alltype.cname.name = keep.len ;
if (!sastr_add_string(&keep, svname))
log_die_nomem("stralloc") ;
if (!parser(&alltype, &frontend, svname, alltype.cname.itype))
log_dieu(LOG_EXIT_SYS, "parse service: ", sv) ;
if (!parse_add_service(parsed_list, &alltype, sv, conf))
log_dieu(LOG_EXIT_SYS, "add service: ", sv) ;
freed:
stralloc_free(&frontend) ;
stralloc_free(&satree) ;
return 1 ;
}
int parse_service_deps(sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force, char const *directory_forced)
{
log_flow() ;
int r, e = 0 ;
stralloc sa = STRALLOC_ZERO ;
if (alltype->cname.nga) {
size_t id = alltype->cname.idga, nid = alltype->cname.nga ;
for (; nid ; id += strlen(deps.s + id) + 1, nid--) {
sa.len = 0 ;
if (alltype->cname.itype != TYPE_BUNDLE) {
log_trace("service: ", keep.s + alltype->cname.name, " depends on: ", deps.s + id) ;
} else log_trace("bundle: ", keep.s + alltype->cname.name, " contents: ", deps.s + id," as service") ;
r = service_frontend_path(&sa, deps.s + id, info->owner, directory_forced) ;
if (r < 1) goto err ;//don't warn here, the ss_revolve_src_path do it
if (!parse_service(sa.s, parsed_list, info, force, alltype->overwrite_conf))
goto err ;
}
} else log_trace(keep.s + alltype->cname.name,": haven't dependencies") ;
e = 1 ;
err:
stralloc_free(&sa) ;
return e ;
}
int parse_service_optsdeps(stralloc *rebuild, sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force, uint8_t field, char const *directory_forced)
{
log_flow() ;
int r, e = 0 ;
stralloc sa = STRALLOC_ZERO ;
size_t id, nid ;
uint8_t ext = field == KEY_MAIN_EXTDEPS ? 1 : 0 ;
int idref = alltype->cname.idopts ;
unsigned int nref = alltype->cname.nopts ;
if (ext) {
idref = alltype->cname.idext ;
nref = alltype->cname.next ;
}
if (nref) {
id = (size_t)idref, nid = (size_t)nref ;
for (; nid ; id += strlen(deps.s + id) + 1, nid--) {
sa.len = 0 ;
// 0 -> not found, 1 -> found, -1 -> system error
r = service_isenabled(deps.s + id) ;
if (r == -1)
log_dieu(LOG_EXIT_SYS, "check already enabled services") ;
if (r > 0) {
if (!ext)
break ;
else
continue ;
}
r = service_frontend_path(&sa, deps.s + id, info->owner, directory_forced) ;
if (r == -1)
goto err ;
if (!r) {
log_trace("unable to find", ext ? " external " : " optional ", "dependency: ", deps.s + id, " for service: ", keep.s + alltype->cname.name) ;
// external deps must exist
if (ext)
goto err ;
continue ;
}
if (!parse_service(sa.s, parsed_list, info, force, alltype->overwrite_conf))
goto err ;
if (!sastr_add_string(rebuild, deps.s + id))
log_die_nomem("stralloc") ;
// we only keep the first optsdepends found
if (!ext) break ;
}
} else log_trace(keep.s + alltype->cname.name,": haven't", ext ? " external " : " optional ", "dependencies") ;
e = 1 ;
err:
stralloc_free(&sa) ;
return e ;
}
int parse_service_alldeps(sv_alltype *alltype, ssexec_t *info, stralloc *parsed_list, uint8_t force, char const *directory_forced)
{
log_flow() ;
int e = 0 ;
size_t id, nid, pos ;
char *name = keep.s + alltype->cname.name ;
stralloc sa = STRALLOC_ZERO ;
stralloc rebuild = STRALLOC_ZERO ;
if (!parse_service_deps(alltype, info, parsed_list, force, directory_forced)) {
log_warnu("parse dependencies of: ", name) ;
goto err ;
}
if (!parse_service_optsdeps(&rebuild, alltype, info, parsed_list, force, KEY_MAIN_EXTDEPS, directory_forced)) {
log_warnu("parse external dependencies of: ", name) ;
goto err ;
}
if (!parse_service_optsdeps(&rebuild, alltype, info, parsed_list, force, KEY_MAIN_OPTSDEPS, directory_forced)) {
log_warnu("parse optional dependencies of: ", name) ;
goto err ;
}
// rebuild the dependencies list of the service to add the new dependencies.
if (rebuild.len) {
pos = 0 ;
sa.len = 0 ;
id = alltype->cname.idga ;
nid = alltype->cname.nga ;
{
for (; nid ; id += strlen(deps.s + id) + 1, nid--) {
if (!sastr_add_string(&sa, deps.s + id)) {
log_warn("stralloc") ;
goto err ;
}
}
FOREACH_SASTR(&rebuild, pos) {
if (!sastr_add_string(&sa, rebuild.s + pos)) {
log_warn("stralloc") ;
goto err ;
}
}
}
alltype->cname.idga = deps.len ;
alltype->cname.nga = 0 ;
pos = 0 ;
FOREACH_SASTR(&sa, pos) {
log_info("rebuil list", sa.s + pos) ;
if (!sastr_add_string(&deps,sa.s + pos)) {
log_warn("stralloc") ;
goto err ;
}
alltype->cname.nga++ ;
}
}
e = 1 ;
err:
stralloc_free(&rebuild) ;
stralloc_free(&sa) ;
return e ;
}