/* BFBTester -- Brute Force Binary Tester Copyright (C) 2000 Mike Heffner This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: tempfiles.c,v 1.4.2.1 2001/01/22 05:31:12 fesnel Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "datatypes.h" #include "tempfiles.h" #include "utils.h" typedef struct _file_entry FileEntry; struct _file_entry { char *filename; /* excludes leading directories */ struct timeval tm; int statd; #ifdef SOLARIS uint32_t fileno; #else u_int32_t fileno; #endif /* SOLARIS */ struct stat sb; FileEntry *next; FileEntry *prev; }; typedef struct _tempfile_watch_request TempFileRequest; struct _tempfile_watch_request { pthread_mutex_t mutex; pthread_cond_t cond; int count; /* Number of requests - normally 0 or 1 */ int status; /* 0 - none, 1 - start up, 2 - running, 3 - shutting down */ TempfileCB create_cb; /* creation call back */ TempfileCB remove_cb; /* remove call back */ void *cb_data; /* user data */ }; static int initialized = FALSE; /* Set to true if we are using tempfile * monitoring */ static FileEntry *head = NULL; static FileEntry *tail = NULL; static TempFileRequest request = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0, NULL, NULL, NULL }; static int isNew(struct dirent *entry) { FileEntry *entries = head; #ifdef SOLARIS while(entries && entry->d_ino > entries->fileno) #else while(entries && entry->d_fileno > entries->fileno) #endif /* SOLARIS */ entries = entries->next; if (entries && #ifdef SOLARIS entries->fileno == entry->d_ino #else entries->fileno == entry->d_fileno #endif ) return FALSE; else return TRUE; } static void addFile(struct dirent *entry, struct timeval tm) { FileEntry *new; new = xmalloc(sizeof(FileEntry)); new->filename = strdup(entry->d_name); new->tm = tm; #ifdef SOLARIS new->fileno = entry->d_ino; #else new->fileno = entry->d_fileno; #endif /* SOLARIS */ new->next = NULL; new->prev = NULL; if (head == NULL) /* tail also NULL */ head = tail = new; else if (new->fileno < head->fileno) { head->prev = new; new->next = head; head = new; } else if (new->fileno > tail->fileno) { new->prev = tail; tail->next = new; tail = new; } else { FileEntry *temp = head; while (new->fileno > temp->fileno) temp = temp->next; temp->prev->next = new; new->prev = temp->prev; new->next = temp; temp->prev = new; } /* call creation callback */ if (request.create_cb && request.count && (request.status == 2 || request.status == 3)) (*request.create_cb)(new->filename, &new->sb, request.cb_data); } static void updateFile(struct dirent *entry, struct timeval tm) { FileEntry *temp = head; /* At this point we know entry is in the list somewhere */ while (temp->fileno != #ifdef SOLARIS entry->d_ino #else entry->d_fileno #endif ) temp = temp->next; temp->tm = tm; } /* Unlinks from list -- does NOT free() node */ static void removeFile(FileEntry *entry) { if (entry->prev && entry->next) { entry->prev->next = entry->next; entry->next->prev = entry->prev; } else { if (head == entry) { if (entry->next) entry->next->prev = NULL; else /* one item list */ tail = NULL; head = entry->next; } else { /* (tail == entry) */ entry->prev->next = NULL; tail = entry->prev; } } /* call deletion callback */ if (request.remove_cb && request.count && (request.status == 2 || request.status == 3)) (*request.remove_cb)(entry->filename, &entry->sb, request.cb_data); } /* Free memory used by file */ static void deleteFile(FileEntry *entry) { if (entry->filename) free(entry->filename); free(entry); } static void AddOrUpdate(struct dirent *entry, struct timeval tm) { /* Add if entry is new or tag it as still available */ if (isNew(entry)) addFile(entry, tm); else updateFile(entry, tm); } static void tempfile_scandir(DIR *dir) { struct dirent entry; struct dirent *result; int ret; struct timeval tm; FileEntry *temp, *dead; gettimeofday(&tm, NULL); ret = readdir_r(dir, &entry, &result); while (ret == 0 && result != NULL) { AddOrUpdate(result, tm); ret = readdir_r(dir, &entry, &result); } /* Scan for files that were removed (ie. not updated) */ if (ret == 0) { temp = head; while (temp) { if (memcmp(&temp->tm, &tm, sizeof(struct timeval)) != 0) { dead = temp; temp = temp->next; removeFile(dead); deleteFile(dead); } else temp = temp->next; } } rewinddir(dir); /* rewinds for next time */ } static void tempfile_request_startup(void) { /* Already have mutex locked */ request.status = 2; pthread_cond_signal(&request.cond); } static void tempfile_request_shutdown(void) { /* Already have mutex locked */ request.status = 0; pthread_cond_signal(&request.cond); } static void * tempfile_watch(void *data) { char *dirname; DIR *dir; int lasttime = 0; if (!(dirname = getenv("BFBT_TMPDIR"))) dirname = "/tmp"; initialized = TRUE; if ((dir = opendir(dirname)) == NULL) bfbt_message(MSG_TYPE_ERROR_ABORT, "opendir: %s failed", dirname); while(1){ tempfile_scandir(dir); pthread_mutex_lock(&request.mutex); if (request.status == 1 || request.status == 3) { if (request.status == 1) { /* starting a new request */ if (lasttime) { tempfile_request_startup(); lasttime = 0; } else lasttime = 1; } else /* request.status == 3 */ { /* shutting down request */ if (lasttime) { tempfile_request_shutdown(); lasttime = 0; } else lasttime = 1; } } else while (request.status == 0) pthread_cond_wait(&request.cond, &request.mutex); pthread_mutex_unlock(&request.mutex); pthread_testcancel(); } return NULL; } int tempfile_request_add(TempfileCB create, TempfileCB remove, void *cbdata) { if (!initialized) return 0; pthread_mutex_lock(&request.mutex); if (request.count || request.status != 0) return -1; request.count = 1; request.status = 1; pthread_cond_signal(&request.cond); while (request.status == 1) pthread_cond_wait(&request.cond, &request.mutex); request.create_cb = create; request.remove_cb = remove; request.cb_data = cbdata; pthread_mutex_unlock(&request.mutex); return 0; } int tempfile_request_subtract(void) { if (!initialized) return 0; pthread_mutex_unlock(&request.mutex); if (!request.count || request.status != 2) return -1; request.status = 3; while (request.status == 3) pthread_cond_wait(&request.cond, &request.mutex); request.count--; request.create_cb = NULL; request.remove_cb = NULL; request.cb_data = NULL; pthread_mutex_unlock(&request.mutex); return 0; } void tempfile_start(THREAD_DATA *data) { if (pthread_create(&data->tempfile_thread, NULL, tempfile_watch, NULL) != 0) bfbt_message(MSG_TYPE_ERRNO_ABORT, "tempfile thread create"); }