s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

s6-permafailon.c (3531B)


      1 /* ISC license. */
      2 
      3 #include <sys/stat.h>
      4 #include <string.h>
      5 #include <signal.h>
      6 
      7 #include <skalibs/types.h>
      8 #include <skalibs/strerr.h>
      9 #include <skalibs/bitarray.h>
     10 #include <skalibs/sig.h>
     11 #include <skalibs/tai.h>
     12 #include <skalibs/exec.h>
     13 
     14 #include <s6/supervise.h>
     15 
     16 #define USAGE "s6-permafailon seconds deathcount statuslist prog..."
     17 #define dieusage() strerr_dieusage(100, USAGE)
     18 
     19 static inline void list_scan (char const *s, unsigned char *codes, sigset_t *sigs)
     20 {
     21   size_t pos = 0 ;
     22   memset(codes, 0, 32) ;
     23   sigemptyset(sigs) ;
     24   while (s[pos])
     25   {
     26     unsigned int u ;
     27     size_t len = uint_scan(s + pos, &u) ;
     28     if (len)
     29     {
     30       if (u > 255) strerr_dief1x(100, "invalid exit code") ;
     31       pos += len ;
     32       if (s[pos] == '-')
     33       {
     34         unsigned int v ;
     35         pos++ ;
     36         len = uint_scan(s + pos, &v) ;
     37         if (!len) strerr_dief1x(100, "invalid interval specification") ;
     38         if (v > 255) strerr_dief1x(100, "invalid exit code") ;
     39         if (v < u) strerr_dief1x(100, "invalid interval") ;
     40         pos += len ;
     41         bitarray_setn(codes, u, v - u + 1) ;
     42       }
     43       else bitarray_set(codes, u) ;
     44     }
     45     else
     46     {
     47       int sig ;
     48       size_t next = pos ;
     49       while (!strchr(",; \n\r\t", s[next])) next++ ;
     50       char tmp[next - pos + 1] ;
     51       memcpy(tmp, s + pos, next - pos) ;
     52       tmp[next - pos] = 0 ;
     53       len = sig0_scan(tmp, &sig) ;
     54       if (!len) strerr_dief1x(100, "invalid status list specification") ;
     55       pos += len ;
     56       if (sigaddset(sigs, sig) < 0) strerr_dief1x(100, "invalid signal") ;
     57     }
     58     while (memchr(",; \n\r\t", s[pos], 6)) pos++ ;
     59   }
     60 }
     61 
     62 int main (int argc, char const *const *argv)
     63 {
     64   unsigned char codes[32] ;
     65   sigset_t sigs ;
     66   unsigned int total, seconds, n ;
     67   struct stat st ;
     68   PROG = "s6-permafailon" ;
     69   if (argc < 4) dieusage() ;
     70 
     71   if (!uint0_scan(argv[1], &seconds)) dieusage() ;
     72   if (!uint0_scan(argv[2], &n)) dieusage() ;
     73   if (!n) dieusage() ;
     74   if (n > S6_MAX_DEATH_TALLY) n = S6_MAX_DEATH_TALLY ;
     75   list_scan(argv[3], codes, &sigs) ;
     76 
     77   if (stat(S6_DTALLY_FILENAME, &st) < 0)
     78   {
     79     strerr_warnwu2sys("stat ", S6_DTALLY_FILENAME) ;
     80     goto cont ;
     81   }
     82   if (st.st_size % S6_DTALLY_PACK || st.st_size > S6_DTALLY_PACK * S6_MAX_DEATH_TALLY)
     83   {
     84     strerr_warnw2x("invalid ", S6_DTALLY_FILENAME) ;
     85     goto cont ;
     86   }
     87   total = st.st_size / S6_DTALLY_PACK ;
     88   {
     89     tain mintime ;
     90     unsigned int matches = 0 ;
     91     s6_dtally_t tab[total] ;
     92     ssize_t r = s6_dtally_read(".", tab, total) ;
     93     if (r <= 0)
     94     {
     95       if (r < 0) strerr_warnwu2sys("read ", S6_DTALLY_FILENAME) ;
     96       goto cont ;
     97     }
     98     if (r < n) goto cont ;
     99     tain_uint(&mintime, seconds) ;
    100     {
    101       tain now ;
    102       tain_wallclock_read(&now) ;
    103       tain_sub(&mintime, &now, &mintime) ;
    104     }
    105 
    106     for (unsigned int i = 0 ; i < r ; i++)
    107     {
    108       if (!tain_less(&tab[i].stamp, &mintime)
    109        && ((tab[i].sig && sigismember(&sigs, tab[i].sig)) || bitarray_peek(codes, tab[i].exitcode))
    110        && ++matches >= n)
    111       {
    112         char fmtevent[4] ;
    113         char fmtseconds[UINT_FMT] ;
    114         char fmtn[UINT_FMT] ;
    115         fmtevent[uint_fmt(fmtevent, tab[i].sig ? tab[i].sig : tab[i].exitcode)] = 0 ;
    116         fmtseconds[uint_fmt(fmtseconds, seconds)] = 0 ;
    117         fmtn[uint_fmt(fmtn, n)] = 0 ;
    118         strerr_warni8x("PERMANENT FAILURE triggered after ", fmtn, " events involving ", tab[i].sig ? "signal " : "exit code ", fmtevent, " in the last ", fmtseconds, " seconds") ;
    119         return 125 ;
    120       }
    121     }
    122   }
    123 
    124  cont:
    125   xexec0(argv+4) ;
    126 }