18
18
#include <fcntl.h>
19
19
#include <stdlib.h>
20
20
#include <string.h>
21
+ #include <stddef.h>
22
+ #include <sys/avl.h>
21
23
#include <sys/stat.h>
22
24
#include <sys/wait.h>
23
25
#include <time.h>
24
26
#include <unistd.h>
27
+ #include <pthread.h>
25
28
#include "zed_exec.h"
26
29
#include "zed_file.h"
27
30
#include "zed_log.h"
28
31
#include "zed_strings.h"
29
32
30
33
#define ZEVENT_FILENO 3
31
34
35
+ struct launched_process_node {
36
+ avl_node_t node ;
37
+ pid_t pid ;
38
+ uint64_t eid ;
39
+ char * name ;
40
+ };
41
+
42
+ static int
43
+ _launched_process_node_compare (const void * x1 , const void * x2 )
44
+ {
45
+ pid_t p1 ;
46
+ pid_t p2 ;
47
+
48
+ assert (x1 != NULL );
49
+ assert (x2 != NULL );
50
+
51
+ p1 = ((const struct launched_process_node * ) x1 )-> pid ;
52
+ p2 = ((const struct launched_process_node * ) x2 )-> pid ;
53
+
54
+ if (p1 < p2 )
55
+ return (-1 );
56
+ else if (p1 == p2 )
57
+ return (0 );
58
+ else
59
+ return (1 );
60
+ }
61
+
62
+ static pthread_t _reap_children_tid = (pthread_t )- 1 ;
63
+ static volatile boolean_t _reap_children_stop ;
64
+ static avl_tree_t _launched_processes ;
65
+ static pthread_mutex_t _launched_processes_lock = PTHREAD_MUTEX_INITIALIZER ;
66
+
32
67
/*
33
68
* Create an environment string array for passing to execve() using the
34
69
* NAME=VALUE strings in container [zsp].
@@ -85,8 +120,8 @@ _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
85
120
int n ;
86
121
pid_t pid ;
87
122
int fd ;
88
- pid_t wpid ;
89
- int status ;
123
+ struct launched_process_node * node ;
124
+ sigset_t mask ;
90
125
91
126
assert (dir != NULL );
92
127
assert (prog != NULL );
@@ -107,6 +142,9 @@ _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
107
142
prog , eid , strerror (errno ));
108
143
return ;
109
144
} else if (pid == 0 ) {
145
+ (void ) sigemptyset (& mask );
146
+ (void ) sigprocmask (SIG_SETMASK , & mask , NULL );
147
+
110
148
(void ) umask (022 );
111
149
if ((fd = open ("/dev/null" , O_RDWR )) != -1 ) {
112
150
(void ) dup2 (fd , STDIN_FILENO );
@@ -124,57 +162,108 @@ _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
124
162
zed_log_msg (LOG_INFO , "Invoking \"%s\" eid=%llu pid=%d" ,
125
163
prog , eid , pid );
126
164
127
- /* FIXME: Timeout rogue child processes with sigalarm? */
128
-
129
- /*
130
- * Wait for child process using WNOHANG to limit
131
- * the time spent waiting to 10 seconds (10,000ms).
132
- */
133
- for (n = 0 ; n < 1000 ; n ++ ) {
134
- wpid = waitpid (pid , & status , WNOHANG );
135
- if (wpid == (pid_t )- 1 ) {
136
- if (errno == EINTR )
137
- continue ;
138
- zed_log_msg (LOG_WARNING ,
139
- "Failed to wait for \"%s\" eid=%llu pid=%d" ,
140
- prog , eid , pid );
141
- break ;
142
- } else if (wpid == 0 ) {
143
- struct timespec t ;
144
-
145
- /* child still running */
146
- t .tv_sec = 0 ;
147
- t .tv_nsec = 10000000 ; /* 10ms */
148
- (void ) nanosleep (& t , NULL );
149
- continue ;
150
- }
165
+ node = calloc (1 , sizeof (* node ));
166
+ if (node ) {
167
+ node -> pid = pid ;
168
+ node -> eid = eid ;
169
+ node -> name = strdup (prog );
170
+ (void ) pthread_mutex_lock (& _launched_processes_lock );
171
+ avl_add (& _launched_processes , node );
172
+ (void ) pthread_mutex_unlock (& _launched_processes_lock );
173
+ }
174
+ }
151
175
152
- if (WIFEXITED (status )) {
153
- zed_log_msg (LOG_INFO ,
154
- "Finished \"%s\" eid=%llu pid=%d exit=%d" ,
155
- prog , eid , pid , WEXITSTATUS (status ));
156
- } else if (WIFSIGNALED (status )) {
157
- zed_log_msg (LOG_INFO ,
158
- "Finished \"%s\" eid=%llu pid=%d sig=%d/%s" ,
159
- prog , eid , pid , WTERMSIG (status ),
160
- strsignal (WTERMSIG (status )));
176
+ static void
177
+ _nop (int sig )
178
+ {}
179
+
180
+ static void *
181
+ _reap_children (void * arg )
182
+ {
183
+ struct launched_process_node node , * pnode ;
184
+ pid_t pid ;
185
+ int status ;
186
+ struct sigaction sa = {};
187
+
188
+ (void ) sigfillset (& sa .sa_mask );
189
+ (void ) sigdelset (& sa .sa_mask , SIGCHLD );
190
+ (void ) pthread_sigmask (SIG_SETMASK , & sa .sa_mask , NULL );
191
+
192
+ (void ) sigemptyset (& sa .sa_mask );
193
+ sa .sa_handler = _nop ;
194
+ sa .sa_flags = SA_NOCLDSTOP ;
195
+ (void ) sigaction (SIGCHLD , & sa , NULL );
196
+
197
+ for (_reap_children_stop = B_FALSE ; !_reap_children_stop ; ) {
198
+ pid = waitpid (0 , & status , 0 );
199
+
200
+ if (pid == (pid_t )- 1 ) {
201
+ if (errno == ECHILD )
202
+ pause ();
203
+ else if (errno != EINTR )
204
+ zed_log_msg (LOG_WARNING ,
205
+ "Failed to wait for children: %s" ,
206
+ strerror (errno ));
161
207
} else {
162
- zed_log_msg (LOG_INFO ,
163
- "Finished \"%s\" eid=%llu pid=%d status=0x%X" ,
164
- prog , eid , (unsigned int ) status );
208
+ memset (& node , 0 , sizeof (node ));
209
+ node .pid = pid ;
210
+ (void ) pthread_mutex_lock (& _launched_processes_lock );
211
+ pnode = avl_find (& _launched_processes , & node , NULL );
212
+ if (pnode ) {
213
+ memcpy (& node , pnode , sizeof (node ));
214
+
215
+ avl_remove (& _launched_processes , pnode );
216
+ free (pnode );
217
+ }
218
+ (void ) pthread_mutex_unlock (& _launched_processes_lock );
219
+
220
+ if (WIFEXITED (status )) {
221
+ zed_log_msg (LOG_INFO ,
222
+ "Finished \"%s\" eid=%llu pid=%d exit=%d" ,
223
+ node .name , node .eid , pid ,
224
+ WEXITSTATUS (status ));
225
+ } else if (WIFSIGNALED (status )) {
226
+ zed_log_msg (LOG_INFO ,
227
+ "Finished \"%s\" eid=%llu pid=%d sig=%d/%s" ,
228
+ node .name , node .eid , pid , WTERMSIG (status ),
229
+ strsignal (WTERMSIG (status )));
230
+ } else {
231
+ zed_log_msg (LOG_INFO ,
232
+ "Finished \"%s\" eid=%llu pid=%d "
233
+ "status=0x%X" ,
234
+ node .name , node .eid , (unsigned int ) status );
235
+ }
236
+
237
+ free (node .name );
165
238
}
166
- break ;
167
239
}
168
240
169
- /*
170
- * kill child process after 10 seconds
171
- */
172
- if (wpid == 0 ) {
173
- zed_log_msg (LOG_WARNING , "Killing hung \"%s\" pid=%d" ,
174
- prog , pid );
175
- (void ) kill (pid , SIGKILL );
176
- (void ) waitpid (pid , & status , 0 );
241
+ return (NULL );
242
+ }
243
+
244
+ void
245
+ zed_exec_fini (void )
246
+ {
247
+ struct launched_process_node * node ;
248
+ void * ck = NULL ;
249
+
250
+ if (_reap_children_tid == (pthread_t )- 1 )
251
+ return ;
252
+
253
+ _reap_children_stop = B_TRUE ;
254
+ (void ) pthread_kill (_reap_children_tid , SIGCHLD );
255
+ (void ) pthread_join (_reap_children_tid , NULL );
256
+
257
+ while ((node = avl_destroy_nodes (& _launched_processes , & ck )) != NULL ) {
258
+ free (node -> name );
259
+ free (node );
177
260
}
261
+ avl_destroy (& _launched_processes );
262
+
263
+ (void ) pthread_mutex_destroy (& _launched_processes_lock );
264
+ (void ) pthread_mutex_init (& _launched_processes_lock , NULL );
265
+
266
+ _reap_children_tid = (pthread_t )- 1 ;
178
267
}
179
268
180
269
/*
@@ -206,6 +295,17 @@ zed_exec_process(uint64_t eid, const char *class, const char *subclass,
206
295
if (!dir || !zedlets || !envs || zfd < 0 )
207
296
return (-1 );
208
297
298
+ if (_reap_children_tid == (pthread_t )- 1 ) {
299
+ if (pthread_create (& _reap_children_tid , NULL ,
300
+ _reap_children , NULL ) != 0 )
301
+ return (-1 );
302
+ pthread_setname_np (_reap_children_tid , "reap ZEDLETs" );
303
+
304
+ avl_create (& _launched_processes , _launched_process_node_compare ,
305
+ sizeof (struct launched_process_node ),
306
+ offsetof(struct launched_process_node , node ));
307
+ }
308
+
209
309
csp = class_strings ;
210
310
211
311
if (class )
0 commit comments