diff options
Diffstat (limited to 'arch/um/kernel/tty_log.c')
| -rw-r--r-- | arch/um/kernel/tty_log.c | 230 | 
1 files changed, 230 insertions, 0 deletions
diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c new file mode 100644 index 00000000000..9ada656f68c --- /dev/null +++ b/arch/um/kernel/tty_log.c @@ -0,0 +1,230 @@ +/*  + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and  + * geoffrey hing <ghing@net.ohio-state.edu> + * Licensed under the GPL + */ + +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> +#include "init.h" +#include "user.h" +#include "kern_util.h" +#include "os.h" + +#define TTY_LOG_DIR "./" + +/* Set early in boot and then unchanged */ +static char *tty_log_dir = TTY_LOG_DIR; +static int tty_log_fd = -1; + +#define TTY_LOG_OPEN 1 +#define TTY_LOG_CLOSE 2 +#define TTY_LOG_WRITE 3 +#define TTY_LOG_EXEC 4 + +#define TTY_READ 1 +#define TTY_WRITE 2 + +struct tty_log_buf { +	int what; +	unsigned long tty; +	int len; +	int direction; +	unsigned long sec; +	unsigned long usec; +}; + +int open_tty_log(void *tty, void *current_tty) +{ +	struct timeval tv; +	struct tty_log_buf data; +	char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; +	int fd; + +	gettimeofday(&tv, NULL); +	if(tty_log_fd != -1){ +		data = ((struct tty_log_buf) { .what 	= TTY_LOG_OPEN, +					       .tty  = (unsigned long) tty, +					       .len  = sizeof(current_tty), +					       .direction = 0, +					       .sec = tv.tv_sec, +					       .usec = tv.tv_usec } ); +		os_write_file(tty_log_fd, &data, sizeof(data)); +		os_write_file(tty_log_fd, ¤t_tty, data.len); +		return(tty_log_fd); +	} + +	sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,  + 		(unsigned int) tv.tv_usec); + +	fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), +			  0644); +	if(fd < 0){ +		printk("open_tty_log : couldn't open '%s', errno = %d\n", +		       buf, -fd); +	} +	return(fd); +} + +void close_tty_log(int fd, void *tty) +{ +	struct tty_log_buf data; +	struct timeval tv; + +	if(tty_log_fd != -1){ +		gettimeofday(&tv, NULL); +		data = ((struct tty_log_buf) { .what 	= TTY_LOG_CLOSE, +					       .tty  = (unsigned long) tty, +					       .len  = 0, +					       .direction = 0, +					       .sec = tv.tv_sec, +					       .usec = tv.tv_usec } ); +		os_write_file(tty_log_fd, &data, sizeof(data)); +		return; +	} +	os_close_file(fd); +} + +static int log_chunk(int fd, const char *buf, int len) +{ +	int total = 0, try, missed, n; +	char chunk[64]; + +	while(len > 0){ +		try = (len > sizeof(chunk)) ? sizeof(chunk) : len; +		missed = copy_from_user_proc(chunk, (char *) buf, try); +		try -= missed; +		n = os_write_file(fd, chunk, try); +		if(n != try) { +			if(n < 0) +				return(n); +			return(-EIO); +		} +		if(missed != 0) +			return(-EFAULT); + +		len -= try; +		total += try; +		buf += try; +	} + +	return(total); +} + +int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) +{ +	struct timeval tv; +	struct tty_log_buf data; +	int direction; + +	if(fd == tty_log_fd){ +		gettimeofday(&tv, NULL); +		direction = is_read ? TTY_READ : TTY_WRITE; +		data = ((struct tty_log_buf) { .what 	= TTY_LOG_WRITE, +					       .tty  = (unsigned long) tty, +					       .len  = len, +					       .direction = direction, +					       .sec = tv.tv_sec, +					       .usec = tv.tv_usec } ); +		os_write_file(tty_log_fd, &data, sizeof(data)); +	} + +	return(log_chunk(fd, buf, len)); +} + +void log_exec(char **argv, void *tty) +{ +	struct timeval tv; +	struct tty_log_buf data; +	char **ptr,*arg; +	int len; + +	if(tty_log_fd == -1) return; + +	gettimeofday(&tv, NULL); + +	len = 0; +	for(ptr = argv; ; ptr++){ +		if(copy_from_user_proc(&arg, ptr, sizeof(arg))) +			return; +		if(arg == NULL) break; +		len += strlen_user_proc(arg); +	} + +	data = ((struct tty_log_buf) { .what 	= TTY_LOG_EXEC, +				       .tty  = (unsigned long) tty, +				       .len  = len, +				       .direction = 0, +				       .sec = tv.tv_sec, +				       .usec = tv.tv_usec } ); +	os_write_file(tty_log_fd, &data, sizeof(data)); + +	for(ptr = argv; ; ptr++){ +		if(copy_from_user_proc(&arg, ptr, sizeof(arg))) +			return; +		if(arg == NULL) break; +		log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); +	} +} + +extern void register_tty_logger(int (*opener)(void *, void *), +				int (*writer)(int, const char *, int, +					      void *, int), +				void (*closer)(int, void *)); + +static int register_logger(void) +{ +	register_tty_logger(open_tty_log, write_tty_log, close_tty_log); +	return(0); +} + +__uml_initcall(register_logger); + +static int __init set_tty_log_dir(char *name, int *add) +{ +	tty_log_dir = name; +	return 0; +} + +__uml_setup("tty_log_dir=", set_tty_log_dir, +"tty_log_dir=<directory>\n" +"    This is used to specify the directory where the logs of all pty\n" +"    data from this UML machine will be written.\n\n" +); + +static int __init set_tty_log_fd(char *name, int *add) +{ +	char *end; + +	tty_log_fd = strtoul(name, &end, 0); +	if((*end != '\0') || (end == name)){ +		printf("set_tty_log_fd - strtoul failed on '%s'\n", name); +		tty_log_fd = -1; +	} + +	*add = 0; +	return 0; +} + +__uml_setup("tty_log_fd=", set_tty_log_fd, +"tty_log_fd=<fd>\n" +"    This is used to specify a preconfigured file descriptor to which all\n" +"    tty data will be written.  Preconfigure the descriptor with something\n" +"    like '10>tty_log tty_log_fd=10'.\n\n" +); + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only.  This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */  |