| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
52
|
|
|
|
|
|
bool parse_actions(SV **spec, int n_spec, struct action *actions, size_t *n_actions, char *aux_buf, size_t *aux_len) { |
|
2
|
|
|
|
|
|
|
bool success; |
|
3
|
52
|
|
|
|
|
|
size_t action_pos= 0; |
|
4
|
52
|
|
|
|
|
|
size_t aux_pos= 0; |
|
5
|
|
|
|
|
|
|
int spec_i; |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
// Default is one SIGALRM to self |
|
8
|
52
|
100
|
|
|
|
|
if (!spec || n_spec == 0) { |
|
|
|
100
|
|
|
|
|
|
|
9
|
10
|
100
|
|
|
|
|
if (*n_actions) { |
|
10
|
5
|
|
|
|
|
|
actions[0].op= ACT_KILL; |
|
11
|
5
|
|
|
|
|
|
actions[0].orig_idx= 0; |
|
12
|
5
|
|
|
|
|
|
actions[0].act.kill.signal= SIGALRM; |
|
13
|
5
|
|
|
|
|
|
actions[0].act.kill.pid= getpid(); |
|
14
|
|
|
|
|
|
|
} |
|
15
|
10
|
|
|
|
|
|
action_pos++; |
|
16
|
|
|
|
|
|
|
} |
|
17
|
84
|
100
|
|
|
|
|
else for (spec_i= 0; spec_i < n_spec; spec_i++) { |
|
18
|
|
|
|
|
|
|
AV *action_spec; |
|
19
|
42
|
|
|
|
|
|
const char *act_name= NULL; |
|
20
|
42
|
|
|
|
|
|
STRLEN act_namelen= 0; |
|
21
|
|
|
|
|
|
|
SV **el; |
|
22
|
|
|
|
|
|
|
size_t n_el; |
|
23
|
|
|
|
|
|
|
pid_t common_pid; |
|
24
|
|
|
|
|
|
|
int common_op, common_signal; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
// Get the arrayref for the next action |
|
27
|
42
|
50
|
|
|
|
|
if (!(spec[spec_i] && SvROK(spec[spec_i]) && SvTYPE(SvRV(spec[spec_i])) == SVt_PVAV)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
28
|
0
|
|
|
|
|
|
croak("Actions must be arrayrefs"); |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
// Get the 'command' name of the action |
|
31
|
42
|
|
|
|
|
|
action_spec= (AV*) SvRV(spec[spec_i]); |
|
32
|
42
|
|
|
|
|
|
n_el= av_count(action_spec); |
|
33
|
42
|
50
|
|
|
|
|
if (n_el < 1 || !(el= av_fetch(action_spec, 0, 0)) || !SvPOK(*el)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
34
|
0
|
|
|
|
|
|
croak("First element of action must be a string"); |
|
35
|
42
|
|
|
|
|
|
act_name= SvPV(*el, act_namelen); |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
// Dispatch based on the command |
|
38
|
42
|
|
|
|
|
|
switch (act_namelen) { |
|
39
|
4
|
|
|
|
|
|
case 3: |
|
40
|
4
|
100
|
|
|
|
|
if (strcmp(act_name, "sig") == 0) { |
|
41
|
2
|
50
|
|
|
|
|
if (n_el > 2) |
|
42
|
0
|
|
|
|
|
|
croak("Too many parameters for 'sig' action"); |
|
43
|
2
|
50
|
|
|
|
|
common_signal= (n_el == 2 && (el= av_fetch(action_spec, 1, 0)) != NULL && SvOK(*el))? |
|
|
|
50
|
|
|
|
|
|
|
44
|
4
|
50
|
|
|
|
|
parse_signal(*el) : SIGALRM; |
|
45
|
2
|
|
|
|
|
|
common_pid= getpid(); |
|
46
|
2
|
|
|
|
|
|
goto parse_kill_common; |
|
47
|
|
|
|
|
|
|
} |
|
48
|
2
|
50
|
|
|
|
|
if (strcmp(act_name, "run") == 0) { |
|
49
|
2
|
|
|
|
|
|
common_op= ACT_RUN; |
|
50
|
2
|
|
|
|
|
|
goto parse_run_common; |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
case 4: |
|
53
|
4
|
100
|
|
|
|
|
if (strcmp(act_name, "kill") == 0) { |
|
54
|
2
|
50
|
|
|
|
|
if (n_el != 3) |
|
55
|
0
|
|
|
|
|
|
croak("Expected 2 parameters for 'kill' action"); |
|
56
|
2
|
|
|
|
|
|
el= av_fetch(action_spec, 1, 0); |
|
57
|
2
|
50
|
|
|
|
|
if (!el || !SvOK(*el)) |
|
|
|
50
|
|
|
|
|
|
|
58
|
0
|
|
|
|
|
|
croak("Expected Signal as first parameter to 'kill'"); |
|
59
|
2
|
|
|
|
|
|
common_signal= parse_signal(*el); |
|
60
|
2
|
|
|
|
|
|
el= av_fetch(action_spec, 2, 0); |
|
61
|
2
|
50
|
|
|
|
|
if (!el || !SvIOK(*el)) |
|
|
|
50
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
|
croak("Expected PID as second parameter to 'kill'"); |
|
63
|
2
|
|
|
|
|
|
common_pid= SvIV(*el); |
|
64
|
2
|
|
|
|
|
|
goto parse_kill_common; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
2
|
50
|
|
|
|
|
if (strcmp(act_name, "exec") == 0) { |
|
67
|
2
|
|
|
|
|
|
common_op= ACT_EXEC; |
|
68
|
2
|
|
|
|
|
|
goto parse_run_common; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
case 5: |
|
71
|
8
|
100
|
|
|
|
|
if (strcmp(act_name, "sleep") == 0) { |
|
72
|
2
|
50
|
|
|
|
|
if (n_el != 2) |
|
73
|
0
|
|
|
|
|
|
croak("Expected 1 parameter to 'sleep' action"); |
|
74
|
2
|
|
|
|
|
|
el= av_fetch(action_spec, 1, 0); |
|
75
|
2
|
50
|
|
|
|
|
if (!el || !SvOK(*el) || !looks_like_number(*el)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
76
|
0
|
|
|
|
|
|
croak("Expected number of seconds in 'sleep' action"); |
|
77
|
2
|
100
|
|
|
|
|
if (action_pos < *n_actions) { |
|
78
|
1
|
|
|
|
|
|
actions[action_pos].op= ACT_SLEEP; |
|
79
|
1
|
|
|
|
|
|
actions[action_pos].orig_idx= spec_i; |
|
80
|
1
|
|
|
|
|
|
actions[action_pos].act.slp.seconds= SvNV(*el); |
|
81
|
|
|
|
|
|
|
} |
|
82
|
2
|
|
|
|
|
|
++action_pos; |
|
83
|
2
|
|
|
|
|
|
continue; |
|
84
|
|
|
|
|
|
|
} |
|
85
|
6
|
50
|
|
|
|
|
if (strcmp(act_name, "close") == 0) { |
|
86
|
6
|
|
|
|
|
|
common_op= ACT_x_CLOSE; |
|
87
|
6
|
|
|
|
|
|
goto parse_close_common; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
case 6: |
|
90
|
|
|
|
|
|
|
// The repeat feature opens the possibility of infinite busy-loops, |
|
91
|
|
|
|
|
|
|
// and probably creates more problems than it solves. |
|
92
|
|
|
|
|
|
|
//if (strcmp(act_name, "repeat") == 0) { |
|
93
|
|
|
|
|
|
|
// int act_count= spec_i; |
|
94
|
|
|
|
|
|
|
// if (!act_count) |
|
95
|
|
|
|
|
|
|
// croak("'repeat' cannot be the first action"); |
|
96
|
|
|
|
|
|
|
// if (n_el != 1) { // default is to repeat all, via act_count=i above |
|
97
|
|
|
|
|
|
|
// if (n_el != 2) |
|
98
|
|
|
|
|
|
|
// croak("Expected 0 or 1 parameters to 'repeat'"); |
|
99
|
|
|
|
|
|
|
// el= av_fetch(action_spec, 1, 0); |
|
100
|
|
|
|
|
|
|
// if (!el || !SvOK(*el) || !looks_like_number(*el) || SvIV(*el) <= 0) |
|
101
|
|
|
|
|
|
|
// croak("Expected positive integer of actions to repeat"); |
|
102
|
|
|
|
|
|
|
// act_count= SvIV(*el); |
|
103
|
|
|
|
|
|
|
// } |
|
104
|
|
|
|
|
|
|
// if (action_pos < *n_actions) { |
|
105
|
|
|
|
|
|
|
// int dest_act_idx, dest_spec_idx= spec_i - act_count; |
|
106
|
|
|
|
|
|
|
// // Locate the first action record with orig_idx == dest_spec_idx; |
|
107
|
|
|
|
|
|
|
// for (dest_act_idx= 0; dest_act_idx < spec_i; dest_act_idx++) |
|
108
|
|
|
|
|
|
|
// if (actions[dest_act_idx].orig_idx == dest_spec_idx) |
|
109
|
|
|
|
|
|
|
// break; |
|
110
|
|
|
|
|
|
|
// actions[action_pos].op= ACT_JUMP; |
|
111
|
|
|
|
|
|
|
// actions[action_pos].orig_idx= spec_i; |
|
112
|
|
|
|
|
|
|
// actions[action_pos].act.jmp.idx= dest_act_idx; |
|
113
|
|
|
|
|
|
|
// } |
|
114
|
|
|
|
|
|
|
// ++action_pos; |
|
115
|
|
|
|
|
|
|
// continue; |
|
116
|
|
|
|
|
|
|
//} |
|
117
|
24
|
100
|
|
|
|
|
if (strcmp(act_name, "shut_r") == 0) { |
|
118
|
4
|
|
|
|
|
|
common_op= ACT_x_SHUT_R; |
|
119
|
4
|
|
|
|
|
|
goto parse_close_common; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
20
|
50
|
|
|
|
|
if (strcmp(act_name, "shut_w") == 0) { |
|
122
|
20
|
|
|
|
|
|
common_op= ACT_x_SHUT_W; |
|
123
|
20
|
|
|
|
|
|
goto parse_close_common; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
case 7: |
|
126
|
2
|
50
|
|
|
|
|
if (strcmp(act_name, "shut_rw") == 0) { |
|
127
|
2
|
|
|
|
|
|
common_op= ACT_x_SHUT_RW; |
|
128
|
2
|
|
|
|
|
|
goto parse_close_common; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
default: |
|
131
|
0
|
|
|
|
|
|
croak("Unknown command '%s' in action list", act_name); |
|
132
|
|
|
|
|
|
|
} |
|
133
|
4
|
|
|
|
|
|
if (0) parse_kill_common: { // arrive from 'kill' and 'sig' |
|
134
|
|
|
|
|
|
|
// common_signal, common_pid will be set. |
|
135
|
|
|
|
|
|
|
// Is there an available action? |
|
136
|
4
|
100
|
|
|
|
|
if (action_pos < *n_actions) { |
|
137
|
2
|
|
|
|
|
|
actions[action_pos].op= ACT_KILL; |
|
138
|
2
|
|
|
|
|
|
actions[action_pos].orig_idx= spec_i; |
|
139
|
2
|
|
|
|
|
|
actions[action_pos].act.kill.signal= common_signal; |
|
140
|
2
|
|
|
|
|
|
actions[action_pos].act.kill.pid= common_pid; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
4
|
|
|
|
|
|
++action_pos; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
4
|
|
|
|
|
|
if (0) parse_run_common: { // arrive from 'run' and 'exec' |
|
145
|
4
|
|
|
|
|
|
char **argv= NULL, *str; |
|
146
|
|
|
|
|
|
|
STRLEN len; |
|
147
|
4
|
|
|
|
|
|
int j, argc= n_el-1; |
|
148
|
|
|
|
|
|
|
// common_op will be set. |
|
149
|
4
|
50
|
|
|
|
|
if (n_el < 2) |
|
150
|
0
|
|
|
|
|
|
croak("Expected at least one parameter for '%s'", act_name); |
|
151
|
|
|
|
|
|
|
// Align to pointer boundary within aux_buf |
|
152
|
4
|
|
|
|
|
|
aux_pos += sizeof(void*) - 1; |
|
153
|
4
|
|
|
|
|
|
aux_pos &= ~(sizeof(void*) - 1); |
|
154
|
|
|
|
|
|
|
// allocate an array of char* within aux_buf |
|
155
|
|
|
|
|
|
|
// argv remains NULL if there isn't room for it |
|
156
|
4
|
100
|
|
|
|
|
if (aux_pos + sizeof(void*) * n_el <= *aux_len) |
|
157
|
2
|
|
|
|
|
|
argv= (char**)(aux_buf + aux_pos); |
|
158
|
4
|
|
|
|
|
|
aux_pos += sizeof(void*) * (argc+1); |
|
159
|
|
|
|
|
|
|
// size up each of the strings, and copy them to the buffer if space available |
|
160
|
12
|
100
|
|
|
|
|
for (j= 0; j < argc; j++) { |
|
161
|
8
|
|
|
|
|
|
el= av_fetch(action_spec, j+1, 0); |
|
162
|
8
|
50
|
|
|
|
|
if (!el || !*el || !SvOK(*el)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
163
|
0
|
|
|
|
|
|
croak("Found undef element in arguments for '%s'", act_name); |
|
164
|
8
|
|
|
|
|
|
str= SvPV(*el, len); |
|
165
|
8
|
100
|
|
|
|
|
if (argv && aux_pos + len + 1 <= *aux_len) { |
|
|
|
50
|
|
|
|
|
|
|
166
|
4
|
|
|
|
|
|
argv[j]= aux_buf + aux_pos; |
|
167
|
4
|
|
|
|
|
|
memcpy(argv[j], str, len+1); |
|
168
|
|
|
|
|
|
|
} |
|
169
|
8
|
|
|
|
|
|
aux_pos += len+1; |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
// argv lists must end with NULL |
|
172
|
4
|
100
|
|
|
|
|
if (argv) |
|
173
|
2
|
|
|
|
|
|
argv[argc]= NULL; |
|
174
|
|
|
|
|
|
|
// store in an action if space remaining. |
|
175
|
4
|
100
|
|
|
|
|
if (action_pos < *n_actions) { |
|
176
|
2
|
|
|
|
|
|
actions[action_pos].op= common_op; |
|
177
|
2
|
|
|
|
|
|
actions[action_pos].orig_idx= spec_i; |
|
178
|
2
|
|
|
|
|
|
actions[action_pos].act.run.argc= argc; |
|
179
|
2
|
|
|
|
|
|
actions[action_pos].act.run.argv= argv; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
4
|
|
|
|
|
|
++action_pos; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
32
|
|
|
|
|
|
if (0) parse_close_common: { // arrive from 'close', 'shut_r', 'shut_w', 'shut_rw' |
|
184
|
|
|
|
|
|
|
int j; |
|
185
|
|
|
|
|
|
|
const char *str; |
|
186
|
|
|
|
|
|
|
STRLEN len; |
|
187
|
|
|
|
|
|
|
// common_op will be set, and can be ORed with the variant |
|
188
|
32
|
50
|
|
|
|
|
if (n_el < 2) |
|
189
|
0
|
|
|
|
|
|
croak("Expected 1 or more parameters to '%s'", act_name); |
|
190
|
|
|
|
|
|
|
// Each parameter is another action_fd or action_sockname action |
|
191
|
72
|
100
|
|
|
|
|
for (j= 1; j < n_el; j++) { |
|
192
|
40
|
|
|
|
|
|
el= av_fetch(action_spec, j, 0); |
|
193
|
40
|
50
|
|
|
|
|
if (!el || !*el || !SvOK(*el)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
194
|
0
|
|
|
|
|
|
croak("'%s' parameter %d is undefined", act_name, j-1); |
|
195
|
|
|
|
|
|
|
// If not a ref... |
|
196
|
40
|
100
|
|
|
|
|
if (!SvROK(*el)) { |
|
197
|
|
|
|
|
|
|
// Is it a file descriptor integer? |
|
198
|
22
|
100
|
|
|
|
|
if (looks_like_number(*el)) { |
|
199
|
20
|
|
|
|
|
|
IV fd= SvIV(*el); |
|
200
|
20
|
50
|
|
|
|
|
if (fd >= 0 && fd < 0x10000) { |
|
|
|
50
|
|
|
|
|
|
|
201
|
20
|
100
|
|
|
|
|
if (action_pos < *n_actions) { |
|
202
|
10
|
|
|
|
|
|
actions[action_pos].op= common_op | ACT_FD_x; |
|
203
|
10
|
|
|
|
|
|
actions[action_pos].orig_idx= spec_i; |
|
204
|
10
|
|
|
|
|
|
actions[action_pos].act.fd.fd= fd; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
20
|
|
|
|
|
|
++action_pos; |
|
207
|
20
|
|
|
|
|
|
continue; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
} |
|
210
|
2
|
|
|
|
|
|
str= SvPV(*el, len); |
|
211
|
|
|
|
|
|
|
// Is the length one of struct sockaddr_in, sockaddr_un, or sockaddr? |
|
212
|
2
|
50
|
|
|
|
|
if (len == sizeof(struct sockaddr) |
|
213
|
0
|
0
|
|
|
|
|
|| len == sizeof(struct sockaddr_in) |
|
214
|
0
|
0
|
|
|
|
|
|| len == sizeof(struct sockaddr_un) |
|
215
|
|
|
|
|
|
|
) { |
|
216
|
2
|
100
|
|
|
|
|
if (action_pos < *n_actions) { |
|
217
|
1
|
|
|
|
|
|
actions[action_pos].op= common_op | ACT_PNAME_x; |
|
218
|
1
|
|
|
|
|
|
actions[action_pos].orig_idx= spec_i; |
|
219
|
1
|
|
|
|
|
|
actions[action_pos].act.nam.addr_len= len; |
|
220
|
1
|
|
|
|
|
|
actions[action_pos].act.nam.addr= (struct sockaddr*) (aux_buf+aux_pos); |
|
221
|
|
|
|
|
|
|
} |
|
222
|
2
|
100
|
|
|
|
|
if (aux_pos + len <= *aux_len) |
|
223
|
1
|
|
|
|
|
|
memcpy((aux_buf+aux_pos), str, len); |
|
224
|
2
|
|
|
|
|
|
aux_pos += len; |
|
225
|
2
|
|
|
|
|
|
action_pos++; |
|
226
|
2
|
|
|
|
|
|
continue; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
// TODO: parse host:port strings |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
else { |
|
231
|
|
|
|
|
|
|
// Try getting a file descriptor from the ref |
|
232
|
18
|
|
|
|
|
|
int fd= fileno_from_sv(*el); |
|
233
|
18
|
50
|
|
|
|
|
if (fd >= 0) { |
|
234
|
18
|
100
|
|
|
|
|
if (action_pos < *n_actions) { |
|
235
|
9
|
|
|
|
|
|
actions[action_pos].op= common_op | ACT_FD_x; |
|
236
|
9
|
|
|
|
|
|
actions[action_pos].orig_idx= spec_i; |
|
237
|
9
|
|
|
|
|
|
actions[action_pos].act.fd.fd= fd; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
18
|
|
|
|
|
|
++action_pos; |
|
240
|
18
|
|
|
|
|
|
continue; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
// TODO: allow notation for socket self-name like { sockname => $x } |
|
243
|
|
|
|
|
|
|
// and maybe allow a full pair of { sockname => $x, peername => $y } |
|
244
|
|
|
|
|
|
|
// or even partial matches like { port => $num } |
|
245
|
|
|
|
|
|
|
} |
|
246
|
0
|
|
|
|
|
|
str= SvPV(*el, len); |
|
247
|
0
|
|
|
|
|
|
croak("Invalid parameter to '%s': '%s'; must be integer (fileno), file handle, or socket name like from getpeername", act_name, str); |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
} |
|
251
|
52
|
100
|
|
|
|
|
success= (action_pos <= *n_actions) && (aux_pos <= *aux_len); |
|
|
|
50
|
|
|
|
|
|
|
252
|
52
|
|
|
|
|
|
*n_actions= action_pos; |
|
253
|
52
|
|
|
|
|
|
*aux_len= aux_pos; |
|
254
|
52
|
|
|
|
|
|
return success; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
12
|
|
|
|
|
|
bool execute_action(struct action *act, bool resume, struct timespec *now_ts, struct socketalarm *parent) { |
|
258
|
12
|
|
|
|
|
|
int low= act->op & 0xF; |
|
259
|
12
|
|
|
|
|
|
int high= act->op & ~0xF; |
|
260
|
|
|
|
|
|
|
int how; |
|
261
|
|
|
|
|
|
|
char msgbuf[128]; |
|
262
|
|
|
|
|
|
|
|
|
263
|
12
|
|
|
|
|
|
switch (high) { |
|
264
|
3
|
|
|
|
|
|
case ACT_KILL: |
|
265
|
3
|
50
|
|
|
|
|
if (kill(act->act.kill.pid, act->act.kill.signal) != 0) |
|
266
|
0
|
|
|
|
|
|
perror("kill"); |
|
267
|
3
|
|
|
|
|
|
return true; // move to next action |
|
268
|
0
|
|
|
|
|
|
case ACT_SLEEP: { |
|
269
|
0
|
|
|
|
|
|
lazy_build_now_ts(now_ts); |
|
270
|
|
|
|
|
|
|
// On initial entry to this action, use current time to calculate the wake time |
|
271
|
0
|
0
|
|
|
|
|
if (!resume) { |
|
272
|
|
|
|
|
|
|
double t_seconds; |
|
273
|
0
|
|
|
|
|
|
t_seconds= (double) now_ts->tv_sec + .000000001 * now_ts->tv_nsec; |
|
274
|
|
|
|
|
|
|
// Add seconds to this time |
|
275
|
0
|
|
|
|
|
|
t_seconds += act->act.slp.seconds; |
|
276
|
0
|
|
|
|
|
|
parent->wake_ts.tv_sec= (time_t) t_seconds; |
|
277
|
0
|
|
|
|
|
|
parent->wake_ts.tv_nsec= (t_seconds - (long) t_seconds) * 1000000000; |
|
278
|
0
|
0
|
|
|
|
|
if (!parent->wake_ts.tv_nsec) |
|
279
|
0
|
|
|
|
|
|
parent->wake_ts.tv_nsec= 1; // because using tv_nsec as a defined-test |
|
280
|
0
|
|
|
|
|
|
return false; // come back later |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
// Else see whether we have reached that time yet |
|
283
|
0
|
0
|
|
|
|
|
if (now_ts->tv_sec > parent->wake_ts.tv_sec |
|
284
|
0
|
0
|
|
|
|
|
|| (now_ts->tv_sec == parent->wake_ts.tv_sec && now_ts->tv_nsec >= parent->wake_ts.tv_nsec)) |
|
|
|
0
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
|
return true; // reached end_ts |
|
286
|
0
|
|
|
|
|
|
return false; // still waiting |
|
287
|
|
|
|
|
|
|
} |
|
288
|
|
|
|
|
|
|
//case ACT_JUMP: |
|
289
|
|
|
|
|
|
|
// parent->cur_action= act->act.jmp.idx - 1; // parent will ++ after we return true |
|
290
|
|
|
|
|
|
|
// return true; |
|
291
|
9
|
|
|
|
|
|
case ACT_FD_x: |
|
292
|
9
|
|
|
|
|
|
switch (low) { |
|
293
|
0
|
|
|
|
|
|
case ACT_x_SHUT_R: how= SHUT_RD; if (0) |
|
294
|
9
|
|
|
|
|
|
case ACT_x_SHUT_W: how= SHUT_WR; if (0) |
|
295
|
0
|
|
|
|
|
|
case ACT_x_SHUT_RW: how= SHUT_RDWR; |
|
296
|
9
|
50
|
|
|
|
|
if (shutdown(act->act.fd.fd, how) < 0) perror("shutdown"); |
|
297
|
9
|
|
|
|
|
|
break; |
|
298
|
0
|
|
|
|
|
|
default: |
|
299
|
0
|
0
|
|
|
|
|
if (close(act->act.fd.fd) < 0) perror("close"); |
|
300
|
|
|
|
|
|
|
} |
|
301
|
9
|
|
|
|
|
|
return true; |
|
302
|
0
|
|
|
|
|
|
case ACT_PNAME_x: |
|
303
|
|
|
|
|
|
|
case ACT_SNAME_x: { |
|
304
|
|
|
|
|
|
|
struct sockaddr_storage addr; |
|
305
|
|
|
|
|
|
|
socklen_t len; |
|
306
|
|
|
|
|
|
|
int ret, i; |
|
307
|
0
|
0
|
|
|
|
|
for (i= 0; i < 1024; i++) { |
|
308
|
0
|
|
|
|
|
|
len= sizeof(addr); |
|
309
|
0
|
|
|
|
|
|
ret= high == ACT_PNAME_x? getpeername(i, (struct sockaddr*)&addr, &len) |
|
310
|
0
|
0
|
|
|
|
|
: getsockname(i, (struct sockaddr*)&addr, &len); |
|
311
|
0
|
0
|
|
|
|
|
if (ret == 0 && len == act->act.nam.addr_len |
|
|
|
0
|
|
|
|
|
|
|
312
|
0
|
0
|
|
|
|
|
&& memcmp(act->act.nam.addr, &addr, len) == 0 |
|
313
|
|
|
|
|
|
|
) { |
|
314
|
0
|
|
|
|
|
|
switch (low) { |
|
315
|
0
|
|
|
|
|
|
case ACT_x_SHUT_R: how= SHUT_RD; if (0) |
|
316
|
0
|
|
|
|
|
|
case ACT_x_SHUT_W: how= SHUT_WR; if (0) |
|
317
|
0
|
|
|
|
|
|
case ACT_x_SHUT_RW: how= SHUT_RDWR; |
|
318
|
0
|
0
|
|
|
|
|
if (shutdown(i, how) < 0) perror("shutdown"); |
|
319
|
0
|
|
|
|
|
|
break; |
|
320
|
0
|
|
|
|
|
|
default: |
|
321
|
0
|
0
|
|
|
|
|
if (close(i) < 0) perror("close"); |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
} |
|
325
|
0
|
|
|
|
|
|
return true; |
|
326
|
|
|
|
|
|
|
} |
|
327
|
0
|
|
|
|
|
|
case ACT_EXEC: { |
|
328
|
0
|
|
|
|
|
|
char **argv= act->act.run.argv; |
|
329
|
0
|
0
|
|
|
|
|
if (act->op == ACT_RUN) { |
|
330
|
|
|
|
|
|
|
// double-fork, so that parent can reap child, and grandchild gets cleaned up by init() |
|
331
|
|
|
|
|
|
|
pid_t child, gchild; |
|
332
|
0
|
0
|
|
|
|
|
if ((child= fork()) < 0) { // fork failure |
|
333
|
0
|
|
|
|
|
|
perror("fork"); |
|
334
|
0
|
|
|
|
|
|
return true; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
0
|
0
|
|
|
|
|
else if (child > 0) { // parent - wait for immediate child to return |
|
337
|
0
|
|
|
|
|
|
int status= -1; |
|
338
|
0
|
|
|
|
|
|
waitpid(child, &status, 0); |
|
339
|
0
|
0
|
|
|
|
|
if (status != 0) |
|
340
|
0
|
|
|
|
|
|
perror("waitpid"); // not accurate, but probably not going to happen unless child fails to fork |
|
341
|
0
|
|
|
|
|
|
return true; |
|
342
|
|
|
|
|
|
|
} |
|
343
|
0
|
0
|
|
|
|
|
else if ((gchild= fork()) != 0) { // second fork |
|
344
|
0
|
0
|
|
|
|
|
if (gchild < 0) perror("fork"); |
|
345
|
0
|
|
|
|
|
|
_exit(gchild < 0? 1 : 0); // immediately exit |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
// else we are the grandchild now |
|
348
|
|
|
|
|
|
|
} |
|
349
|
0
|
|
|
|
|
|
close(0); |
|
350
|
0
|
|
|
|
|
|
open("/dev/null", O_RDONLY); |
|
351
|
0
|
|
|
|
|
|
execvp(argv[0], argv); |
|
352
|
0
|
|
|
|
|
|
perror("exec"); // if we got here, it failed. Log the error. |
|
353
|
0
|
|
|
|
|
|
_exit(1); // make sure we don't continue this process. |
|
354
|
|
|
|
|
|
|
} |
|
355
|
0
|
|
|
|
|
|
default: { |
|
356
|
0
|
|
|
|
|
|
int unused= write(2, msgbuf, snprintf(msgbuf, sizeof(msgbuf), "BUG: No such action code %d", act->op)); |
|
357
|
|
|
|
|
|
|
(void) unused; |
|
358
|
0
|
|
|
|
|
|
return true; // pretend success; false would cause it to come back to this action later |
|
359
|
|
|
|
|
|
|
}} |
|
360
|
|
|
|
|
|
|
} |
|
361
|
|
|
|
|
|
|
|
|
362
|
11
|
|
|
|
|
|
const char *act_fd_variant_name(int variant) { |
|
363
|
11
|
|
|
|
|
|
switch (variant) { |
|
364
|
5
|
|
|
|
|
|
case ACT_x_CLOSE: return "close"; |
|
365
|
4
|
|
|
|
|
|
case ACT_x_SHUT_R: return "shut_r"; |
|
366
|
1
|
|
|
|
|
|
case ACT_x_SHUT_W: return "shut_w"; |
|
367
|
1
|
|
|
|
|
|
case ACT_x_SHUT_RW: return "shut_rw"; |
|
368
|
0
|
|
|
|
|
|
default: return "BUG"; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
|
|
372
|
11
|
|
|
|
|
|
const char *act_fd_variant_description(int variant) { |
|
373
|
11
|
|
|
|
|
|
switch (variant) { |
|
374
|
5
|
|
|
|
|
|
case ACT_x_CLOSE: return "close"; |
|
375
|
4
|
|
|
|
|
|
case ACT_x_SHUT_R: return "shutdown SHUT_RD"; |
|
376
|
1
|
|
|
|
|
|
case ACT_x_SHUT_W: return "shutdown SHUT_WR"; |
|
377
|
1
|
|
|
|
|
|
case ACT_x_SHUT_RW: return "shutdown SHUT_RDWR"; |
|
378
|
0
|
|
|
|
|
|
default: return "BUG"; |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
18
|
|
|
|
|
|
static void inflate_action(struct action *act, AV *dest) { |
|
383
|
18
|
|
|
|
|
|
int low= act->op & 0xF; |
|
384
|
18
|
|
|
|
|
|
int high= act->op & ~0xF; |
|
385
|
|
|
|
|
|
|
int i; |
|
386
|
18
|
|
|
|
|
|
switch (high) { |
|
387
|
4
|
|
|
|
|
|
case ACT_KILL: av_extend(dest, 2); |
|
388
|
4
|
|
|
|
|
|
av_push(dest, newSVpvs("kill")); |
|
389
|
4
|
|
|
|
|
|
av_push(dest, newSViv(act->act.kill.signal)); |
|
390
|
4
|
|
|
|
|
|
av_push(dest, newSViv(act->act.kill.pid)); |
|
391
|
4
|
|
|
|
|
|
return; |
|
392
|
1
|
|
|
|
|
|
case ACT_SLEEP: av_extend(dest, 1); |
|
393
|
1
|
|
|
|
|
|
av_push(dest, newSVpvs("sleep")); |
|
394
|
1
|
|
|
|
|
|
av_push(dest, newSVnv(act->act.slp.seconds)); |
|
395
|
1
|
|
|
|
|
|
return; |
|
396
|
|
|
|
|
|
|
//case ACT_JUMP: return snprintf(buffer, buflen, "goto %d", (int)act->act.jmp.idx); |
|
397
|
10
|
|
|
|
|
|
case ACT_FD_x: av_extend(dest, 1); |
|
398
|
10
|
|
|
|
|
|
av_push(dest, newSVpv(act_fd_variant_name(low), 0)); |
|
399
|
10
|
|
|
|
|
|
av_push(dest, newSViv(act->act.fd.fd)); |
|
400
|
10
|
|
|
|
|
|
return; |
|
401
|
1
|
|
|
|
|
|
case ACT_PNAME_x: av_extend(dest, 1); |
|
402
|
1
|
|
|
|
|
|
av_push(dest, newSVpv(act_fd_variant_name(low), 0)); |
|
403
|
1
|
|
|
|
|
|
av_push(dest, newSVpvn((char*)act->act.nam.addr, act->act.nam.addr_len)); |
|
404
|
1
|
|
|
|
|
|
return; |
|
405
|
2
|
|
|
|
|
|
case ACT_EXEC: av_extend(dest, act->act.run.argc); |
|
406
|
2
|
100
|
|
|
|
|
av_push(dest, newSVpv(act->op == ACT_RUN? "run":"exec", 0)); |
|
407
|
6
|
100
|
|
|
|
|
for (i= 0; i < act->act.run.argc; i++) |
|
408
|
4
|
|
|
|
|
|
av_push(dest, newSVpv(act->act.run.argv[i], 0)); |
|
409
|
2
|
|
|
|
|
|
return; |
|
410
|
0
|
|
|
|
|
|
default: |
|
411
|
0
|
|
|
|
|
|
croak("BUG: action code %d", act->op); |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
|
|
415
|
18
|
|
|
|
|
|
int snprint_action(char *buffer, size_t buflen, struct action *act) { |
|
416
|
18
|
|
|
|
|
|
int low= act->op & 0xF; |
|
417
|
18
|
|
|
|
|
|
int high= act->op & ~0xF; |
|
418
|
18
|
|
|
|
|
|
switch (high) { |
|
419
|
4
|
|
|
|
|
|
case ACT_KILL: return snprintf(buffer, buflen, "kill sig=%d pid=%d", (int)act->act.kill.signal, (int) act->act.kill.pid); |
|
420
|
1
|
|
|
|
|
|
case ACT_SLEEP: return snprintf(buffer, buflen, "sleep %.3lfs", (double)act->act.slp.seconds); |
|
421
|
|
|
|
|
|
|
//case ACT_JUMP: return snprintf(buffer, buflen, "goto %d", (int)act->act.jmp.idx); |
|
422
|
10
|
|
|
|
|
|
case ACT_FD_x: return snprintf(buffer, buflen, "%s %d", act_fd_variant_description(low), act->act.fd.fd); |
|
423
|
1
|
|
|
|
|
|
case ACT_PNAME_x: |
|
424
|
|
|
|
|
|
|
case ACT_SNAME_x: { |
|
425
|
1
|
50
|
|
|
|
|
int pos= snprintf(buffer, buflen, "%s %s ", |
|
426
|
|
|
|
|
|
|
act_fd_variant_description(low), |
|
427
|
|
|
|
|
|
|
high == ACT_PNAME_x? "peername":"sockname" |
|
428
|
|
|
|
|
|
|
); |
|
429
|
1
|
50
|
|
|
|
|
return pos + snprint_sockaddr(buffer+pos, buflen > pos? buflen-pos : 0, act->act.nam.addr); |
|
430
|
|
|
|
|
|
|
} |
|
431
|
2
|
|
|
|
|
|
case ACT_EXEC: { |
|
432
|
2
|
100
|
|
|
|
|
int i, pos= snprintf(buffer, buflen, "%sexec(", act->op == ACT_RUN? "fork,fork," : ""); |
|
433
|
6
|
100
|
|
|
|
|
for (i= 0; i < act->act.run.argc; i++) { |
|
434
|
4
|
50
|
|
|
|
|
pos += snprintf(buffer+pos, buflen > pos? buflen-pos : 0, "'%s',", act->act.run.argv[i]); |
|
435
|
|
|
|
|
|
|
} |
|
436
|
|
|
|
|
|
|
// if still in bounds, overwrite final character with ')' |
|
437
|
2
|
50
|
|
|
|
|
if (pos < buflen) |
|
438
|
2
|
|
|
|
|
|
buffer[pos-1]= ')'; |
|
439
|
2
|
|
|
|
|
|
return pos; |
|
440
|
|
|
|
|
|
|
} |
|
441
|
0
|
|
|
|
|
|
default: |
|
442
|
0
|
|
|
|
|
|
return snprintf(buffer, buflen, "BUG: action code %d", act->op); |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
} |