/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #define USAGE "s6-permafailon seconds deathcount statuslist prog..." #define dieusage() strerr_dieusage(100, USAGE) static void list_scan (char const *s, unsigned char *codes, sigset_t *sigs) { size_t pos = 0 ; while (s[pos]) { unsigned int u ; size_t len = uint_scan(s + pos, &u) ; if (len) { if (u > 255) strerr_dief1x(100, "invalid exit code") ; pos += len ; if (s[pos] == '-') { unsigned int v ; pos++ ; len = uint_scan(s + pos, &v) ; if (!len) strerr_dief1x(100, "invalid interval specification") ; if (v > 255) strerr_dief1x(100, "invalid exit code") ; if (v < u) strerr_dief1x(100, "invalid interval") ; pos += len ; bitarray_setn(codes, u, v - u + 1) ; } else bitarray_set(codes, u) ; } else { int sig ; size_t next = pos ; while (!strchr(",; \n\r\t", s[next])) next++ ; char tmp[next - pos + 1] ; memcpy(tmp, s + pos, next - pos) ; tmp[next - pos] = 0 ; len = sig0_scan(tmp, &sig) ; if (!len) strerr_dief1x(100, "invalid status list specification") ; pos += len ; if (sigaddset(sigs, sig) < 0) strerr_dief1x(100, "invalid signal") ; } while (memchr(",; \n\r\t", s[pos], 6)) pos++ ; } } int main (int argc, char const *const *argv, char const *const *envp) { unsigned char codes[32] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ; sigset_t sigs ; unsigned int total, seconds, n ; struct stat st ; PROG = "s6-permafailon" ; if (argc < 4) dieusage() ; if (!uint0_scan(argv[1], &seconds)) dieusage() ; if (!uint0_scan(argv[2], &n)) dieusage() ; if (!n) dieusage() ; if (n > S6_MAX_DEATH_TALLY) n = S6_MAX_DEATH_TALLY ; list_scan(argv[3], codes, &sigs) ; if (stat(S6_DTALLY_FILENAME, &st) < 0) { strerr_warnwu2sys("stat ", S6_DTALLY_FILENAME) ; goto cont ; } if (st.st_size % S6_DTALLY_PACK || st.st_size > S6_DTALLY_PACK * S6_MAX_DEATH_TALLY) { strerr_warnw2x("invalid ", S6_DTALLY_FILENAME) ; goto cont ; } total = st.st_size / S6_DTALLY_PACK ; { tain_t mintime ; unsigned int matches = 0 ; s6_dtally_t tab[total] ; ssize_t r = s6_dtally_read(".", tab, total) ; if (r <= 0) { if (r < 0) strerr_warnwu2sys("read ", S6_DTALLY_FILENAME) ; goto cont ; } if (r < n) goto cont ; tain_uint(&mintime, seconds) ; { tain_t now ; tain_wallclock_read(&now) ; tain_sub(&mintime, &now, &mintime) ; } for (unsigned int i = 0 ; i < r ; i++) { if (!tain_less(&tab[i].stamp, &mintime) && ((tab[i].sig && sigismember(&sigs, tab[i].sig)) || bitarray_peek(codes, tab[i].exitcode)) && ++matches >= n) { char fmtevent[4] ; char fmtseconds[UINT_FMT] ; char fmtn[UINT_FMT] ; fmtevent[uint_fmt(fmtevent, tab[i].sig ? tab[i].sig : tab[i].exitcode)] = 0 ; fmtseconds[uint_fmt(fmtseconds, seconds)] = 0 ; fmtn[uint_fmt(fmtn, n)] = 0 ; strerr_warni8x("PERMANENT FAILURE triggered after ", fmtn, " events involving ", tab[i].sig ? "signal " : "exit code ", fmtevent, " in the last ", fmtseconds, " seconds") ; return 125 ; } } } cont: xpathexec0_run(argv + 4, envp) ; }