/* * ssexec_enable.c * * Copyright (c) 2018-2019 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 <errno.h> //#include <stdio.h> #include <oblibs/obgetopt.h> #include <oblibs/error2.h> #include <oblibs/string.h> #include <oblibs/sastr.h> #include <skalibs/stralloc.h> #include <skalibs/genalloc.h> #include <skalibs/djbunix.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> /** 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 ; static void cleanup(char const *dst) { int e = errno ; rm_rf(dst) ; errno = e ; } static void check_identifier(char const *name) { if (!memcmp(name,SS_MASTER+1,6)) strerr_dief3x(111,"service: ",name,": starts with reserved prefix") ; } static void start_parser(stralloc *list,ssexec_t *info, unsigned int *nbsv) { int r ; uint8_t exist = 0 ; size_t i = 0, len = list->len ; stralloc sasv = STRALLOC_ZERO ; stralloc tmp = STRALLOC_ZERO ; for (;i < len; i += strlen(list->s + i) + 1) { exist = 0 ; char *name = list->s+i ; size_t namelen = strlen(name) ; char svname[namelen + 1] ; if (!basename(svname,name)) strerr_diefu2sys(111,"get basename of: ", svname) ; r = parse_service_check_enabled(info,svname,FORCE,&exist) ; if (!r) strerr_diefu2x(111,"check enabled service: ",svname) ; if (r == 2) continue ; if (!parse_service_before(info,&tmp,name,nbsv,&sasv,FORCE,&exist)) strerr_diefu3x(111,"parse service file: ",svname,": or its dependencies") ; } stralloc_free(&sasv) ; stralloc_free(&tmp) ; } 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 = 0 ; CONF = 0 ; int r ; size_t pos = 0 ; unsigned int nbsv, nlongrun, nclassic, start ; stralloc home = STRALLOC_ZERO ; stralloc workdir = STRALLOC_ZERO ; stralloc sasrc = STRALLOC_ZERO ; stralloc tostart = STRALLOC_ZERO ; r = nbsv = nclassic = nlongrun = start = 0 ; { subgetopt_t l = SUBGETOPT_ZERO ; for (;;) { int opt = getopt_args(argc,argv, ">cCfFS", &l) ; if (opt == -1) break ; if (opt == -2) strerr_dief1x(110,"options must be set first") ; switch (opt) { case 'f' : if (FORCE) exitusage(usage_enable) ; FORCE = 1 ; break ; case 'F' : if (FORCE) exitusage(usage_enable) ; FORCE = 2 ; break ; case 'c' : if (CONF) exitusage(usage_enable) ; CONF = 1 ; break ; case 'C' : if (CONF) exitusage(usage_enable) ; CONF = 2 ; break ; case 'S' : start = 1 ; break ; default : exitusage(usage_enable) ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 1) exitusage(usage_enable) ; for(;*argv;argv++) { check_identifier(*argv) ; if (!ss_resolve_src_path(&sasrc,*argv,info)) strerr_diefu2x(111,"resolve source path of: ",*argv) ; } start_parser(&sasrc,info,&nbsv) ; if (!tree_copy(&workdir,info->tree.s,info->treename.s)) strerr_diefu1sys(111,"create tmp working directory") ; for (unsigned int i = 0; i < genalloc_len(sv_alltype,&gasv); i++) { sv_alltype_ref sv = &genalloc_s(sv_alltype,&gasv)[i] ; char *name = keep.s + sv->cname.name ; r = write_services(info,sv, workdir.s,FORCE,CONF) ; if (!r) { cleanup(workdir.s) ; strerr_diefu2x(111,"write service: ",name) ; } if (r > 1) continue ; //service already added VERBO2 strerr_warni2x("write resolve file of: ",name) ; if (!ss_resolve_setnwrite(sv,info,workdir.s)) { cleanup(workdir.s) ; strerr_diefu2x(111,"write revolve file for: ",name) ; } VERBO2 strerr_warni2x("Service written successfully: ", name) ; if (sastr_cmp(&tostart,name) == -1) { if (sv->cname.itype == CLASSIC) nclassic++ ; else nlongrun++ ; if (!sastr_add_string(&tostart,name)) { cleanup(workdir.s) ; retstralloc(111,"main") ; } } } if (nclassic) { if (!svc_switch_to(info,SS_SWBACK)) { cleanup(workdir.s) ; strerr_diefu3x(111,"switch ",info->treename.s," to backup") ; } } if(nlongrun) { ss_resolve_graph_t graph = RESOLVE_GRAPH_ZERO ; r = ss_resolve_graph_src(&graph,workdir.s,0,1) ; if (!r) { cleanup(workdir.s) ; strerr_diefu2x(111,"resolve source of graph for tree: ",info->treename.s) ; } r = ss_resolve_graph_publish(&graph,0) ; if (r <= 0) { cleanup(workdir.s) ; if (r < 0) strerr_dief1x(110,"cyclic graph detected") ; strerr_diefu1sys(111,"publish service graph") ; } if (!ss_resolve_write_master(info,&graph,workdir.s,0)) { cleanup(workdir.s) ; strerr_diefu1sys(111,"update inner bundle") ; } ss_resolve_graph_free(&graph) ; if (!db_compile(workdir.s,info->tree.s,info->treename.s,envp)) { cleanup(workdir.s) ; strerr_diefu4x(111,"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)) { cleanup(workdir.s) ; strerr_diefu3x(111,"switch ",info->treename.s," to backup") ; } } if (!tree_copy_tmp(workdir.s,info)) { cleanup(workdir.s) ; strerr_diefu4x(111,"copy: ",workdir.s," to: ", info->tree.s) ; } cleanup(workdir.s) ; /** parser allocation*/ freed_parser() ; /** inner allocation */ stralloc_free(&home) ; stralloc_free(&workdir) ; stralloc_free(&sasrc) ; for (; pos < tostart.len; pos += strlen(tostart.s + pos) + 1) VERBO1 strerr_warni2x("Enabled successfully: ", tostart.s + pos) ; if (start && tostart.len) { int nargc = 2 + sastr_len(&tostart) ; char const *newargv[nargc] ; unsigned int m = 0 ; newargv[m++] = "fake_name" ; 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 ; } } stralloc_free(&tostart) ; return 0 ; }