/* * 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 <sys/stat.h> #include <stdlib.h> #include <oblibs/obgetopt.h> #include <oblibs/error2.h> #include <oblibs/directory.h> #include <oblibs/files.h> #include <oblibs/string.h> #include <oblibs/types.h> #include <oblibs/stralist.h> #include <skalibs/stralloc.h> #include <skalibs/genalloc.h> #include <skalibs/djbunix.h> #include <skalibs/buffer.h> #include <skalibs/direntry.h> #include <skalibs/unix-transactional.h> #include <skalibs/diuint32.h> #include <66/constants.h> #include <66/utils.h> #include <66/enum.h> #include <66/tree.h> #include <66/db.h> #include <66/parser.h> #include <66/backup.h> #include <66/svc.h> #include <66/graph.h> #include <66/resolve.h> #include <66/ssexec.h> #include <stdio.h> static unsigned int FORCE = 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,"Master",6)) strerr_dief3x(111,"service: ",name,": starts with reserved prefix") ; } static int start_parser(char const *src,char const *svname,char const *tree, unsigned int *nbsv) { stralloc sasv = STRALLOC_ZERO ; if (!parse_service_before(src,svname,tree,nbsv,&sasv,FORCE)) strerr_dief3x(111,"invalid service file: ",src,svname) ; stralloc_free(&sasv) ; return 1 ; } 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 ; int r ; unsigned int nbsv, nlongrun, nclassic, start ; char const *src ; stralloc home = STRALLOC_ZERO ; stralloc workdir = STRALLOC_ZERO ; stralloc sasrc = STRALLOC_ZERO ; stralloc sares = STRALLOC_ZERO ; genalloc gasrc = GENALLOC_ZERO ; //type diuint32 genalloc tostart = GENALLOC_ZERO ; // type stralist ss_resolve_t res = RESOLVE_ZERO ; graph_t g = GRAPH_ZERO ; stralloc sagraph = STRALLOC_ZERO ; genalloc master = GENALLOC_ZERO ; genalloc tokeep = GENALLOC_ZERO ; r = nbsv = nclassic = nlongrun = start = 0 ; if (!info->owner) src = SS_SERVICE_SYSDIR ; else { if (!set_ownerhome(&home,info->owner)) strerr_diefu1sys(111,"set home directory"); if (!stralloc_cats(&home,SS_SERVICE_USERDIR)) retstralloc(111,"main") ; if (!stralloc_0(&home)) retstralloc(111,"main") ; home.len-- ; src = home.s ; } { subgetopt_t l = SUBGETOPT_ZERO ; for (;;) { int opt = getopt_args(argc,argv, ">fS", &l) ; if (opt == -1) break ; if (opt == -2) strerr_dief1x(110,"options must be set first") ; switch (opt) { case 'f' : FORCE = 1 ; break ; case 'S' : start = 1 ; break ; default : exitusage(usage_enable) ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 1) exitusage(usage_enable) ; if (!ss_resolve_pointo(&sares,info,SS_NOTYPE,SS_RESOLVE_SRC)) strerr_diefu1sys(111,"set revolve pointer to source") ; for(;*argv;argv++) { check_identifier(*argv) ; if (ss_resolve_check(sares.s,*argv)) { if (!ss_resolve_read(&res,sares.s,*argv)) strerr_diefu2sys(111,"read resolve file of: ",*argv) ; if (res.disen && !FORCE) { VERBO1 strerr_warnw3x("Ignoring: ",*argv," service: already enabled") ; continue ; } } unsigned int found = 0 ; r = ss_resolve_src(&gasrc,&sasrc,*argv,src,&found) ; if (r < 0) strerr_diefu2sys(111,"parse source directory: ",src) ; if (!r) { src = SS_SERVICE_SYSDIR ; r = ss_resolve_src(&gasrc,&sasrc,*argv,src,&found) ; if (r < 0) strerr_diefu2sys(111,"parse source directory: ",src) ; if (!r) { src = SS_SERVICE_PACKDIR ; r = ss_resolve_src(&gasrc,&sasrc,*argv,src,&found) ; if (r < 0) strerr_diefu2sys(111,"parse source directory: ",src) ; if (!r) strerr_dief2sys(110,"unknow service: ",*argv) ; } } } ss_resolve_free(&res) ; stralloc_free(&sares) ; if (!genalloc_len(diuint32,&gasrc)) goto freed ; for (unsigned int i = 0 ; i < genalloc_len(diuint32,&gasrc) ; i++) start_parser(sasrc.s + genalloc_s(diuint32,&gasrc)[i].right,sasrc.s + genalloc_s(diuint32,&gasrc)[i].left,info->tree.s,&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) ; 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 (!stra_cmp(&tostart,name)) { if (sv->cname.itype == CLASSIC) nclassic++ ; else nlongrun++ ; if (!stra_add(&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) { r = graph_type_src(&tokeep,workdir.s,1) ; if (!r) { cleanup(workdir.s) ; strerr_diefu2x(111,"resolve source of graph for tree: ",info->treename.s) ; } if (!graph_build(&g,&sagraph,&tokeep,workdir.s)) { cleanup(workdir.s) ; strerr_diefu1x(111,"make dependencies graph") ; } if (graph_sort(&g) < 0) { cleanup(workdir.s) ; strerr_dief1x(111,"cyclic graph detected") ; } if (!graph_master(&master,&g)) { cleanup(workdir.s) ; strerr_dief1x(111,"find master service") ; } genalloc_reverse(stralist,&master) ; if (!db_write_master(info,&master,workdir.s,SS_SIMPLE)) { cleanup(workdir.s) ; strerr_diefu2sys(111,"update bundle: ", SS_MASTER + 1) ; } 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) ; freed: /** parser allocation*/ freed_parser() ; /** inner allocation */ stralloc_free(&home) ; stralloc_free(&workdir) ; stralloc_free(&sasrc) ; genalloc_free(diuint32,&gasrc) ; /** graph allocation */ graph_free(&g) ; genalloc_deepfree(stralist,&master,stra_free) ; stralloc_free(&sagraph) ; genalloc_deepfree(stralist,&tokeep,stra_free) ; for (unsigned int i = 0 ; i < genalloc_len(stralist,&tostart); i++) VERBO1 strerr_warni2x("Enabled successfully: ", gaistr(&tostart,i)) ; if (start && genalloc_len(stralist,&tostart)) { int nargc = 2 + genalloc_len(stralist,&tostart) ; char const *newargv[nargc] ; unsigned int m = 0 ; newargv[m++] = "fake_name" ; for (unsigned int i = 0 ; i < genalloc_len(stralist,&tostart); i++) newargv[m++] = gaistr(&tostart,i) ; newargv[m++] = 0 ; if (ssexec_start(nargc,newargv,envp,info)) { genalloc_deepfree(stralist,&tostart,stra_free) ; return 111 ; } } genalloc_deepfree(stralist,&tostart,stra_free) ; return 0 ; }