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 */
349
379
if(execv(filename, p->argv) < 0){
352
381
_exit(EXIT_FAILURE);
356
386
close(pipefd[1]); /* close unused write end of pipe */
357
387
process *new_process = malloc(sizeof(process));
358
388
if (new_process == NULL){
364
new_process->fd = pipefd[0];
365
new_process->buffer = malloc(BUFFER_SIZE);
366
if (new_process->buffer == NULL){
368
exitstatus = EXIT_FAILURE;
371
new_process->buffer_size = BUFFER_SIZE;
372
new_process->buffer_length = 0;
394
*new_process = (struct process){ .pid = pid,
396
.next = process_list };
373
397
FD_SET(new_process->fd, &rfds_all);
375
399
if (maxfd < new_process->fd){
376
400
maxfd = new_process->fd;
380
new_process->next = process_list;
381
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);
386
if (process_list != NULL){
388
fd_set rfds = rfds_all;
389
int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
390
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;
394
for(process *process_itr = process_list; process_itr != NULL;
395
process_itr = process_itr->next){
396
if(FD_ISSET(process_itr->fd, &rfds)){
397
if(process_itr->buffer_length + BUFFER_SIZE
398
> process_itr->buffer_size){
399
process_itr->buffer = realloc(process_itr->buffer,
400
process_itr->buffer_size
401
+ (size_t) BUFFER_SIZE);
402
if (process_itr->buffer == NULL){
406
process_itr->buffer_size += BUFFER_SIZE;
408
ret = read(process_itr->fd, process_itr->buffer
409
+ process_itr->buffer_length, BUFFER_SIZE);
411
/* Read error from this process; ignore it */
414
process_itr->buffer_length += (size_t) ret;
417
/* wait for process exit */
419
waitpid(process_itr->pid, &status, 0);
420
if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
421
for(size_t written = 0;
422
written < process_itr->buffer_length;){
423
ret = write(STDOUT_FILENO,
424
process_itr->buffer + written,
425
process_itr->buffer_length - written);
430
written += (size_t)ret;
434
FD_CLR(process_itr->fd, &rfds_all);
444
for(process *process_itr = process_list; process_itr != NULL;
445
process_itr = process_itr->next){
446
close(process_itr->fd);
447
kill(process_itr->pid, SIGTERM);
448
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);