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 | } | |
| 14
by Björn Påhlsson Fixed a overbufferflow bug, thanks to a forgotten \0 | 63 | |
| 64 | char *filename = malloc(d_name_len + plugindir_len + 2); | |
| 13
by Björn Påhlsson Added following support: | 65 | strcpy(filename, plugindir); | 
| 66 | strcat(filename, "/"); | |
| 67 | strcat(filename, dirst->d_name); | |
| 14
by Björn Påhlsson Fixed a overbufferflow bug, thanks to a forgotten \0 | 68 | |
| 13
by Björn Påhlsson Added following support: | 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 */ | |
| 14
by Björn Påhlsson Fixed a overbufferflow bug, thanks to a forgotten \0 | 83 | char **new_argv = malloc(sizeof(char *) * (argc + 1)); | 
| 13
by Björn Påhlsson Added following support: | 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 | }
 |