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