From 290d1b2bd03adb0af3cc513d11bbe05e288859ca Mon Sep 17 00:00:00 2001 From: obarun <eric@obarun.org> Date: Fri, 27 Jan 2023 12:59:31 +1100 Subject: [PATCH] follow workflow of svctl tool --- src/lib66/exec/ssexec_all.c | 932 +++++++++++++++++++--------------- src/lib66/exec/ssexec_start.c | 3 +- 2 files changed, 513 insertions(+), 422 deletions(-) diff --git a/src/lib66/exec/ssexec_all.c b/src/lib66/exec/ssexec_all.c index 057ccbee..653172fd 100644 --- a/src/lib66/exec/ssexec_all.c +++ b/src/lib66/exec/ssexec_all.c @@ -42,11 +42,10 @@ #include <66/ssexec.h> #include <66/constants.h> #include <66/tree.h> -#include <66/utils.h>//scandir_ok -#include <66/db.h> +#include <66/svc.h>//scandir_ok +#include <66/utils.h> #include <66/graph.h> -#include <s6-rc/s6rc-servicedir.h> #include <s6/ftrigr.h> #include <s6/ftrigw.h> @@ -58,18 +57,29 @@ #define FLAGS_UNBLOCK (1 << 5) // 32 all deps up/down #define FLAGS_FATAL (1 << 6) // 64 process crashed -typedef struct pidvertex_s pidvertex_t, *pidvertex_t_ref ; -struct pidvertex_s +static unsigned int napid = 0 ; +static unsigned int npid = 0 ; + +static resolve_tree_t_ref pares = 0 ; +static unsigned int *pareslen = 0 ; +static uint8_t reloadmsg = 0 ; + +typedef struct pidtree_s pidtree_t, *pidtree_t_ref ; +struct pidtree_s { + int pipe[2] ; pid_t pid ; - uint16_t ids ; - char *eventdir ; + int aresid ; // id at array ares unsigned int vertex ; // id at graph_hash_t struct uint8_t state ; int nedge ; - unsigned int *edge ; // array of id at graph_hash_t struct + unsigned int edge[SS_MAX_SERVICE + 1] ; // array of id at graph_hash_t struct + int nnotif ; + /** id at graph_hash_t struct of depends/requiredby service + * to notify when a tree is started/stopped */ + unsigned int notif[SS_MAX_SERVICE + 1] ; } ; -#define PIDINDEX_ZERO { 0, 0, 0, 0, 0, 0 } +#define PIDTREE_ZERO { { -1, -1 }, -1, -1, 0, 0, 0, { 0 } } typedef enum fifo_e fifo_t, *fifo_t_ref ; enum fifo_e @@ -86,20 +96,20 @@ enum fifo_e typedef enum tree_action_e tree_action_t, *tree_action_t_ref ; enum tree_action_e { - GOTIT = 0, - WAIT, - FATAL, - UNKNOWN + TREE_ACTION_GOTIT = 0, + TREE_ACTION_WAIT, + TREE_ACTION_FATAL, + TREE_ACTION_UNKNOWN } ; static const unsigned char actions[2][7] = { // u U d D F b B - { WAIT, GOTIT, UNKNOWN, UNKNOWN, FATAL, WAIT, GOTIT }, // !what -> up - { UNKNOWN, UNKNOWN, WAIT, GOTIT, FATAL, WAIT, GOTIT } // what -> down + { TREE_ACTION_WAIT, TREE_ACTION_GOTIT, TREE_ACTION_UNKNOWN, TREE_ACTION_UNKNOWN, TREE_ACTION_FATAL, TREE_ACTION_WAIT, TREE_ACTION_WAIT }, // !what -> up + { TREE_ACTION_UNKNOWN, TREE_ACTION_UNKNOWN, TREE_ACTION_WAIT, TREE_ACTION_GOTIT, TREE_ACTION_FATAL, TREE_ACTION_WAIT, TREE_ACTION_WAIT } // what -> down } ; -// convert signal receive into enum number +// convert signal into enum number static const unsigned int char2enum[128] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //8 @@ -120,15 +130,6 @@ static const unsigned int char2enum[128] = 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 //128 } ; -static unsigned int napid = 0 ; -static unsigned int npid = 0 ; -static ftrigr_t FIFO = FTRIGR_ZERO ; -static int flag ; -static int flag_run ; - -static int async(pidvertex_t *apidv, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, tain *deadline) ; -static int unsupervise(ssexec_t *info, int what) ; - static inline unsigned int lookup (char const *const *table, char const *signal) { log_flow() ; @@ -180,282 +181,154 @@ static void all_redir_fd(void) umask(022) ; } -static int doit(ssexec_t *info, char const *treename, unsigned int what) +void tree_resolve_array_free(resolve_tree_t *ares, unsigned int areslen) { - log_flow() ; - - int r, e = 0 ; - - { - info->treename.len = 0 ; - - if (!auto_stra(&info->treename, treename)) - log_die_nomem("stralloc") ; - - info->tree.len = 0 ; - - if (!auto_stra(&info->tree, treename)) - log_die_nomem("stralloc") ; - - r = tree_sethome(info) ; - if (r <= 0) - log_warnu_return(LOG_EXIT_ZERO, "find tree: ", info->treename.s) ; - - if (!tree_get_permissions(info->tree.s, info->owner)) - log_warn_return(LOG_EXIT_ZERO, "You're not allowed to use the tree: ", info->tree.s) ; - - } - - if (!tree_isinitialized(info->base.s, info->treename.s) && !what) { - - if (!what) { - - int nargc = 3 ; - char const *newargv[nargc] ; - unsigned int m = 0 ; - - newargv[m++] = "fake_name" ; - newargv[m++] = "b" ; - newargv[m++] = 0 ; - - if (ssexec_init(nargc, newargv, (char const *const *)environ, info)) - log_warnu_return(LOG_EXIT_ZERO, "initiate services of tree: ", info->treename.s) ; - - log_trace("reload scandir: ", info->scandir.s) ; - if (scandir_send_signal(info->scandir.s, "h") <= 0) - log_warnu_return(LOG_EXIT_ZERO, "reload scandir: ", info->scandir.s) ; - - } else { - - log_warn ("uninitialized tree: ", info->treename.s) ; - goto end ; - } - } - - if (what == 2) { - - if (unsupervise(info, what)) - goto err ; - - } else { - - char const *exclude[1] = { 0 } ; - char ownerstr[UID_FMT] ; - size_t ownerlen = uid_fmt(ownerstr, info->owner) ; - ownerstr[ownerlen] = 0 ; - - stralloc salist = STRALLOC_ZERO ; - - char src[info->live.len + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len + 1] ; - - auto_strings(src, info->live.s, SS_STATE + 1, "/", ownerstr, "/", info->treename.s) ; - if (!sastr_dir_get(&salist, src, exclude, S_IFREG)) - log_warnusys_return(LOG_EXIT_ONE, "get contents of directory: ", src) ; + unsigned int pos = 0 ; + for (; pos < areslen ; pos++) + stralloc_free(&ares[pos].sa) ; +} - if (salist.len) { +static inline void kill_all(pidtree_t *apidt) +{ + log_flow() ; - size_t pos = 0, len = sastr_len(&salist) ; - int n = what == 2 ? 3 : 2 ; - int nargc = n + len ; - char const *newargv[nargc] ; - unsigned int m = 0 ; + unsigned int j = napid ; + while (j--) kill(apidt[j].pid, SIGKILL) ; +} - newargv[m++] = "fake_name" ; - if (what == 2) - newargv[m++] = "-u" ; +static pidtree_t pidtree_init(unsigned int len) +{ + log_flow() ; - FOREACH_SASTR(&salist, pos) - newargv[m++] = salist.s + pos ; + pidtree_t pids = PIDTREE_ZERO ; - newargv[m++] = 0 ; + if (len > SS_MAX_SERVICE) + log_die(LOG_EXIT_SYS, "too many trees") ; - if (!what) { + graph_array_init_single(pids.edge, len) ; - if (ssexec_start(nargc, newargv, (char const *const *)environ, info)) - goto err ; + return pids ; +} - } else { - if (ssexec_stop(nargc, newargv, (char const *const *)environ, info)) - goto err ; - } +static int pidtree_get_id(pidtree_t *apidt, unsigned int id) +{ + log_flow() ; - } else log_info("Empty tree: ", info->treename.s, " -- nothing to do") ; + unsigned int pos = 0 ; - stralloc_free(&salist) ; + for (; pos < napid ; pos++) { + if (apidt[pos].vertex == id) + return (unsigned int) pos ; } - - end: - e = 1 ; - err: - return e ; + return -1 ; } -static int unsupervise(ssexec_t *info, int what) + +static void notify(pidtree_t *apidt, unsigned int pos, char const *sig, unsigned int what) { log_flow() ; - size_t newlen = info->livetree.len + 1, pos = 0 ; - char const *exclude[1] = { 0 } ; - - char ownerstr[UID_FMT] ; - size_t ownerlen = uid_fmt(ownerstr, info->owner) ; - ownerstr[ownerlen] = 0 ; - - stralloc salist = STRALLOC_ZERO ; - - /** set what we need */ - char prefix[info->treename.len + 2] ; - auto_strings(prefix, info->treename.s, "-") ; + unsigned int i = 0, idx = 0 ; + char fmt[UINT_FMT] ; + uint8_t flag = what ? FLAGS_DOWN : FLAGS_UP ; - char livestate[info->live.len + SS_STATE_LEN + 1 + ownerlen + 1 + info->treename.len + 1] ; - auto_strings(livestate, info->live.s, SS_STATE + 1, "/", ownerstr, "/", info->treename.s) ; + for (; i < apidt[pos].nnotif ; i++) { - /** bring down service */ - if (doit(info, info->treename.s, what)) - log_warnusys("stop services") ; + for (idx = 0 ; idx < napid ; idx++) { - if (db_find_compiled_state(info->livetree.s, info->treename.s) >=0) { + if (apidt[pos].notif[i] == apidt[idx].vertex && !FLAGS_ISSET(apidt[idx].state, flag)) { - salist.len = 0 ; - char livetree[newlen + info->treename.len + SS_SVDIRS_LEN + 1] ; - auto_strings(livetree, info->livetree.s, "/", info->treename.s, SS_SVDIRS) ; + size_t nlen = uint_fmt(fmt, apidt[pos].aresid) ; + fmt[nlen] = 0 ; + size_t len = nlen + 1 + 2 ; + char s[len + 1] ; + auto_strings(s, fmt, ":", sig, "@") ; - if (!sastr_dir_get(&salist,livetree,exclude,S_IFDIR)) - log_warnusys_return(LOG_EXIT_ONE, "get service list at: ", livetree) ; + log_trace("sends notification ", sig, " to: ", pares[apidt[idx].aresid].sa.s + pares[apidt[idx].aresid].name, " from: ", pares[apidt[pos].aresid].sa.s + pares[apidt[pos].aresid].name) ; - livetree[newlen + info->treename.len] = 0 ; - - pos = 0 ; - FOREACH_SASTR(&salist,pos) { - - s6rc_servicedir_unsupervise(livetree, prefix, salist.s + pos, 0) ; + if (write(apidt[idx].pipe[1], s, strlen(s)) < 0) + log_dieusys(LOG_EXIT_SYS, "send notif to: ", pares[apidt[idx].aresid].sa.s + pares[apidt[idx].aresid].name) ; + } } - - char *realsym = realpath(livetree, 0) ; - if (!realsym) - log_warnusys_return(LOG_EXIT_ONE, "find realpath of: ", livetree) ; - - if (rm_rf(realsym) == -1) - log_warnusys_return(LOG_EXIT_ONE, "remove: ", realsym) ; - - free(realsym) ; - - if (rm_rf(livetree) == -1) - log_warnusys_return(LOG_EXIT_ONE, "remove: ", livetree) ; - - /** remove the symlink itself */ - unlink_void(livetree) ; } - - if (scandir_send_signal(info->scandir.s,"h") <= 0) - log_warnusys_return(LOG_EXIT_ONE, "reload scandir: ", info->scandir.s) ; - - /** remove /run/66/state/uid/treename directory */ - log_trace("delete: ", livestate, "..." ) ; - if (rm_rf(livestate) < 0) - log_warnusys_return(LOG_EXIT_ONE, "delete ", livestate) ; - - log_info("Unsupervised successfully tree: ", info->treename.s) ; - - stralloc_free(&salist) ; - - return 0 ; } -static inline void kill_all(pidvertex_t *apidv) +/** + * @what: up or down + * @success: 0 fail, 1 win + * */ +static void announce(unsigned int pos, pidtree_t *apidt, char const *base, unsigned int what, unsigned int success, unsigned int exitcode) { log_flow() ; - unsigned int j = npid ; - while (j--) kill(apidv[j].pid, SIGKILL) ; -} - -static void announce(pidvertex_t *apidv, unsigned int i, unsigned int what, unsigned int success, graph_t *graph, ssexec_t *info) -{ - log_flow() ; + char fmt[UINT_FMT] ; + char const *treename = pares[apidt[pos].aresid].sa.s + pares[apidt[pos].aresid].name ; resolve_tree_t tres = RESOLVE_TREE_ZERO ; resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ; - char *treename = graph->data.s + genalloc_s(graph_hash_t,&graph->hash)[apidv[i].vertex].vertex ; + uint8_t flag = what ? FLAGS_DOWN : FLAGS_UP ; - if (!resolve_modify_field_g(wres, info->base.s, treename, TREE_ENUM_INIT, what ? (success ? "1" : "0") : (success ? "0" : "1"))) + if (!resolve_modify_field_g(wres, base, treename, E_RESOLVE_TREE_INIT, what ? (success ? "1" : "0") : (success ? "0" : "1"))) log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ; - resolve_free(wres) ; - - log_trace("sends notification ", !success ? (what ? "D" : "U") : "F", " to : ", apidv[i].eventdir) ; - if (ftrigw_notify(apidv[i].eventdir, !success ? (what ? 'D' : 'U') : 'F') < 0) - log_dieusys(LOG_EXIT_SYS, "notifies event directory: ", apidv[i].eventdir) ; + if (success) { -} + notify(apidt, pos, "F", what) ; -static pidvertex_t pidvertex_init(unsigned int len) -{ - log_flow() ; + fmt[uint_fmt(fmt, exitcode)] = 0 ; - pidvertex_t pidv = PIDINDEX_ZERO ; + log_1_warnu(reloadmsg == 0 ? "start" : reloadmsg > 1 ? "unsupervise" : what == 0 ? "start" : "stop", " tree: ", treename, " -- exited with signal: ", fmt) ; - pidv.edge = (unsigned int *)malloc(len*sizeof(unsigned int)) ; + FLAGS_SET(apidt[pos].state, FLAGS_BLOCK|FLAGS_FATAL) ; - graph_array_init_single(pidv.edge, len) ; - - return pidv ; -} + } else { -static void pidvertex_free(pidvertex_t *pidv) -{ - log_flow() ; + notify(apidt, pos, what ? "D" : "U", what) ; - free(pidv->edge) ; - free(pidv->eventdir) ; -} + FLAGS_CLEAR(apidt[pos].state, FLAGS_BLOCK) ; + FLAGS_SET(apidt[pos].state, flag|FLAGS_UNBLOCK) ; -static void pidvertex_array_free(pidvertex_t *apidv, unsigned int len) -{ - log_flow() ; + log_info("Successfully ", reloadmsg == 0 ? "started" : reloadmsg > 1 ? "unsupervised" : what == 0 ? "started" : "stopped", " tree: ", treename) ; + } - size_t pos = 0 ; + resolve_free(wres) ; - for(; pos < len ; pos++) - pidvertex_free(&apidv[pos]) ; } -static void pidvertex_init_array(pidvertex_t *apidv, graph_t *g, unsigned int *list, unsigned int count, ssexec_t *info, uint8_t requiredby) +static void pidtree_init_array(unsigned int *list, unsigned int listlen, pidtree_t *apidt, graph_t *g, resolve_tree_t *ares, unsigned int areslen, ssexec_t *info, uint8_t requiredby) { log_flow() ; - int r = -1 ; - size_t pos = 0 ; + int r = 0 ; + unsigned int pos = 0 ; - char ownerstr[UID_FMT] ; - size_t ownerlen = uid_fmt(ownerstr, info->owner) ; - ownerstr[ownerlen] = 0 ; + for (; pos < listlen ; pos++) { - for (; pos < count ; pos++) { + pidtree_t pids = pidtree_init(g->mlen) ; char *name = g->data.s + genalloc_s(graph_hash_t,&g->hash)[list[pos]].vertex ; - size_t eventlen = info->live.len + SS_STATE_LEN + 1 + ownerlen + 1 + strlen(name) + SS_ENVDIR_LEN ; - - char event[eventlen + 1] ; + pids.aresid = tree_resolve_array_search(ares, areslen, name) ; - pidvertex_t pidv = pidvertex_init(g->mlen) ; + if (pids.aresid < 0) + log_dieu(LOG_EXIT_SYS,"find ares id of: ", name, " -- please make a bug reports") ; - auto_strings(event, info->live.s, SS_STATE + 1, "/", ownerstr, "/", name, SS_EVENTDIR) ; + pids.nedge = graph_matrix_get_edge_g_sorted_list(pids.edge, g, name, requiredby, 1) ; - pidv.eventdir = strdup(event) ; + if (pids.nedge < 0) + log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", name) ; - pidv.nedge = graph_matrix_get_edge_g_sorted_list(pidv.edge, g, name, requiredby) ; + pids.nnotif = graph_matrix_get_edge_g_sorted_list(pids.notif, g, name, !requiredby, 1) ; - if (pidv.nedge < 0) - log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", name) ; + if (pids.nnotif < 0) + log_dieu(LOG_EXIT_SYS,"get sorted ", !requiredby ? "required by" : "dependency", " list of tree: ", name) ; - pidv.vertex = list[pos] ; + pids.vertex = graph_hash_vertex_get_id(g, name) ; - if (pidv.vertex < 0) + if (pids.vertex < 0) log_dieu(LOG_EXIT_SYS, "get vertex id -- please make a bug report") ; r = tree_isinitialized(info->base.s, name) ; @@ -464,64 +337,19 @@ static void pidvertex_init_array(pidvertex_t *apidv, graph_t *g, unsigned int *l log_dieu(LOG_EXIT_SYS, "read resolve file of tree: ", name) ; if (r) - FLAGS_SET(pidv.state, FLAGS_UP) ; + FLAGS_SET(pids.state, FLAGS_UP) ; else - FLAGS_SET(pidv.state, FLAGS_DOWN) ; + FLAGS_SET(pids.state, FLAGS_DOWN) ; - apidv[pos] = pidv ; + apidt[pos] = pids ; } } -static int pidvertex_get_id(pidvertex_t *apidv, unsigned int id) +static int handle_signal(pidtree_t *apidt, unsigned int what, graph_t *graph, ssexec_t *info) { log_flow() ; - unsigned int pos = 0 ; - - for (; pos < napid ; pos++) { - if (apidv[pos].vertex == id) - return (unsigned int) pos ; - } - return -1 ; -} - -static void pidvertex_init_fifo(pidvertex_t *apidv, graph_t *graph, ssexec_t *info, tain *deadline) -{ - log_flow() ; - - unsigned int pos = 0 ; - gid_t gid ; - - if (!yourgid(&gid,info->owner)) - log_dieusys(LOG_EXIT_SYS, "get gid") ; - - if (!ftrigr_startf_g(&FIFO, deadline)) - log_dieusys(LOG_EXIT_SYS, "ftrigr_startf") ; - - for (; pos < napid ; pos++) { - - if (!dir_create_parent(apidv[pos].eventdir, 0700)) - log_dieusys(LOG_EXIT_SYS, "create directory: ", apidv[pos].eventdir) ; - - if (!ftrigw_fifodir_make(apidv[pos].eventdir, gid, 0)) - log_dieusys(LOG_EXIT_SYS, "make fifo directory: ", apidv[pos].eventdir) ; - - /** may already exist, cleans it */ - if (!ftrigw_clean(apidv[pos].eventdir)) - log_dieusys(LOG_EXIT_SYS, "clean fifo directory: ", apidv[pos].eventdir) ; - - apidv[pos].ids = ftrigr_subscribe_g(&FIFO, apidv[pos].eventdir, "[uUdDFbB]", FTRIGR_REPEAT, deadline) ; - - if (!apidv[pos].ids) - log_dieusys(LOG_EXIT_SYS, "subcribe to events for: ", apidv[pos].eventdir) ; - } -} - -static int handle_signal(pidvertex_t *apidv, unsigned int what, graph_t *graph, ssexec_t *info) -{ - log_flow() ; - - int ok = 1 ; + int ok = 0 ; for (;;) { @@ -547,21 +375,23 @@ static int handle_signal(pidvertex_t *apidv, unsigned int what, graph_t *graph, } else if (!r) break ; - for (; pos < napid ; pos++) - if (apidv[pos].pid == r) + if (apidt[pos].pid == r) break ; if (pos < napid) { if (!WIFSIGNALED(wstat) && !WEXITSTATUS(wstat)) { - announce(apidv, pos, what, 0, graph, info) ; + announce(pos, apidt, info->base.s, what, 0, 0) ; } else { - ok = 0 ; - announce(apidv, pos, what, 1, graph, info) ; + ok = WIFSIGNALED(wstat) ? WTERMSIG(wstat) : WEXITSTATUS(wstat) ; + announce(pos, apidt, info->base.s, what, 1, ok) ; + + kill_all(apidt) ; + break ; } npid-- ; @@ -569,9 +399,11 @@ static int handle_signal(pidvertex_t *apidv, unsigned int what, graph_t *graph, } break ; case SIGTERM : + case SIGKILL : case SIGINT : - log_1_warn("received SIGINT, aborting tree transition") ; - kill_all(apidv) ; + log_1_warn("received SIGINT, aborting transaction") ; + kill_all(apidt) ; + ok = 111 ; break ; default : log_die(LOG_EXIT_SYS, "unexpected data in selfpipe") ; } @@ -580,142 +412,325 @@ static int handle_signal(pidvertex_t *apidv, unsigned int what, graph_t *graph, return ok ; } -static int async_deps(pidvertex_t *apidv, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, tain *deadline) +/** this following function come from: + * https://git.skarnet.org/cgi-bin/cgit.cgi/s6-rc/tree/src/s6-rc/s6-rc.c#n111 + * under license ISC where parameters was modified */ +static uint32_t compute_timeout (uint32_t timeout, tain *deadline) +{ + uint32_t t = timeout ; + int globalt ; + tain globaltto ; + tain_sub(&globaltto, deadline, &STAMP) ; + globalt = tain_to_millisecs(&globaltto) ; + if (!globalt) globalt = 1 ; + if (globalt > 0 && (!t || (unsigned int)globalt < t)) + t = (uint32_t)globalt ; + return t ; +} + +static int ssexec_callback(stralloc *sa, ssexec_t *info, unsigned int what) +{ + size_t pos = 0, len = sastr_len(sa), e = 1 ; + + int n = what == 2 ? 2 : 1 ; + int nargc = n + len ; + char const *prog = PROG ; + char const *newargv[nargc] ; + unsigned int m = 0 ; + + newargv[m++] = "all" ; + if (what == 2) + newargv[m++] = "-u" ; + + FOREACH_SASTR(sa, pos) + newargv[m++] = sa->s + pos ; + + newargv[m] = 0 ; + + if (!what) { + + PROG = "start" ; + e = ssexec_start(nargc, newargv, info) ; + PROG = prog ; + + } else { + + PROG = "stop" ; + e = ssexec_stop(nargc, newargv, info) ; + PROG = prog ; + } + + return e ; +} + +static int doit(char const *treename, ssexec_t *sinfo, unsigned int what, tain *deadline) { log_flow() ; - int e = 0, r ; - unsigned int pos = 0 ; + int r, e = 0 ; + ssexec_t info = SSEXEC_ZERO ; - iopause_fd x = { .fd = ftrigr_fd(&FIFO), .events = IOPAUSE_READ } ; - stralloc sa = STRALLOC_ZERO ; + ssexec_copy(&info, sinfo) ; - while (apidv[i].nedge) { + { + info.treename.len = 0 ; - /** TODO: the pidvertex_get_id() function make a loop - * through the apidv array to find the corresponding - * index of the edge at the apidv array. - * This is clearly a waste of time and should be optimized. */ - unsigned int id = pidvertex_get_id(apidv, apidv[i].edge[pos]) ; + if (!auto_stra(&info.treename, treename)) + log_die_nomem("stralloc") ; - if (id < 0) - log_dieu(LOG_EXIT_SYS, "get apidvertex id -- please make a bug report") ; + info.tree.len = 0 ; + + if (!auto_stra(&info.tree, treename)) + log_die_nomem("stralloc") ; + + r = tree_sethome(&info) ; + if (r <= 0) + log_warnu_return(LOG_EXIT_ZERO, "find tree: ", info.treename.s) ; + + if (!tree_get_permissions(info.tree.s, info.owner)) + log_warn_return(LOG_EXIT_ZERO, "You're not allowed to use the tree: ", info.tree.s) ; + + } + + if (!tree_isinitialized(info.base.s, info.treename.s) && !what) { + + if (!what) { + + int nargc = 3 ; + char const *prog = PROG ; + char const *newargv[nargc] ; + unsigned int m = 0 ; + + newargv[m++] = "all (child)" ; + newargv[m++] = info.treename.s ; + newargv[m++] = 0 ; + + PROG = "init" ; + if (ssexec_init(nargc, newargv, &info)) + log_warnu_return(LOG_EXIT_ZERO, "initiate services of tree: ", info.treename.s) ; + PROG = prog ; + + } else { + + log_warn ("uninitialized tree: ", info.treename.s) ; + goto end ; + } + } + + { + stralloc sa = STRALLOC_ZERO ; + char const *exclude[2] = { SS_MASTER + 1 , 0 } ; + size_t treelen = info.tree.len + SS_SVDIRS_LEN + SS_RESOLVE_LEN ; + char tree[treelen + 1] ; + + auto_strings(tree, info.tree.s, SS_SVDIRS, SS_RESOLVE) ; + + if (!sastr_dir_get(&sa, tree, exclude, S_IFREG)) + log_dieu(LOG_EXIT_SYS, "get services list from tree: ", info.treename.s) ; + + if (!sa.len) { + + log_info("Empty tree: ", info.treename.s, " -- nothing to do") ; + + } else { + + if (!ssexec_callback(&sa, &info, what)) + goto err ; + + if (what == 2) + log_info("Unsupervised successfully tree: ", info.treename.s) ; + } + + stralloc_free(&sa) ; + } + end: + e = 1 ; + err: + ssexec_free(&info) ; + return e ; +} + +static int check_action(pidtree_t *apidt, unsigned int pos, unsigned int receive, unsigned int what) +{ + unsigned int p = char2enum[receive] ; + unsigned char action = actions[what][p] ; + + switch(action) { + + case TREE_ACTION_GOTIT: + FLAGS_SET(apidt[pos].state, (!what ? FLAGS_UP : FLAGS_DOWN)) ; + return 1 ; + + case TREE_ACTION_FATAL: + FLAGS_SET(apidt[pos].state, FLAGS_FATAL) ; + return -1 ; + + case TREE_ACTION_WAIT: + return 0 ; + + case TREE_ACTION_UNKNOWN: + default: + log_die(LOG_EXIT_ZERO,"invalid action -- please make a bug report") ; + } + +} + +static int async_deps(pidtree_t *apidt, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, tain *deadline) +{ + log_flow() ; + + int r ; + unsigned int pos = 0, id = 0, ilog = 0, idx = 0 ; + char buf[(UINT_FMT*2)*SS_MAX_SERVICE + 1] ; + + tain dead ; + tain_now_set_stopwatch_g() ; + tain_add_g(&dead, deadline) ; + + iopause_fd x = { .fd = apidt[i].pipe[0], .events = IOPAUSE_READ, 0 } ; + + unsigned int n = apidt[i].nedge ; + unsigned int visit[n] ; + + graph_array_init_single(visit, n) ; + + while (pos < n) { + + r = iopause_g(&x, 1, &dead) ; - r = iopause_g(&x, 1, deadline) ; if (r < 0) log_dieusys(LOG_EXIT_SYS, "iopause") ; - if (!r) - log_die(LOG_EXIT_SYS,"time out") ; + + if (!r) { + errno = ETIMEDOUT ; + log_dieusys(LOG_EXIT_SYS,"time out", pares[apidt[i].aresid].sa.s + pares[apidt[i].aresid].name) ; + } if (x.revents & IOPAUSE_READ) { - if (ftrigr_update(&FIFO) < 0) - log_dieusys(LOG_EXIT_SYS, "ftrigr_update") ; + memset(buf, 0, sizeof(buf)) ; + r = read(apidt[i].pipe[0], buf, sizeof(buf)) ; + if (r < 0) + log_dieu(LOG_EXIT_SYS, "read from pipe") ; + buf[r] = 0 ; - for(pos = 0 ; pos < napid ; pos++) { + idx = 0 ; - sa.len = 0 ; - r = ftrigr_checksa(&FIFO, apidv[pos].ids, &sa) ; + while (r != -1) { + /** The buf might contain multiple signal coming + * from the dependencies if they finished before + * the start of this read process. Check every + * signal received.*/ + r = get_len_until(buf + idx, '@') ; if (r < 0) - log_dieusys(LOG_EXIT_SYS, "ftrigr_check") ; - else if (r) { + /* no more signal */ + goto next ; - size_t l = 0 ; + char line[r + 1] ; + memcpy(line, buf + idx, r) ; + line[r] = 0 ; - for (; l < sa.len ; l++) { + idx += r + 1 ; - unsigned int p = char2enum[(unsigned int)sa.s[l]] ; - unsigned char action = actions[what][p] ; + /** + * the received string have the format: + * index_of_the_ares_array_of_the_tree_dependency:signal_receive + * + * typically: + * - 10:D + * - 30:u + * - ... + * + * Split it and check the signal receive.*/ + int sep = get_len_until(line, ':') ; + if (sep < 0) + log_die(LOG_EXIT_SYS, "received bad signal format -- please make a bug report") ; - switch(action) { + unsigned int c = line[sep + 1] ; + char pc[2] = { c, 0 } ; + line[sep] = 0 ; - case GOTIT: - FLAGS_SET(apidv[pos].state, (!what ? FLAGS_UP : FLAGS_DOWN)) ; - goto next ; + if (!uint0_scan(line, &id)) + log_dieusys(LOG_EXIT_SYS, "retrieve service number -- please make a bug report") ; - case FATAL: - FLAGS_SET(apidv[pos].state, FLAGS_FATAL) ; - goto err ; + ilog = id ; - case WAIT: - break ; + log_trace(pares[apidt[i].aresid].sa.s + pares[apidt[i].aresid].name, " acknowledges: ", pc, " from: ", pares[ilog].sa.s + pares[ilog].name) ; - case UNKNOWN: - default: - log_die(LOG_EXIT_ZERO,"invalid action -- please make a bug report") ; - } - } + if (!visit[pos]) { + + id = pidtree_get_id(apidt, id) ; + if (id < 0) + log_dieu(LOG_EXIT_SYS, "get apidtree id -- please make a bug report") ; + + id = check_action(apidt, id, c, what) ; + if (id < 0) + log_die(LOG_EXIT_SYS, "tree dependency: ", pares[ilog].sa.s + pares[ilog].name, " of: ", pares[apidt[i].aresid].sa.s + pares[apidt[i].aresid].name," crashed") ; + + if (!id) + continue ; + + visit[pos++]++ ; } } } next: - apidv[i].nedge-- ; - pos++ ; + } - e = 1 ; - err: - stralloc_free(&sa) ; - return e ; + return 1 ; } -static int async(pidvertex_t *apidv, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, tain *deadline) +static int async(pidtree_t *apidt, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, tain *deadline) { log_flow() ; - int r = 1 ; + int e = 0 ; - char *treename = graph->data.s + genalloc_s(graph_hash_t,&graph->hash)[apidv[i].vertex].vertex ; + char *name = graph->data.s + genalloc_s(graph_hash_t,&graph->hash)[apidt[i].vertex].vertex ; - if (FLAGS_ISSET(apidv[i].state, (!what ? FLAGS_DOWN : FLAGS_UP))) { + log_trace("beginning of the process of: ", name) ; - if (!FLAGS_ISSET(apidv[i].state, FLAGS_BLOCK)) { + if (FLAGS_ISSET(apidt[i].state, (!what ? FLAGS_DOWN : FLAGS_UP))) { - FLAGS_SET(apidv[i].state, FLAGS_BLOCK) ; + if (!FLAGS_ISSET(apidt[i].state, FLAGS_BLOCK)) { - if (apidv[i].nedge) - if (!async_deps(apidv, i, what, info, graph, deadline)) - log_warnu_return(LOG_EXIT_ZERO, !what ? "start" : "stop", " dependencies of tree: ", treename) ; + FLAGS_SET(apidt[i].state, FLAGS_BLOCK) ; - r = doit(info, treename, what) ; + if (apidt[i].nedge) + if (!async_deps(apidt, i, what, info, graph, deadline)) + log_warnu_return(LOG_EXIT_ZERO, !what ? "start" : "stop", " dependencies of tree: ", name) ; - if (r) - log_info("Successfully ", what ? "stopped" : "started", " tree: ", treename) ; - else - log_info("Unable to ", what ? "stop" : "start", " tree: ", treename) ; + e = doit(name, info, what, deadline) ; } else { - log_info("Skipping tree: ", treename, " -- already in ", what ? "stopping" : "starting", " process") ; + log_trace("skipping tree: ", name, " -- already in ", what ? "stopping" : "starting", " process") ; + + notify(apidt, i, what ? "d" : "u", what) ; - log_trace("sends notification ", what ? "d" : "u", " to : ", apidv[i].eventdir) ; - if (ftrigw_notify(apidv[i].eventdir, what ? 'd' : 'u') < 0) - log_warnusys_return(LOG_EXIT_ZERO, "notifies event directory: ", apidv[i].eventdir) ; } } else { - log_info("Skipping tree: ", treename, " -- already ", what ? "down" : "up") ; - - log_trace("sends notification ", what ? "D" : "U", " to : ", apidv[i].eventdir) ; - if (ftrigw_notify(apidv[i].eventdir, what ? 'D' : 'U') < 0) - log_warnusys_return(LOG_EXIT_ZERO, "notifies event directory: ", apidv[i].eventdir) ; + /** do not notify here, the handle will make it for us */ + log_trace("skipping service: ", name, " -- already ", what ? "down" : "up") ; } - return r ; + return e ; } -static int waitit(pidvertex_t *apidv, unsigned int what, graph_t *graph, tain *deadline, ssexec_t *info) +static int waitit(pidtree_t *apidt, unsigned int what, graph_t *graph, tain *deadline, ssexec_t *info) { log_flow() ; - unsigned int e = 1, pos = 0 ; + unsigned int e = 0, pos = 0 ; int r ; pid_t pid ; - pidvertex_t apidvertextable[napid] ; - pidvertex_t_ref apidvertex = apidvertextable ; + pidtree_t apidtreetable[napid] ; + pidtree_t_ref apidtree = apidtreetable ; tain_now_set_stopwatch_g() ; tain_add_g(deadline, deadline) ; @@ -727,16 +742,24 @@ static int waitit(pidvertex_t *apidv, unsigned int what, graph_t *graph, tain *d if (!selfpipe_trap(SIGCHLD) || !selfpipe_trap(SIGINT) || + !selfpipe_trap(SIGKILL) || !selfpipe_trap(SIGTERM) || !sig_altignore(SIGPIPE)) log_dieusys(LOG_EXIT_SYS, "selfpipe_trap") ; - pidvertex_init_fifo(apidv, graph, info, deadline) ; - for (pos = 0 ; pos < napid ; pos++) - apidvertex[pos] = apidv[pos] ; + iopause_fd x = { .fd = spfd, .events = IOPAUSE_READ, .revents = 0 } ; + + for (; pos < napid ; pos++) { + + apidtree[pos] = apidt[pos] ; + + if (pipe(apidtree[pos].pipe) < 0) + log_dieusys(LOG_EXIT_SYS, "pipe"); - for (pos = 0 ; pos < napid ; pos++) { + } + + for (pos = 0 ; pos < napid ; pos++) { pid = fork() ; @@ -744,44 +767,68 @@ static int waitit(pidvertex_t *apidv, unsigned int what, graph_t *graph, tain *d log_dieusys(LOG_EXIT_SYS, "fork") ; if (!pid) { - r = async(apidvertex, pos, what, info, graph, deadline) ; - _exit(!r) ; + + selfpipe_finish() ; + + close(apidtree[pos].pipe[1]) ; + + e = async(apidtree, pos, what, info, graph, deadline) ; + + goto end ; } - apidvertex[pos].pid = pid ; + apidtree[pos].pid = pid ; + + close(apidtree[pos].pipe[0]) ; npid++ ; } - iopause_fd x = { .fd = spfd, .events = IOPAUSE_READ } ; - while (npid) { r = iopause_g(&x, 1, deadline) ; + if (r < 0) log_dieusys(LOG_EXIT_SYS, "iopause") ; - if (!r) - log_die(LOG_EXIT_SYS,"time out") ; - if (x.revents & IOPAUSE_READ) - if (!handle_signal(apidvertex, what, graph, info)) - e = 0 ; + if (!r) { + errno = ETIMEDOUT ; + log_diesys(LOG_EXIT_SYS,"time out") ; + } + + if (x.revents & IOPAUSE_READ) { + e = handle_signal(apidtree, what, graph, info) ; + + if (e) + break ; + } } - ftrigr_end(&FIFO) ; + selfpipe_finish() ; + end: + for (pos = 0 ; pos < napid ; pos++) { + close(apidtree[pos].pipe[1]) ; + close(apidtree[pos].pipe[0]) ; + } - return e ; + return e ; } -int ssexec_all(int argc, char const *const *argv,char const *const *envp, ssexec_t *info) +int ssexec_all(int argc, char const *const *argv, ssexec_t *info) { + log_flow() ; int r, shut = 0, fd ; tain deadline ; - unsigned int what ; + uint8_t what = 0, requiredby = 0, found = 0 ; + stralloc sa = STRALLOC_ZERO ; + size_t pos = 0 ; + + unsigned int areslen = 0, list[SS_MAX_SERVICE], visit[SS_MAX_SERVICE] ; + resolve_tree_t ares[SS_MAX_SERVICE] ; + resolve_wrapper_t_ref wres = 0 ; - uint8_t requiredby = 0 ; graph_t graph = GRAPH_ZERO ; { @@ -789,9 +836,9 @@ int ssexec_all(int argc, char const *const *argv,char const *const *envp, ssexec for (;;) { - int opt = getopt_args(argc,argv, ">" OPTS_ALL, &l) ; + int opt = subgetopt_r(argc, argv, OPTS_ALL, &l) ; if (opt == -1) break ; - if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; + switch (opt) { case 'f' : shut = 1 ; break ; @@ -801,7 +848,15 @@ int ssexec_all(int argc, char const *const *argv,char const *const *envp, ssexec argc -= l.ind ; argv += l.ind ; } - if (argc != 1) log_usage(usage_all) ; + if (argc < 1) + log_usage(usage_all) ; + + info->treename.len = 0 ; + + if (argv[1]) { + if (!auto_stra(&info->treename, argv[1])) + log_die_nomem("stralloc") ; + } if (info->timeout) tain_from_millisecs(&deadline, info->timeout) ; @@ -810,58 +865,86 @@ int ssexec_all(int argc, char const *const *argv,char const *const *envp, ssexec what = parse_signal(*argv) ; - if (what) { + reloadmsg = what ; + if (what) requiredby = 1 ; - FLAGS_SET(flag, FLAGS_UP) ; - FLAGS_SET(flag_run, FLAGS_STOPPING) ; - } else { + if ((svc_scandir_ok(info->scandir.s)) <= 0) + log_die(LOG_EXIT_SYS,"scandir: ", info->scandir.s," is not running") ; - FLAGS_SET(flag, FLAGS_DOWN) ; - FLAGS_SET(flag_run, FLAGS_STARTING) ; - } + graph_build_tree(&graph, info->base.s, E_RESOLVE_TREE_MASTER_ENABLED) ; - if ((scandir_ok(info->scandir.s)) <= 0) - log_die(LOG_EXIT_SYS,"scandir: ", info->scandir.s," is not running") ; + if (!graph.mlen) + log_die(LOG_EXIT_USER, "trees selection is not created -- creates its first") ; - if (!graph_build_g(&graph, info->base.s, 0, DATA_TREE, 0)) - log_dieu(LOG_EXIT_SYS,"build the graph") ; + graph_array_init_single(visit, SS_MAX_SERVICE) ; - /** initialize and allocate apidvertex array */ + if (!graph_matrix_sort_tosa(&sa, &graph)) + log_dieu(LOG_EXIT_SYS, "get list of trees for graph -- please make a bug report") ; - pidvertex_t apidv[graph.mlen] ; + FOREACH_SASTR(&sa, pos) { - /** only on tree */ - if (info->treename.len) { + char *treename = sa.s + pos ; - unsigned int *alist ; + /** only on tree */ + if (info->treename.len) { - alist = (unsigned int *)malloc(graph.mlen*sizeof(unsigned int)) ; + if (!strcmp(info->treename.s, treename)) + found = 1 ; + else continue ; + } - graph_array_init_single(alist, graph.mlen) ; + if (tree_resolve_array_search(ares, areslen, treename) < 0) { - napid = graph_matrix_get_edge_g_sorted_list(alist, &graph, info->treename.s, requiredby) ; + resolve_tree_t tres = RESOLVE_TREE_ZERO ; + /** need to make a copy of the resolve due of the freed + * of the wres struct at the end of the process */ + resolve_tree_t cp = RESOLVE_TREE_ZERO ; + wres = resolve_set_struct(DATA_TREE, &tres) ; - if (napid < 0) - log_dieu(LOG_EXIT_SYS, "get ", requiredby ? "required" : "dependencies", " sorted list of: ", info->treename.s) ; + if (!resolve_read_g(wres, info->base.s, treename)) + log_dieu(LOG_EXIT_SYS, "read resolve file of: ", treename, " -- please make a bug report") ; - alist[napid++] = (unsigned int)graph_hash_vertex_get_id(&graph, info->treename.s) ; + tree_resolve_copy(&cp, &tres) ; - pidvertex_init_array(apidv, &graph, alist, napid, info, requiredby) ; + ares[areslen++] = cp ; - free(alist) ; + resolve_free(wres) ; + } - } else { + unsigned int l[graph.mlen], c = 0, pos = 0, idx = 0 ; + + idx = graph_hash_vertex_get_id(&graph, treename) ; - napid = graph.sort_count ; + if (!visit[idx]) { + /** avoid double entry */ + list[napid++] = idx ; + visit[idx] = 1 ; + + } - if (requiredby) - graph_matrix_sort_reverse(&graph) ; + /** find dependencies of the tree from the graph, do it recursively */ + c = graph_matrix_get_edge_g_sorted_list(l, &graph, treename, requiredby, 1) ; - pidvertex_init_array(apidv, &graph, graph.sort, graph.sort_count, info, requiredby) ; + /** append to the list to deal with */ + for (; pos < c ; pos++) { + if (!visit[l[pos]]) { + list[napid++] = l[pos] ; + visit[l[pos]] = 1 ; + } + } + if (found) + break ; } + pidtree_t apidt[graph.mlen] ; + + pares = ares ; + pareslen = &areslen ; + + pidtree_init_array(list, napid, apidt, &graph, ares, areslen, info, requiredby) ; + if (shut) { pid_t pid ; @@ -890,7 +973,13 @@ int ssexec_all(int argc, char const *const *argv,char const *const *envp, ssexec } } - r = waitit(apidv, what, &graph, &deadline, info) ; + if (!areslen) { + log_warn("empty trees -- nothing to do") ; + r = 0 ; + goto end ; + } + + r = waitit(apidt, what, &graph, &deadline, info) ; end: @@ -907,7 +996,8 @@ int ssexec_all(int argc, char const *const *argv,char const *const *envp, ssexec } graph_free_all(&graph) ; - pidvertex_array_free(apidv, napid) ; + stralloc_free(&sa) ; + tree_resolve_array_free(ares, areslen) ; - return (!r) ? 111 : 0 ; + return r ; } diff --git a/src/lib66/exec/ssexec_start.c b/src/lib66/exec/ssexec_start.c index e2fb1523..7268b8ce 100644 --- a/src/lib66/exec/ssexec_start.c +++ b/src/lib66/exec/ssexec_start.c @@ -36,7 +36,8 @@ int ssexec_start(int argc, char const *const *argv, ssexec_t *info) graph_t graph = GRAPH_ZERO ; uint8_t siglen = 3 ; - unsigned int areslen = 0, list[SS_MAX_SERVICE], visit[SS_MAX_SERVICE], nservice = 0, n = 0 ; + int n = 0 ; + unsigned int areslen = 0, list[SS_MAX_SERVICE], visit[SS_MAX_SERVICE], nservice = 0 ; resolve_service_t ares[SS_MAX_SERVICE] ; FLAGS_SET(flag, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_TOINIT|STATE_FLAGS_WANTUP) ; -- GitLab