/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk
13 by Björn Påhlsson
Added following support:
1
#include <stdio.h>	/* popen, fileno */
2
#include <iso646.h>	/* and, or, not */
3
#include <sys/types.h>	/* DIR, opendir, stat, struct stat, waitpid,
4
			   WIFEXITED, WEXITSTATUS, wait */
5
#include <sys/wait.h>	/* wait */
6
#include <dirent.h>	/* DIR, opendir */
7
#include <sys/stat.h>	/* stat, struct stat */
8
#include <unistd.h>	/* stat, struct stat, chdir */
9
#include <stdlib.h>	/* EXIT_FAILURE */
10
#include <sys/select.h>	/* fd_set, select, FD_ZERO, FD_SET, FD_ISSET */
11
#include <string.h>	/* strlen, strcpy, strcat */
12
#include <stdbool.h>	/* true */
13
#include <sys/wait.h>	/* waitpid, WIFEXITED, WEXITSTATUS */
14
#include <errno.h>	/* errno */
15
16
struct process;
17
18
typedef struct process{
19
  pid_t pid;
20
  int fd;
21
  char *buffer;
22
  int buffer_size;
23
  int buffer_length;
24
  struct process *next;
25
} process;
26
27
#define BUFFER_SIZE 256
28
29
int main(int argc, char *argv[]){
30
  char plugindir[] = "plugins.d";
31
  size_t d_name_len, plugindir_len = sizeof(plugindir)-1;
32
  DIR *dir;
33
  struct dirent *dirst;
34
  struct stat st;
35
  fd_set rfds_orig;
36
  int ret, maxfd = 0;
37
  process *process_list = NULL;
38
  
39
  dir = opendir(plugindir);
40
41
  if(dir == NULL){
42
    fprintf(stderr, "Can not open directory\n");
43
    return EXIT_FAILURE;
44
  }
45
  
46
  FD_ZERO(&rfds_orig);
47
  
48
  while(true){
49
    dirst = readdir(dir);
50
    
51
    // All directory entries have been processed
52
    if(dirst == NULL){
53
      break;
54
    }
55
    
56
    d_name_len = strlen(dirst->d_name);
57
    
58
    // Ignore dotfiles and backup files
59
    if (dirst->d_name[0] == '.'
60
	or dirst->d_name[d_name_len - 1] == '~'){
61
      continue;
62
    }
63
    
64
    char *filename = malloc(d_name_len + plugindir_len + 1);
65
    strcpy(filename, plugindir);
66
    strcat(filename, "/");
67
    strcat(filename, dirst->d_name);    
68
    
69
    stat(filename, &st);
70
71
    if (S_ISREG(st.st_mode) and (access(filename, X_OK) == 0)){
72
      // Starting a new process to be watched
73
      process *new_process = malloc(sizeof(process));
74
      int pipefd[2];
75
      pipe(pipefd);
76
      new_process->pid = fork();
77
      if(new_process->pid == 0){
78
	/* this is the child process */
79
	closedir(dir);
80
	close(pipefd[0]);	/* close unused read end of pipe */
81
	dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
82
	/* create a new modified argument list */
83
	char **new_argv = malloc(sizeof(char *) * argc + 1);
84
	new_argv[0] = filename;
85
	for(int i = 1; i < argc; i++){
86
	  new_argv[i] = argv[i];
87
	}
88
	new_argv[argc] = NULL;
89
	if(execv(filename, new_argv) < 0){
90
	  perror(argv[0]);
91
	  close(pipefd[1]);
92
	  exit(EXIT_FAILURE);
93
	}
94
	/* no return */
95
      }
96
      close(pipefd[1]);		/* close unused write end of pipe */
97
      new_process->fd = pipefd[0];
98
      new_process->buffer = malloc(BUFFER_SIZE);
99
      if (new_process->buffer == NULL){
100
	perror(argv[0]);
101
	goto end;
102
      }
103
      new_process->buffer_size = BUFFER_SIZE;
104
      new_process->buffer_length = 0;
105
      FD_SET(new_process->fd, &rfds_orig);
106
      
107
      if (maxfd < new_process->fd){
108
	maxfd = new_process->fd;
109
      }
110
      
111
      //List handling
112
      new_process->next = process_list;
113
      process_list = new_process;
114
    }
115
  }
116
  
117
  closedir(dir);
118
  
119
  if (process_list != NULL){
120
    while(true){
121
      fd_set rfds = rfds_orig;
122
      int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
123
      if (select_ret == -1){
124
	perror(argv[0]);
125
	goto end;
126
      }else{	
127
	for(process *process_itr = process_list; process_itr != NULL;
128
	    process_itr = process_itr->next){
129
	  if(FD_ISSET(process_itr->fd, &rfds)){
130
	    if(process_itr->buffer_length + BUFFER_SIZE
131
	       > process_itr->buffer_size){
132
		process_itr->buffer = realloc(process_itr->buffer,
133
					      process_itr->buffer_size
134
					      + BUFFER_SIZE);
135
		if (process_itr->buffer == NULL){
136
		  perror(argv[0]);
137
		  goto end;
138
		}
139
		process_itr->buffer_size += BUFFER_SIZE;
140
	    }
141
	    ret = read(process_itr->fd, process_itr->buffer
142
		       + process_itr->buffer_length, BUFFER_SIZE);
143
	    process_itr->buffer_length+=ret;
144
	    if(ret == 0){
145
	      /* got EOF */
146
	      /* wait for process exit */
147
	      int status;
148
	      waitpid(process_itr->pid, &status, 0);
149
	      if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
150
		write(STDOUT_FILENO, process_itr->buffer,
151
		      process_itr->buffer_length);
152
		goto end;
153
	      } else {
154
		FD_CLR(process_itr->fd, &rfds_orig);
155
	      }
156
	    }
157
	  }
158
	}
159
      }
160
    }
161
  }
162
  
163
 end:
164
  for(process *process_itr = process_list; process_itr != NULL;
165
      process_itr = process_itr->next){
166
    close(process_itr->fd);
167
    kill(process_itr->pid, SIGTERM);
168
    free(process_itr->buffer);
169
  }
170
  
171
  while(true){
172
    int status;
173
    ret = wait(&status);
174
    if (ret == -1){
175
      if(errno != ECHILD){
176
	perror("wait");
177
      }
178
      break;
179
    }
180
  }  
181
  return EXIT_SUCCESS;
182
}