work around bluetooth linger bug
[trinity.git] / files.c
blob8f4ff2d82d7f1d3da1d5ad3ac9ecc8780c9b7a9c
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"
23 static int files_added = 0;
24 const char **fileindex;
25 unsigned int files_in_index = 0;
27 struct namelist {
28 struct list_head list;
29 const char *name;
32 static struct namelist *names = NULL;
34 static uid_t my_uid;
35 static gid_t my_gid;
37 static int ignore_files(const char *path)
39 unsigned int i, j;
40 unsigned int pathlen, offset = 0;
42 /* These are exact matches. */
43 const char *ignored_paths[] = {
44 ".", "..",
46 /* dangerous/noisy/annoying stuff in /proc */
47 "/proc/sysrq-trigger", "/proc/kmem", "/proc/kcore",
49 /* dangerous/noisy/annoying stuff in /dev */
50 "/dev/log", "/dev/mem", "/dev/kmsg",
51 NULL
54 /* Partial matches. */ //FIXME: This whole function should just use globs to pattern match.
55 const char *ignored_patterns[] = {
57 /* dangerous/noisy/annoying per-process stuff. */
58 "coredump_filter", "make-it-fail", "oom_adj", "oom_score_adj",
59 NULL
62 pathlen = strlen(path);
64 /* First do the exact matches */
65 for (i = 0; ignored_paths[i]; i++) {
66 if (strlen(ignored_paths[i]) != pathlen) {
67 continue;
70 if (!strcmp(path, ignored_paths[i])) {
71 debugf("Skipping %s\n", path);
72 return 1;
76 /* Now make sure none of the patterns match the end of the pathname */
77 for (j = 0; j < pathlen; j++) {
78 if (path[j] == '/')
79 offset = j;
81 offset++;
83 if (offset == 1)
84 return 0;
86 for (i = 0; ignored_patterns[i]; i++) {
87 if (!strcmp(path + offset, ignored_patterns[i])) {
88 debugf("Skipping pattern %s\n", path);
89 return 1;
93 /* special case to match tty* until I do globbing */
94 if (!strncmp(path + offset, "tty", 3)) {
95 debugf("Skipping %s\n", path);
96 return 1;
98 return 0;
102 static struct namelist * alloc_namenode(void)
104 struct namelist *newnode;
106 newnode = malloc(sizeof(struct namelist));
107 if (newnode == NULL)
108 exit(EXIT_FAILURE);
110 memset(newnode, 0, sizeof(struct namelist));
111 return newnode;
114 static void add_to_namelist(const char *name)
116 struct namelist *newnode;
117 struct list_head *list = (struct list_head *) names;
119 newnode = alloc_namenode();
120 newnode->name = strdup(name);
121 list_add_tail(&newnode->list, list);
124 static int check_stat_file(const struct stat *sb)
126 int openflag;
127 bool set_read = FALSE;
128 bool set_write = FALSE;
130 if (S_ISLNK(sb->st_mode))
131 return -1;
133 if (sb->st_uid == my_uid) {
134 if (sb->st_mode & S_IRUSR)
135 set_read = TRUE;
136 if (sb->st_mode & S_IWUSR)
137 set_write = TRUE;
140 if (sb->st_gid == my_gid) {
141 if (sb->st_mode & S_IRGRP)
142 set_read = TRUE;
143 if (sb->st_mode & S_IWGRP)
144 set_write = TRUE;
147 if (sb->st_mode & S_IROTH)
148 set_read = TRUE;
149 if (sb->st_mode & S_IWOTH)
150 set_write = TRUE;
153 if ((set_read | set_write) == 0)
154 return -1;
156 if (set_read == TRUE)
157 openflag = O_RDONLY;
158 if (set_write == TRUE)
159 openflag = O_WRONLY;
160 if ((set_read == TRUE) && (set_write == TRUE))
161 openflag = O_RDWR;
163 if (S_ISDIR(sb->st_mode))
164 openflag = O_RDONLY;
166 return openflag;
169 static int file_tree_callback(const char *fpath, const struct stat *sb, __unused__ int typeflag, __unused__ struct FTW *ftwbuf)
172 if (ignore_files(fpath)) {
173 return FTW_SKIP_SUBTREE;
176 // Check we can read it.
177 if (check_stat_file(sb) == -1)
178 return FTW_CONTINUE;
180 if (shm->exit_reason != STILL_RUNNING)
181 return FTW_STOP;
183 add_to_namelist(fpath);
184 files_added++;
186 return FTW_CONTINUE;
190 static void open_fds(const char *dirpath)
192 int before = files_added;
193 int flags = FTW_DEPTH | FTW_ACTIONRETVAL | FTW_MOUNT;
194 int ret;
196 /* By default, don't follow symlinks so we only get each file once.
197 * But, if we do something like -V /lib, then follow it
199 * I'm not sure about this, might remove later.
201 if (victim_path == NULL)
202 flags |= FTW_PHYS;
204 ret = nftw(dirpath, file_tree_callback, 32, flags);
205 if (ret != 0) {
206 if (shm->exit_reason != EXIT_SIGINT)
207 output(0, "Something went wrong during nftw(%s). (%d:%s)\n",
208 dirpath, ret, strerror(errno));
209 return;
212 output(0, "Added %d filenames from %s\n", files_added - before, dirpath);
215 void generate_filelist(void)
217 unsigned int i = 0;
218 struct list_head *node;
219 struct namelist *nl;
221 my_uid = getuid();
222 my_gid = getgid();
224 names = alloc_namenode();
225 INIT_LIST_HEAD(&names->list);
227 output(1, "Generating file descriptors\n");
229 if (victim_path != NULL) {
230 open_fds(victim_path);
231 } else {
232 open_fds("/dev");
233 open_fds("/proc");
234 open_fds("/sys");
237 if (shm->exit_reason != STILL_RUNNING)
238 return;
240 if (files_added == 0) {
241 output(1, "Didn't add any files!!\n");
242 return;
245 /* Generate an index of pointers to the filenames */
247 fileindex = malloc(sizeof(char *) * files_added);
249 list_for_each(node, &names->list) {
250 nl = (struct namelist *) node;
251 fileindex[i++] = nl->name;
253 files_in_index = i;
256 static int open_file(void)
258 int fd;
259 int ret;
260 const char *filename;
261 int flags;
262 const char *modestr;
263 struct stat sb;
265 retry:
266 filename = get_filename();
267 ret = lstat(filename, &sb);
268 if (ret == -1)
269 goto retry;
271 flags = check_stat_file(&sb);
272 if (flags == -1)
273 goto retry;
275 fd = open(filename, flags | O_NONBLOCK);
276 if (fd < 0) {
277 output(2, "Couldn't open %s : %s\n", filename, strerror(errno));
278 return fd;
281 switch (flags) {
282 case O_RDONLY: modestr = "read-only"; break;
283 case O_WRONLY: modestr = "write-only"; break;
284 case O_RDWR: modestr = "read-write"; break;
285 default: modestr = "unknown"; break;
287 output(2, "fd[%i] = %s (%s)\n", fd, filename, modestr);
288 return fd;
291 void open_files(void)
293 unsigned int i, nr_to_open;
294 int fd;
296 if (files_in_index < NR_FILE_FDS)
297 nr_to_open = files_in_index;
298 else
299 nr_to_open = NR_FILE_FDS;
301 if (fileindex == NULL) /* this can happen if we ctrl-c'd */
302 return;
304 for (i = 0; i < nr_to_open; i++) {
305 fd = open_file();
307 shm->file_fds[i] = fd;
308 nr_file_fds++;
312 void close_files(void)
314 unsigned int i;
315 int fd;
317 shm->current_fd = 0;
318 shm->fd_lifetime = 0;
320 // FIXME: Does this need locking? At the least, check for NULL fd's
321 for (i = 0; i < nr_file_fds; i++) {
322 fd = shm->file_fds[i];
323 shm->file_fds[i] = 0;
324 if (fd != 0)
325 close(fd);
328 nr_file_fds = 0;
331 const char * get_filename(void)
333 if (files_in_index == 0) /* This can happen if we run with -n. Should we do something else ? */
334 return NULL;
336 return fileindex[rand() % files_in_index];