diff --git a/src/lib66/ssexec_help.c b/src/lib66/ssexec_help.c index c7625d96286f73182c7727dfc7af05bd0e9b4313..8ad754b0a44c4f241f7bf4ede1aeacbb4a92f44f 100644 --- a/src/lib66/ssexec_help.c +++ b/src/lib66/ssexec_help.c @@ -155,7 +155,7 @@ char const *help_all = " -f: fork the process\n" ; -char const *usage_tree = "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -n|R ] [ -a|d ] [ -c ] [ -o depends=:requiredby=:rename= ] [ -E|D ] [ -C clone ] tree" ; +char const *usage_tree = "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -c ] [ -o depends=:... ] [ -E|D ] [ -R ] tree" ; char const *help_tree = "\n" @@ -163,20 +163,20 @@ char const *help_tree = " -h: print this help\n" " -z: use color\n" " -v: increase/decrease verbosity\n" -" -n: create a new empty tree\n" -" -R: remove the tree\n" -" -a: allow user(s) at tree\n" -" -d: deny user(s) at tree\n" " -c: set tree as default\n" -" -o: colon separated list of dependencies\n" +" -o: colon separated list of options\n" " -E: enable the tree\n" " -D: disable the tree\n" -" -C: clone the tree\n" +" -R: remove the tree\n" "\n" "valid fields for -o options are:\n" "\n" -" depends=: comma separated list of dependencies for tree\n" -" requiredby=: comma separated list of trees required by tree\n" -" rename=: rename tree with as rename\n" +" depends=: comma separated list of dependencies for tree or none\n" +" requiredby=: comma separated list of trees required by tree or none\n" +" groups=: add tree to the specified groups\n" +" allow=: comma separated list of account to allow at tree\n" +" deny=: comma separated list of account to deny at tree\n" +" clone=: make a clone of tree\n" +" noseed: do not use seed file to build the tree\n" ; diff --git a/src/lib66/ssexec_tree.c b/src/lib66/ssexec_tree.c index daa64a9c5ebcce56495392f798786a904ea069d4..ba21427ccbfa5063081fb5e1eb58f73b344304bd 100644 --- a/src/lib66/ssexec_tree.c +++ b/src/lib66/ssexec_tree.c @@ -19,6 +19,7 @@ #include <sys/stat.h> #include <stdio.h>//rename #include <pwd.h> +#include <stdlib.h>//free #include <oblibs/obgetopt.h> #include <oblibs/log.h> @@ -42,34 +43,18 @@ #include <66/state.h> #include <66/service.h> #include <66/resolve.h> +#include <66/graph.h> #include <s6/supervise.h> #include <s6-rc/s6rc-servicedir.h> #include <s6-rc/s6rc-constants.h> - -/** - * - * - * - * -o depends=boot,system:requiredby=graphics - * - * depends/requiredby automatically enable the trees found at field except for boot - * - * -S options dissappear but it kept as it with a warn to user for the compatibility. - * - * -G for groups - * - * - * */ #define TREE_COLON_DELIM ':' #define TREE_COMMA_DELIM ',' -#define TREE_MAXOPTS 4 +#define TREE_MAXOPTS 9 #define tree_checkopts(n) if (n >= TREE_MAXOPTS) log_die(LOG_EXIT_USER, "too many -o options") -stralloc TREE_SAOPTS = STRALLOC_ZERO ; static char const *cleantree = 0 ; -static graph_t GRAPH = GRAPH_ZERO ; typedef struct tree_opts_map_s tree_opts_map_t ; struct tree_opts_map_s @@ -84,25 +69,79 @@ enum enum_ns_opts_e TREE_OPTS_DEPENDS = 0, TREE_OPTS_REQUIREDBY, TREE_OPTS_RENAME, + TREE_OPTS_GROUPS, + TREE_OPTS_NOSEED, + TREE_OPTS_ALLOW, + TREE_OPTS_DENY, + TREE_OPTS_CLONE, TREE_OPTS_ENDOFKEY } ; tree_opts_map_t const tree_opts_table[] = { - { .str = "depends", .id = TREE_OPTS_DEPENDS }, - { .str = "requiredby", .id = TREE_OPTS_REQUIREDBY }, - { .str = "rename", .id = TREE_OPTS_RENAME }, + { .str = "depends", .id = TREE_OPTS_DEPENDS }, + { .str = "requiredby", .id = TREE_OPTS_REQUIREDBY }, + { .str = "rename", .id = TREE_OPTS_RENAME }, + { .str = "groups", .id = TREE_OPTS_GROUPS }, + { .str = "noseed", .id = TREE_OPTS_NOSEED }, + { .str = "allow", .id = TREE_OPTS_ALLOW }, + { .str = "deny", .id = TREE_OPTS_DENY }, + { .str = "clone", .id = TREE_OPTS_CLONE }, { .str = 0 } } ; -typedef struct tree_opts_s tree_opts_t, *tree_opts_t_ref ; -struct tree_opts_s +typedef struct tree_what_s tree_what_t, *tree_what_t_ref ; +struct tree_what_s { - int depends ; //index of depends at TREE_SAOPTS - int requiredby ; //index of requiredby at TREE_SAOPTS - int rename ; //index of rename at TREE_SAOPTS + uint8_t create ; + uint8_t depends ; + uint8_t requiredby ; + uint8_t allow ; + uint8_t deny ; + uint8_t enable ; + uint8_t disable ; + uint8_t remove ; + uint8_t clone ; + uint8_t groups ; + uint8_t current ; + uint8_t rename ; + uint8_t noseed ; + + char gr[6] ; + char sclone[100] ; + uid_t auids[256] ; + uid_t duids[256] ; + uint8_t ndepends ; // only used if the term none is passed as dependencies + uint8_t nrequiredby ; // only used if the term none is passed as dependencies + + uint8_t nopts ; } ; -#define TREE_OPTS_ZERO { -1, -1, -1 } +#define TREE_WHAT_ZERO { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, { 0 }, { 0 }, { 0 }, 1, 1, 0 } + +tree_what_t what_init(void) +{ + log_flow() ; + + tree_what_t what = TREE_WHAT_ZERO ; + + memset(what.gr, 0, 6) ; + memset(what.auids, 0, 256 * sizeof(uid_t)); + memset(what.duids, 0, 256 * sizeof(uid_t)) ; + + return what ; +} + +void visit_init(visit *v, size_t len) +{ + log_flow() ; + + size_t pos = 0 ; + for (; pos < len; pos++) + v[pos] = SS_WHITE ; + +} + +void tree_enable_disable(graph_t *g, char const *base, char const *treename, uint8_t action) ; static void cleanup(void) { @@ -111,10 +150,18 @@ static void cleanup(void) if (cleantree) { log_trace("removing: ",cleantree,"...") ; - rm_rf(cleantree) ; + if (!dir_rm_rf(cleantree)) + log_dieusys(LOG_EXIT_SYS, "remove: ", cleantree) ; } } +static void check_identifier(char const *name) +{ + if (!memcmp(name, SS_MASTER + 1, 6)) + log_die(LOG_EXIT_USER,"tree name: ",name,": starts with reserved prefix Master") ; + +} + static void auto_dir(char const *dst,mode_t mode) { log_flow() ; @@ -171,16 +218,16 @@ static ssize_t tree_get_key(char *table,char const *str) return pos ; } -int sanitize_tree(ssexec_t *info, char const *tree) +void sanitize_system(ssexec_t *info) { log_flow() ; - ssize_t r ; + log_trace("sanitize system..." ) ; + size_t baselen = info->base.len ; - size_t treelen = strlen(tree) ; uid_t log_uid ; gid_t log_gid ; - char dst[baselen + SS_SYSTEM_LEN + SS_RESOLVE_LEN + 1 + treelen + 1] ; + char dst[baselen + SS_SYSTEM_LEN + SS_RESOLVE_LEN + SS_MASTER_LEN + 1] ; auto_strings(dst,info->base.s, SS_SYSTEM) ; /** base is /var/lib/66 or $HOME/.66*/ @@ -190,9 +237,6 @@ int sanitize_tree(ssexec_t *info, char const *tree) /** create extra directory for service part */ if (!info->owner) { - auto_strings(dst,info->base.s, SS_SYSTEM, SS_RESOLVE) ; - auto_check(dst) ; - auto_check(SS_LOGGER_SYSDIR) ; if (!youruid(&log_uid,SS_LOGGER_RUNNER) || @@ -253,150 +297,54 @@ int sanitize_tree(ssexec_t *info, char const *tree) auto_strings(dst,info->base.s, SS_SYSTEM, SS_RESOLVE) ; auto_check(dst) ; + auto_strings(dst + baselen + SS_SYSTEM_LEN + SS_RESOLVE_LEN, SS_MASTER) ; + + if (!scan_mode(dst, S_IFREG)) + if (!tree_resolve_create_master(info->base.s, info->owner)) + log_dieu(LOG_EXIT_SYS, "write resolve file of inner tree") ; + auto_strings(dst + baselen, SS_TREE_CURRENT) ; auto_check(dst) ; auto_strings(dst + baselen,SS_SYSTEM, SS_BACKUP) ; auto_check(dst) ; - auto_strings(dst + baselen + SS_SYSTEM_LEN, SS_STATE) ; - - if (!scan_mode(dst,S_IFREG)) { - - auto_strings(dst + baselen,SS_SYSTEM) ; - if(!file_create_empty(dst,SS_STATE + 1,0644)) - log_dieusys(LOG_EXIT_SYS,"create ",dst,SS_STATE) ; - } - - auto_strings(dst + baselen + SS_SYSTEM_LEN,"/",tree) ; - r = scan_mode(dst,S_IFDIR) ; - if (r == -1) log_die(LOG_EXIT_SYS,"invalid directory: ",dst) ; - /** we have one, keep it*/ - info->tree.len = 0 ; - if (!auto_stra(&info->tree,dst)) - log_die_nomem("stralloc") ; - - if (!r) return 0 ; - - return 1 ; } -void create_tree(ssexec_t *info) +static void tree_parse_options_groups(char *store, char const *str) { log_flow() ; - size_t newlen = 0 ; - size_t treelen = info->tree.len ; - - char const *tree = info->tree.s, *treename = info->treename.s ; - - char dst[treelen + SS_SVDIRS_LEN + SS_DB_LEN + SS_SRC_LEN + 16 + 1] ; - resolve_service_t res = RESOLVE_SERVICE_ZERO ; - resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ; - resolve_init(wres) ; - - auto_strings(dst, tree) ; - newlen = treelen ; - - res.name = resolve_add_string(wres,SS_MASTER+1) ; - res.description = resolve_add_string(wres,"inner bundle - do not use it") ; - res.tree = resolve_add_string(wres,dst) ; - res.treename = resolve_add_string(wres,treename) ; - res.type = TYPE_BUNDLE ; - res.disen = 1 ; - - auto_create(dst, SS_SVDIRS, newlen) ; - auto_create(dst, SS_RULES, newlen) ; - auto_strings(dst + newlen, SS_SVDIRS) ; - newlen = newlen + SS_SVDIRS_LEN ; - auto_create(dst, SS_DB, newlen) ; - auto_create(dst, SS_SVC, newlen) ; - auto_create(dst, SS_RESOLVE, newlen) ; - dst[newlen] = 0 ; - log_trace("write resolve file of inner bundle") ; - if (!resolve_write(wres,dst,SS_MASTER+1)) { - - resolve_free(wres) ; - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ; - } - resolve_free(wres) ; - - char sym[newlen + 1 + SS_SYM_SVC_LEN + 1] ; - char dstsym[newlen + SS_SVC_LEN + 1] ; - - auto_strings(sym,dst, "/", SS_SYM_SVC) ; - auto_strings(dstsym, dst, SS_SVC) ; - - log_trace("point symlink: ",sym," to ",dstsym) ; - if (symlink(dstsym,sym) < 0) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; - - auto_strings(sym + newlen + 1, SS_SYM_DB) ; - auto_strings(dstsym + newlen, SS_DB) ; - - log_trace("point symlink: ",sym," to ",dstsym) ; - if (symlink(dstsym,sym) < 0) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; - - auto_strings(dst + newlen, SS_DB) ; - newlen = newlen + SS_DB_LEN ; - auto_create(dst, SS_SRC, newlen) ; - auto_strings(dst + newlen, SS_SRC) ; - newlen = newlen + SS_SRC_LEN ; - auto_create(dst, SS_MASTER, newlen) ; - auto_strings(dst + newlen, SS_MASTER) ; - newlen = newlen + SS_MASTER_LEN ; + uid_t uid = getuid() ; - log_trace("create file: ",dst,"/contents") ; - if (!file_create_empty(dst,"contents",0644)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create: ",dst,"/contents") ; + if (strcmp(str, TREE_GROUPS_BOOT) && + strcmp(str, TREE_GROUPS_ADM) && + strcmp(str, TREE_GROUPS_USER) && + strcmp(str, "none")) + log_die(LOG_EXIT_SYS, "invalid group: ", str) ; - auto_strings(dst + newlen,"/type") ; + if (!uid && (!strcmp(str, TREE_GROUPS_USER))) + log_die(LOG_EXIT_SYS, "Only regular user can use this group") ; - log_trace("create file: ",dst) ; - if(!openwritenclose_unsafe(dst,"bundle\n",7)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write: ",dst) ; + else if (uid && (!strcmp(str, TREE_GROUPS_ADM) || !strcmp(str, TREE_GROUPS_BOOT))) + log_die(LOG_EXIT_SYS, "Only root user can use this group") ; + auto_strings(store, str) ; } -void create_backupdir(ssexec_t *info) +void tree_parse_uid_list(uid_t *uids, char const *str) { log_flow() ; - int r ; - - size_t baselen = info->base.len ; - size_t treenamelen = info->treename.len ; - - char const *base = info->base.s, *treename = info->treename.s ; - - char treetmp[baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ; - - auto_strings(treetmp, base, SS_SYSTEM, SS_BACKUP, "/", treename) ; - - r = scan_mode(treetmp,S_IFDIR) ; - if (r || (r == -1)) { - - log_trace("remove existing backup: ",treetmp) ; - if (rm_rf(treetmp) < 0) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"remove: ",treetmp) ; - } - - if (!r) - auto_dir(treetmp,0755) ; -} - -void parse_uid_list(uid_t *uids, char const *str) -{ size_t pos = 0 ; stralloc sa = STRALLOC_ZERO ; - if (!sastr_clean_string_wdelim(&sa, str, ',')) + if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM)) log_dieu(LOG_EXIT_SYS,"parse uid list") ; - uid_t owner = MYUID ; + uid_t owner = getuid() ; /** special case, we don't know which user want to use - * the service, we need a general name to allow all user - * the term "user" is took here to allow the current user*/ - ssize_t p = sastr_cmp(&sa,"user") ; + * the tree, we need a general name to allow all users. + * The term "user" is took here to allow the current user*/ + ssize_t p = sastr_cmp(&sa, "user") ; FOREACH_SASTR(&sa, pos) { @@ -407,7 +355,7 @@ void parse_uid_list(uid_t *uids, char const *str) if (!pw) { if (!errno) errno = ESRCH ; - log_dieu(LOG_EXIT_ZERO,"get user name") ; + log_dieu(LOG_EXIT_SYS,"get user name") ; } if (!scan_uidlist(pw->pw_name, uids)) @@ -420,200 +368,111 @@ void parse_uid_list(uid_t *uids, char const *str) log_dieu(LOG_EXIT_USER,"scan account: ",sa.s + pos) ; } -} - -/** @what -> 0 deny - * @what -> 1 allow */ -void set_rules(char const *tree, uid_t *uids, uint8_t what) -{ - log_flow() ; - - log_trace("set ", !what ? "denied" : "allowed"," user for tree: ",tree,"..." ) ; - - int r ; - size_t treelen = strlen(tree), uidn = uids[0], pos = 0 ; - uid_t owner = MYUID ; - char pack[256] ; - char tmp[treelen + SS_RULES_LEN + 1] ; - - auto_strings(tmp, tree, SS_RULES) ; - - if (!uidn && what) { - - uids[0] = 1 ; - uids[1] = owner ; - uidn++ ; - } - - //allow - if (what) { - - for (; pos < uidn ; pos++) { - - uint32_pack(pack,uids[pos+1]) ; - pack[uint_fmt(pack,uids[pos+1])] = 0 ; - log_trace("create file: ",pack," at ",tmp) ; - if(!file_create_empty(tmp,pack,0644) && errno != EEXIST) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; - - log_trace("user: ",pack," is allowed for tree: ",tree) ; - } - goto announce ; - } - //else deny - for (pos = 0 ; pos < uidn ; pos++) { - - if (owner == uids[pos+1]) continue ; - uint32_pack(pack,uids[pos+1]) ; - pack[uint_fmt(pack,uids[pos+1])] = 0 ; - char ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos+1]) + 1] ; - memcpy(ut,tmp,treelen + SS_RULES_LEN) ; - memcpy(ut + treelen + SS_RULES_LEN,"/",1) ; - memcpy(ut + treelen + SS_RULES_LEN + 1,pack,uint_fmt(pack,uids[pos+1])) ; - ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos + 1])] = 0 ; - r = scan_mode(ut,S_IFREG) ; - if (r == 1) { - - log_trace("unlink: ",ut) ; - r = unlink(ut) ; - if (r == -1) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; - } - log_trace("user: ",pack," is denied for tree: ",tree) ; - } - announce: - log_info("Permissions rules set successfully for tree: ",tree) ; + stralloc_free(&sa) ; } -/** @action -> 0 disable - * @action -> 1 enable */ -void tree_enable_disable(ssexec_t *info, uint8_t action) +static void tree_parse_options_depends(graph_t *g, ssexec_t *info, char const *str, uint8_t requiredby, tree_what_t *what) { log_flow() ; int r ; - char const *base = info->base.s, *dst = info->tree.s , *tree = info->treename.s ; - - log_trace(!action ? "disable " : "enable ",dst,"...") ; - r = tree_cmd_state(VERBOSITY,!action ? "-d" : "-a", tree) ; - if (!r) - - log_dieusys(LOG_EXIT_SYS,!action ? "disable: " : "enable: ",dst," at: ",base,SS_SYSTEM,SS_STATE) ; - - else if (r == 1) { - - log_info(!action ? "Disabled" : "Enabled"," successfully tree: ",tree) ; - - } - - else log_info("Already ",!action ? "disabled" : "enabled"," tree: ",tree) ; - -} - -void tree_modify_resolve(resolve_service_t *res, resolve_service_enum_t field,char const *regex,char const *by) -{ - log_flow() ; - + size_t pos = 0 ; + char *name = 0 ; stralloc sa = STRALLOC_ZERO ; - resolve_service_t modif = RESOLVE_SERVICE_ZERO ; - resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &modif) ; - - log_trace("modify field: ", resolve_service_field_table[field].field," of service: ",res->sa.s + res->name) ; - if (!service_resolve_copy(&modif,res)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ", res->sa.s + res->name) ; - - if (!service_resolve_field_to_sa(&sa,&modif, field)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get copy of field: ",resolve_service_field_table[field].field) ; - - if (sa.len) { - if (!sastr_replace(&sa,regex,by)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"replace field: ",resolve_service_field_table[field].field) ; + if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM)) + log_dieu(LOG_EXIT_SYS,"clean sub options") ; - if (!stralloc_0(&sa)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"stralloc") ; + if (sastr_cmp(&sa, "none") >= 0) { + if (!requiredby) + what->ndepends = 0 ; + else + what->nrequiredby = 0 ; - sa.len-- ; + stralloc_free(&sa) ; + return ; } - if (!service_resolve_modify_field(&modif,field,sa.s)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"modify field: ",resolve_service_field_table[field].field) ; - - if (!service_resolve_copy(res,&modif)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ",res->sa.s + res->name) ; - - stralloc_free(&sa) ; + FOREACH_SASTR(&sa, pos) { - resolve_free(wres) ; -} + name = sa.s + pos ; + + r = tree_isvalid(info->base.s, name) ; + if (r < 0) + log_diesys(LOG_EXIT_SYS, "invalid tree directory") ; + /** We only creates trees declared as dependency. + * TreeA depends on TreeB, we create TreeB + * if it doesn't exist yet */ + if (!r && !requiredby) { + + ssexec_t newinfo = SSEXEC_ZERO ; + if (!auto_stra(&newinfo.base, info->base.s) || + !auto_stra(&newinfo.treename, name)) + log_die_nomem("stralloc") ; + newinfo.owner = info->owner ; + newinfo.prog = info->prog ; + newinfo.help = info->help ; + newinfo.usage = info->usage ; + newinfo.opt_color = info->opt_color ; + newinfo.skip_opt_tree = info->skip_opt_tree ; + + + int nwhat = what->noseed ? 2 : 0 ; + int nargc = 3 + nwhat ; + char const *newargv[nargc] ; + uint8_t m = 0 ; + newargv[m++] = "66-tree (child)" ; + + if (nwhat) { + newargv[m++] = "-o" ; + newargv[m++] = "noseed" ; + } -void tree_remove(ssexec_t *info) -{ - log_flow() ; + newargv[m++] = name ; + newargv[m++] = 0 ; - char const *base = info->base.s, *dst = info->tree.s, *tree = info->treename.s ; - int r ; + log_trace("launch 66-tree sub-process for tree: ", name) ; - log_trace("delete: ",dst,"..." ) ; + if (ssexec_tree(nargc, newargv, (char const *const *)environ, &newinfo)) + log_dieusys(LOG_EXIT_SYS, "create tree: ", name) ; - if (rm_rf(dst) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ", dst) ; + ssexec_free(&newinfo) ; - size_t treelen = strlen(tree) ; - size_t baselen = strlen(base) ; - char treetmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treelen + 1] ; + r = 1 ; - auto_strings(treetmp, base, SS_SYSTEM, SS_BACKUP, "/", tree) ; + } - r = scan_mode(treetmp,S_IFDIR) ; - if (r || (r < 0)) { + if (!requiredby) { - log_trace("delete backup of tree: ",treetmp,"...") ; - if (rm_rf(treetmp) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ",treetmp) ; + if (!graph_vertex_add_with_edge(g, info->treename.s, name)) + log_die(LOG_EXIT_SYS,"add edge: ", name, " to vertex: ", info->treename.s) ; + } else if (r) { + /** if TreeA is requiredby TreeB, we don't want to create TreeB. + * We only manages it if it exist yet */ + if (!graph_vertex_add_with_requiredby(g, info->treename.s, name)) + log_die(LOG_EXIT_SYS,"add requiredby: ", name, " to: ", info->treename.s) ; + } } - tree_enable_disable(info,0) ; - - log_info("Deleted successfully: ",tree) ; -} - -#include <stdio.h> - -static void tree_parse_depends(char const *treename, char const *str) -{ - size_t pos = 0 ; - char *sv = 0 ; - stralloc sa = STRALLOC_ZERO ; - - if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM)) - log_dieu(LOG_EXIT_SYS,"clean sub options") ; - - FOREACH_SASTR(&sa, pos) { - - sv = sa.s + pos ; - - if (!graph_vertex_add(&GRAPH, sv)) - log_die(LOG_EXIT_SYS,"add vertex: ", sv) ; - - if (!graph_edge_add_g(&GRAPH, treename, sv)) - log_die(LOG_EXIT_SYS,"add edge: ", sv, " to vertex: ", treename) ; - - } stralloc_free(&sa) ; } -static void tree_parse_options(tree_opts_t *opts, char const *str) +static void tree_parse_options(graph_t *g, char const *str, ssexec_t *info, tree_what_t *what) { + log_flow() ; + + if (!str) + return ; size_t pos = 0, len = 0 ; ssize_t r ; char *line = 0, *key = 0, *val = 0 ; - tree_opts_map_t const *t ; - stralloc sa = STRALLOC_ZERO ; + tree_opts_map_t const *t ; - if (!sastr_clean_string_wdelim(&sa,str,TREE_COLON_DELIM)) + if (!sastr_clean_string_wdelim(&sa, str, TREE_COLON_DELIM)) log_dieu(LOG_EXIT_SYS,"clean options") ; unsigned int n = sastr_len(&sa), nopts = 0 , old ; @@ -632,38 +491,66 @@ static void tree_parse_options(tree_opts_t *opts, char const *str) char tmp[len + 1] ; r = tree_get_key(tmp,line) ; - if (r == -1) + if (r == -1 && strcmp(line, "noseed")) log_die(LOG_EXIT_USER,"invalid key: ", line) ; - key = tmp ; - val = line + r ; + if (!strcmp(line, "noseed")) { + key = line ; + } else { + key = tmp ; + val = line + r ; + } if (!strcmp(key, t->str)) { switch(t->id) { case TREE_OPTS_DEPENDS : + tree_parse_options_depends(g, info, val, 0, what) ; + what->depends = 1 ; + break ; - opts->depends = TREE_SAOPTS.len ; - if (!sastr_add_string(&TREE_SAOPTS, val)) - log_die_nomem("stralloc") ; + case TREE_OPTS_REQUIREDBY : - break ; + tree_parse_options_depends(g, info, val, 1, what) ; + what->requiredby = 1 ; + break ; - case TREE_OPTS_REQUIREDBY : + case TREE_OPTS_RENAME: + + what->rename = 1 ; + break ; - opts->requiredby = TREE_SAOPTS.len ; - if (!sastr_add_string(&TREE_SAOPTS, val)) - log_die_nomem("stralloc") ; + case TREE_OPTS_GROUPS: + tree_parse_options_groups(what->gr, val) ; + what->groups = 1 ; break ; - case TREE_OPTS_RENAME: + case TREE_OPTS_NOSEED: - opts->rename = TREE_SAOPTS.len ; - if (!sastr_add_string(&TREE_SAOPTS, val)) - log_die_nomem("stralloc") ; + what->noseed = 1 ; + break ; + + case TREE_OPTS_ALLOW: + + tree_parse_uid_list(what->auids, val) ; + what->allow = 1 ; + break ; + + case TREE_OPTS_DENY: + + tree_parse_uid_list(what->duids, val) ; + what->deny = 1 ; + break ; + + case TREE_OPTS_CLONE: + if (strlen(val) > 99) + log_die(LOG_EXIT_USER, "clone name cannot exceed 100 characters") ; + + auto_strings(what->sclone, val) ; + what->clone = 1 ; break ; default : @@ -677,407 +564,1070 @@ static void tree_parse_options(tree_opts_t *opts, char const *str) if (old == nopts) log_die(LOG_EXIT_SYS,"invalid option: ",line) ; } + stralloc_free(&sa) ; } -int ssexec_tree(int argc, char const *const *argv,char const *const *envp,ssexec_t *info) +void tree_parse_seed(char const *treename, tree_seed_t *seed, tree_what_t *what) { - int r, current, create, allow, deny, enable, disable, remove, snap ; + log_flow() ; - uid_t auids[256] = { 0 }, duids[256] = { 0 } ; + log_trace("checking seed file: ", treename, "..." ) ; - char const *tree, *after_tree = 0 ; + if (tree_seed_isvalid(treename)) { - stralloc clone = STRALLOC_ZERO ; - tree_seed_t seed = TREE_SEED_ZERO ; - tree_opts_t opts = TREE_OPTS_ZERO ; + if (!tree_seed_setseed(seed, treename, 0)) + log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "parse seed file: ", treename) ; - current = create = allow = deny = enable = disable = remove = snap = 0 ; + if (seed->depends) + what->depends = 1 ; - { - subgetopt l = SUBGETOPT_ZERO ; + if (seed->requiredby) + what->requiredby = 1 ; - for (;;) - { - int opt = getopt_args(argc,argv, ">" OPTS_TREE, &l) ; - if (opt == -1) break ; - if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; - switch (opt) - { + if (seed->disen) + what->enable = 1 ; - case 'n' : create = 1 ; break ; - case 'a' : parse_uid_list(auids, l.arg) ; - allow = 1 ; - break ; - case 'd' : parse_uid_list(duids, l.arg) ; - deny = 1 ; - break ; - case 'c' : current = 1 ; break ; - case 'S' : after_tree = l.arg ; break ; - case 'E' : enable = 1 ; if (disable) log_usage(usage_tree) ; break ; - case 'D' : disable = 1 ; if (enable) log_usage(usage_tree) ; break ; - case 'R' : remove = 1 ; if (create) log_usage(usage_tree) ; break ; - case 'C' : if (remove) log_usage(usage_tree) ; - if (!auto_stra(&clone,l.arg)) log_die_nomem("stralloc") ; - snap = 1 ; - break ; - case 'o' : tree_parse_options(&opts, l.arg) ; - break ; - default : log_usage(usage_tree) ; - } + if (seed->allow > 0) { + + tree_parse_uid_list(what->auids, seed->sa.s + seed->allow) ; + what->allow = 1 ; } - argc -= l.ind ; argv += l.ind ; - } - if (argc < 1) log_usage(usage_tree) ; + if (seed->deny > 0) { - // make create the default option - if (!current && !create && !allow && !deny && !enable && !disable && !remove && !snap && (opts.rename >= 0)) - create = 1 ; + tree_parse_uid_list(what->duids, seed->sa.s + seed->deny) ; + what->deny = 1 ; + } - info->treename.len = 0 ; - if (!auto_stra(&info->treename, argv[0])) - log_die_nomem("stralloc") ; + if (seed->current) + what->current = 1 ; - tree = info->treename.s ; + if (seed->groups) { - log_trace("sanitize ",tree,"..." ) ; - r = sanitize_tree(info,tree) ; + tree_parse_options_groups(what->gr, seed->sa.s + seed->groups) ; + what->groups = 1 ; + } + } +} - if (!graph_vertex_add(&GRAPH, tree)) - log_dieu(LOG_EXIT_SYS,"add vertex: ",tree) ; +void create_tree(ssexec_t *info) +{ + log_flow() ; - if (opts.depends >= 0) - tree_parse_depends(tree, TREE_SAOPTS.s + opts.depends) ; + size_t newlen = 0, treelen = info->tree.len ; + char const *tree = info->tree.s ; + char dst[treelen + SS_SVDIRS_LEN + SS_DB_LEN + SS_SRC_LEN + 16 + 1] ; + char sym[treelen + SS_SVDIRS_LEN + 1 + SS_SYM_SVC_LEN + 1] ; + char dstsym[treelen + SS_SVDIRS_LEN + SS_SVC_LEN + 1] ; - if(!r && create) { + auto_strings(dst, tree) ; + newlen = treelen ; - /** set cleanup */ - cleantree = info->tree.s ; - log_trace("checking seed file: ",tree,"..." ) ; + auto_create(dst, SS_SVDIRS, newlen) ; + auto_create(dst, SS_RULES, newlen) ; + auto_strings(dst + newlen, SS_SVDIRS) ; + newlen = newlen + SS_SVDIRS_LEN ; + auto_create(dst, SS_DB, newlen) ; + auto_create(dst, SS_SVC, newlen) ; + auto_create(dst, SS_RESOLVE, newlen) ; + dst[newlen] = 0 ; - if (tree_seed_isvalid(tree)) { + if (!service_resolve_create_master(info->base.s, info->treename.s)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ; - if (!tree_seed_setseed(&seed, tree, 0)) - log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "parse seed file: ", tree) ; + auto_strings(sym,dst, "/", SS_SYM_SVC) ; + auto_strings(dstsym, dst, SS_SVC) ; + + log_trace("point symlink: ", sym, " to ", dstsym) ; + if (symlink(dstsym,sym) < 0) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; - if (seed.depends) { + auto_strings(sym + newlen + 1, SS_SYM_DB) ; + auto_strings(dstsym + newlen, SS_DB) ; - tree_parse_depends(tree, saseed.s + seed.depends) ; + log_trace("point symlink: ", sym, " to ", dstsym) ; + if (symlink(dstsym, sym) < 0) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; - } + auto_strings(dst + newlen, SS_DB) ; + newlen = newlen + SS_DB_LEN ; + auto_create(dst, SS_SRC, newlen) ; + auto_strings(dst + newlen, SS_SRC) ; + newlen = newlen + SS_SRC_LEN ; + auto_create(dst, SS_MASTER, newlen) ; + auto_strings(dst + newlen, SS_MASTER) ; + newlen = newlen + SS_MASTER_LEN ; - if (seed.requiredby) { + log_trace("create file: ", dst, "/contents") ; + if (!file_create_empty(dst, "contents", 0644)) + log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "create: ", dst, "/contents") ; - } + auto_strings(dst + newlen, "/type") ; - if (seed.enabled) - enable = 1 ; + log_trace("create file: ", dst) ; + if(!openwritenclose_unsafe(dst, "bundle\n",7)) + log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "write: ", dst) ; - if (seed.allow > 0) { +} - parse_uid_list(auids, saseed.s + seed.allow) ; +void tree_groups(char const *base, char const *treename, char const *value) +{ + log_flow() ; - allow = 1 ; - } + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; + size_t nb = 0, baselen = strlen(base) ; + char pack[UINT_FMT] ; + char solve[baselen + SS_SYSTEM_LEN + 1] ; + char const *val ; - if (seed.deny > 0) { + auto_strings(solve, base, SS_SYSTEM) ; - parse_uid_list(duids, saseed.s + seed.deny) ; + log_trace("set: ", treename," to group ..." ) ; - deny = 1 ; - } + if (!strcmp(value, "none")) { + val = 0 ; + goto write ; + } + + nb = 1 ; + val = value ; + + write: + + uint_pack(pack, nb) ; + pack[uint_fmt(pack, nb)] = 0 ; + + if (!resolve_read(wres, solve, treename)) + log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", solve, "/.resolve/", treename) ; + + if (!resolve_modify_field(wres, TREE_ENUM_GROUPS, val) || + !resolve_modify_field(wres, TREE_ENUM_NGROUPS, pack)) + log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ; + + if (!resolve_write(wres, solve, treename)) + log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", solve, "/.resolve/", treename) ; + + resolve_free(wres) ; + + log_info("Set successfully: ", treename, " to group: ", value) ; +} + +void create_backupdir(char const *base, char const *treename) +{ + log_flow() ; + + int r ; + size_t baselen = strlen(base) ; + size_t treenamelen = strlen(treename) ; + char tmp[baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ; + + auto_strings(tmp, base, SS_SYSTEM, SS_BACKUP, "/", treename) ; + + r = scan_mode(tmp,S_IFDIR) ; + if (r || (r == -1)) { + + log_trace("remove existing backup: ",tmp) ; + if (!dir_rm_rf(tmp)) + log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "remove: ", tmp) ; + } + + auto_dir(tmp,0755) ; +} + +void tree_create(graph_t *g, ssexec_t *info, tree_what_t *what, char const *const *envp) +{ + log_flow() ; + + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; + tree_seed_t seed = TREE_SEED_ZERO ; + char solve[info->base.len + SS_SYSTEM_LEN + 1] ; + + auto_strings(solve, info->base.s, SS_SYSTEM) ; + + resolve_init(wres) ; + + /** set cleanup */ + cleantree = info->tree.s ; + + /** check seed file */ + if (!what->noseed) + tree_parse_seed(info->treename.s, &seed, what) ; + + log_trace("creating: ", info->tree.s, "..." ) ; + create_tree(info) ; + + log_trace("creating backup directory of tree: ", info->treename.s, "...") ; + create_backupdir(info->base.s, info->treename.s) ; + + /** unset cleanup */ + cleantree = 0 ; + + // set permissions + what->allow = 1 ; + + // compilation of the db + size_t dblen = info->tree.len ; + char newdb[dblen + SS_SVDIRS_LEN + 1] ; + auto_strings(newdb, info->tree.s, SS_SVDIRS) ; + + log_trace("compile: ",newdb, "/db/", info->treename.s, "..." ) ; + if (!db_compile(newdb, info->tree.s, info->treename.s, envp)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup, "compile ", newdb, "/db/", info->treename.s) ; + + tres.name = resolve_add_string(wres, info->treename.s) ; + tres.groups = resolve_add_string(wres, info->owner ? TREE_GROUPS_USER : TREE_GROUPS_ADM) ; + tres.ngroups = 1 ; + + log_trace("write resolve file of: ", info->treename.s) ; + if (!resolve_write(wres, solve, info->treename.s)) + log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "write resolve file: ", solve, SS_RESOLVE, "/", info->treename.s) ; + + if (what->depends) + tree_parse_options_depends(g, info, seed.sa.s + seed.depends, 0, what) ; + + if (what->requiredby) + tree_parse_options_depends(g, info, seed.sa.s + seed.requiredby, 1, what) ; + + resolve_free(wres) ; + tree_seed_free(&seed) ; + + log_info("Created successfully tree: ", info->treename.s) ; +} + +/** + * + * WARNING: The order of the trees are not sorted by dependencies order + * + * + * !action -> disable + * action -> disable */ +void tree_master_enable_disable(char const *base, char const *treename, uint8_t action) +{ + log_flow() ; + + size_t pos = 0, nb = 0, baselen = strlen(base), len = 0 ; + stralloc sa = STRALLOC_ZERO ; + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; + char solve[baselen + SS_SYSTEM_LEN + 1] ; + + log_trace(!action ? "disable" : "enable"," tree: ", treename, " from: ", SS_MASTER + 1) ; + + auto_strings(solve, base, SS_SYSTEM) ; + + if (!resolve_read(wres, solve, SS_MASTER)) + log_dieusys(LOG_EXIT_SYS, "read resolve file of inner tree") ; + + if (!tres.nenabled && action) { + if (!resolve_modify_field(wres, TREE_ENUM_ENABLED, treename)) + log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", SS_MASTER + 1) ; - if (seed.current) - current = 1 ; + tres.nenabled = 1 ; + goto write ; + } + + if (tres.nenabled) { + + if (!sastr_clean_string(&sa, tres.sa.s + tres.enabled)) + log_dieu(LOG_EXIT_SYS, "clean string") ; + + len = sa.len ; + + char t[len + 1] ; + + sastr_to_char(t, &sa) ; - if (seed.group) { + sa.len = 0 ; + + for (; pos < len ; pos += strlen(t + pos) + 1) { + + char *name = t + pos ; + + if (!strcmp(name, treename)) + continue ; + + if (!auto_stra(&sa, name, " ")) + log_die_nomem("stralloc") ; + + nb++ ; + } + if (action) { + if (!auto_stra(&sa, treename)) + log_die_nomem("stralloc") ; + nb++ ; + } + + if (!action && sa.len) + sa.len-- ; //remove last " " + + if (!stralloc_0(&sa)) + log_die_nomem("stralloc") ; + + if (!resolve_modify_field(wres, TREE_ENUM_ENABLED, sa.s)) + log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", SS_MASTER + 1) ; + + tres.nenabled = nb ; + } + + write: + if (!resolve_write(wres, solve, SS_MASTER + 1)) + log_dieusys(LOG_EXIT_SYS, "read resolve file of inner tree") ; + + resolve_free(wres) ; + stralloc_free(&sa) ; +} + +void tree_enable_disable_deps(graph_t *g,char const *base, char const *treename, uint8_t action) +{ + log_flow() ; + + size_t pos = 0 ; + stralloc sa = STRALLOC_ZERO ; + + if (graph_matrix_get_edge_g(&sa, g, treename, action ? 0 : 1) < 0) + log_dieu(LOG_EXIT_SYS, "get ", action ? "dependencies" : "required by" ," of: ", treename) ; + + size_t len = sastr_nelement(&sa) ; + visit v[len] ; + + visit_init(v, len) ; + + if (sa.len) { + + FOREACH_SASTR(&sa, pos) { + + if (v[pos] == SS_WHITE) { + + char *name = sa.s + pos ; + + tree_enable_disable(g, base, name, action) ; + + v[pos] = SS_GRAY ; } + } + } + + stralloc_free(&sa) ; +} + +/** @action -> 0 disable + * @action -> 1 enable */ +void tree_enable_disable(graph_t *g, char const *base, char const *treename, uint8_t action) +{ + log_flow() ; + + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; + size_t baselen = strlen(base) ; + + char solve[baselen + SS_SYSTEM_LEN + 1] ; + + uint8_t disen = tree_isenabled(base, treename) ; + if (disen < 0) + log_dieu(LOG_EXIT_SYS, "read resolve file of: ", treename) ; - //if (seed.services) + if ((disen && !action) || (!disen && action)){ + + log_trace(!action ? "disable " : "enable ", base, SS_SYSTEM, "/" , treename, "...") ; + + if (tree_ongroups(base, treename, TREE_GROUPS_BOOT) && action) { + log_1_warn(treename," is a part of group ", TREE_GROUPS_BOOT," -- ignoring enable request") ; + return ; } + auto_strings(solve, base, SS_SYSTEM) ; - log_trace("creating: ",info->tree.s,"..." ) ; - create_tree(info) ; + if (!resolve_read(wres, solve, treename)) + log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", solve, "/", treename) ; - log_trace("creating backup directory for: ", tree,"...") ; - create_backupdir(info) ; - /** unset cleanup */ - cleantree = 0 ; + if (!resolve_modify_field_g(wres, base, treename, TREE_ENUM_DISEN, !action ? "0" : "1")) + log_dieu(LOG_EXIT_SYS, "modify field: ", resolve_tree_field_table[TREE_ENUM_DISEN].field," of tree: ", treename, " with value: ", !action ? "0" : "1") ; - // set permissions - allow = 1 ; + tree_enable_disable_deps(g, base, treename, action) ; + tree_master_enable_disable(base, treename, action) ; - size_t dblen = info->tree.len ; - char newdb[dblen + SS_SVDIRS_LEN + 1] ; - auto_strings(newdb, info->tree.s, SS_SVDIRS) ; + log_info(!action ? "Disabled" : "Enabled"," successfully tree: ", treename) ; - log_trace("compile: ",newdb,"/db/",tree,"..." ) ; - if (!db_compile(newdb,info->tree.s,tree,envp)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"compile ",newdb,"/db/",tree) ; + } else { - r = 1 ; - create = 0 ; - log_info("Created successfully tree: ",tree) ; + log_info("Already ",!action ? "disabled" : "enabled"," tree: ",treename) ; } - if ((!r && !create) || (!r && enable)) log_dieusys(LOG_EXIT_SYS,"find tree: ",info->tree.s) ; - if (r && create) log_dieu(LOG_EXIT_USER,"create: ",info->tree.s,": already exist") ; + resolve_free(wres) ; +} +/* !deps -> add + * deps -> remove */ +void tree_depends_requiredby(graph_t *g, char const *base, char const *treename, uint8_t requiredby, uint8_t none, char const *deps) +{ + log_flow() ; + + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; + size_t pos = 0, len = 0, nb = 0, baselen = strlen(base) ; + uint8_t ewhat = !requiredby ? TREE_ENUM_DEPENDS : TREE_ENUM_REQUIREDBY ; + uint8_t nwhat = !requiredby ? TREE_ENUM_NDEPENDS : TREE_ENUM_NREQUIREDBY ; + stralloc sa = STRALLOC_ZERO ; + char pack[UINT_FMT] ; + char solve[baselen + SS_SYSTEM_LEN + 1] ; + + log_trace("manage ", !requiredby ? "dependencies" : "required by", " for tree: ", treename, "..." ) ; + + auto_strings(solve, base, SS_SYSTEM) ; + + if (graph_matrix_get_edge_g_sorted(&sa, g, treename, requiredby) < 0) + log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", treename) ; + + size_t vlen = sastr_nelement(&sa) ; + visit v[vlen] ; + + visit_init(v, vlen) ; + + len = sa.len ; + { + char t[len + 1] ; + + sastr_to_char(t, &sa) ; + + sa.len = 0 ; + for(; pos < len ; pos += strlen(t + pos) + 1) { - if (enable) { - /** - * - * - * Also, check if depends of the tree are enabled. - * - * - * - * */ + if (v[pos] == SS_WHITE) { + char *name = t + pos ; - if (!graph_matrix_build(&GRAPH)) - log_dieu(LOG_EXIT_SYS,"build the graph") ; + if (!none) { - if (!graph_matrix_analyze_cycle(&GRAPH)) - log_die(LOG_EXIT_SYS,"found cycle") ; + if (!graph_edge_remove_g(g, treename, name)) + log_dieu(LOG_EXIT_SYS,"remove edge: ", name, " from vertex: ", treename); - if (!graph_matrix_sort(&GRAPH)) - log_dieu(LOG_EXIT_SYS,"sort the graph") ; + } else { - graph_show_matrix(&GRAPH) ; + if (deps) { + if (!strcmp(name, deps)) { + v[pos] = SS_GRAY ; + continue ; + } + } - for (unsigned int i = 0 ; i < GRAPH.sort_count ; i++) - printf("%s\n",GRAPH.data.s + genalloc_s(graph_hash_t,&GRAPH.hash)[GRAPH.sort[i]].vertex) ; - tree_enable_disable(info,1) ; + if (!auto_stra(&sa, name, " ")) + log_die_nomem("stralloc") ; + nb++ ; + } + + v[pos] = SS_GRAY ; + } + } } + if (sa.len) + sa.len-- ; //remove last " " + + if (!stralloc_0(&sa)) + log_die_nomem("stralloc") ; - if (disable) - tree_enable_disable(info,0) ; + uint_pack(pack, nb) ; + pack[uint_fmt(pack, nb)] = 0 ; - if (allow) - set_rules(info->tree.s,auids,1) ; + if (!resolve_read(wres, solve, treename)) + log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", solve, "/.resolve/", treename) ; - if (deny) - set_rules(info->tree.s,duids,0) ; + if (!resolve_modify_field(wres, ewhat, sa.s) || + !resolve_modify_field(wres, nwhat, pack)) + log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ; - if(current) { + if (!resolve_write(wres, solve, treename)) + log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", solve, "/.resolve/", treename) ; - log_trace("make: ",info->tree.s," as default ..." ) ; + if (!none) { - if (!tree_switch_current(info->base.s,tree)) - log_dieusys(LOG_EXIT_SYS,"set: ",info->tree.s," as default") ; + graph_free_matrix(g) ; + graph_free_sort(g) ; + + if (!graph_matrix_build(g)) + log_die(LOG_EXIT_SYS, "build the graph") ; + + if (!graph_matrix_analyze_cycle(g)) + log_die(LOG_EXIT_SYS, "found cycle") ; + + if (!graph_matrix_sort(g)) + log_die(LOG_EXIT_SYS, "sort the graph") ; - log_info("Set successfully: ",tree," as default") ; } - if (remove) - tree_remove(info) ; + stralloc_free(&sa) ; + resolve_free(wres) ; - if (snap) { + log_info(requiredby ? "Required by " : "Dependencies ", "successfully managed for tree: ", treename) ; +} - stralloc salist = STRALLOC_ZERO ; - resolve_service_t res = RESOLVE_SERVICE_ZERO ; - resolve_wrapper_t_ref wres = resolve_set_struct(SERVICE_STRUCT, &res) ; - char const *exclude[1] = { 0 } ; +void tree_depends_requiredby_deps(graph_t *g, char const *base, char const *treename, uint8_t requiredby, uint8_t none, char const *deps) +{ + log_flow() ; - size_t syslen = info->base.len + SS_SYSTEM_LEN ; - size_t treelen = info->treename.len ; - size_t pos = 0 ; + size_t baselen = strlen(base), pos = 0, len = 0 ; + stralloc sa = STRALLOC_ZERO ; + char solve[baselen + SS_SYSTEM_LEN + 1] ; - char system[syslen + 1] ; - auto_strings(system,info->base.s,SS_SYSTEM) ; + if (graph_matrix_get_edge_g_sorted(&sa, g, treename, requiredby) < 0) + log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", treename) ; - size_t clone_target_len = syslen + 1 + clone.len ; - char clone_target[clone_target_len + 1] ; - auto_strings(clone_target,system,"/",clone.s) ; + size_t vlen = sastr_nelement(&sa) ; + visit v[vlen] ; - r = scan_mode(clone_target,S_IFDIR) ; - if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ; + visit_init(v, vlen) ; - // clone main directory - log_trace("clone: ",tree," as: ",clone.s,"..." ) ; - if (!hiercopy(info->tree.s,clone_target)) - log_dieusys(LOG_EXIT_SYS,"copy: ",info->tree.s," to: ",clone_target) ; + auto_strings(solve, base, SS_SYSTEM) ; - // clone backup directory - size_t clone_backup_len = syslen + SS_BACKUP_LEN + 1 + clone.len ; - char clone_backup[clone_backup_len + 1] ; - auto_strings(clone_backup,system,SS_BACKUP,"/",clone.s) ; + len = sa.len ; + char t[len + 1] ; - char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ; - auto_strings(tree_backup,system,SS_BACKUP,"/",tree) ; + sastr_to_char(t, &sa) ; - /* make cleantree pointing to the clone to be able to remove it - * in case of crach */ - cleantree = clone_target ; + for(; pos < len ; pos += strlen(t + pos) + 1) { - log_trace("clone backup of: ",tree," as: ",clone.s,"..." ) ; - if (!hiercopy(tree_backup,clone_backup)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tree_backup," to: ",clone_backup) ; + if (v[pos] == SS_WHITE) { - // modify the resolve file to match the new name - // main directory first - char src_resolve[clone_target_len + SS_SVDIRS_LEN + SS_RESOLVE_LEN + 1] ; - auto_strings(src_resolve,clone_target,SS_SVDIRS,SS_RESOLVE) ; + char *name = t + pos ; - if (!sastr_dir_get(&salist,src_resolve,exclude,S_IFREG)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ; + tree_depends_requiredby(g, base, name, !requiredby, none, deps) ; - char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ; - auto_strings(clone_res,clone_target,SS_SVDIRS) ; + v[pos] = SS_GRAY ; + } + } - FOREACH_SASTR(&salist, pos) { + stralloc_free(&sa) ; +} - char *name = salist.s + pos ; +/** @what -> 0 deny + * @what -> 1 allow */ +void tree_rules(char const *base, char const *treename, uid_t *uids, uint8_t what) +{ + log_flow() ; - if (!resolve_read(wres,clone_res,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ; + int r ; + size_t baselen = strlen(base), treenamelen = strlen(treename), uidn = uids[0], pos = 0, len = 0 ; + uid_t owner = MYUID ; + char pack[256] ; + char tmp[baselen + SS_SYSTEM_LEN + 1 + treenamelen + SS_RULES_LEN + 1] ; + stralloc sa = STRALLOC_ZERO ; + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; - tree_modify_resolve(&res,SERVICE_ENUM_RUNAT,tree,clone.s) ; - tree_modify_resolve(&res,SERVICE_ENUM_TREENAME,tree,clone.s) ; - tree_modify_resolve(&res,SERVICE_ENUM_TREE,tree,clone.s) ; - tree_modify_resolve(&res,SERVICE_ENUM_STATE,tree,clone.s) ; + log_trace("set ", !what ? "denied" : "allowed", " user for tree: ", treename, "..." ) ; - if (!resolve_write(wres,clone_res,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; + auto_strings(tmp, base, SS_SYSTEM) ; + + if (!resolve_read(wres, tmp, treename)) + log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", tmp, "/.resolve/", treename) ; + + if (tres.nallow) + if (!sastr_clean_string(&sa, tres.sa.s + tres.allow)) + log_dieu(LOG_EXIT_SYS, "clean string") ; + + /** fresh creation of the tree */ + if (!tres.nallow) { + + if (!uids[0]) { + + uids[0] = 1 ; + uids[1] = owner ; + + } else { + /** command can be 66-tree -a <account> <tree> + * where <tree> doesn't exist yet. + * Keep the -a option value and append the owner + * of the process at the end of the list. */ + uids[0]++ ; + uids[uidn + 1] = owner ; } - // rename db - char clone_db_old[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + treelen + 1] ; - auto_strings(clone_db_old,clone_target,SS_SVDIRS,SS_DB,"/",tree) ; + uidn++ ; + + } + + //allow + if (what) { - char clone_db_new[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + clone.len + 1] ; - auto_strings(clone_db_new,clone_target,SS_SVDIRS,SS_DB,"/",clone.s) ; + auto_strings(tmp, base, SS_SYSTEM, "/", treename, SS_RULES) ; - log_trace("rename tree db: ",tree," as: ",clone.s,"..." ) ; - if (rename(clone_db_old,clone_db_new) == -1) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_old," to: ",clone_db_new) ; + for (; pos < uidn ; pos++) { - // backup directory - char src_resolve_backup[clone_backup_len + SS_RESOLVE_LEN + 1] ; - auto_strings(src_resolve_backup,clone_backup,SS_RESOLVE) ; + uint32_pack(pack,uids[pos+1]) ; + pack[uint_fmt(pack,uids[pos+1])] = 0 ; - salist.len = 0 ; + log_trace("create file: ",tmp,"/", pack) ; - /** main and backup can be different,so rebuild the list - * Also, a backup directory can be empty, check it first */ - r = scan_mode(src_resolve_backup,S_IFDIR) ; - if (r == 1) { + if(!file_create_empty(tmp,pack,0644) && errno != EEXIST) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; - if (!sastr_dir_get(&salist,src_resolve_backup,exclude,S_IFREG)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ; + /** avoid double entry of the owner of the tree */ + if (sastr_cmp(&sa, pack) < 0) { - pos = 0 ; - FOREACH_SASTR(&salist, pos) { + if (!sastr_add_string(&sa, pack)) + log_die_nomem("stralloc") ; - char *name = salist.s + pos ; + tres.nallow++ ; + } - if (!resolve_read(wres,clone_backup,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ; + log_trace("user: ", pack, " is allowed for tree: ", treename) ; + } - tree_modify_resolve(&res,SERVICE_ENUM_RUNAT,tree,clone.s) ; - tree_modify_resolve(&res,SERVICE_ENUM_TREENAME,tree,clone.s) ; - tree_modify_resolve(&res,SERVICE_ENUM_TREE,tree,clone.s) ; - tree_modify_resolve(&res,SERVICE_ENUM_STATE,tree,clone.s) ; + } else { + //deny + for (; pos < uidn ; pos++) { - if (!resolve_write(wres,clone_backup,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; + /** Keep at least the current owner of the process + * of the tree */ + if (owner == uids[pos+1]) { + log_1_warn("you can not deny yourself -- ignoring request") ; + continue ; } - // rename db - char clone_db_backup_old[clone_backup_len + SS_DB_LEN + 1 + treelen + 1] ; - auto_strings(clone_db_backup_old,clone_backup,SS_DB,"/",tree) ; - char clone_db_backup_new[clone_backup_len + SS_DB_LEN + 1 + clone.len + 1] ; - auto_strings(clone_db_backup_new,clone_backup,SS_DB,"/",clone.s) ; + uint32_pack(pack,uids[pos+1]) ; + pack[uint_fmt(pack,uids[pos+1])] = 0 ; + char ut[baselen + SS_SYSTEM_LEN + 1 + treenamelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos+1]) + 1] ; + + auto_strings(ut, base, SS_SYSTEM, "/", treename, SS_RULES, "/", pack) ; + + r = scan_mode(ut,S_IFREG) ; + if (r == 1) { + + if (!sastr_remove_element(&sa, pack)) + log_dieu(LOG_EXIT_SYS, "remove: ", pack, " from list") ; + + for (size_t poss = 0 ; poss < len ; poss += strlen(sa.s + pos) + 1) + printf(" name::%s\n",sa.s + poss) ; + tres.nallow-- ; + + log_trace("unlink: ",ut) ; + r = unlink(ut) ; + if (r == -1) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; + } - log_trace("rename tree backup db: ",tree," as: ",clone.s,"..." ) ; - if (rename(clone_db_backup_old,clone_db_backup_new) == -1) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_backup_old," to: ",clone_db_backup_new) ; + log_trace("user: ", pack, " is denied for tree: ", treename) ; } + } - stralloc_free(&salist) ; - resolve_free(wres) ; + tmp[baselen + SS_SYSTEM_LEN] = 0 ; + len = sa.len ; + + char t[len + 1] ; + + sastr_to_char(t, &sa) ; + + sa.len = 0 ; + + for (pos = 0 ; pos < len ; pos += strlen(t + pos) + 1) + if (!auto_stra(&sa, t + pos, " ")) + log_die_nomem("stralloc") ; + + if (sa.len) + sa.len-- ; + + if (!stralloc_0(&sa)) + log_die_nomem("stralloc") ; + + if (!resolve_modify_field(wres, TREE_ENUM_ALLOW, sa.s)) + log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ; + + if (!resolve_write(wres, tmp, treename)) + log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", treename) ; + + stralloc_free(&sa) ; + resolve_free(wres) ; + + log_info("Permissions rules set successfully for tree: ", treename) ; +} + +void tree_remove(graph_t *g, char const *base, char const *treename) +{ + log_flow() ; + + int r ; + size_t baselen = strlen(base), treenamelen = strlen(treename) ; + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; + + char tree[baselen + SS_SYSTEM_LEN + 1 + treenamelen + 1] ; + + auto_strings(tree, base, SS_SYSTEM, "/", treename) ; + + log_trace("delete: ", tree, "..." ) ; + + if (!dir_rm_rf(tree)) + log_dieusys(LOG_EXIT_SYS,"delete: ", tree) ; + + char tmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ; + + auto_strings(tmp, base, SS_SYSTEM) ; + + if (!resolve_read(wres, tmp, treename)) + log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", tmp, "/.resolve/", treename) ; + + tree_enable_disable(g, base, treename, 0) ; + + /** depends */ + tree_depends_requiredby_deps(g, base, treename, 0, 1, treename) ; + + /** requiredby */ + tree_depends_requiredby_deps(g, base, treename, 1, 1, treename) ; + + log_trace("remove resolve file of tree: ", treename) ; + + resolve_rmfile(tmp, treename) ; + + auto_strings(tmp + baselen + SS_SYSTEM_LEN, SS_BACKUP, "/", treename) ; + + r = scan_mode(tmp,S_IFDIR) ; + if (r || (r < 0)) { + + log_trace("delete backup of tree: ", tmp, "...") ; + if (!dir_rm_rf(tmp)) + log_dieusys(LOG_EXIT_SYS, "delete: ", tmp) ; - log_info("Cloned successfully: ",tree," to ",clone.s) ; } - if (after_tree) { + resolve_free(wres) ; + + log_info("Deleted successfully: ", treename) ; +} + +void tree_current(ssexec_t *info) +{ + log_trace("mark: ", info->treename.s," as default ..." ) ; + + if (!tree_switch_current(info->base.s, info->treename.s)) + log_dieusys(LOG_EXIT_SYS,"set: ", info->treename.s, " as default") ; + + log_info("Set successfully: ", info->treename.s," as default") ; + +} + +void tree_clone(char const *clone, ssexec_t *info) +{ + log_flow() ; + + int r ; + resolve_service_t res = RESOLVE_SERVICE_ZERO ; + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ; + stralloc sa = STRALLOC_ZERO ; + char const *exclude[1] = { 0 } ; + + size_t syslen = info->base.len + SS_SYSTEM_LEN ; + size_t treelen = info->treename.len, clonelen = strlen(clone) ; + size_t pos = 0 ; - stralloc contents = STRALLOC_ZERO ; - stralloc tmp = STRALLOC_ZERO ; - int befirst = obstr_equal(tree,after_tree) ; - size_t baselen = info->base.len, pos = 0 ; - char ste[baselen + SS_SYSTEM_LEN + 1] ; - auto_strings(ste,info->base.s,SS_SYSTEM) ; + char system[syslen + 1] ; + auto_strings(system,info->base.s,SS_SYSTEM) ; - int enabled = tree_cmd_state(VERBOSITY,"-s",tree) ; - if (enabled != 1) - log_die(LOG_EXIT_USER,"tree: ",tree," is not enabled") ; + size_t clone_target_len = syslen + 1 + clonelen ; + char clone_target[clone_target_len + 1] ; + auto_strings(clone_target,system,"/",clone) ; - enabled = tree_cmd_state(VERBOSITY,"-s",after_tree) ; - if (enabled != 1) - log_die(LOG_EXIT_USER,"tree: ",after_tree," is not enabled") ; + r = scan_mode(clone_target,S_IFDIR) ; + if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ; - r = tree_cmd_state(VERBOSITY,"-d",tree) ; - if (!r) log_dieusys(LOG_EXIT_SYS,"disable: ",tree," at: ",ste,SS_STATE) ; + // clone main directory + log_trace("clone: ",info->treename.s," as: ",clone,"..." ) ; + if (!hiercopy(info->tree.s,clone_target)) + log_dieusys(LOG_EXIT_SYS,"copy: ",info->tree.s," to: ",clone_target) ; - r = file_readputsa(&tmp,ste,SS_STATE + 1) ; - if(!r) log_dieusys(LOG_EXIT_SYS,"open: ", ste,SS_STATE) ; + // clone backup directory + size_t clone_backup_len = syslen + SS_BACKUP_LEN + 1 + clonelen ; + char clone_backup[clone_backup_len + 1] ; + auto_strings(clone_backup,system,SS_BACKUP,"/",clone) ; - /** if you have only one tree enabled, the state file will be - * empty because we disable it before reading the file(see line 803). - * This will make a crash at sastr_? call. - * So write directly the name of the tree at state file. */ + char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ; + auto_strings(tree_backup,system,SS_BACKUP,"/",info->treename.s) ; - if (tmp.len) { + /* make cleantree pointing to the clone to be able to remove it + * in case of crach */ + cleantree = clone_target ; - if (!sastr_rebuild_in_oneline(&tmp) || - !sastr_clean_element(&tmp)) - log_dieu(LOG_EXIT_SYS,"rebuild state list") ; + log_trace("clone backup of: ",info->treename.s," as: ",clone,"..." ) ; + if (!hiercopy(tree_backup,clone_backup)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tree_backup," to: ",clone_backup) ; - pos = 0 ; - FOREACH_SASTR(&tmp, pos) { + // modify the resolve file to match the new name + // main directory first + char src_resolve[clone_target_len + SS_SVDIRS_LEN + SS_RESOLVE_LEN + 1] ; + auto_strings(src_resolve,clone_target,SS_SVDIRS,SS_RESOLVE) ; - char *name = tmp.s + pos ; + if (!sastr_dir_get(&sa,src_resolve,exclude,S_IFREG)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ; - /* e.g 66-tree -S root root -> meaning root need to - * be the first to start */ - if ((befirst) && (pos == 0)) - { - if (!auto_stra(&contents,tree,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; - } - if (!auto_stra(&contents,name,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; + char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ; + auto_strings(clone_res,clone_target,SS_SVDIRS) ; - if (obstr_equal(name,after_tree)) - { - if (!auto_stra(&contents,tree,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; - } + FOREACH_SASTR(&sa, pos) { + + char *name = sa.s + pos ; + + if (!resolve_read(wres,clone_res,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ; + + if (!resolve_modify_field(wres, SERVICE_ENUM_RUNAT, clone) || + !resolve_modify_field(wres, SERVICE_ENUM_TREENAME, clone) || + !resolve_modify_field(wres, SERVICE_ENUM_TREE, clone) || + !resolve_modify_field(wres, SERVICE_ENUM_STATE, clone)) + log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "modify resolve file of: ", name) ; + + if (!resolve_write(wres,clone_res,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; + } + + // rename db + char clone_db_old[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + treelen + 1] ; + auto_strings(clone_db_old,clone_target,SS_SVDIRS,SS_DB,"/",info->treename.s) ; + + char clone_db_new[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + clonelen + 1] ; + auto_strings(clone_db_new,clone_target,SS_SVDIRS,SS_DB,"/",clone) ; + + log_trace("rename tree db: ",info->treename.s," as: ",clone,"..." ) ; + if (rename(clone_db_old,clone_db_new) == -1) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_old," to: ",clone_db_new) ; + + // backup directory + char src_resolve_backup[clone_backup_len + SS_RESOLVE_LEN + 1] ; + auto_strings(src_resolve_backup,clone_backup,SS_RESOLVE) ; + + sa.len = 0 ; + + /** main and backup can be different,so rebuild the list + * Also, a backup directory can be empty, check it first */ + r = scan_mode(src_resolve_backup,S_IFDIR) ; + if (r == 1) { + + if (!sastr_dir_get(&sa,src_resolve_backup,exclude,S_IFREG)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ; + + pos = 0 ; + FOREACH_SASTR(&sa, pos) { + + char *name = sa.s + pos ; + + if (!resolve_read(wres,clone_backup,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ; + + if (!resolve_modify_field(wres, SERVICE_ENUM_RUNAT, clone) || + !resolve_modify_field(wres, SERVICE_ENUM_TREENAME, clone) || + !resolve_modify_field(wres, SERVICE_ENUM_TREE, clone) || + !resolve_modify_field(wres, SERVICE_ENUM_STATE, clone)) + log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "modify resolve file of: ", name) ; + + if (!resolve_write(wres,clone_backup,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; + } + // rename db + char clone_db_backup_old[clone_backup_len + SS_DB_LEN + 1 + treelen + 1] ; + auto_strings(clone_db_backup_old,clone_backup,SS_DB,"/",info->treename.s) ; + + char clone_db_backup_new[clone_backup_len + SS_DB_LEN + 1 + clonelen + 1] ; + auto_strings(clone_db_backup_new,clone_backup,SS_DB,"/",clone) ; + + log_trace("rename tree backup db: ",info->treename.s," as: ",clone,"..." ) ; + if (rename(clone_db_backup_old,clone_db_backup_new) == -1) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_backup_old," to: ",clone_db_backup_new) ; + } + /** tree resolve file */ + + resolve_free(wres) ; + + wres = resolve_set_struct(DATA_TREE, &tres) ; + + if (!resolve_read(wres, system, info->treename.s)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ", system, "/", info->treename.s) ; + + if (!resolve_modify_field(wres, TREE_ENUM_ENABLED, 0) || + !resolve_modify_field(wres, TREE_ENUM_NAME, clone)) + log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", clone) ; + + tres.disen = 0 ; + + if (!resolve_write(wres, system, clone)) + log_dieusys_nclean(LOG_EXIT_SYS, &cleanup, "write resolve file of: ", system, "/", clone) ; + + resolve_free(wres) ; + + log_info("Cloned successfully: ", info->treename.s, " to: ", clone) ; +} + +int ssexec_tree(int argc, char const *const *argv, char const *const *envp, ssexec_t *info) +{ + int r ; + + stralloc sa = STRALLOC_ZERO ; + graph_t graph = GRAPH_ZERO ; + + tree_what_t what = what_init() ; + + { + subgetopt l = SUBGETOPT_ZERO ; + + for (;;) + { + int opt = getopt_args(argc,argv, ">" OPTS_TREE, &l) ; + if (opt == -1) break ; + if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; + + switch (opt) + { + case 'c' : + + what.current = 1 ; + what.nopts++ ; + break ; + + case 'o' : + + if (!auto_stra(&sa, l.arg)) + log_die_nomem("stralloc") ; + what.nopts++ ; + break ; + + case 'E' : + + what.enable = 1 ; + what.nopts++ ; + break ; + + case 'D' : + + what.disable = 1 ; + what.nopts++ ; + break ; + + case 'R' : + + what.remove = 1 ; + what.create = 0 ; + what.nopts++ ; + break ; + + case 'n': + + log_1_warn("deprecated option -n -- creation of a tree is the default option") ; + break ; + + case 'a' : + + log_1_warn("deprecated option -a -- see allow field at -o options") ; + break ; + + case 'd' : + + log_1_warn("deprecated option -d -- see allow field at -o options") ; + break ; + + case 'C' : + + log_1_warn("deprecated option -C -- see clone field at -o options") ; + break ; + + case 'S' : + + log_1_warn("deprecated option -S -- see depends/requiredb fields at -o options") ; + break ; + + default : + + log_usage(usage_tree) ; } + } + argc -= l.ind ; argv += l.ind ; + } - } else { + if (argc < 1) log_usage(usage_tree) ; + + check_identifier(argv[0]) ; + + info->treename.len = 0 ; + if (!auto_stra(&info->treename, argv[0])) + log_die_nomem("stralloc") ; + + sanitize_system(info) ; - if (!auto_stra(&contents,tree,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; + r = tree_isvalid(info->base.s, info->treename.s) ; + if (r < 0) + log_diesys(LOG_EXIT_SYS, "invalid tree directory") ; + + info->tree.len = 0 ; + if (!auto_stra(&info->tree, info->base.s, SS_SYSTEM, "/", info->treename.s)) + log_die_nomem("stralloc") ; + + tree_parse_options(&graph, sa.s, info, &what) ; + + /** create is the option by default + * mark it false if the tree already exist */ + if (r) { + if (!what.nopts) { + log_1_warn(info->treename.s, ": already exist") ; + goto freed ; } + what.create = 0 ; + } - if (!file_write_unsafe(ste,SS_STATE + 1,contents.s,contents.len)) - log_dieusys(LOG_EXIT_ZERO,"write: ",ste,SS_STATE) ; + if(!r && what.create) + tree_create(&graph, info, &what, envp) ; - log_info("Ordered successfully: ",tree," starts after tree: ",after_tree) ; + if (!r && what.remove) + log_dieusys(LOG_EXIT_SYS,"find tree: ", info->treename.s) ; + + if (!graph_build(&graph, info->base.s, info->treename.s, DATA_TREE)) + log_dieu(LOG_EXIT_SYS,"build the graph") ; + + if (what.remove) { + tree_remove(&graph, info->base.s, info->treename.s) ; + goto freed ; } - stralloc_free(&clone) ; - stralloc_free(&TREE_SAOPTS) ; - graph_free_all(&GRAPH) ; - tree_seed_free(); + /** groups influence on enable. Apply it first */ + if (what.groups) + tree_groups(info->base.s, info->treename.s, what.gr) ; + + if (what.depends) { + + tree_depends_requiredby(&graph, info->base.s, info->treename.s, 0, what.ndepends, 0) ; + + tree_depends_requiredby_deps(&graph, info->base.s, info->treename.s, 0, what.ndepends, 0) ; + } + + if (what.requiredby) { + + tree_depends_requiredby(&graph, info->base.s, info->treename.s, 1, what.nrequiredby, 0) ; + + tree_depends_requiredby_deps(&graph, info->base.s, info->treename.s, 1, what.nrequiredby, 0) ; + } + + if (what.enable) + tree_enable_disable(&graph, info->base.s, info->treename.s, 1) ; + + if (what.disable) + tree_enable_disable(&graph, info->base.s, info->treename.s, 0) ; + + if (what.allow) + tree_rules(info->base.s, info->treename.s, what.auids, 1) ; + + if (what.deny) + tree_rules(info->base.s, info->treename.s, what.duids, 0) ; + + if (what.current) + tree_current(info) ; + + if (what.clone) + tree_clone(what.sclone, info) ; + + freed: + stralloc_free(&sa) ; + graph_free_all(&graph) ; return 0 ; }