Skip to content
Snippets Groups Projects
Commit 51a471ff authored by Eric Vidal's avatar Eric Vidal :speech_balloon:
Browse files

temporarily 66-rebuild tool

parent 10235ee0
No related branches found
No related tags found
No related merge requests found
/*
* 66-rebuild.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 <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <oblibs/log.h>
#include <oblibs/string.h>
#include <oblibs/sastr.h>
#include <oblibs/types.h>
#include <oblibs/directory.h>
#include <oblibs/files.h>
#include <skalibs/stralloc.h>
#include <skalibs/sgetopt.h>
#include <skalibs/djbunix.h>
#include <skalibs/unix-transactional.h>
#include <skalibs/cdb.h>
#include <66/ssexec.h>
#include <66/constants.h>
#include <66/utils.h>
#include <66/db.h>
#include <66/svc.h>
#include <66/tree.h>
#include <66/backup.h>
#include <66/resolve.h>
#include <66/parser.h>
#define USAGE "66-rebuild [ -h ] [ -z ] [ -v verbosity ] [ -l live ] [ -d ] tree(s)"
static stralloc WORKDIR = STRALLOC_ZERO ;
static uint8_t DRYRUN = 0 ;
static char *drun = "dry run do: " ;
static inline void info_help (void)
{
DEFAULT_MSG = 0 ;
static char const *help =
"\n"
"options :\n"
" -h: print this help\n"
" -z: use color\n"
" -v: increase/decrease verbosity\n"
" -l: live directory\n"
" -d: dry run\n"
"\n"
"if no tree is given, all trees will be processed.\n"
;
log_info(USAGE,"\n",help) ;
}
static void cleanup(void)
{
log_flow() ;
int e = errno ;
if (WORKDIR.len)
{
log_trace(DRYRUN ? drun : "","delete temporary directory: ",WORKDIR.s) ;
rm_rf(WORKDIR.s) ;
}
errno = e ;
}
int tree_is_current(char const *base,char const *treename,uid_t owner)
{
log_flow() ;
stralloc sacurr = STRALLOC_ZERO ;
int current = 0 ;
if (tree_find_current(&sacurr,base,owner))
{
char name[sacurr.len + 1] ;
if (!ob_basename(name,sacurr.s)) log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"basename of: ",sacurr.s) ;
current = obstr_equal(treename,name) ;
}
stralloc_free(&sacurr) ;
return current ;
}
int tree_is_enabled(char const *treename)
{
log_flow() ;
return tree_cmd_state(VERBOSITY,"-s",treename) ;
}
void tree_allowed(stralloc *list,char const *base, char const *treename)
{
log_flow() ;
stralloc sa = STRALLOC_ZERO ;
size_t treenamelen = strlen(treename), baselen = strlen(base), pos ;
char tmp[baselen + SS_SYSTEM_LEN + 1 + treenamelen + SS_RULES_LEN + 1] ;
auto_strings(tmp,base,SS_SYSTEM,"/",treename,SS_RULES) ;
if (!sastr_dir_get(&sa,tmp,"",S_IFREG))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get permissions of tree at: ",tmp) ;
for (pos = 0 ;pos < sa.len; pos += strlen(sa.s + pos) + 1)
{
char *suid = sa.s + pos ;
uid_t uid = 0 ;
if (!uid0_scan(suid, &uid))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get uid of: ",suid) ;
if (pos)
if (!stralloc_cats(list,",")) log_die_nomem_nclean(&cleanup,"stralloc") ;
if (!get_namebyuid(uid,list))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get name of uid: ",suid) ;
}
if (!stralloc_0(list)) log_die_nomem_nclean(&cleanup,"stralloc") ;
log_trace(DRYRUN ? drun : "","allowed user(s) for tree: ",treename," are: ",list->s) ;
stralloc_free(&sa) ;
}
void tree_contents(stralloc *list,char const *tree,ssexec_t *info)
{
log_flow() ;
size_t treelen = strlen(tree), pos ;
stralloc sa = STRALLOC_ZERO ;
char solve[treelen + SS_SVDIRS_LEN + SS_RESOLVE_LEN + SS_DB_LEN + SS_SRC_LEN + 1] ;
ss_resolve_t res = RESOLVE_ZERO ;
auto_strings(solve,tree,SS_SVDIRS,SS_RESOLVE) ;
if (!sastr_dir_get(&sa,solve,SS_MASTER + 1,S_IFREG))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get the service resolve files of: ",tree) ;
auto_strings(solve,tree,SS_SVDIRS) ;
for (pos = 0 ;pos < sa.len; pos += strlen(sa.s + pos) + 1)
{
char *name = sa.s + pos ;
int logname = get_rstrlen_until(name,SS_LOG_SUFFIX) ;
if (logname > 0) continue ;
if (!ss_resolve_read(&res,solve,name))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",solve,"/",name) ;
if (res.disen)
if (!stralloc_catb(list,res.sa.s + res.src,strlen(res.sa.s + res.src) + 1))
log_diesys_nclean(LOG_EXIT_SYS,&cleanup,"stralloc") ;
log_trace(DRYRUN ? drun : "","tree: ",info->treename.s," contain service: ",res.sa.s + res.src) ;
}
stralloc_free(&sa) ;
}
static int run_cmdline(char const *prog,char const **add,int len,char const *const *envp)
{
log_flow() ;
pid_t pid ;
int wstat ;
char fmt[UINT_FMT] ;
fmt[uint_fmt(fmt, VERBOSITY)] = 0 ;
int m = 4 + len, i = 0, n = 0 ;
char const *newargv[m] ;
newargv[n++] = prog ;
newargv[n++] = "-v" ;
newargv[n++] = fmt ;
for (;i<len;i++)
newargv[n++] = add[i] ;
newargv[n] = 0 ;
pid = child_spawn0(newargv[0],newargv,envp) ;
if (waitpid_nointr(pid,&wstat, 0) < 0)
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"wait for: ",newargv[0]) ;
if (wstat) return 0 ;
return 1 ;
}
int main(int argc, char const *const *argv,char const *const *envp)
{
int r ;
unsigned int nclassic = 0, nlongrun = 0, nbsv = 0 ;
size_t systemlen, optslen = 5, pos, len ;
char tree_opts_create[optslen] ;
char *fdir = 0 ;
log_color = &log_color_disable ;
stralloc satree = STRALLOC_ZERO ;
stralloc allow = STRALLOC_ZERO ;
stralloc contents = STRALLOC_ZERO ;
stralloc tree_enabled = STRALLOC_ZERO ;
ssexec_t info = SSEXEC_ZERO ;
PROG = "66-rebuild" ;
{
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
int opt = subgetopt_r(argc,argv, "hzv:l:d", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'h' : info_help(); return 0 ;
case 'v' : if (!uint0_scan(l.arg, &VERBOSITY)) log_usage(USAGE) ; break ;
case 'l' : if (!stralloc_cats(&info.live,l.arg)) log_die_nomem("stralloc") ;
if (!stralloc_0(&info.live)) log_die_nomem("stralloc") ;
break ;
case 'z' : log_color = !isatty(1) ? &log_color_disable : &log_color_enable ; break ;
case 'd' : DRYRUN = 1 ; break ;
default : log_usage(USAGE) ;
}
}
argc -= l.ind ; argv += l.ind ;
}
info.owner = getuid() ;
if (!set_ownersysdir(&info.base,info.owner)) log_dieusys(LOG_EXIT_SYS, "set owner directory") ;
char system[info.base.len + SS_SYSTEM_LEN + 2] ;
auto_strings(system,info.base.s,SS_SYSTEM,"/") ;
systemlen = info.base.len + SS_SYSTEM_LEN + 1 ;
if (!argc)
{
if (info.owner)
{
/** check if user system dir already exist */
if (!scan_mode(info.base.s,S_IFDIR)) {
log_info(DRYRUN ? drun : "","No trees exist yet -- Nothing to do") ;
goto exit ;
}
}
if (!sastr_dir_get(&satree,system,SS_BACKUP + 1,S_IFDIR))
log_dieusys(LOG_EXIT_SYS,"get list of trees at: ",system) ;
if (!satree.len)
{
log_info(DRYRUN ? drun : "","No trees exist yet -- Nothing to do") ;
goto exit ;
}
}
else
{
int i = 0 ;
size_t arglen = 0 ;
for (;i < argc ; i++)
{
arglen = strlen(argv[i]) ;
char tree[systemlen + arglen + 1] ;
auto_strings(tree,system,argv[i]) ;
r = scan_mode(tree,S_IFDIR) ;
if (r == -1) { errno = EEXIST ; log_diesys(LOG_EXIT_SYS,"conflicting format of: ",tree) ; }
if (!r) log_die(LOG_EXIT_USER,"tree: ",tree," doesn't exist") ;
if (!stralloc_catb(&satree,argv[i],strlen(argv[i]) + 1))
log_die_nomem("stralloc") ;
}
}
/** keep start order of trees */
if (!file_readputsa(&tree_enabled,system,"state"))
log_dieusys(LOG_EXIT_SYS,"read contents of file: ",system,"state") ;
len = satree.len ;
for (pos = 0 ; pos < len; pos += strlen(satree.s + pos) + 1)
{
int dbok = 0 ;
nclassic = nlongrun = nbsv = 0 ;
info.base.len = info.tree.len = info.treename.len = 0 ;
allow.len = WORKDIR.len = contents.len = 0 ;
auto_strings(tree_opts_create,"-n") ;
optslen = 2 ;
if (!auto_stra(&info.tree,satree.s + pos))
log_die_nomem("stralloc") ;
set_ssinfo(&info) ;
char tmp[systemlen + SS_BACKUP_LEN + info.treename.len + SS_SVDIRS_LEN + SS_DB_LEN + 1] ;
char current[info.livetree.len + 1 + info.treename.len + 9 + 1] ;
log_info(DRYRUN ? drun : "","save state of tree: ", info.treename.s) ;
if (tree_is_current(info.base.s,info.treename.s,info.owner))
{
log_trace(DRYRUN ? drun : "","tree: ",info.treename.s," is marked current") ;
auto_string_from(tree_opts_create,optslen,"c") ;
optslen +=1 ;
}
if (tree_is_enabled(info.treename.s) == 1)
{
log_trace(DRYRUN ? drun : "","tree: ",info.treename.s," is marked enabled") ;
auto_string_from(tree_opts_create,optslen,"E") ;
optslen +=1 ;
}
tree_allowed(&allow,info.base.s,info.treename.s) ;
log_info(DRYRUN ? drun : "","save service(s) list of tree: ", info.treename.s) ;
tree_contents(&contents,info.tree.s,&info) ;
dbok = db_ok(info.livetree.s, info.treename.s) ;
if (dbok)
{
fdir = 0 ;
log_trace(DRYRUN ? drun : "","find current source of live db: ",info.livetree.s,"/",info.treename.s) ;
r = db_find_compiled_state(info.livetree.s,info.treename.s) ;
if (r == -1) log_die(LOG_EXIT_SYS,"inconsistent state of: ",info.livetree.s) ;
if (r == 1) {
auto_strings(tmp,system,SS_BACKUP + 1,"/",info.treename.s,SS_DB) ;
}
else auto_strings(tmp,system,info.treename.s,SS_SVDIRS,SS_DB) ;
log_trace(DRYRUN ? drun : "","created temporary directory at: /tmp") ;
fdir = dir_create_tmp(&WORKDIR,"/tmp",info.treename.s) ;
if (!fdir) log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create temporary directory") ;
log_trace(DRYRUN ? drun : "","copy contents of: ",tmp," to: ",WORKDIR.s) ;
if (!hiercopy(tmp,fdir)) log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tmp," to: ",WORKDIR.s) ;
char new[WORKDIR.len + 1 + info.treename.len + 1] ;
auto_strings(current,info.livetree.s,"/",info.treename.s,"/compiled") ;
auto_strings(new,WORKDIR.s,"/",info.treename.s) ;
log_info(DRYRUN ? drun : "","update ",info.livetree.s,"/",info.treename.s," to: ",new) ;
if (!DRYRUN)
if (!atomic_symlink(new, current, PROG))
log_dieusys(LOG_EXIT_SYS,"update: ",current," to: ", new) ;
if (DRYRUN) cleanup() ;
}
/** finally we can destroy the tree and recreate it*/
// destroy
{
char const *t[] = { "-l", info.live.s, "-R", info.treename.s } ;
if (DRYRUN)
{
log_info(drun,"66-tree -l ",info.live.s," -R ",info.treename.s) ;
}
else
{
if (!run_cmdline(SS_EXTBINPREFIX "66-tree",t,4,envp))
log_dieu(LOG_EXIT_SYS,"delete tree: ", info.treename.s) ;
}
}
//create
{
char const *t[] = { "-l", info.live.s, tree_opts_create,"-a",allow.s, info.treename.s } ;
if (DRYRUN)
{
log_info(drun,"66-tree -l ",info.live.s," ",tree_opts_create," -a ",allow.s," ",info.treename.s) ;
}
else
{
if (!run_cmdline(SS_EXTBINPREFIX "66-tree",t,6,envp))
log_dieu(LOG_EXIT_SYS,"create tree: ", info.treename.s) ;
}
}
// reorganize the trees start order
if (tree_enabled.len)
{
if (!sastr_split_string_in_nline(&tree_enabled))
log_dieu(LOG_EXIT_SYS,"split elements") ;
unsigned int enabled ;
ssize_t r = sastr_find_element_byname(&tree_enabled,info.treename.s,&enabled) ;
if (r >= 0)
{
char *after_tree = tree_enabled.s + sastr_find_element_byid(&tree_enabled,!enabled ? enabled : enabled - 1) ;
char const *t[] = { "-S", after_tree, info.treename.s } ;
if (DRYRUN)
{
log_info(drun,"66-tree -S ",after_tree," ",info.treename.s) ;
}
else
{
if (!run_cmdline(SS_EXTBINPREFIX "66-tree",t,3,envp))
log_dieu(LOG_EXIT_SYS,"orders the start order of tree: ", info.treename.s) ;
}
}
}
/* we must reimplement the enable process instead of
* using directly 66-enable. The 66-enable program will use
* is own workdir with an empty tree. At call of db_update(),
* the service already running will be brought down. We don't
* want this behavior. A nope update is necessary.
* So remake the things with the enable API */
if (contents.len)
{
stralloc tostart = STRALLOC_ZERO ;
log_info(DRYRUN ? drun : "","enable service(s) of tree: ",info.treename.s) ;
if (!DRYRUN)
{
auto_strings(tmp,system,info.treename.s,SS_SVDIRS) ;
}
else
{
WORKDIR.len = 0 ;
log_trace(drun,"copy: ", info.tree.s,SS_SVDIRS," to a temporary directory") ;
if (!tree_copy(&WORKDIR,info.tree.s,info.treename.s))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create tmp working directory") ;
/* we need to remove the contain of .resolve directory
* The write process will try to read it and obviously it
* get a wrong information*/
auto_strings(tmp,WORKDIR.s,SS_RESOLVE) ;
log_trace(drun,"remove directory: ", tmp) ;
if (rm_rf(tmp) < 0) log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"remove: ",tmp) ;
log_trace(drun,"create directory: ", tmp) ;
if (!dir_create_parent(tmp,0755))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create directory: ",tmp) ;
auto_string_from(tmp,0,WORKDIR.s) ;
}
start_parser(&contents,&info,&nbsv,1) ;
start_write(&tostart,&nclassic,&nlongrun,tmp,&gasv,&info,1,0) ;
/** we don't care about nclassic. Classic service are copies
* of original and we retrieve the original at the end of the
* process*/
if(nlongrun)
{
ss_resolve_graph_t graph = RESOLVE_GRAPH_ZERO ;
r = ss_resolve_graph_src(&graph,tmp,0,1) ;
if (!r)
log_dieu(LOG_EXIT_SYS,"resolve source of graph for tree: ",info.treename.s) ;
r = ss_resolve_graph_publish(&graph,0) ;
if (r <= 0)
{
if (r < 0) log_die(LOG_EXIT_USER,"cyclic graph detected") ;
log_dieusys(LOG_EXIT_SYS,"publish service graph") ;
}
if (!ss_resolve_write_master(&info,&graph,tmp,0))
log_dieusys(LOG_EXIT_SYS,"update inner bundle") ;
ss_resolve_graph_free(&graph) ;
if (!db_compile(tmp,info.tree.s,info.treename.s,envp))
log_dieu(LOG_EXIT_SYS,"compile ",tmp,"/",info.treename.s) ;
}
stralloc_free(&tostart) ;
freed_parser() ;
genalloc_free(sv_alltype,&gasv) ;
}
if (dbok)
{
auto_strings(tmp,system,info.treename.s,SS_SVDIRS,SS_DB) ;
log_info(DRYRUN ? drun : "","update db: ",info.livetree.s,"/",info.treename.s, " to: ",tmp,"/",info.treename.s) ;
/* Be paranoid here and use db_update instead of atomic_symlink.
* db_update() allow to make a running test and to see
* if the db match exactly the same state.
* We prefer to die in this case instead of leaving an
* inconsistent state. */
if (!DRYRUN)
if (!db_update(tmp,&info,envp))
log_dieu(LOG_EXIT_SYS,"update: ",info.livetree.s,"/",info.treename.s," to: ", tmp,"/",info.treename.s) ;
}
cleanup() ;
log_info(DRYRUN ? drun : "","tree: ",info.treename.s," rebuild successfully") ;
}
exit:
stralloc_free(&satree) ;
stralloc_free(&allow) ;
stralloc_free(&WORKDIR) ;
stralloc_free(&contents) ;
stralloc_free(&tree_enabled) ;
ssexec_free(&info) ;
return 0 ;
}
${LIB66}
-ls6rc
-ls6
-loblibs
-lskarnet
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment