21
21
* Contact the authors at <mandos@fukt.bsnet.se>.
24
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY() */
24
26
#include <stdio.h> /* popen(), fileno(), fprintf(),
25
27
stderr, STDOUT_FILENO */
26
28
#include <iso646.h> /* and, or, not */
27
#include <sys/types.h> /* DIR, opendir(), stat(), struct stat,
28
waitpid(), WIFEXITED(),
29
WEXITSTATUS(), wait() */
29
#include <sys/types.h> /* DIR, opendir(), stat(),
30
struct stat, waitpid(),
31
WIFEXITED(), WEXITSTATUS(),
30
33
#include <sys/wait.h> /* wait() */
31
34
#include <dirent.h> /* DIR, struct dirent, opendir(),
32
35
readdir(), closedir() */
313
327
if (not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
315
fprintf(stderr, "Ignoring plugin dir entry name \"%s\""
329
fprintf(stderr, "Ignoring plugin dir entry \"%s\""
316
330
" with bad type or mode\n", filename);
320
334
if(getplugin(dirst->d_name, &plugin_list)->disabled){
322
fprintf(stderr, "Ignoring disabled plugin \"%s\"",
336
fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
327
// Starting a new process to be watched
334
341
plugin *p = getplugin(dirst->d_name, &plugin_list);
336
343
/* Add global arguments to argument list for this plugin */
339
346
addargument(p, *a);
353
exitstatus = EXIT_FAILURE;
356
ret = set_cloexec_flag(pipefd[0]);
358
perror("set_cloexec_flag");
359
exitstatus = EXIT_FAILURE;
362
ret = set_cloexec_flag(pipefd[1]);
364
perror("set_cloexec_flag");
365
exitstatus = EXIT_FAILURE;
368
// Starting a new process to be watched
342
369
pid_t pid = fork();
344
371
/* this is the child process */
346
close(pipefd[0]); /* close unused read end of pipe */
347
372
dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
375
/* If dir has no file descriptor, we could not set FD_CLOEXEC
376
and must close it manually */
352
379
if(execv(filename, p->argv) < 0){
355
381
_exit(EXIT_FAILURE);
359
386
close(pipefd[1]); /* close unused write end of pipe */
360
387
process *new_process = malloc(sizeof(process));
361
388
if (new_process == NULL){
367
new_process->fd = pipefd[0];
368
new_process->buffer = malloc(BUFFER_SIZE);
369
if (new_process->buffer == NULL){
371
exitstatus = EXIT_FAILURE;
374
new_process->buffer_size = BUFFER_SIZE;
375
new_process->buffer_length = 0;
394
*new_process = (struct process){ .pid = pid,
396
.next = process_list };
376
397
FD_SET(new_process->fd, &rfds_all);
378
399
if (maxfd < new_process->fd){
379
400
maxfd = new_process->fd;
383
new_process->next = process_list;
384
404
process_list = new_process;
407
/* Free the plugin list */
408
for(plugin *next; plugin_list != NULL; plugin_list = next){
409
next = plugin_list->next;
410
free(plugin_list->argv);
389
if (process_list != NULL){
391
fd_set rfds = rfds_all;
392
int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
393
if (select_ret == -1){
416
if (process_list == NULL){
417
fprintf(stderr, "No plugin processes started, exiting\n");
421
fd_set rfds = rfds_all;
422
int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
423
if (select_ret == -1){
425
exitstatus = EXIT_FAILURE;
428
for(process *proc = process_list; proc ; proc = proc->next){
429
if(not FD_ISSET(proc->fd, &rfds)){
432
if(proc->buffer_length + BUFFER_SIZE > proc->buffer_size){
433
proc->buffer = realloc(proc->buffer, proc->buffer_size
434
+ (size_t) BUFFER_SIZE);
435
if (proc->buffer == NULL){
437
exitstatus = EXIT_FAILURE;
440
proc->buffer_size += BUFFER_SIZE;
442
ret = read(proc->fd, proc->buffer + proc->buffer_length,
445
/* Read error from this process; ignore it */
448
proc->buffer_length += (size_t) ret;
451
/* wait for process exit */
453
waitpid(proc->pid, &status, 0);
454
if(not WIFEXITED(status) or WEXITSTATUS(status) != 0){
455
FD_CLR(proc->fd, &rfds_all);
458
for(size_t written = 0;
459
written < proc->buffer_length; written += (size_t)ret){
460
ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
461
proc->buffer + written,
466
exitstatus = EXIT_FAILURE;
397
for(process *process_itr = process_list; process_itr != NULL;
398
process_itr = process_itr->next){
399
if(FD_ISSET(process_itr->fd, &rfds)){
400
if(process_itr->buffer_length + BUFFER_SIZE
401
> process_itr->buffer_size){
402
process_itr->buffer = realloc(process_itr->buffer,
403
process_itr->buffer_size
404
+ (size_t) BUFFER_SIZE);
405
if (process_itr->buffer == NULL){
409
process_itr->buffer_size += BUFFER_SIZE;
411
ret = read(process_itr->fd, process_itr->buffer
412
+ process_itr->buffer_length, BUFFER_SIZE);
414
/* Read error from this process; ignore it */
417
process_itr->buffer_length += (size_t) ret;
420
/* wait for process exit */
422
waitpid(process_itr->pid, &status, 0);
423
if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
424
for(size_t written = 0;
425
written < process_itr->buffer_length;){
426
ret = write(STDOUT_FILENO,
427
process_itr->buffer + written,
428
process_itr->buffer_length - written);
433
written += (size_t)ret;
437
FD_CLR(process_itr->fd, &rfds_all);
447
for(process *process_itr = process_list; process_itr != NULL;
448
process_itr = process_itr->next){
449
close(process_itr->fd);
450
kill(process_itr->pid, SIGTERM);
451
free(process_itr->buffer);
476
for(process *next; process_list != NULL; process_list = next){
477
close(process_list->fd);
478
kill(process_list->pid, SIGTERM);
479
free(process_list->buffer);