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

[WIP]revamp ssexec_disable function

parent 06978a20
No related branches found
No related tags found
No related merge requests found
......@@ -13,366 +13,127 @@
*/
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <oblibs/obgetopt.h>
#include <oblibs/log.h>
#include <oblibs/types.h>
#include <oblibs/string.h>
#include <oblibs/sastr.h>
#include <skalibs/sgetopt.h>
#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>
#include <skalibs/djbunix.h>
#include <66/constants.h>
#include <66/tree.h>
#include <66/db.h>
#include <66/resolve.h>
#include <66/svc.h>
#include <66/state.h>
#include <66/utils.h>
#include <66/ssexec.h>
#include <66/config.h>
#include <66/service.h>
#include <66/graph.h>
#include <66/resolve.h>
static stralloc workdir = STRALLOC_ZERO ;
static uint8_t FORCE = 0 ;
static uint8_t REMOVE = 0 ;
static void cleanup(void)
static void check_identifier(char const *name)
{
log_flow() ;
int e = errno ;
rm_rf(workdir.s) ;
errno = e ;
int logname = get_rstrlen_until(name,SS_LOG_SUFFIX) ;
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") ;
}
int svc_remove(genalloc *tostop,resolve_service_t *res, char const *src,ssexec_t *info)
int ssexec_disable(int argc, char const *const *argv, ssexec_t *info)
{
log_flow() ;
unsigned int i = 0 ;
int r, e = 0 ;
genalloc rdeps = GENALLOC_ZERO ;
stralloc dst = STRALLOC_ZERO ;
resolve_service_t cp = RESOLVE_SERVICE_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &cp) ;
ss_state_t sta = STATE_ZERO ;
size_t newlen ;
char *name = res->sa.s + res->name ;
if (!service_resolve_copy(&cp,res))
{
log_warnusys("copy resolve file") ;
goto err ;
}
if (!stralloc_cats(&dst,src)) goto err ;
if (cp.type == TYPE_CLASSIC)
{
if (!stralloc_cats(&dst,SS_SVC)) goto err ;
}
else if (!stralloc_cats(&dst,SS_DB SS_SRC)) goto err ;
if (!stralloc_cats(&dst,"/")) goto err ;
newlen = dst.len ;
if (!FORCE)
{
if (!service_resolve_add_rdeps(&rdeps,&cp,src))
{
log_warnusys("resolve recursive dependencies of: ",name) ;
goto err ;
}
}
else
{
if (!resolve_append(&rdeps,wres)) goto err ;
}
uint32_t flag = 0 ;
uint8_t stop = 0, remove = 0 ;
int n = 0, e = 1 ;
size_t pos = 0 ;
graph_t graph = GRAPH_ZERO ;
stralloc sa = STRALLOC_ZERO ;
if (!service_resolve_add_logger(&rdeps,src))
{
log_warnusys("resolve logger") ;
goto err ;
}
unsigned int areslen = 0 ;
resolve_service_t ares[SS_MAX_SERVICE] ;
resolve_free(wres) ;
for (;i < genalloc_len(resolve_service_t,&rdeps) ; i++)
{
resolve_service_t_ref pres = &genalloc_s(resolve_service_t,&rdeps)[i] ;
resolve_wrapper_t_ref dwres = resolve_set_struct(DATA_SERVICE, pres) ;
char *str = pres->sa.s ;
char *name = str + pres->name ;
char *ste = str + pres->state ;
dst.len = newlen ;
if (!stralloc_cats(&dst,name)) goto err ;
if (!stralloc_0(&dst)) goto err ;
log_trace("delete source service file of: ",name) ;
if (rm_rf(dst.s) < 0)
{
log_warnusys("delete source service file: ",dst.s) ;
goto err ;
}
/** r == -1 means the state file is not present,
* r > 0 means service need to be initialized,
* so not initialized at all.*/
r = state_check_flags(ste,name,SS_FLAGS_INIT) ;
if (!r)
{
/** modify the resolve file for 66-stop*/
pres->disen = 0 ;
log_trace("Write resolve file of: ",name) ;
if (!resolve_write(dwres,src,name))
{
log_warnusys("write resolve file of: ",name) ;
goto err ;
}
if (!state_read(&sta,ste,name)) {
log_warnusys("read state of: ",name) ;
goto err ;
}
state_setflag(&sta,SS_FLAGS_RELOAD,SS_FLAGS_FALSE) ;
state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_FALSE) ;
state_setflag(&sta,SS_FLAGS_UNSUPERVISE,SS_FLAGS_TRUE) ;
log_trace("Write state file of: ",name) ;
if (!state_write(&sta,ste,name))
{
log_warnusys("write state file of: ",name) ;
goto err ;
}
}
else
{
if (REMOVE)
{
// remove configuration file
log_trace("Delete configuration file of: ",name) ;
if (rm_rf(str + pres->srconf) == -1)
log_warnusys("remove configuration file of: ",name) ;
// remove the logger directory
log_trace("Delete logger directory of: ",name) ;
if (rm_rf(str + pres->dstlog) == -1)
log_warnusys("remove logger directory of: ",name) ;
if (pres->type == TYPE_MODULE) {
// remove service source file
log_trace("Delete service file of: ",name) ;
if (rm_rf(str + pres->src) == -1)
log_warnusys("remove configuration file of: ",name) ;
}
}
log_trace("Delete resolve file of: ",name) ;
resolve_rmfile(src,name) ;
}
if (!resolve_cmp(tostop, name, DATA_SERVICE))
if (!resolve_append(tostop,wres)) goto err ;
free(dwres) ;
}
e = 1 ;
err:
resolve_free(wres) ;
resolve_deep_free(DATA_SERVICE, &rdeps) ;
stralloc_free(&dst) ;
return e ;
}
int ssexec_disable(int argc, char const *const *argv,char const *const *envp,ssexec_t *info)
{
int r, logname ;
unsigned int nlongrun, nclassic, stop, force ;
genalloc tostop = GENALLOC_ZERO ;//resolve_service_t
genalloc gares = GENALLOC_ZERO ; //resolve_service_t
resolve_service_t res = RESOLVE_SERVICE_ZERO ;
resolve_service_t_ref pres ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ;
r = nclassic = nlongrun = stop = logname = force = 0 ;
FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP) ;
{
subgetopt l = SUBGETOPT_ZERO ;
for (;;)
{
int opt = getopt_args(argc,argv, ">" OPTS_DISABLE, &l) ;
int opt = subgetopt_r(argc, argv, OPTS_DISABLE, &l) ;
if (opt == -1) break ;
if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ;
switch (opt)
{
case 'S' : if (FORCE) log_usage(usage_disable) ; stop = 1 ; break ;
case 'F' : if (stop) log_usage(usage_disable) ; FORCE = 1 ; break ;
case 'R' : if (stop) log_usage(usage_disable) ; REMOVE = 1 ; break ;
default : log_usage(usage_disable) ;
}
}
argc -= l.ind ; argv += l.ind ;
}
if (argc < 1) log_usage(usage_disable) ;
if (!tree_copy(&workdir,info->tree.s,info->treename.s))
log_dieusys(LOG_EXIT_SYS,"create tmp working directory") ;
for (;*argv;argv++)
{
char const *name = *argv ;
if (!resolve_check(workdir.s,name))
log_info_nclean_return(LOG_EXIT_ZERO,&cleanup,name," is not enabled") ;
if (!resolve_read(wres,workdir.s,name))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",name) ;
switch (opt) {
if (REMOVE)
{
stralloc sa = STRALLOC_ZERO ;
r = service_intree(&sa,name,0) ;
if (r > 2)
log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"use -R option -- ",name," is set on different tree") ;
stralloc_free(&sa) ;
}
if (res.type == TYPE_MODULE)
{
if (!module_in_cmdline(&gares,&res,workdir.s))
log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"add dependencies of module: ",name) ;
}
else
{
if (!resolve_append(&gares,wres))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"append services selection with: ",name) ;
}
}
case 'S' :
for(unsigned int i = 0 ; i < genalloc_len(resolve_service_t,&gares) ; i++)
{
pres = &genalloc_s(resolve_service_t,&gares)[i] ;
char *string = pres->sa.s ;
char *name = string + pres->name ;
char *state = string + pres->state ;
uint8_t found = 0 ;
char module_name[256] ;
/** The force options can be only used if the service is not marked initialized.
* This option should only be used when we have a inconsistent state between
* the /var/lib/66/system/<tree>/servicedirs/ and /var/lib/66/system/<tree>/.resolve
* directory meaning a service which is not present in the compiled db but its resolve file
* exist.
* Also, the remove option can be only used if the service is not marked initialized too.*/
if (FORCE || REMOVE) {
r = state_check_flags(state,name,SS_FLAGS_INIT) ;
if (!r)
log_die_nclean(LOG_EXIT_USER,&cleanup,name," is marked initialized -- ",FORCE ? "-F" : "-R"," is not allowed") ;
}
stop = 1 ;
break ;
if (!module_search_service(workdir.s,&gares,name,&found,module_name))
log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"search in module") ;
case 'F' :
if (found && !FORCE)
log_die_nclean(LOG_EXIT_USER,&cleanup,name," is a part of: ",module_name," module -- it's not allowed to disable it alone") ;
log_1_warn("options -F is deprecated -- skipping it") ;
break ;
if (found && REMOVE)
log_die_nclean(LOG_EXIT_USER,&cleanup,name," is a part of: ",module_name," module -- -R options is not allowed") ;
case 'R' :
logname = 0 ;
if (obstr_equal(name,SS_MASTER + 1))
log_die_nclean(LOG_EXIT_USER,&cleanup,"nice try peon") ;
if (stop)
log_usage(usage_disable) ;
remove = 1 ;
break ;
logname = get_rstrlen_until(name,SS_LOG_SUFFIX) ;
if (logname > 0 && (!resolve_cmp(&gares, string + pres->logassoc, DATA_SERVICE)))
log_die_nclean(LOG_EXIT_USER,&cleanup,"logger detected - disabling is not allowed") ;
if (!pres->disen && !FORCE)
{
log_info(name,": is already disabled") ;
continue ;
default :
log_usage(usage_disable) ;
}
}
if (!svc_remove(&tostop,pres,workdir.s,info))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"remove service: ",name) ;
if (pres->type == TYPE_CLASSIC) nclassic++ ;
else nlongrun++ ;
argc -= l.ind ; argv += l.ind ;
}
if (nclassic)
{
if (!svc_switch_to(info,SS_SWBACK))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"switch classic service to backup") ;
}
if (argc < 1)
log_usage(usage_disable) ;
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,&cleanup,"resolve source of graph for tree: ",info->treename.s) ;
/** build the graph of the entire system */
graph_build_service(&graph, ares, &areslen, info, flag) ;
r= ss_resolve_graph_publish(&graph,0) ;
if (r <= 0)
{
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,1))
log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"update inner bundle") ;
if (!graph.mlen)
log_die(LOG_EXIT_USER, "services selection is not available -- try to parse it first") ;
ss_resolve_graph_free(&graph) ;
if (!db_compile(workdir.s,info->tree.s, info->treename.s,envp))
log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"compile ",workdir.s,"/",info->treename.s) ;
for (; n < argc ; n++) {
check_identifier(argv[n]) ;
service_enable_disable(&graph, info->base.s, argv[n], 0) ;
/** 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,&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,&cleanup,"copy: ",workdir.s," to: ", info->tree.s) ;
if (stop && sa.len) {
cleanup() ;
stralloc_free(&workdir) ;
resolve_free(wres) ;
resolve_deep_free(DATA_SERVICE, &gares) ;
for (unsigned int i = 0 ; i < genalloc_len(resolve_service_t,&tostop); i++)
log_info("Disabled successfully: ",genalloc_s(resolve_service_t,&tostop)[i].sa.s + genalloc_s(resolve_service_t,&tostop)[i].name) ;
if (stop && genalloc_len(resolve_service_t,&tostop))
{
int nargc = 3 + genalloc_len(resolve_service_t,&tostop) ;
size_t len = sastr_nelement(&sa) ;
int nargc = 2 + len ;
char const *prog = PROG ;
char const *newargv[nargc] ;
unsigned int m = 0 ;
newargv[m++] = "fake_name" ;
newargv[m++] = "stop" ;
newargv[m++] = "-u" ;
for (unsigned int i = 0 ; i < genalloc_len(resolve_service_t,&tostop); i++)
newargv[m++] = genalloc_s(resolve_service_t,&tostop)[i].sa.s + genalloc_s(resolve_service_t,&tostop)[i].name ;
newargv[m++] = 0 ;
if (ssexec_stop(nargc,newargv,envp,info))
{
resolve_deep_free(DATA_SERVICE, &tostop) ;
return 111 ;
}
FOREACH_SASTR(&sa, pos)
newargv[m++] = sa.s + pos ;
newargv[m] = 0 ;
PROG = "stop" ;
e = ssexec_stop(nargc, newargv, info) ;
PROG = prog ;
goto end ;
}
e = 0 ;
resolve_deep_free(DATA_SERVICE, &tostop) ;
end:
stralloc_free(&sa) ;
service_resolve_array_free(ares, areslen) ;
graph_free_all(&graph) ;
return 0 ;
return e ;
}
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