1/* 2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and 3 * geoffrey hing <ghing@net.ohio-state.edu> 4 * Licensed under the GPL 5 */ 6 7#include <errno.h> 8#include <string.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <unistd.h> 12#include <sys/time.h> 13#include "init.h" 14#include "user.h" 15#include "kern_util.h" 16#include "os.h" 17 18#define TTY_LOG_DIR "./" 19 20/* Set early in boot and then unchanged */ 21static char *tty_log_dir = TTY_LOG_DIR; 22static int tty_log_fd = -1; 23 24#define TTY_LOG_OPEN 1 25#define TTY_LOG_CLOSE 2 26#define TTY_LOG_WRITE 3 27#define TTY_LOG_EXEC 4 28 29#define TTY_READ 1 30#define TTY_WRITE 2 31 32struct tty_log_buf { 33 int what; 34 unsigned long tty; 35 int len; 36 int direction; 37 unsigned long sec; 38 unsigned long usec; 39}; 40 41int open_tty_log(void *tty, void *current_tty) 42{ 43 struct timeval tv; 44 struct tty_log_buf data; 45 char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; 46 int fd; 47 48 gettimeofday(&tv, NULL); 49 if(tty_log_fd != -1){ 50 data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, 51 .tty = (unsigned long) tty, 52 .len = sizeof(current_tty), 53 .direction = 0, 54 .sec = tv.tv_sec, 55 .usec = tv.tv_usec } ); 56 write(tty_log_fd, &data, sizeof(data)); 57 write(tty_log_fd, ¤t_tty, data.len); 58 return tty_log_fd; 59 } 60 61 sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, 62 (unsigned int) tv.tv_usec); 63 64 fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), 65 0644); 66 if(fd < 0){ 67 printk("open_tty_log : couldn't open '%s', errno = %d\n", 68 buf, -fd); 69 } 70 return fd; 71} 72 73void close_tty_log(int fd, void *tty) 74{ 75 struct tty_log_buf data; 76 struct timeval tv; 77 78 if(tty_log_fd != -1){ 79 gettimeofday(&tv, NULL); 80 data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, 81 .tty = (unsigned long) tty, 82 .len = 0, 83 .direction = 0, 84 .sec = tv.tv_sec, 85 .usec = tv.tv_usec } ); 86 write(tty_log_fd, &data, sizeof(data)); 87 return; 88 } 89 os_close_file(fd); 90} 91 92static int log_chunk(int fd, const char *buf, int len) 93{ 94 int total = 0, try, missed, n; 95 char chunk[64]; 96 97 while(len > 0){ 98 try = (len > sizeof(chunk)) ? sizeof(chunk) : len; 99 missed = copy_from_user_proc(chunk, (char *) buf, try); 100 try -= missed; 101 n = write(fd, chunk, try); 102 if(n != try) { 103 if(n < 0) 104 return -errno; 105 return -EIO; 106 } 107 if(missed != 0) 108 return -EFAULT; 109 110 len -= try; 111 total += try; 112 buf += try; 113 } 114 115 return total; 116} 117 118int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) 119{ 120 struct timeval tv; 121 struct tty_log_buf data; 122 int direction; 123 124 if(fd == tty_log_fd){ 125 gettimeofday(&tv, NULL); 126 direction = is_read ? TTY_READ : TTY_WRITE; 127 data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, 128 .tty = (unsigned long) tty, 129 .len = len, 130 .direction = direction, 131 .sec = tv.tv_sec, 132 .usec = tv.tv_usec } ); 133 write(tty_log_fd, &data, sizeof(data)); 134 } 135 136 return log_chunk(fd, buf, len); 137} 138 139void log_exec(char **argv, void *tty) 140{ 141 struct timeval tv; 142 struct tty_log_buf data; 143 char **ptr,*arg; 144 int len; 145 146 if(tty_log_fd == -1) return; 147 148 gettimeofday(&tv, NULL); 149 150 len = 0; 151 for(ptr = argv; ; ptr++){ 152 if(copy_from_user_proc(&arg, ptr, sizeof(arg))) 153 return; 154 if(arg == NULL) break; 155 len += strlen_user_proc(arg); 156 } 157 158 data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, 159 .tty = (unsigned long) tty, 160 .len = len, 161 .direction = 0, 162 .sec = tv.tv_sec, 163 .usec = tv.tv_usec } ); 164 write(tty_log_fd, &data, sizeof(data)); 165 166 for(ptr = argv; ; ptr++){ 167 if(copy_from_user_proc(&arg, ptr, sizeof(arg))) 168 return; 169 if(arg == NULL) break; 170 log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); 171 } 172} 173 174extern void register_tty_logger(int (*opener)(void *, void *), 175 int (*writer)(int, const char *, int, 176 void *, int), 177 void (*closer)(int, void *)); 178 179static int register_logger(void) 180{ 181 register_tty_logger(open_tty_log, write_tty_log, close_tty_log); 182 return 0; 183} 184 185__uml_initcall(register_logger); 186 187static int __init set_tty_log_dir(char *name, int *add) 188{ 189 tty_log_dir = name; 190 return 0; 191} 192 193__uml_setup("tty_log_dir=", set_tty_log_dir, 194"tty_log_dir=<directory>\n" 195" This is used to specify the directory where the logs of all pty\n" 196" data from this UML machine will be written.\n\n" 197); 198 199static int __init set_tty_log_fd(char *name, int *add) 200{ 201 char *end; 202 203 tty_log_fd = strtoul(name, &end, 0); 204 if((*end != '\0') || (end == name)){ 205 printf("set_tty_log_fd - strtoul failed on '%s'\n", name); 206 tty_log_fd = -1; 207 } 208 209 *add = 0; 210 return 0; 211} 212 213__uml_setup("tty_log_fd=", set_tty_log_fd, 214"tty_log_fd=<fd>\n" 215" This is used to specify a preconfigured file descriptor to which all\n" 216" tty data will be written. Preconfigure the descriptor with something\n" 217" like '10>tty_log tty_log_fd=10'.\n\n" 218); 219