From 95670584e56f408cc32addf490c5b27c9561b34d Mon Sep 17 00:00:00 2001 From: obarun <eric@obarun.org> Date: Sat, 28 Jan 2023 20:56:19 +1100 Subject: [PATCH] revamp of the enable tool --- src/lib66/exec/ssexec_enable.c | 476 ++++++++++----------------------- 1 file changed, 142 insertions(+), 334 deletions(-) diff --git a/src/lib66/exec/ssexec_enable.c b/src/lib66/exec/ssexec_enable.c index 62af8f09..6090009b 100644 --- a/src/lib66/exec/ssexec_enable.c +++ b/src/lib66/exec/ssexec_enable.c @@ -14,428 +14,236 @@ #include <string.h> #include <stdint.h> -#include <errno.h> -#include <stdio.h> - -#include <oblibs/obgetopt.h> #include <oblibs/log.h> #include <oblibs/string.h> #include <oblibs/sastr.h> -#include <oblibs/files.h> +#include <oblibs/types.h> #include <skalibs/stralloc.h> -#include <skalibs/genalloc.h> -#include <skalibs/djbunix.h> +#include <skalibs/sgetopt.h> +#include <66/graph.h> #include <66/constants.h> -#include <66/utils.h> -#include <66/tree.h> -#include <66/db.h> -#include <66/parser.h> -#include <66/svc.h> -#include <66/resolve.h> -#include <66/ssexec.h> -#include <66/environ.h> +#include <66/sanitize.h> +#include <66/state.h> #include <66/service.h> +#include <66/ssexec.h> +typedef enum visit_e visit ; +enum visit_e +{ + SS_WHITE = 0, + SS_GRAY, + SS_BLACK +} ; -static stralloc workdir = STRALLOC_ZERO ; -stralloc PARSED_LIST = STRALLOC_ZERO ; - -/** force == 1, only rewrite the service - * force == 2, rewrite the service and it dependencies*/ -static uint8_t FORCE = 0 ; -/** rewrite configuration file */ -static uint8_t CONF = 0 ; - -void ssexec_enable_cleanup(void) +static void visit_init(visit *v, size_t len) { log_flow() ; - if (!workdir.len) - return ; - int e = errno ; - rm_rf(workdir.s) ; - errno = e ; + size_t pos = 0 ; + for (; pos < len; pos++) + v[pos] = SS_WHITE ; + } +void service_enable_disable(graph_t *g, char const *base, char const *name, uint8_t action) ; + static void check_identifier(char const *name) { log_flow() ; int logname = get_rstrlen_until(name,SS_LOG_SUFFIX) ; - if (logname > 0) log_die(LOG_EXIT_USER,"service name: ",name,": ends with reserved suffix -log") ; - if (!memcmp(name, SS_MASTER + 1, 6)) log_die(LOG_EXIT_USER,"service name: ",name,": starts with reserved prefix Master") ; + if (logname > 0) log_die(LOG_EXIT_USER,"service: ",name,": ends with reserved suffix -log") ; + if (!memcmp(name,SS_MASTER+1,6)) log_die(LOG_EXIT_USER,"service: ",name,": starts with reserved prefix Master") ; if (!strcmp(name,SS_SERVICE)) log_die(LOG_EXIT_USER,"service as service name is a reserved name") ; if (!strcmp(name,"service@")) log_die(LOG_EXIT_USER,"service@ as service name is a reserved name") ; } -void start_parser(char const *sv, ssexec_t *info, uint8_t disable_module, char const *directory_forced) +void service_enable_disable_deps(graph_t *g, char const *base, char const *sv, uint8_t action) { log_flow() ; - size_t pos = 0 ; - - stralloc parsed_list = STRALLOC_ZERO ; - - char *name = 0 ; - int r ; - - r = parse_service(sv, &parsed_list, info, FORCE, CONF) ; - if (!r) - log_dieu(LOG_EXIT_SYS, "parse service file: ",name,": or its dependencies") ; - - // already enabled - if (r == 2) - goto freed ; - - // parse deps - pos = 0 ; - for (; pos < genalloc_len(sv_alltype, &gasv) ; pos ++) { - - sv_alltype_ref sv = &genalloc_s(sv_alltype,&gasv)[pos] ; - - name = keep.s + sv->cname.name ; - - int exist = service_isenabled(name) ; + size_t pos = 0, element = 0 ; + stralloc sa = STRALLOC_ZERO ; - if (sv->cname.itype != TYPE_CLASSIC) { + if (graph_matrix_get_edge_g_sa(&sa, g, sv, action ? 0 : 1, 0) < 0) + log_dieu(LOG_EXIT_SYS, "get ", action ? "dependencies" : "required by" ," of: ", sv) ; - if (FORCE > 1 || !exist) { + size_t len = sastr_nelement(&sa) ; + visit v[len] ; - if (!parse_service_alldeps(sv, info, &parsed_list, FORCE, directory_forced)) - log_dieu(LOG_EXIT_SYS, "parse dependencies of: ", name) ; + visit_init(v, len) ; - if (sv->cname.itype == TYPE_MODULE) { + if (sa.len) { - r = parse_module(sv, info, &parsed_list, FORCE) ; - if (!r) - log_dieu(LOG_EXIT_SYS, "parse module: ", name) ; + FOREACH_SASTR(&sa, pos) { - else if (r == 2) - continue ; + if (v[element] == SS_WHITE) { - if ((FORCE > 1) && (exist > 0) && disable_module) { + char *name = sa.s + pos ; - char const *newargv[4] ; - unsigned int m = 0 ; + service_enable_disable(g, base, name, action) ; - newargv[m++] = "fake_name" ; - newargv[m++] = name ; - newargv[m++] = 0 ; - if (ssexec_disable(m, newargv, (char const *const *)environ, info)) - log_dieu(LOG_EXIT_SYS, "disable module: ", name) ; - } - } + v[element] = SS_GRAY ; } + element++ ; } } - freed: - stralloc_free(&parsed_list) ; + + stralloc_free(&sa) ; } -void start_write(stralloc *tostart,unsigned int *nclassic,unsigned int *nlongrun,char const *workdir, genalloc *gasv,ssexec_t *info) +/** @action -> 0 disable + * @action -> 1 enable */ +void service_enable_disable(graph_t *g, char const *base, char const *name, uint8_t action) { log_flow() ; - int r ; - stralloc module = STRALLOC_ZERO ; - stralloc version = STRALLOC_ZERO ; - - for (unsigned int i = 0; i < genalloc_len(sv_alltype,gasv); i++) - { - sv_alltype_ref sv = &genalloc_s(sv_alltype,gasv)[i] ; - char *name ; + if (!state_messenger(base, name, STATE_FLAGS_ISENABLED, !action ? STATE_FLAGS_FALSE : STATE_FLAGS_TRUE)) + log_dieusys(LOG_EXIT_SYS, "send message to state of: ", name) ; - r = write_services(sv, workdir,FORCE,CONF) ; - if (!r) - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"write service: ",name) ; + service_enable_disable_deps(g, base, name, action) ; - if (r > 1) continue ; //service already added + log_info(!action ? "Disabled" : "Enabled"," successfully service: ", name) ; - /** only read name after the write_services process. - * it change the sv_alltype appending the real_exec element */ - name = keep.s + sv->cname.name ; - - log_trace("write resolve file of: ",name) ; - if (!service_resolve_setnwrite(sv,info,workdir)) - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"write revolve file for: ",name) ; +} - if (sastr_cmp(tostart,name) == -1) - { - if (sv->cname.itype == TYPE_CLASSIC) (*nclassic)++ ; - else (*nlongrun)++ ; - if (!sastr_add_string(tostart,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"stralloc") ; - } +static void parse_it(char const *name, uint8_t force, uint8_t conf, ssexec_t *info) +{ - log_trace("Service written successfully: ", name) ; + int argc = 4 + (force ? 1 : 0) + (conf ? 1 : 0) ; + int m = 0 ; + char const *prog = PROG ; + char const *newargv[argc] ; + + newargv[m++] = "parse" ; + if (force) + newargv[m++] = force == 2 ? "-F" : "-f" ; + if (conf) + newargv[m++] = "-I" ; + newargv[m++] = name ; + newargv[m++] = 0 ; + + PROG = "parse" ; + if (ssexec_parse(argc, newargv, info)) + log_dieu(LOG_EXIT_SYS, "parse service: ", name) ; + PROG = prog ; +} - if (sv->cname.itype == TYPE_MODULE) - stralloc_catb(&module,name,strlen(name) + 1) ; - } +int ssexec_enable(int argc, char const *const *argv, ssexec_t *info) +{ + log_flow() ; - if (module.len) - { - /** we need to rewrite the contents file of each module - * in the good order. we cannot make this before here because - * we need the resolve file for each services*/ - int r ; - size_t pos = 0, gpos = 0 ; - size_t workdirlen = strlen(workdir) ; - resolve_service_t res = RESOLVE_SERVICE_ZERO ; - resolve_service_t dres = RESOLVE_SERVICE_ZERO ; - resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ; - resolve_wrapper_t_ref dwres = resolve_set_struct(DATA_SERVICE, &dres) ; - stralloc salist = STRALLOC_ZERO ; - genalloc gamodule = GENALLOC_ZERO ; - ss_resolve_graph_t mgraph = RESOLVE_GRAPH_ZERO ; - char *name = 0 ; - char *err_msg = 0 ; - - FOREACH_SASTR(&module, pos) { - - salist.len = 0 ; - name = module.s + pos ; - size_t namelen = strlen(name) ; - char dst[workdirlen + SS_DB_LEN + SS_SRC_LEN + 1 + namelen + 1]; - auto_strings(dst,workdir,SS_DB,SS_SRC,"/",name) ; - - if (!resolve_read(wres,workdir,name)) { - err_msg = "read resolve file of: " ; - goto err ; - } + uint32_t flag = 0 ; + uint8_t force = 0, conf = 0, start = 0 ; + int n = 0, e = 1 ; + size_t pos = 0 ; + graph_t graph = GRAPH_ZERO ; + stralloc sa = STRALLOC_ZERO ; - if (!sastr_clean_string(&salist,res.sa.s + res.contents)) { - err_msg = "rebuild dependencies list of: " ; - goto err ; - } + unsigned int areslen = 0 ; + resolve_service_t ares[SS_MAX_SERVICE] ; - { - gpos = 0 ; - FOREACH_SASTR(&salist,gpos) { - - if (!resolve_read(dwres,workdir,salist.s + gpos)) { - err_msg = "read resolve file of: " ; - goto err ; - } - - if (dres.type != TYPE_CLASSIC) - { - if (resolve_search(&gamodule, name, DATA_SERVICE) == -1) - { - if (!resolve_append(&gamodule,dwres)) - { - err_msg = "append genalloc with: " ; - goto err ; - } - } - } - } - } + FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ; - for (gpos = 0 ; gpos < genalloc_len(resolve_service_t,&gamodule) ; gpos++) - { - if (!ss_resolve_graph_build(&mgraph,&genalloc_s(resolve_service_t,&gamodule)[gpos],workdir,0)) - { - err_msg = "build the graph of: " ; - goto err ; - } - } + { + subgetopt l = SUBGETOPT_ZERO ; - r = ss_resolve_graph_publish(&mgraph,0) ; - if (r < 0) { - err_msg = "publish graph -- cyclic graph detected in: " ; - goto err ; - } - else if (!r) - { - err_msg = "publish service graph of: " ; - goto err ; - } + for (;;) + { + int opt = subgetopt_r(argc, argv, OPTS_ENABLE, &l) ; + if (opt == -1) break ; - salist.len = 0 ; - for (gpos = 0 ; gpos < genalloc_len(resolve_service_t,&mgraph.sorted) ; gpos++) - { - char *string = genalloc_s(resolve_service_t,&mgraph.sorted)[gpos].sa.s ; - char *name = string + genalloc_s(resolve_service_t,&mgraph.sorted)[gpos].name ; - if (!auto_stra(&salist,name,"\n")) - { - err_msg = "append stralloc for: " ; - goto err ; - } - } + switch (opt) { - /** finally write it */ - if (!file_write_unsafe(dst,SS_CONTENTS,salist.s,salist.len)) - { - err_msg = "create contents file of: " ; - goto err ; - } + case 'f' : - resolve_deep_free(DATA_SERVICE, &gamodule) ; - ss_resolve_graph_free(&mgraph) ; - } + /** only rewrite the service itself */ + if (force) + log_usage(usage_enable) ; + force = 1 ; + break ; - stralloc_free(&module) ; - stralloc_free(&version) ; - return ; - - err: - resolve_deep_free(DATA_SERVICE, &gamodule) ; - ss_resolve_graph_free(&mgraph) ; - resolve_free(wres) ; - resolve_free(dwres) ; - stralloc_free(&salist) ; - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,err_msg,name) ; - } - stralloc_free(&module) ; - stralloc_free(&version) ; -} + case 'F' : -int ssexec_enable(int argc, char const *const *argv,char const *const *envp,ssexec_t *info) -{ - // be sure that the global var are set correctly - FORCE = CONF = 0 ; + /** force to rewrite it dependencies */ + if (force) + log_usage(usage_enable) ; + force = 2 ; + break ; - int r ; - size_t pos = 0 ; - unsigned int nbsv, nlongrun, nclassic, start ; + case 'I' : - stralloc sasrc = STRALLOC_ZERO ; - stralloc tostart = STRALLOC_ZERO ; + conf = 1 ; + break ; - r = nbsv = nclassic = nlongrun = start = 0 ; + case 'S' : - { - subgetopt l = SUBGETOPT_ZERO ; + start = 1 ; + break ; - for (;;) - { - int opt = getopt_args(argc,argv, ">" OPTS_ENABLE, &l) ; - if (opt == -1) break ; - if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; - switch (opt) - { - case 'f' : if (FORCE) log_usage(usage_enable) ; - FORCE = 1 ; break ; - case 'F' : if (FORCE) log_usage(usage_enable) ; - FORCE = 2 ; break ; - case 'I' : CONF = 1 ; break ; - case 'S' : start = 1 ; break ; - default : log_usage(usage_enable) ; + default : + log_usage(usage_enable) ; } } argc -= l.ind ; argv += l.ind ; } - if (argc < 1) log_usage(usage_enable) ; + if (argc < 1) + log_usage(usage_enable) ; - for(;*argv;argv++) - { - check_identifier(*argv) ; - size_t len = strlen(*argv) ; - char const *sv = 0 ; - char const *directory_forced = 0 ; - char bname[len + 1] ; - char dname[len + 1] ; - - if (argv[0][0] == '/') { - if (!ob_dirname(dname,*argv)) - log_dieu(LOG_EXIT_SYS,"get dirname of: ",*argv) ; - if (!ob_basename(bname,*argv)) log_dieu(LOG_EXIT_SYS,"get basename of: ",*argv) ; - sv = bname ; - directory_forced = dname ; - } else sv = *argv ; - - if (service_frontend_path(&sasrc,sv,info->owner,!directory_forced ? 0 : directory_forced) < 1) - log_dieu(LOG_EXIT_SYS,"resolve source path of: ",*argv) ; + for(; n < argc ; n++) { + check_identifier(argv[n]) ; + parse_it(argv[n], force, conf, info) ; } - FOREACH_SASTR(&sasrc, pos) - start_parser(sasrc.s + pos, info, 1, 0) ; + /** build the graph of the entire system */ + graph_build_service(&graph, ares, &areslen, info, flag) ; - /** - * - * - * ATTENTION si -t ne pas passait alors info->tree et info->treename.s - * n'est pas definie - * - * - * */ - if (!tree_copy(&workdir,info->tree.s,info->treename.s)) log_dieusys(LOG_EXIT_SYS,"create tmp working directory") ; + if (!graph.mlen) + log_die(LOG_EXIT_USER, "services selection is not available -- try first to install the corresponding frontend file") ; - start_write(&tostart,&nclassic,&nlongrun,workdir.s,&gasv,info) ; + for (n = 0 ; n < argc ; n++) { - if (nclassic) - { - if (!svc_switch_to(info,SS_SWBACK)) - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"switch ",info->treename.s," to backup") ; - } + service_enable_disable(&graph, info->base.s, argv[n], 1) ; - if(nlongrun) - { - ss_resolve_graph_t graph = RESOLVE_GRAPH_ZERO ; - r = ss_resolve_graph_src(&graph,workdir.s,0,1) ; - if (!r) - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"resolve source of graph for tree: ",info->treename.s) ; + int aresid = service_resolve_array_search(ares, areslen, argv[n]) ; + if (aresid < 0) + log_die(LOG_EXIT_USER, "service: ", argv[n], " not available -- please make a bug report") ; - r = ss_resolve_graph_publish(&graph,0) ; - if (r <= 0) - { - ssexec_enable_cleanup() ; - if (r < 0) log_die(LOG_EXIT_USER,"cyclic graph detected") ; - log_dieusys(LOG_EXIT_SYS,"publish service graph") ; - } - if (!service_resolve_master_write(info,&graph,workdir.s,0)) - log_dieusys_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"update inner bundle") ; + char *treename = ares[aresid].sa.s + ares[aresid].treename ; - ss_resolve_graph_free(&graph) ; - if (!db_compile(workdir.s,info->tree.s,info->treename.s,envp)) - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"compile ",workdir.s,"/",info->treename.s) ; - - /** this is an important part, we call s6-rc-update here */ - if (!db_switch_to(info,envp,SS_SWBACK)) - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"switch ",info->treename.s," to backup") ; + if (!sastr_add_string(&sa, argv[n])) + log_dieu(LOG_EXIT_SYS, "add string") ; } - if (!tree_copy_tmp(workdir.s,info)) - log_dieu_nclean(LOG_EXIT_SYS,&ssexec_enable_cleanup,"copy: ",workdir.s," to: ", info->tree.s) ; - + if (start && sa.len) { - ssexec_enable_cleanup() ; - - /** parser allocation*/ - freed_parser() ; - /** inner allocation */ - stralloc_free(&workdir) ; - stralloc_free(&sasrc) ; - - for (pos = 0 ; pos < tostart.len; pos += strlen(tostart.s + pos) + 1) - log_info("Enabled successfully: ", tostart.s + pos) ; - - if (start && tostart.len) - { - int nargc = 2 + sastr_len(&tostart) ; + size_t len = sastr_len(&sa) ; + pos = 0 ; + int nargc = 1 + len ; + char const *prog = PROG ; char const *newargv[nargc] ; unsigned int m = 0 ; - newargv[m++] = "fake_name" ; + newargv[m++] = "start" ; + FOREACH_SASTR(&sa, pos) + newargv[m++] = sa.s + pos ; + newargv[m] = 0 ; - for (pos = 0 ; pos < tostart.len; pos += strlen(tostart.s + pos) + 1) - newargv[m++] = tostart.s + pos ; - - newargv[m++] = 0 ; - - if (ssexec_start(nargc,newargv,envp,info)) - { - stralloc_free(&tostart) ; - return 111 ; - } + PROG = "start" ; + e = ssexec_start(nargc, newargv, info) ; + PROG = prog ; + goto end ; } + e = 0 ; - stralloc_free(&tostart) ; + end: + stralloc_free(&sa) ; + service_resolve_array_free(ares, areslen) ; + graph_free_all(&graph) ; - return 0 ; + return e ; } -- GitLab