diff --git a/src/lib66/exec/ssexec_svctl.c b/src/lib66/exec/ssexec_svctl.c index 60d00e7186d7183edc702e63518d3b42bc18704e..da47413346d706a08a5ed911024f546786d8a9e0 100644 --- a/src/lib66/exec/ssexec_svctl.c +++ b/src/lib66/exec/ssexec_svctl.c @@ -17,12 +17,15 @@ #include <sys/wait.h> #include <signal.h> #include <unistd.h>//access -//#include <stdio.h> -//#include <stdlib.h> +#include <stdlib.h>//malloc, free #include <oblibs/obgetopt.h> #include <oblibs/log.h> +#include <oblibs/types.h> #include <oblibs/string.h> +#include <oblibs/directory.h> +#include <oblibs/graph.h> +#include <oblibs/sastr.h> #include <skalibs/types.h> #include <skalibs/stralloc.h> @@ -32,11 +35,12 @@ #include <skalibs/selfpipe.h> #include <skalibs/iopause.h> #include <skalibs/tai.h> +#include <skalibs/types.h> #include <skalibs/sig.h>//sig_ignore #include <s6/supervise.h>//s6_svstatus_t #include <s6/ftrigr.h> - +#include <s6/ftrigw.h> #include <66/utils.h> #include <66/constants.h> @@ -45,85 +49,86 @@ #include <66/resolve.h> #include <66/state.h> #include <66/service.h> +#include <66/enum.h> +#include <66/graph.h> -unsigned int SV_DEADLINE = 3000 ; -unsigned int DEATHSV = 5 ; -ftrigr_t fifo = FTRIGR_ZERO ; -typedef struct pidindex_s pidindex_t ; -struct pidindex_s -{ - ss_resolve_sig_t_ref sv ; - pid_t pid ; -} ; -static pidindex_t *pidindex ; -static unsigned int npids = 0 ; -static int read_file (char const *file, char *buf, size_t n) -{ - log_flow() ; - ssize_t r = openreadnclose_nb(file, buf, n) ; - if (r < 0) - { - if (errno != ENOENT) - log_warnusys_return(LOG_EXIT_ZERO,"open: ", file) ; - } - buf[byte_chr(buf, r, '\n')] = 0 ; - return 1 ; -} -static int read_uint (char const *file, unsigned int *fd) -{ - log_flow() ; - char buf[UINT_FMT + 1] ; - if (!read_file(file, buf, UINT_FMT)) return 0 ; - if (!uint0_scan(buf, fd)) - log_warn_return(LOG_EXIT_ZERO,"invalid: ", file) ; +#include <stdio.h> - return 1 ; -} -/** @Return 0 on fail - * @Return 1 on success */ -int handle_signal_svc(ss_resolve_sig_t *sv_signal) -{ - log_flow() ; - s6_svstatus_t status = S6_SVSTATUS_ZERO ; - char *sv = sv_signal->res.sa.s + sv_signal->res.runat ; - if (!s6_svstatus_read(sv,&status)) - log_warnusys_return(LOG_EXIT_ZERO,"read status of: ",sv) ; - sv_signal->pid = status.pid ; +#define FLAGS_STARTING 1 // 1 starting not really up +#define FLAGS_STOPPING (1 << 1) // 2 stopping not really down +#define FLAGS_UP (1 << 2) // 4 really up +#define FLAGS_DOWN (1 << 3) // 8 really down +#define FLAGS_BLOCK (1 << 4) // 16 all deps are not up/down +#define FLAGS_UNBLOCK (1 << 5) // 32 all deps are up/down +#define FLAGS_FATAL (1 << 6) // 64 process crashed - if (WIFSIGNALED(status.wstat) && !WEXITSTATUS(status.wstat)) return 1 ;// && (WTERMSIG(status.wstat) == 15 )) return 1 ; - if (!WIFSIGNALED(status.wstat) && !WEXITSTATUS(status.wstat)) return 1 ; - else return 0 ; -} +#define DATASIZE 63 -static unsigned char const svctl_actions[9][9] = +static ftrigr_t FIFO = FTRIGR_ZERO ; +static unsigned int napid = 0 ; +static unsigned int npid = 0 ; + +static resolve_service_t_ref pares = 0 ; +static unsigned int *pareslen = 0 ; +static char updown[4] = "-w \0" ; +static uint8_t opt_updown = 0 ; +static char data[DATASIZE + 1] = "-" ; +static unsigned int datalen = 1 ; +static uint8_t reloadmsg = 0 ; + +typedef struct pidservice_s pidservice_t, *pidservice_t_ref ; +struct pidservice_s { - //signal receive: - // c->u U r/u R/U d D x O s - //signal wanted - { GOTIT, DONE, GOTIT, DONE, DEAD, DEAD, PERM, PERM, UKNOW },// SIGUP - { WAIT, GOTIT, WAIT, GOTIT, DEAD, DEAD, PERM, PERM, UKNOW },// SIGRUP - { DONE, DONE, GOTIT, DONE, WAIT, WAIT, PERM, PERM, UKNOW },// SIGR - { WAIT, GOTIT, WAIT, GOTIT, WAIT, WAIT, PERM, PERM, UKNOW },// SIGRR - { DEAD, DEAD, WAIT, DEAD, GOTIT, DONE, PERM, PERM, UKNOW },// SIGDOWN - { DEAD, DEAD, WAIT, DEAD, WAIT, GOTIT, PERM, PERM, UKNOW },// SIGRDOWN - { DEAD, DEAD, DEAD, DEAD, WAIT, WAIT, DONE, WAIT, DONE },// SIGX - { WAIT, WAIT, WAIT, WAIT, WAIT, WAIT, PERM, GOTIT, UKNOW },// SIGO - { UKNOW, UKNOW, UKNOW, UKNOW, UKNOW, UKNOW, UKNOW, UKNOW, DONE }, // SIGSUP + pid_t pid ; + uint16_t ids ; + 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 +} ; +#define PIDSERVICE_ZERO { 0, 0, -1, 0, 0, 0, 0 } +typedef enum fifo_e fifo_t, *fifo_t_ref ; +enum fifo_e +{ + FIFO_u = 0, + FIFO_U, + FIFO_d, + FIFO_D, + FIFO_F, + FIFO_b, + FIFO_B } ; -// convert signal receive into enum number -static const uint8_t chtenum[128] = +typedef enum service_action_e service_action_t, *service_action_t_ref ; +enum service_action_e +{ + SERVICE_ACTION_GOTIT = 0, + SERVICE_ACTION_WAIT, + SERVICE_ACTION_FATAL, + SERVICE_ACTION_UNKNOWN +} ; + +static const unsigned char actions[2][7] = { + // u U d D F b B + { SERVICE_ACTION_WAIT, SERVICE_ACTION_GOTIT, SERVICE_ACTION_UNKNOWN, SERVICE_ACTION_UNKNOWN, SERVICE_ACTION_FATAL, SERVICE_ACTION_WAIT, SERVICE_ACTION_GOTIT }, // !what -> up + { SERVICE_ACTION_UNKNOWN, SERVICE_ACTION_UNKNOWN, SERVICE_ACTION_WAIT, SERVICE_ACTION_GOTIT, SERVICE_ACTION_FATAL, SERVICE_ACTION_WAIT, SERVICE_ACTION_GOTIT } // what -> down + +} ; + +// convert signal into enum number +static const unsigned int char2enum[128] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //8 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //16 @@ -133,572 +138,801 @@ static const uint8_t chtenum[128] = 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //48 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //56 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //64 - 0 , 0 , 0 , 0 , 5 , 0 , 0 , 0 , //72 - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 7 , //80 - 0 , 0 , 0 , 0 , 0 , 1, 0 , 0 , //88 - 6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //96 - 0 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , //104 + 0 , 0 , FIFO_B , 0 , FIFO_D , 0 , FIFO_F , 0 , //72 + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //80 + 0 , 0 , 0 , 0 , 0 , FIFO_U, 0 , 0 , //88 + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //96 + 0 , 0 , FIFO_b , 0 , FIFO_d , 0 , 0 , 0 , //104 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , //112 - 0 , 0 , 0 , 8 , 0 , 0 , 0 , 0 , //120 - 6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 //128 + 0 , 0 , 0 , 0 , 0 , FIFO_u , 0 , 0 , //120 + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 //128 } ; -/** we use three file more than s6-svc program : - * - * timeout-up and timeout-down will define the deadline for the iopause - * each service contain his deadline into the sv_signal.deadline key. - * If thoses files doesn't exit 3000 millisec is set by default. - * This deadline value can be set on commandline by the -T options. - * max-death-tally - * We let s6-supervise make what it need to do with this file but - * we take the same number to set the sv_signal.death value - * accepted for every daemon before exiting if the SIGNAL is not reached. - * If this file doesn't exist a number of 5 death (death -> number - * of wrong signal received) is set by default. - * This ndeath value can be set on commandline by the -n options. - * - * In all case the loop is broken to avoids infinite iopause - * - * The notication-fd file is used as the original one. If the file - * exist and the SIGNAL is u , we change SIGNAL to U. - */ -/**@Return 0 on success - * @Return 1 on if signal is not complete (e.g. want U receive only u) - * @Return 2 on fail - * @Return 3 for PERMANENT failure */ -int handle_case(stralloc *sa, ss_resolve_sig_t *svc) +static pidservice_t pidservice_init(unsigned int len) { log_flow() ; - int p, h, err ; - unsigned int state, i = 0 ; - state = svc->sig ; + pidservice_t pids = PIDSERVICE_ZERO ; - err = 2 ; + pids.edge = (unsigned int *)malloc(len * sizeof(unsigned int)) ; - for (;i < sa->len ; i++) - { - p = chtenum[(unsigned char)sa->s[i]] ; - unsigned char action = svctl_actions[state][p] ; + graph_array_init_single(pids.edge, len) ; - switch (action) - { - case GOTIT: - h = handle_signal_svc(svc) ; - if (!h) - { - err = 0 ; - break ; - } - return 1 ; - case WAIT: err = 0 ; - break ; - case DEAD: return 2 ; - case DONE: return 1 ; - case PERM: return 3 ; - default: log_warn_return(2,"invalid state, make a bug report") ; - } - } - return err ; + return pids ; } -static void write_state(ss_resolve_sig_t *svc) +static int pidservice_get_id(pidservice_t *apids, unsigned int id) { log_flow() ; - ss_state_t sta = STATE_ZERO ; - char const *state = svc->res.sa.s + svc->res.state ; - char const *sv = svc->res.sa.s + svc->res.name ; - if (svc->sig <= 3) - { - if (svc->state <= 1) - { - state_setflag(&sta,SS_FLAGS_PID,svc->pid) ; - state_setflag(&sta,SS_FLAGS_STATE,SS_FLAGS_TRUE) ; - } - else - { - state_setflag(&sta,SS_FLAGS_PID,SS_FLAGS_FALSE) ; - state_setflag(&sta,SS_FLAGS_STATE,SS_FLAGS_FALSE) ; - } + unsigned int pos = 0 ; + + for (; pos < napid ; pos++) { + if (apids[pos].vertex == id) + return (unsigned int) pos ; } - else - { - if (svc->state <=1) - { - state_setflag(&sta,SS_FLAGS_PID,SS_FLAGS_FALSE) ; - state_setflag(&sta,SS_FLAGS_STATE,SS_FLAGS_FALSE) ; + return -1 ; +} + +static void pidservice_free(pidservice_t *pids) +{ + log_flow() ; + + free(pids->edge) ; +} + +static void pidservice_array_free(pidservice_t *apids, unsigned int len) +{ + log_flow() ; + + size_t pos = 0 ; + + for(; pos < len ; pos++) + pidservice_free(&apids[pos]) ; +} + +static void pidservice_init_array(unsigned int *list, unsigned int listlen, pidservice_t *apids, graph_t *g, resolve_service_t *ares, unsigned int areslen, ssexec_t *info, uint8_t requiredby, uint32_t flag) { + + log_flow() ; + + int r = 0 ; + unsigned int pos = 0 ; + + for (; pos < listlen ; pos++) { + + pidservice_t pids = pidservice_init(g->mlen) ; + + char *name = g->data.s + genalloc_s(graph_hash_t,&g->hash)[list[pos]].vertex ; + + pids.aresid = service_resolve_array_search(ares, areslen, name) ; + + if (pids.aresid < 0) + log_dieu(LOG_EXIT_SYS,"find ares id of: ", name, " -- please make a bug reports") ; + + if (FLAGS_ISSET(flag, STATE_FLAGS_TOPROPAGATE)) { + /** + * This is should be recursive as long as the user ask for the propagation. + * So, call graph_matrix_get_edge_g_sorted_list() with recursive mode. + * This is overkill if we come from other 66 tools. Its call with the complete + * service selection to deal with. + * No choice here, we want a complete 66-svctl independence + * */ + pids.nedge = graph_matrix_get_edge_g_sorted_list(pids.edge, g, name, requiredby, 1) ; + + if (pids.nedge < 0) + log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", name) ; } - else - { - state_setflag(&sta,SS_FLAGS_PID,svc->pid) ; - state_setflag(&sta,SS_FLAGS_STATE,SS_FLAGS_TRUE) ; + + pids.vertex = graph_hash_vertex_get_id(g, name) ; + + if (pids.vertex < 0) + log_dieu(LOG_EXIT_SYS, "get vertex id -- please make a bug report") ; + + if (ares[pids.aresid].type == TYPE_ONESHOT) { + + ss_state_t ste = STATE_ZERO ; + + if (!state_read(&ste, ares[pids.aresid].sa.s + ares[pids.aresid].path.home, name)) + log_dieusys(LOG_EXIT_SYS, "read state file of: ", name) ; + + if (ste.isup == STATE_FLAGS_TRUE) + FLAGS_SET(pids.state, FLAGS_UP) ; + else + FLAGS_SET(pids.state, FLAGS_DOWN) ; + + } else { + + s6_svstatus_t status ; + + r = s6_svstatus_read(ares[pids.aresid].sa.s + ares[pids.aresid].live.scandir, &status) ; + + pid_t pid = !r ? 0 : status.pid ; + + if (pid > 0) { + + FLAGS_SET(pids.state, FLAGS_UP) ; + } + else + FLAGS_SET(pids.state, FLAGS_DOWN) ; } + + apids[pos] = pids ; } - state_setflag(&sta,SS_FLAGS_RELOAD,SS_FLAGS_FALSE) ; - state_setflag(&sta,SS_FLAGS_INIT,SS_FLAGS_FALSE) ; -// state_setflag(&sta,SS_FLAGS_UNSUPERVISE,SS_FLAGS_FALSE) ; - log_trace("Write state file of: ",sv) ; - if (!state_write(&sta,state,sv)) - log_warnusys("write state file of: ",sv) ; } -static int announce(ss_resolve_sig_t *svc) +static void pidservice_init_fifo(pidservice_t *apids, graph_t *graph, ssexec_t *info, unsigned int deadline) { log_flow() ; - int r = svc->state ; - char *sv = svc->res.sa.s + svc->res.name ; - /** special case time out reached or number execeeded, - * last check with s6-svstat framboise*/ - if (r == 0 || r == 4 || r == 5) - { - int e = handle_signal_svc(svc) ; - if (!e){ - if (!r) r = 2 ; - else r = r ; - } - else r = r == 0 ? 0 : 1 ; - svc->state = r ; - } - switch(r) - { - case 0: log_info(sv," is ",(svc->sig > 3) ? "down" : "up"," but not notified by the daemon itself") ; - break ; - case 1: log_info(sv,": ",(svc->sig > 3) ? "stopped" : (svc->sig == 2 || svc->sig == 3) ? "reloaded" : "started"," successfully") ; - break ; - case 2: log_1_warn("unable to ",(svc->sig > 3) ? "stop " : (svc->sig == 2 || svc->sig == 3) ? "reload" : "start ", sv) ; - break ; - case 3: log_1_warn(sv," report permanent failure -- unable to ",(svc->sig > 1) ? "stop" : (svc->sig == 2 || svc->sig == 3) ? "reload" : "start") ; - break ; - case 4: log_1_warn("unable to ",(svc->sig > 3) ? "stop: " : (svc->sig == 2 || svc->sig == 3) ? "reload" : "start: ",sv, ": number of try exceeded") ; - break ; - case 5: log_1_warn("unable to ",(svc->sig > 3) ? "stop: " : (svc->sig == 2 || svc->sig == 3) ? "reload" : "start: ",sv, ": time out reached") ; - break ; - case-1: - default:log_warn("unexpected data in state file of: ",sv," -- please make a bug report") ; - break ; + unsigned int pos = 0 ; + gid_t gid ; + + tain dead ; + tain_from_millisecs(&dead, deadline) ; + tain_now_set_stopwatch_g() ; + tain_add_g(&dead, &dead) ; + + if (!yourgid(&gid, info->owner)) + log_dieusys(LOG_EXIT_SYS, "get gid") ; + + if (!ftrigr_startf_g(&FIFO, &dead)) + log_dieusys(LOG_EXIT_SYS, "ftrigr_startf") ; + + for (; pos < napid ; pos++) { + + char *notifdir = pares[apids[pos].aresid].sa.s + pares[apids[pos].aresid].live.notifdir ; + + if (!dir_create_parent(notifdir, 0700)) + log_dieusys(LOG_EXIT_SYS, "create directory: ", notifdir) ; + + if (!ftrigw_fifodir_make(notifdir, gid, 0)) + log_dieusys(LOG_EXIT_SYS, "make fifo directory: ", notifdir) ; + + /** may already exist, cleans it */ + if (!ftrigw_clean(notifdir)) + log_dieusys(LOG_EXIT_SYS, "clean fifo directory: ", notifdir) ; + + apids[pos].ids = ftrigr_subscribe_g(&FIFO, notifdir, "[uUdDFbB]", FTRIGR_REPEAT, &dead) ; + + if (!apids[pos].ids) + log_dieusys(LOG_EXIT_SYS, "subcribe to: ", notifdir) ; } - return r ; } -static inline void kill_all (void) +static inline void kill_all(pidservice_t *apids) { log_flow() ; - unsigned int j = npids ; - while (j--) kill(pidindex[j].pid, SIGTERM) ; + unsigned int j = napid ; + while (j--) kill(apids[j].pid, SIGKILL) ; } -static int handle_signal_pipe(genalloc *gakeep) +/** + * @what: up or down + * @success: 0 fail, 1 win + * */ +static void announce(pidservice_t *apids, unsigned int what, unsigned int success, unsigned int exitcode) +{ + log_flow() ; + + int fd = 0 ; + char const *notifdir = pares[apids->aresid].sa.s + pares[apids->aresid].live.notifdir ; + char const *name = pares[apids->aresid].sa.s + pares[apids->aresid].name ; + char const *base = pares[apids->aresid].sa.s + pares[apids->aresid].path.home ; + char const *scandir = pares[apids->aresid].sa.s + pares[apids->aresid].live.scandir ; + size_t scandirlen = strlen(scandir) ; + char file[scandirlen + 6] ; + + auto_strings(file, scandir, "/down") ; + + uint8_t flag = what ? FLAGS_DOWN : FLAGS_UP ; + + if (success) { + + FLAGS_SET(apids->state, FLAGS_BLOCK|FLAGS_FATAL) ; + + fd = open_trunc(file) ; + if (fd < 0) + log_dieusys(LOG_EXIT_SYS, "create file: ", scandir) ; + fd_close(fd) ; + + log_trace("sends notification F to: ", notifdir) ; + if (ftrigw_notify(notifdir, 'F') < 0) + log_dieusys(LOG_EXIT_SYS, "notifies event directory: ", notifdir) ; + + char fmt[UINT_FMT] ; + fmt[uint_fmt(fmt, exitcode)] = 0 ; + + log_1_warn("Unable to ", reloadmsg ? "reload" : what ? "stop" : "start", " service: ", name, " -- exited with signal: ", fmt) ; + + + + } else { + + if (!state_messenger(base, name, STATE_FLAGS_ISUP, what ? STATE_FLAGS_FALSE : STATE_FLAGS_TRUE)) + log_dieusys(LOG_EXIT_SYS, "send message to state of: ", name) ; + + FLAGS_SET(apids->state, flag|FLAGS_UNBLOCK) ; + + if (!pares[apids->aresid].execute.down && pares[apids->aresid].type == TYPE_CLASSIC) { + + if (!what) { + + if (!access(scandir, F_OK)) { + log_trace("delete down file: ", file) ; + if (unlink(file) < 0 && errno != ENOENT) + log_warnusys("delete down file: ", file) ; + } + + } else { + + fd = open_trunc(file) ; + if (fd < 0) + log_dieusys(LOG_EXIT_SYS, "create file: ", file) ; + fd_close(fd) ; + } + } + + log_trace("sends notification ", what ? "D" : "U", " to: ", notifdir) ; + if (ftrigw_notify(notifdir, what ? 'D' : 'U') < 0) + log_dieusys(LOG_EXIT_SYS, "notifies event directory: ", notifdir) ; + + log_info("Successfully ", reloadmsg ? "reloaded" : what ? "stopped" : "started", " service: ", name) ; + + } + + tain dead ; + tain_from_millisecs(&dead, 3000) ; + tain_now_set_stopwatch_g() ; + tain_add_g(&dead, &dead) ; + + if (!ftrigr_unsubscribe_g(&FIFO, apids->ids, &dead)) + log_dieusys(LOG_EXIT_SYS, "unsubcribe: ", name) ; +} + +static int handle_signal(pidservice_t *apids, unsigned int what, graph_t *graph, ssexec_t *info) { log_flow() ; int ok = 1 ; - for (;;) - { - switch (selfpipe_read()) - { - case -1 : log_warnusys_return(LOG_EXIT_ZERO,"selfpipe_read") ; - case 0 : goto end ; - case SIGCHLD: - for (;;) - { - unsigned int j = 0 ; + + for (;;) { + + int s = selfpipe_read() ; + switch (s) { + + case -1 : log_dieusys(LOG_EXIT_SYS,"selfpipe_read") ; + case 0 : return ok ; + case SIGCHLD : + + for (;;) { + + unsigned int pos = 0 ; int wstat ; pid_t r = wait_nohang(&wstat) ; - if (r < 0) - if (errno = ECHILD) break ; - else log_dieusys(LOG_EXIT_SYS,"wait for children") ; - else if (!r) break ; - for (; j < npids ; j++) if (pidindex[j].pid == r) break ; - if (j < npids) - { - ss_resolve_sig_t_ref sv = pidindex[j].sv ; - pidindex[j] = pidindex[--npids] ; - if (!WIFSIGNALED(wstat) && !WEXITSTATUS(wstat)) - { - if (announce(sv) > 1) ok = 0 ; - write_state(sv) ; - } + + if (r < 0) { + + if (errno = ECHILD) + break ; else - { - ok = 0 ; announce(sv) ; write_state(sv) ; + log_dieusys(LOG_EXIT_SYS,"wait for children") ; + + } else if (!r) break ; + + + for (; pos < napid ; pos++) + if (apids[pos].pid == r) + break ; + + if (pos < napid) { + + if (!WIFSIGNALED(wstat) && !WEXITSTATUS(wstat)) { + + announce(&apids[pos], what, 0, 0) ; + + } else { + + ok = 0 ; + announce(&apids[pos], what, 1, WIFSIGNALED(wstat) ? WTERMSIG(wstat) : WEXITSTATUS(wstat)) ; } + + npid-- ; } } break ; - case SIGTERM: - case SIGINT: - log_warn("received SIGINT, aborting service transition") ; - kill_all() ; + case SIGTERM : + case SIGINT : + log_1_warn("received SIGINT, aborting tree transition") ; + kill_all(apids) ; break ; - default : log_warn("unexpected data in selfpipe") ; + default : log_die(LOG_EXIT_SYS, "unexpected data in selfpipe") ; } } - end: - return ok ; + return ok ; } -static int compute_timeout(tain *start,tain *tsv) + +static int doit(pidservice_t *sv, unsigned int what, unsigned int deadline) { log_flow() ; - tain now,tpass ; - tain_now_g() ; - tain_copynow(&now) ; - tain_sub(&tpass,&now,start) ; - if (tain_less(tsv,&tpass)) return 0 ; - return 1 ; -} + uint8_t type = pares[sv->aresid].type ; -static void svc_listen_less(int state_val, int *state,unsigned int *did,unsigned int *loop,unsigned int pos) -{ - log_flow() ; + pid_t pid ; + int wstat, e = 0 ; + + if (type == TYPE_MODULE || type == TYPE_BUNDLE) + /** + * Those type are not real services. Passing here with + * this kind of service means that the dependencies + * of the service was made anyway. So, we can consider it as + * already up/down. + * */ + return 1 ; + + if (type == TYPE_CLASSIC) { + + char *scandir = pares[sv->aresid].sa.s + pares[sv->aresid].live.scandir ; + + if (updown[2] == 'U' || updown[2] == 'D' || updown[2] == 'R') { + + if (!pares[sv->aresid].notify) + updown[2] = updown[2] == 'U' ? 'u' : updown[2] == 'D' ? 'd' : updown[2] == 'R' ? 'r' : updown[2] ; + + } + + char tfmt[UINT32_FMT] ; + tfmt[uint_fmt(tfmt, deadline)] = 0 ; + + char const *newargv[8] ; + unsigned int m = 0 ; + + newargv[m++] = "s6-svc" ; + newargv[m++] = data ; + + if (opt_updown) + newargv[m++] = updown ; + + newargv[m++] = "-T" ; + newargv[m++] = tfmt ; + newargv[m++] = "--" ; + newargv[m++] = scandir ; + newargv[m++] = 0 ; + + log_info("sending ", opt_updown ? newargv[2] : "", opt_updown ? " " : "", data, " to: ", scandir) ; + + pid = child_spawn0(newargv[0], newargv, (char const *const *) environ) ; - (*state) = state_val ; - did[pos] = 1 ; - (*loop)--; + if (waitpid_nointr(pid, &wstat, 0) < 0) + log_warnusys_return(LOG_EXIT_ZERO, "wait for s6-svc") ; + + if (!WIFSIGNALED(wstat) && !WEXITSTATUS(wstat)) + e = 1 ; + + } else if (type == TYPE_ONESHOT) { + + char *sa = pares[sv->aresid].sa.s ; + char *name = sa + pares[sv->aresid].name ; + size_t namelen = strlen(name) ; + char *tree = pares[sv->aresid].sa.s + pares[sv->aresid].path.tree ; + size_t treelen = strlen(tree) ; + unsigned int timeout = 0 ; + if (!what) + timeout = pares[sv->aresid].execute.timeout.up ; + else + timeout = pares[sv->aresid].execute.timeout.down ; + + char script[treelen + SS_SVDIRS_LEN + SS_SVC_LEN + 1 + namelen + 7 + 1] ; + auto_strings(script, tree, SS_SVDIRS, SS_SVC, "/", name) ; + + char tfmt[UINT32_FMT] ; + tfmt[uint_fmt(tfmt, timeout)] = 0 ; + + char *oneshotdir = pares[sv->aresid].sa.s + pares[sv->aresid].live.oneshotddir ; + char *scandir = pares[sv->aresid].sa.s + pares[sv->aresid].live.scandir ; + char oneshot[strlen(oneshotdir) + 2 + 1] ; + auto_strings(oneshot, oneshotdir, "/s") ; + + char const *newargv[11] ; + unsigned int m = 0 ; + newargv[m++] = "s6-sudo" ; + newargv[m++] = VERBOSITY >= 4 ? "-vel0" : "-el0" ; + newargv[m++] = "-t" ; + newargv[m++] = "30000" ; + newargv[m++] = "-T" ; + newargv[m++] = tfmt ; + newargv[m++] = "--" ; + newargv[m++] = oneshot ; + newargv[m++] = !what ? "up" : "down" ; + newargv[m++] = script ; + newargv[m++] = 0 ; + + log_info("sending ", !what ? "up" : "down", " to: ", scandir) ; + + pid = child_spawn0(newargv[0], newargv, (char const *const *) environ) ; + + if (waitpid_nointr(pid, &wstat, 0) < 0) + log_warnusys_return(LOG_EXIT_ZERO, "wait for s6-sudo") ; + + + if (!WIFSIGNALED(wstat) && !WEXITSTATUS(wstat)) + e = 1 ; + } + + return e ; } -static void svc_listen(unsigned int nsv,tain *deadline) + +static int async_deps(pidservice_t *apids, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, unsigned int deadline) { log_flow() ; - int r ; - tain start ; + int e = 0, r ; + unsigned int pos = 0 ; + + tain dead ; + tain_from_millisecs(&dead, deadline) ; + tain_now_set_stopwatch_g() ; + tain_add_g(&dead, &dead) ; + + iopause_fd x = { .fd = ftrigr_fd(&FIFO), .events = IOPAUSE_READ } ; stralloc sa = STRALLOC_ZERO ; - iopause_fd x = { .fd = ftrigr_fd(&fifo), .events = IOPAUSE_READ } ; - ss_resolve_sig_t_ref svc ; - int *state = 0 ; - unsigned int *ndeath = 0, i, j ; - unsigned int did[nsv] ; - i = j = nsv ; - tain_now_g() ; - tain_copynow(&start) ; + while (apids[i].nedge) { - while(i--) - did[i] = 0 ; + /** TODO: the pidvertex_get_id() function make a loop + * through the apids array to find the corresponding + * index of the edge at the apids array. + * This is clearly a waste of time and should be optimized. */ + unsigned int id = pidservice_get_id(apids, apids[i].edge[pos]) ; + + if (id < 0) + log_dieu(LOG_EXIT_SYS, "get apidservice id -- please make a bug report") ; + + r = iopause_g(&x, 1, &dead) ; + if (r < 0) + log_dieusys(LOG_EXIT_SYS, "iopause") ; + if (!r) + log_die(LOG_EXIT_SYS,"time out") ; + + if (x.revents & IOPAUSE_READ) { + + if (ftrigr_update(&FIFO) < 0) + log_dieusys(LOG_EXIT_SYS, "ftrigr_update") ; + + for(pos = 0 ; pos < napid ; pos++) { - while(j) - { - r = iopause_g(&x, 1, deadline) ; - if (r < 0) log_diesys(LOG_EXIT_SYS,"listen iopause") ; - else if (!r) log_die(LOG_EXIT_SYS,"listen time out") ; - if (x.revents & IOPAUSE_READ) - { - i = 0 ; - if (ftrigr_update(&fifo) < 0) log_dieusys(LOG_EXIT_SYS,"update fifo") ; - for (;i < nsv;i++) - { - if (did[i]) continue ; - svc = pidindex[i].sv ; - state = &svc->state ; - ndeath = &svc->ndeath ; - if (!compute_timeout(&start,&pidindex[i].sv->deadline)) - { svc_listen_less(5,state,did,&j,i) ; continue ; } sa.len = 0 ; - r = ftrigr_checksa(&fifo,svc->ids, &sa) ; - if (r < 0) log_dieusys(LOG_EXIT_SYS,"check fifo") ; - else if (r) - { - (*ndeath)-- ; - (*state) = handle_case(&sa,svc) ; - if (!(*ndeath)) svc_listen_less(4,state,did,&j,i) ; - if ((*state) >= 1) svc_listen_less(*state,state,did,&j,i) ; - } + r = ftrigr_checksa(&FIFO, apids[pos].ids, &sa) ; + + if (r < 0) + log_dieusys(LOG_EXIT_SYS, "ftrigr_check") ; + else if (r) { + + size_t l = 0 ; + + for (; l < sa.len ; l++) { + + unsigned int p = char2enum[(unsigned int)sa.s[l]] ; + unsigned char action = actions[what][p] ; + char s[2] = { sa.s[l], 0 } ; + log_trace("received signal: ", s, " from: ", pares[apids[pos].aresid].sa.s + pares[apids[pos].aresid].name) ; + switch(action) { + + case SERVICE_ACTION_GOTIT: + FLAGS_SET(apids[pos].state, (!what ? FLAGS_UP : FLAGS_DOWN)) ; + goto next ; + + case SERVICE_ACTION_FATAL: + FLAGS_SET(apids[pos].state, FLAGS_FATAL) ; + goto err ; + + case SERVICE_ACTION_WAIT: + goto next ; + + case SERVICE_ACTION_UNKNOWN: + default: + log_die(LOG_EXIT_ZERO,"invalid action -- please make a bug report") ; + } + } + } } } + next: + apids[i].nedge-- ; } - stralloc_free(&sa) ; + + e = 1 ; + err: + stralloc_free(&sa) ; + return e ; } -/* @return 111 unable to control - * @return 100 "something is wrong with the S6_SUPERVISE_CTLDIR directory. errno reported - * @return 99 supervisor not listening */ -static int svc_writectl(ss_resolve_sig_t *svc) + +static int async(pidservice_t *apids, unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph, unsigned int deadline) { log_flow() ; - int r ; - char *sv = svc->res.sa.s + svc->res.runat ; - size_t siglen = strlen(svc->sigtosend) ; - log_trace("send signal: ",svc->sigtosend," to: ", sv,"/",S6_SUPERVISE_CTLDIR) ; - r = s6_svc_writectl(sv, S6_SUPERVISE_CTLDIR, svc->sigtosend, siglen) ; - if (r == -1) return 111 ; - else if (r == -2) return 100 ; - else if (!r) return 99 ; - return 0 ; + int e = 1 ; + + char *name = graph->data.s + genalloc_s(graph_hash_t,&graph->hash)[apids[i].vertex].vertex ; + char *notifdir = pares[apids[i].aresid].sa.s + pares[apids[i].aresid].live.notifdir ; + + if (FLAGS_ISSET(apids[i].state, (!what ? FLAGS_DOWN : FLAGS_UP))) { + + if (!FLAGS_ISSET(apids[i].state, FLAGS_BLOCK)) { + + FLAGS_SET(apids[i].state, FLAGS_BLOCK) ; + + if (apids[i].nedge) + if (!async_deps(apids, i, what, info, graph, deadline)) + log_warnu_return(LOG_EXIT_ZERO, !what ? "start" : "stop", " dependencies of service: ", name) ; + + e = doit(&apids[i], what, deadline) ; + + } else { + + log_info("Skipping service: ", name, " -- already in ", what ? "stopping" : "starting", " process") ; + + log_trace("sends notification ", what ? "d" : "u", " to : ", notifdir) ; + if (ftrigw_notify(notifdir, what ? 'd' : 'u') < 0) + log_warnusys_return(LOG_EXIT_ZERO, "notifies event directory: ", notifdir) ; + + } + + } else { + + log_info("Skipping service: ", name, " -- already ", what ? "down" : "up") ; + + //log_trace("sends notification ", what ? "D" : "U", " to : ", notifdir) ; + //if (ftrigw_notify(notifdir, what ? 'D' : 'U') < 0) + // log_warnusys_return(LOG_EXIT_ZERO, "notifies event directory: ", notifdir) ; + + } + + return e ; } -static void svc_async(unsigned int i,unsigned int nsv) +static int waitit(pidservice_t *apids, unsigned int what, graph_t *graph, unsigned int deadline, ssexec_t *info) { log_flow() ; + unsigned int e = 1, pos = 0 ; int r ; pid_t pid ; - pid = fork() ; - if (pid < 0) return ; - if (!pid) - { - r = svc_writectl(pidindex[i].sv) ; - _exit(r) ; - } + pidservice_t apidservicetable[napid] ; + pidservice_t_ref apidservice = apidservicetable ; - pidindex[npids].pid = pid ; - pidindex[npids++].sv = pidindex[i].sv ; - return ; -} + tain dead ; + tain_from_millisecs(&dead, deadline) ; + tain_now_set_stopwatch_g() ; + tain_add_g(&dead, &dead) ; -int doit (int spfd, genalloc *gakeep, tain *deadline) -{ - log_flow() ; + int spfd = selfpipe_init() ; - iopause_fd x = { .fd = spfd, .events = IOPAUSE_READ } ; - unsigned int nsv = genalloc_len(ss_resolve_sig_t,gakeep) ; - unsigned int i = 0 ; - int exitcode = 1 ; - pidindex_t pidindextable[nsv] ; - pidindex = pidindextable ; - /** keep the good order service declaration - * of the genalloc*/ - while(i<nsv){ - pidindex[i].sv = &genalloc_s(ss_resolve_sig_t,gakeep)[i] ; - pidindex[i].pid = 0 ; - i++ ; - } - i = 0 ; - while(i < nsv) - { - svc_async(i,nsv) ; - i++ ; - } - svc_listen(nsv,deadline) ; - while (npids) - { - int 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 (!handle_signal_pipe(gakeep)) exitcode = 0 ; + if (spfd < 0) + log_dieusys(LOG_EXIT_SYS, "selfpipe_init") ; + + if (!selfpipe_trap(SIGCHLD) || + !selfpipe_trap(SIGINT) || + !selfpipe_trap(SIGTERM) || + !sig_altignore(SIGPIPE)) + log_dieusys(LOG_EXIT_SYS, "selfpipe_trap") ; + + pidservice_init_fifo(apids, graph, info, deadline) ; + + for (pos = 0 ; pos < napid ; pos++) + apidservice[pos] = apids[pos] ; + + for (pos = 0 ; pos < napid ; pos++) { + + pid = fork() ; + + if (pid < 0) + log_dieusys(LOG_EXIT_SYS, "fork") ; + + if (!pid) { + e = async(apidservice, pos, what, info, graph, deadline) ; + goto freed ; + } + + apidservice[pos].pid = pid ; + + npid++ ; } - return exitcode ; -} -int ssexec_svctl(int argc, char const *const *argv,char const *const *envp,ssexec_t *info) -{ - // be sure that the global var are set correctly - SV_DEADLINE = 3000 ; - DEATHSV = 5 ; + iopause_fd x = { .fd = spfd, .events = IOPAUSE_READ } ; - int e, isup, r, ret = 1 ; - unsigned int death, tsv, reverse, tsv_g ; - int SIGNAL = -1 ; - tain ttmain ; + while (npid) { - genalloc gakeep = GENALLOC_ZERO ; //type ss_resolve_sig - stralloc sares = STRALLOC_ZERO ; - ss_resolve_graph_t graph = RESOLVE_GRAPH_ZERO ; - resolve_service_t res = RESOLVE_SERVICE_ZERO ; - resolve_wrapper_t_ref wres = resolve_set_struct(DATA_SERVICE, &res) ; - ss_state_t sta = STATE_ZERO ; + r = iopause_g(&x, 1, &dead) ; + if (r < 0) + log_dieusys(LOG_EXIT_SYS, "iopause") ; + if (!r) + log_die(LOG_EXIT_SYS,"time out") ; - char *sig = 0 ; + if (x.revents & IOPAUSE_READ) + if (!handle_signal(apidservice, what, graph, info)) + e = 0 ; + } + freed: + ftrigr_end(&FIFO) ; + selfpipe_finish() ; - s6_svstatus_t status = S6_SVSTATUS_ZERO ; + return e ; +} + +int ssexec_svctl(int argc, char const *const *argv, ssexec_t *info) +{ + log_flow() ; - tsv = death = reverse = 0 ; - tsv_g = SV_DEADLINE ; + int r ; + // what = 0 -> up signal + uint8_t what = 0, requiredby = 0 ; + static unsigned int deadline = 3000 ; + graph_t graph = GRAPH_ZERO ; + + unsigned int areslen = 0, list[SS_MAX_SERVICE] ; + resolve_service_t ares[SS_MAX_SERVICE] ; + + /* + * STATE_FLAGS_TOPROPAGATE = 0 + * do not send signal to the depends/requiredby of the service. + * + * STATE_FLAGS_TOPROPAGATE = 1 + * also send signal to the depends/requiredby of the service + * + * When we come from 66-start/stop tool we always want to + * propagate the signal. But we may need/want to send a e.g. SIGHUP signal + * to a specific service without interfering on its depends/requiredby services + * + * Also, we only deal with already supervised service. This tool is the signal sender, + * it not intended to sanitize the state of the services. + * + * */ + uint32_t gflag = STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_ISSUPERVISED|STATE_FLAGS_WANTUP ; - //PROG = "66-svctl" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { - int opt = getopt_args(argc,argv, OPTS_SVCTL, &l) ; + int opt = subgetopt_r(argc,argv, OPTS_SVCTL, &l) ; if (opt == -1) break ; - if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; - switch (opt) - { - case 'n' : if (!uint0_scan(l.arg, &death)) log_usage(usage_svctl) ; break ; - case 'u' : if (SIGNAL > 0) log_usage(usage_svctl) ; SIGNAL = SIGUP ; sig ="u" ; break ; - case 'r' : if (SIGNAL > 0) log_usage(usage_svctl) ; SIGNAL = SIGR ; sig = "r" ; break ; - /** -R is an inner signal and need to come from 66-start.s6-svc do not understand it*/ - case 'R' : - if (!strcmp(info->prog,"66-svctl")) log_usage(usage_svctl) ; - if (SIGNAL > 0) log_usage(usage_svctl) ; - SIGNAL = SIGRR ; sig = "r" ; - break ; - case 'd' : if (SIGNAL > 0) log_usage(usage_svctl) ; SIGNAL = SIGDOWN ; sig = "d" ; break ; - case 'X' : if (SIGNAL > 0) log_usage(usage_svctl) ; SIGNAL = SIGX ; sig = "xd" ; break ; - case 'K' : if (SIGNAL > 0) log_usage(usage_svctl) ; SIGNAL = SIGRDOWN ; sig = "kd" ; break ; + //if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; + + switch (opt) { + + case 'a' : + case 'b' : + case 'q' : + case 'h' : + case 'k' : + case 't' : + case 'i' : + case '1' : + case '2' : + case 'p' : + case 'c' : + case 'y' : + case 'r' : + case 'o' : + case 'd' : + case 'u' : + case 'x' : + case 'O' : + + if (datalen >= DATASIZE) + log_die(LOG_EXIT_USER, "too many arguments") ; + + data[datalen++] = opt ; + break ; + + case 'w' : + + if (!memchr("dDuUrR", l.arg[0], 6)) + log_usage(usage_svctl) ; + + updown[2] = l.arg[0] ; + opt_updown = 1 ; + break ; + + case 'P': + FLAGS_CLEAR(gflag, STATE_FLAGS_TOPROPAGATE) ; + break ; - default : log_usage(usage_svctl) ; + default : + log_usage(usage_svctl) ; } } argc -= l.ind ; argv += l.ind ; } - if (argc < 1 || (SIGNAL < 0)) log_usage(usage_svctl) ; - if (info->timeout) tsv = info->timeout ; - if ((scandir_ok(info->scandir.s)) !=1 ) log_diesys(LOG_EXIT_SYS,"scandir: ", info->scandir.s," is not running") ; - if (!sa_pointo(&sares,info,SS_NOTYPE,SS_RESOLVE_SRC)) log_dieusys(LOG_EXIT_SYS,"set revolve pointer to source") ; - if (SIGNAL > SIGR) reverse = 1 ; - for(;*argv;argv++) - { - char const *name = *argv ; - int logname = 0 ; - logname = get_rstrlen_until(name,SS_LOG_SUFFIX) ; - if (!resolve_check(sares.s,name)) log_diesys(LOG_EXIT_SYS,"unknown service: ",name) ; - if (!resolve_read(wres,sares.s,name)) log_dieusys(LOG_EXIT_SYS,"read resolve file of: ",name) ; - if (res.type >= TYPE_BUNDLE) log_die(LOG_EXIT_SYS,name," has type ",get_key_by_enum(ENUM_TYPE,res.type)) ; - if (SIGNAL == SIGR && logname < 0) reverse = 1 ; - if (!ss_resolve_graph_build(&graph,&res,sares.s,reverse)) log_dieusys(LOG_EXIT_SYS,"build services graph") ; + if (argc < 1) + log_usage(usage_svctl) ; + + if (!datalen) + log_die(LOG_EXIT_USER, "too few arguments") ; + + if (info->timeout) + deadline = info->timeout ; + + if (data[1] != 'u') + what = 1 ; + + if (data[1] == 'r') + reloadmsg++ ; + + if (what) { + + requiredby = 1 ; + FLAGS_SET(gflag, STATE_FLAGS_WANTUP) ; + FLAGS_CLEAR(gflag, STATE_FLAGS_WANTDOWN) ; } - r = ss_resolve_graph_publish(&graph,reverse) ; - if (r < 0) log_die(LOG_EXIT_SYS,"cyclic dependencies detected") ; - if (!r) log_dieusys(LOG_EXIT_SYS,"publish service graph") ; + if ((svc_scandir_ok(info->scandir.s)) != 1) + log_diesys(LOG_EXIT_SYS,"scandir: ", info->scandir.s," is not running") ; + + /** build the graph of the entire system + * + * + * ici tu passe dans le graph sans controle de savoir si le service + * est au minima parsed voir initialized + * + * */ + graph_build_service(&graph, ares, &areslen, info, gflag) ; - for(unsigned int i = 0 ; i < genalloc_len(resolve_service_t,&graph.sorted) ; i++) +/* { - ss_resolve_sig_t sv_signal = RESOLVE_SIG_ZERO ; - sv_signal.res = genalloc_s(resolve_service_t,&graph.sorted)[i] ; - char *string = sv_signal.res.sa.s ; - char *svok = string + sv_signal.res.runat ; - char *state = string + sv_signal.res.state ; - - size_t svoklen = strlen(svok) ; - char file[svoklen + SS_NOTIFICATION_LEN + 1 + 1] ; - memcpy(file,svok,svoklen) ; - if (!state_check(state,string + sv_signal.res.name)) log_die(LOG_EXIT_SYS,"unitialized service: ",string + sv_signal.res.name) ; - if (!state_read(&sta,state,string + sv_signal.res.name)) log_dieusys(LOG_EXIT_SYS,"read state of: ",string + sv_signal.res.name) ; - if (sta.init) log_die(LOG_EXIT_SYS,"unitialized service: ",string + sv_signal.res.name) ; - if (!s6_svstatus_read(svok,&status)) log_dieusys(LOG_EXIT_SYS,"read status of: ",svok) ; - isup = status.pid && !status.flagfinishing ; - - if (isup && (SIGNAL == SIGUP)) - { - log_info("Already up: ",string + sv_signal.res.name) ; - continue ; - } - else if (!isup && (SIGNAL >= SIGDOWN)) - { - log_info("Already down: ",string + sv_signal.res.name) ; - continue ; - } - /** special case on reload signal, if the process is down - * simply bring it up */ - else if (!isup && ((SIGNAL == SIGR) || (SIGNAL == SIGRR))) - { - sig = "u" ; - SIGNAL = SIGUP ; - } - sv_signal.sigtosend = sig ; sv_signal.sig = SIGNAL ; + stralloc sa = STRALLOC_ZERO ; + char const *exclude[1] = { 0 } ; + char solve[info->base.len + SS_SYSTEM_LEN + SS_RESOLVE_LEN + 1 + SS_SERVICE_LEN + 1] ; - /** notification-fd */ - memcpy(file + svoklen,"/" SS_NOTIFICATION,SS_NOTIFICATION_LEN + 1) ; - file[svoklen + SS_NOTIFICATION_LEN + 1] = 0 ; - e = errno ; - errno = 0 ; + auto_strings(solve, info->base.s, SS_SYSTEM, SS_RESOLVE, "/", SS_SERVICE) ; - if (access(file, F_OK) < 0 && errno != ENOENT) - log_warnsys("conflicting format of file: " SS_NOTIFICATION) ; - else if (errno != ENOENT) - { + if (!sastr_dir_get_recursive(&sa,solve,exclude,S_IFREG, 0)) + log_dieu(LOG_EXIT_SYS, "get resolve files") ; - if (!read_uint(file,&sv_signal.notify)) log_dieusys(LOG_EXIT_SYS,"read: ",file) ; - if (SIGNAL == SIGUP) - { sv_signal.sig = SIGRUP ; sv_signal.sigtosend = "uwU" ; } - else if (SIGNAL == SIGR || SIGNAL == SIGRR) - { sv_signal.sig = SIGRR ; sv_signal.sigtosend = "rwR" ; } - else if (SIGNAL == SIGDOWN) - { sv_signal.sig = SIGRDOWN ; sv_signal.sigtosend = "dwD" ; } - } - /** max-death-tally */ - if (!death) - { - memcpy(file + svoklen,"/" SS_MAXDEATHTALLY, SS_MAXDEATHTALLY_LEN + 1) ; - file[svoklen + SS_MAXDEATHTALLY_LEN + 1] = 0 ; - errno = 0 ; - if (access(file, F_OK) < 0) - if (errno != ENOENT) log_dieusys(LOG_EXIT_SYS, "access ", file) ; - - if (errno == ENOENT) - sv_signal.ndeath = DEATHSV ; - else - { - if (!read_uint(file,&sv_signal.ndeath)) log_dieusys(LOG_EXIT_SYS,"read: ",file) ; - } - } - else sv_signal.ndeath = death ; + service_graph_g(sa.s, sa.len, &graph, ares, &areslen, info, STATE_FLAGS_TOPROPAGATE|STATE_FLAGS_WANTUP|STATE_FLAGS_WANTDOWN) ; - tain tcheck ; - tain_from_millisecs(&tcheck,tsv) ; - int check = tain_to_millisecs(&tcheck) ; - if (check > 0) - { - tain_from_millisecs(&sv_signal.deadline, tsv) ; - tsv_g += tsv ; - } - else - { - /** timeout-{up/down} */ - char *tm = NULL ; - unsigned int t ; - if (SIGNAL <= SIGR) - tm="/timeout-up" ; - else tm="/timeout-down" ; - errno = 0 ; - size_t tmlen = strlen(tm) ; - memcpy(file + svoklen,tm, tmlen) ; - file[svoklen + tmlen] = 0 ; - if (access(file, F_OK) < 0) - if (errno != ENOENT) log_dieusys(LOG_EXIT_SYS, "access ", file) ; - - if (errno == ENOENT) - { - tain_from_millisecs(&sv_signal.deadline, SV_DEADLINE) ; - tsv_g += SV_DEADLINE ; - } - else - { - if (!read_uint(file,&t)) log_dieusys(LOG_EXIT_SYS,"read: ",file) ; - { - tain_from_millisecs(&sv_signal.deadline, t) ; - tsv_g += t ; - } - } - } - errno = e ; - if (!genalloc_append(ss_resolve_sig_t,&gakeep,&sv_signal)) log_dieusys(LOG_EXIT_SYS,"append services selection with: ",string + sv_signal.res.name) ; + stralloc_free(&sa) ; } - /** nothing to do */ - if (!genalloc_len(ss_resolve_sig_t,&gakeep)) goto finish ; +*/ + if (!graph.mlen) + log_die(LOG_EXIT_USER, "services selection is not supervised -- initiate its first") ; - //ttmain = tain_infinite_relative ; - tain_from_millisecs(&ttmain,tsv_g) ; - tain_now_set_stopwatch_g() ; - tain_add_g(&ttmain,&ttmain) ; + for (; *argv ; argv++) { - int spfd = selfpipe_init() ; - if (spfd < 0) log_dieusys(LOG_EXIT_SYS, "selfpipe_init") ; - if (!selfpipe_trap(SIGCHLD)) log_dieusys(LOG_EXIT_SYS, "selfpipe_trap") ; - if (!selfpipe_trap(SIGINT)) log_dieusys(LOG_EXIT_SYS, "selfpipe_trap") ; - if (!selfpipe_trap(SIGTERM)) log_dieusys(LOG_EXIT_SYS, "selfpipe_trap") ; - if (!sig_ignore(SIGPIPE)) log_dieusys(LOG_EXIT_SYS,"ignore SIGPIPE") ; + int aresid = service_resolve_array_search(ares, areslen, *argv) ; + if (aresid < 0) + log_die(LOG_EXIT_USER, "service: ", *argv, " not available -- did you parsed it?") ; + + unsigned int l[graph.mlen], c = 0, pos = 0 ; + + /** find dependencies of the service from the graph, do it recursively */ + c = graph_matrix_get_edge_g_sorted_list(l, &graph, *argv, !!requiredby, 1) ; + + /** append to the list to deal with */ + for (; pos < c ; pos++) + list[napid + pos] = l[pos] ; + + napid += c ; + + list[napid++] = aresid ; + } + + pidservice_t apids[napid] ; + + pares = ares ; + pareslen = &areslen ; - if (!svc_init_pipe(&fifo,&gakeep,&ttmain)) log_dieu(LOG_EXIT_SYS,"init pipe") ; + pidservice_init_array(list, napid, apids, &graph, ares, areslen, info, requiredby, gflag) ; - ret = doit(spfd,&gakeep,&ttmain) ; + r = waitit(apids, what, &graph, deadline, info) ; - finish: - ftrigr_end(&fifo) ; - selfpipe_finish() ; - stralloc_free(&sares) ; - ss_resolve_graph_free(&graph) ; - genalloc_free(ss_resolve_sig_t,&gakeep) ; - resolve_free(wres) ; + graph_free_all(&graph) ; + pidservice_array_free(apids, napid) ; + service_resolve_array_free(ares, areslen) ; - return (!ret) ? 111 : 0 ; + return (!r) ? 111 : 0 ; }