diff options
author | Olivier Blin <oblin@mandriva.com> | 2008-01-12 18:42:02 +0000 |
---|---|---|
committer | Olivier Blin <oblin@mandriva.com> | 2008-01-12 18:42:02 +0000 |
commit | 8c2a53c29a3c00af24553cb04bb3350bede221c9 (patch) | |
tree | ecc1cc87ab8a94da82ce70e02eed3b7f0d15c34b /kmod | |
parent | e3700d50428b8e132e17f9244b27113daa31020d (diff) | |
download | drakiso-8c2a53c29a3c00af24553cb04bb3350bede221c9.tar drakiso-8c2a53c29a3c00af24553cb04bb3350bede221c9.tar.gz drakiso-8c2a53c29a3c00af24553cb04bb3350bede221c9.tar.bz2 drakiso-8c2a53c29a3c00af24553cb04bb3350bede221c9.tar.xz drakiso-8c2a53c29a3c00af24553cb04bb3350bede221c9.zip |
import readlog kernel module (from 2006-05-31)
Diffstat (limited to 'kmod')
-rw-r--r-- | kmod/readlog.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/kmod/readlog.c b/kmod/readlog.c new file mode 100644 index 0000000..8a1c5ad --- /dev/null +++ b/kmod/readlog.c @@ -0,0 +1,230 @@ +#include <linux/init.h> +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/syscalls.h> +#include <linux/time.h> + +#include <asm/unistd.h> + +#include <asm/current.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Olivier Blin <blino@mandriva.com>"); + +struct opened_file { + struct list_head s_list; + char *name; +}; + +unsigned long **sys_call_table; +static struct dentry *dbg_dir; +static struct dentry *dbg_file; +struct opened_file bp; +DECLARE_MUTEX(files_mutex); + +ssize_t (*read)(int f, const void *buf, size_t n); +long (*open)(const char __user *filename, int flags, int mode); + +static void *profile_seq_start(struct seq_file *file, loff_t *pos) +{ + struct list_head *p; + loff_t l = *pos; + down(&files_mutex); + list_for_each(p, &bp.s_list) + if (!l--) + return list_entry(p, struct opened_file, s_list); + return NULL; +} + +static void *profile_seq_next(struct seq_file *file, void *v, loff_t *pos) +{ + struct list_head *p = ((struct opened_file *)v)->s_list.next; + (*pos)++; + return p == &bp.s_list ? NULL : list_entry(p, struct opened_file, s_list); +} + +static void profile_seq_stop(struct seq_file *file, void *v) +{ + up(&files_mutex); +} + +static int profile_seq_show(struct seq_file *file, void *v) +{ + seq_printf(file, ((struct opened_file *)v)->name); + seq_putc(file, '\n'); + return 0; +} + +static struct seq_operations profile_seq_ops = { + .start = profile_seq_start, + .next = profile_seq_next, + .stop = profile_seq_stop, + .show = profile_seq_show, +}; + +static int profile_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &profile_seq_ops); +} + +static struct file_operations profile_fops = { + .owner = THIS_MODULE, + .open = profile_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +/* Borrowed from + * http://downloads.securityfocus.com/downloads/scprint.tar.gz + * http://www.gnome.org/~lcolitti/gnome-startup/linux-iolog/readlog.c + * http://kerneltrap.org/node/5793 + */ +unsigned long **find_sys_call_table(void) { + unsigned long *p; + + for (p = (unsigned long *)((init_mm.end_code + 4) & 0xfffffffc); + p < (unsigned long *)init_mm.end_data; p++) { + if (p[__NR_close] == (unsigned long) sys_close){ + return (unsigned long **) p; + } + } + + return NULL; +} + +void addfilename(const char *filename) { + struct opened_file *f; + + f = kmalloc(sizeof(struct opened_file), GFP_KERNEL); + if (f == NULL) + return; + + f->name = kmalloc(strlen(filename) + 1, GFP_KERNEL); + if (f->name == NULL) + return; + strcpy(f->name, filename); + + INIT_LIST_HEAD(&f->s_list); + + printk(KERN_INFO "locking while adding: %s\n", filename); + + down(&files_mutex); + list_add_tail(&f->s_list, &bp.s_list); + up(&files_mutex); + + printk(KERN_INFO "unlocking after adding: %s\n", filename); +} + +long loggingopen(const char __user *filename, int flags, int mode) { + struct file *f = NULL; + long fd; + + fd = open(filename, flags, mode); + + printk(KERN_INFO "opening fd %ld for %s\n", fd, filename); + + if(fd > 0 && current) { + f = current->files->fd_array[fd]; + if(f && f->f_dentry && f->f_vfsmnt) { + char tmpname[PATH_MAX]; + char *name = d_path(f->f_dentry, f->f_vfsmnt, tmpname, sizeof(tmpname) - 1); + if (name) + addfilename(name); + } + } + + return fd; +} + + +ssize_t loggingread(int fd, const void *buf, size_t n) { + struct file *f = NULL; + char *name = NULL; + loff_t offset = 0; + struct timeval tv; + char tmpname[256]; + + do_gettimeofday(&tv); + + if(current) + f = current->files->fd_array[fd]; + + printk(KERN_DEBUG "READ: f: %p\n", f); + + + if(f) + offset = f->f_pos; + + if (f) + printk(KERN_DEBUG "READ: d_entry: %p, vfsmnt: %p\n", f->f_dentry, f->f_vfsmnt); + + if(f && f->f_dentry && f->f_vfsmnt) { + printk(KERN_DEBUG "READ: d_path\n"); + name = d_path(f->f_dentry, f->f_vfsmnt, tmpname, sizeof(tmpname) - 1); + if (name) + addfilename(name); + } + + printk(KERN_DEBUG "READ: %lu.%lu (%s/%d) %Lu %s\n", + tv.tv_sec, tv.tv_usec, + current ? current->comm : "?", + current ? current->pid : 0, + offset, + name ? name : "<no dentry>" + ); + + return read(fd, buf, n); +} + +static int __init readlog_init(void) { + sys_call_table = find_sys_call_table(); + /* compare with grep sys_call_table /boot/System.map */ + printk(KERN_INFO "Found sys_call_table at %p\n", sys_call_table); + + open = (void *) (sys_call_table[__NR_open]); + sys_call_table[__NR_open] = (void *) loggingopen; + + read = (void *) (sys_call_table[__NR_read]); + /* sys_call_table[__NR_read] = (void *) loggingread; */ + + dbg_dir = debugfs_create_dir("dmc", NULL); + if (IS_ERR(dbg_dir)) { + printk(KERN_NOTICE ": debugfs is not available\n"); + return -ENODEV; + } + if (dbg_dir == NULL) { + printk(KERN_NOTICE ": unable to create usbmon directory\n"); + return -ENODEV; + } + + dbg_file = debugfs_create_file("bp", 0600, dbg_dir, NULL, &profile_fops); + if (dbg_file == NULL) { + debugfs_remove(dbg_dir); + return -ENODEV; + } + + INIT_LIST_HEAD(&bp.s_list); + + return 0; +} + +static void __exit readlog_exit(void) { + debugfs_remove(dbg_file); + debugfs_remove(dbg_dir); + + sys_call_table[__NR_open] = (void *) open; + sys_call_table[__NR_read] = (void *) read; + + printk(KERN_INFO "sys_call_table restored\n"); + +} + +module_init(readlog_init); +module_exit(readlog_exit); |