/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and * geoffrey hing * Licensed under the GPL */ #include #include #include #include #include #include #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 } ); write(tty_log_fd, &data, sizeof(data)); write(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 } ); write(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 = write(fd, chunk, try); if(n != try) { if(n < 0) return -errno; 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 } ); write(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 } ); write(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=\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=\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" );