throw away result, we don't care.
[trinity.git] / files.c
blobdf043e4b6611e7edeb977683c924e6dc84a4b70c
1 #include <ftw.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <dirent.h>
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
12 #include "trinity.h" // __unused__
13 #include "arch.h" // page_size
14 #include "files.h"
15 #include "log.h"
16 #include "maps.h"
17 #include "shm.h"
18 #include "sanitise.h"
19 #include "constants.h"
20 #include "list.h"
21 #include "random.h"
22 #include "utils.h"
24 static int files_added = 0;
25 const char **fileindex;
26 unsigned int files_in_index = 0;
28 struct namelist {
29 struct list_head list;
30 const char *name;
33 static struct namelist *names = NULL;
35 static uid_t my_uid;
36 static gid_t my_gid;
38 static int ignore_files(const char *path)
40 unsigned int i, j;
41 unsigned int pathlen, offset = 0;
43 /* These are exact matches. */
44 const char *ignored_paths[] = {
45 ".", "..",
47 /* dangerous/noisy/annoying stuff in /proc */
48 "/proc/sysrq-trigger", "/proc/kmem", "/proc/kcore",
50 /* dangerous/noisy/annoying stuff in /dev */
51 "/dev/log", "/dev/mem", "/dev/kmsg",
52 NULL
55 /* Partial matches. */ //FIXME: This whole function should just use globs to pattern match.
56 const char *ignored_patterns[] = {
58 /* dangerous/noisy/annoying per-process stuff. */
59 "coredump_filter", "make-it-fail", "oom_adj", "oom_score_adj",
60 NULL
63 pathlen = strlen(path);
65 /* First do the exact matches */
66 for (i = 0; ignored_paths[i]; i++) {
67 if (strlen(ignored_paths[i]) != pathlen) {
68 continue;
71 if (!strcmp(path, ignored_paths[i])) {
72 debugf("Skipping %s\n", path);
73 return 1;
77 /* Now make sure none of the patterns match the end of the pathname */
78 for (j = 0; j < pathlen; j++) {
79 if (path[j] == '/')
80 offset = j;
82 offset++;
84 if (offset == 1)
85 return 0;
87 for (i = 0; ignored_patterns[i]; i++) {
88 if (!strcmp(path + offset, ignored_patterns[i])) {
89 debugf("Skipping pattern %s\n", path);
90 return 1;
94 /* special case to match tty* until I do globbing */
95 if (!strncmp(path + offset, "tty", 3)) {
96 debugf("Skipping %s\n", path);
97 return 1;
99 return 0;
102 static void add_to_namelist(const char *name)
104 struct namelist *newnode;
105 struct list_head *list = (struct list_head *) names;
107 newnode = zmalloc(sizeof(struct namelist));
108 newnode->name = strdup(name);
109 list_add_tail(&newnode->list, list);
112 static int check_stat_file(const struct stat *sb)
114 int openflag;
115 bool set_read = FALSE;
116 bool set_write = FALSE;
118 if (S_ISLNK(sb->st_mode))
119 return -1;
121 if (sb->st_uid == my_uid) {
122 if (sb->st_mode & S_IRUSR)
123 set_read = TRUE;
124 if (sb->st_mode & S_IWUSR)
125 set_write = TRUE;
128 if (sb->st_gid == my_gid) {
129 if (sb->st_mode & S_IRGRP)
130 set_read = TRUE;
131 if (sb->st_mode & S_IWGRP)
132 set_write = TRUE;
135 if (sb->st_mode & S_IROTH)
136 set_read = TRUE;
137 if (sb->st_mode & S_IWOTH)
138 set_write = TRUE;
141 if ((set_read | set_write) == 0)
142 return -1;
144 if (set_read == TRUE)
145 openflag = O_RDONLY;
146 if (set_write == TRUE)
147 openflag = O_WRONLY;
148 if ((set_read == TRUE) && (set_write == TRUE))
149 openflag = O_RDWR;
151 if (S_ISDIR(sb->st_mode))
152 openflag = O_RDONLY;
154 return openflag;
157 static int file_tree_callback(const char *fpath, const struct stat *sb, __unused__ int typeflag, __unused__ struct FTW *ftwbuf)
160 if (ignore_files(fpath)) {
161 return FTW_SKIP_SUBTREE;
164 // Check we can read it.
165 if (check_stat_file(sb) == -1)
166 return FTW_CONTINUE;
168 if (shm->exit_reason != STILL_RUNNING)
169 return FTW_STOP;
171 add_to_namelist(fpath);
172 files_added++;
174 return FTW_CONTINUE;
178 static void open_fds(const char *dirpath)
180 int before = files_added;
181 int flags = FTW_DEPTH | FTW_ACTIONRETVAL | FTW_MOUNT;
182 int ret;
184 /* By default, don't follow symlinks so we only get each file once.
185 * But, if we do something like -V /lib, then follow it
187 * I'm not sure about this, might remove later.
189 if (victim_path == NULL)
190 flags |= FTW_PHYS;
192 ret = nftw(dirpath, file_tree_callback, 32, flags);
193 if (ret != 0) {
194 if (shm->exit_reason != EXIT_SIGINT)
195 output(0, "Something went wrong during nftw(%s). (%d:%s)\n",
196 dirpath, ret, strerror(errno));
197 return;
200 output(0, "Added %d filenames from %s\n", files_added - before, dirpath);
203 void generate_filelist(void)
205 unsigned int i = 0;
206 struct list_head *node;
207 struct namelist *nl;
209 my_uid = getuid();
210 my_gid = getgid();
212 names = zmalloc(sizeof(struct namelist));
213 INIT_LIST_HEAD(&names->list);
215 output(1, "Generating file descriptors\n");
217 if (victim_path != NULL) {
218 open_fds(victim_path);
219 } else {
220 open_fds("/dev");
221 open_fds("/proc");
222 open_fds("/sys");
225 if (shm->exit_reason != STILL_RUNNING)
226 return;
228 if (files_added == 0) {
229 output(1, "Didn't add any files!!\n");
230 return;
233 /* Generate an index of pointers to the filenames */
235 fileindex = malloc(sizeof(char *) * files_added);
237 list_for_each(node, &names->list) {
238 nl = (struct namelist *) node;
239 fileindex[i++] = nl->name;
241 files_in_index = i;
244 static int open_file(void)
246 int fd;
247 int ret;
248 const char *filename;
249 int flags;
250 const char *modestr;
251 struct stat sb;
253 retry:
254 filename = get_filename();
255 ret = lstat(filename, &sb);
256 if (ret == -1)
257 goto retry;
259 flags = check_stat_file(&sb);
260 if (flags == -1)
261 goto retry;
263 fd = open(filename, flags | O_NONBLOCK);
264 if (fd < 0) {
265 output(2, "Couldn't open %s : %s\n", filename, strerror(errno));
266 return fd;
269 switch (flags) {
270 case O_RDONLY: modestr = "read-only"; break;
271 case O_WRONLY: modestr = "write-only"; break;
272 case O_RDWR: modestr = "read-write"; break;
273 default: modestr = "unknown"; break;
275 output(2, "fd[%i] = %s (%s)\n", fd, filename, modestr);
276 return fd;
279 void open_files(void)
281 unsigned int i, nr_to_open;
282 int fd;
284 if (files_in_index < NR_FILE_FDS)
285 nr_to_open = files_in_index;
286 else
287 nr_to_open = NR_FILE_FDS;
289 if (fileindex == NULL) /* this can happen if we ctrl-c'd */
290 return;
292 for (i = 0; i < nr_to_open; i++) {
293 fd = open_file();
295 shm->file_fds[i] = fd;
296 nr_file_fds++;
300 void close_files(void)
302 unsigned int i;
303 int fd;
305 shm->current_fd = 0;
306 shm->fd_lifetime = 0;
308 // FIXME: Does this need locking? At the least, check for NULL fd's
309 for (i = 0; i < nr_file_fds; i++) {
310 fd = shm->file_fds[i];
311 shm->file_fds[i] = 0;
312 if (fd != 0)
313 close(fd);
316 nr_file_fds = 0;
319 const char * get_filename(void)
321 if (files_in_index == 0) /* This can happen if we run with -n. Should we do something else ? */
322 return NULL;
324 return fileindex[rand() % files_in_index];