| 
									
										
										
										
											2006-03-27 01:14:36 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * 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 "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 } ); | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:35 -07:00
										 |  |  | 		write(tty_log_fd, &data, sizeof(data)); | 
					
						
							|  |  |  | 		write(tty_log_fd, ¤t_tty, data.len); | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:33 -07:00
										 |  |  | 		return tty_log_fd; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-27 01:14:36 -08:00
										 |  |  | 	sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  		(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); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:33 -07:00
										 |  |  | 	return fd; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 } ); | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:35 -07:00
										 |  |  | 		write(tty_log_fd, &data, sizeof(data)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:35 -07:00
										 |  |  | 		n = write(fd, chunk, try); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if(n != try) { | 
					
						
							|  |  |  | 			if(n < 0) | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:35 -07:00
										 |  |  | 				return -errno; | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:33 -07:00
										 |  |  | 			return -EIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if(missed != 0) | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:33 -07:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		len -= try; | 
					
						
							|  |  |  | 		total += try; | 
					
						
							|  |  |  | 		buf += try; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:33 -07:00
										 |  |  | 	return total; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 } ); | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:35 -07:00
										 |  |  | 		write(tty_log_fd, &data, sizeof(data)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:33 -07:00
										 |  |  | 	return log_chunk(fd, buf, len); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 } ); | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:35 -07:00
										 |  |  | 	write(tty_log_fd, &data, sizeof(data)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:33 -07:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __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" | 
					
						
							|  |  |  | ); |