1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/* ISC license. */
#include <sys/stat.h>
#include <string.h>
#include <signal.h>
#include <skalibs/types.h>
#include <skalibs/strerr2.h>
#include <skalibs/bitarray.h>
#include <skalibs/sig.h>
#include <skalibs/tai.h>
#include <skalibs/exec.h>
#include <s6/s6-supervise.h>
#define USAGE "s6-permafailon seconds deathcount statuslist prog..."
#define dieusage() strerr_dieusage(100, USAGE)
static inline void list_scan (char const *s, unsigned char *codes, sigset_t *sigs)
{
size_t pos = 0 ;
memset(codes, 0, 32) ;
sigemptyset(sigs) ;
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)
{
unsigned char codes[32] ;
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 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 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:
xexec0(argv+4) ;
}
|