summary refs log tree commit diff
path: root/arch/um/os-Linux/tty_log.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-03-29 13:24:50 +1100
committerPaul Mackerras <paulus@samba.org>2006-03-29 13:24:50 +1100
commitbac30d1a78d0f11c613968fc8b351a91ed465386 (patch)
treee52f3c876522a2f6047a6ec1c27df2e8a79486b8 /arch/um/os-Linux/tty_log.c
parente8222502ee6157e2713da9e0792c21f4ad458d50 (diff)
parentca9ba4471c1203bb6e759b76e83167fec54fe590 (diff)
downloadlinux-bac30d1a78d0f11c613968fc8b351a91ed465386.tar.gz
Merge ../linux-2.6
Diffstat (limited to 'arch/um/os-Linux/tty_log.c')
-rw-r--r--arch/um/os-Linux/tty_log.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c
new file mode 100644
index 000000000000..c6ba56c1560f
--- /dev/null
+++ b/arch/um/os-Linux/tty_log.c
@@ -0,0 +1,218 @@
+/*
+ * 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, &current_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"
+);