]>
Commit | Line | Data |
---|---|---|
c554f899 JD |
1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and | |
1da177e4 LT |
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" | |
1da177e4 LT |
15 | #include "os.h" |
16 | ||
17 | #define TTY_LOG_DIR "./" | |
18 | ||
19 | /* Set early in boot and then unchanged */ | |
20 | static char *tty_log_dir = TTY_LOG_DIR; | |
21 | static 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 | ||
31 | struct 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 | ||
40 | int 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 } ); | |
a61f334f JD |
55 | write(tty_log_fd, &data, sizeof(data)); |
56 | write(tty_log_fd, ¤t_tty, data.len); | |
ef0470c0 | 57 | return tty_log_fd; |
1da177e4 LT |
58 | } |
59 | ||
c554f899 | 60 | sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, |
1da177e4 LT |
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 | } | |
ef0470c0 | 69 | return fd; |
1da177e4 LT |
70 | } |
71 | ||
72 | void 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 } ); | |
a61f334f | 85 | write(tty_log_fd, &data, sizeof(data)); |
1da177e4 LT |
86 | return; |
87 | } | |
88 | os_close_file(fd); | |
89 | } | |
90 | ||
91 | static 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; | |
a61f334f | 100 | n = write(fd, chunk, try); |
1da177e4 LT |
101 | if(n != try) { |
102 | if(n < 0) | |
a61f334f | 103 | return -errno; |
ef0470c0 | 104 | return -EIO; |
1da177e4 LT |
105 | } |
106 | if(missed != 0) | |
ef0470c0 | 107 | return -EFAULT; |
1da177e4 LT |
108 | |
109 | len -= try; | |
110 | total += try; | |
111 | buf += try; | |
112 | } | |
113 | ||
ef0470c0 | 114 | return total; |
1da177e4 LT |
115 | } |
116 | ||
117 | int 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 } ); | |
a61f334f | 132 | write(tty_log_fd, &data, sizeof(data)); |
1da177e4 LT |
133 | } |
134 | ||
ef0470c0 | 135 | return log_chunk(fd, buf, len); |
1da177e4 LT |
136 | } |
137 | ||
138 | void 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 } ); | |
a61f334f | 163 | write(tty_log_fd, &data, sizeof(data)); |
1da177e4 LT |
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 | ||
173 | extern void register_tty_logger(int (*opener)(void *, void *), | |
174 | int (*writer)(int, const char *, int, | |
175 | void *, int), | |
176 | void (*closer)(int, void *)); | |
177 | ||
178 | static int register_logger(void) | |
179 | { | |
180 | register_tty_logger(open_tty_log, write_tty_log, close_tty_log); | |
ef0470c0 | 181 | return 0; |
1da177e4 LT |
182 | } |
183 | ||
184 | __uml_initcall(register_logger); | |
185 | ||
186 | static 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 | ||
198 | static 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 | ); |