diff options
Diffstat (limited to 'arch/um/os-Linux')
-rw-r--r-- | arch/um/os-Linux/Makefile | 13 | ||||
-rw-r--r-- | arch/um/os-Linux/irq.c | 162 | ||||
-rw-r--r-- | arch/um/os-Linux/sigio.c | 323 | ||||
-rw-r--r-- | arch/um/os-Linux/start_up.c | 128 | ||||
-rw-r--r-- | arch/um/os-Linux/tt.c | 10 | ||||
-rw-r--r-- | arch/um/os-Linux/tty_log.c | 218 | ||||
-rw-r--r-- | arch/um/os-Linux/umid.c | 33 |
7 files changed, 872 insertions, 15 deletions
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 08a4e628b24c..1659386b42bb 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -3,14 +3,17 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 6 | obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ |
7 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \ | 7 | signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ |
8 | util.o drivers/ sys-$(SUBARCH)/ | 8 | user_syms.o util.o drivers/ sys-$(SUBARCH)/ |
9 | 9 | ||
10 | obj-$(CONFIG_MODE_SKAS) += skas/ | 10 | obj-$(CONFIG_MODE_SKAS) += skas/ |
11 | obj-$(CONFIG_TTY_LOG) += tty_log.o | ||
12 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o | ||
11 | 13 | ||
12 | USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 14 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ |
13 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o | 15 | process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \ |
16 | uaccess.o umid.o util.o | ||
14 | 17 | ||
15 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h | 18 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h |
16 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um | 19 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um |
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c new file mode 100644 index 000000000000..e599be423da1 --- /dev/null +++ b/arch/um/os-Linux/irq.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <unistd.h> | ||
8 | #include <errno.h> | ||
9 | #include <signal.h> | ||
10 | #include <string.h> | ||
11 | #include <sys/poll.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/time.h> | ||
14 | #include "user_util.h" | ||
15 | #include "kern_util.h" | ||
16 | #include "user.h" | ||
17 | #include "process.h" | ||
18 | #include "sigio.h" | ||
19 | #include "irq_user.h" | ||
20 | #include "os.h" | ||
21 | |||
22 | static struct pollfd *pollfds = NULL; | ||
23 | static int pollfds_num = 0; | ||
24 | static int pollfds_size = 0; | ||
25 | |||
26 | int os_waiting_for_events(struct irq_fd *active_fds) | ||
27 | { | ||
28 | struct irq_fd *irq_fd; | ||
29 | int i, n, err; | ||
30 | |||
31 | n = poll(pollfds, pollfds_num, 0); | ||
32 | if(n < 0){ | ||
33 | err = -errno; | ||
34 | if(errno != EINTR) | ||
35 | printk("sigio_handler: os_waiting_for_events:" | ||
36 | " poll returned %d, errno = %d\n", n, errno); | ||
37 | return err; | ||
38 | } | ||
39 | |||
40 | if(n == 0) | ||
41 | return 0; | ||
42 | |||
43 | irq_fd = active_fds; | ||
44 | |||
45 | for(i = 0; i < pollfds_num; i++){ | ||
46 | if(pollfds[i].revents != 0){ | ||
47 | irq_fd->current_events = pollfds[i].revents; | ||
48 | pollfds[i].fd = -1; | ||
49 | } | ||
50 | irq_fd = irq_fd->next; | ||
51 | } | ||
52 | return n; | ||
53 | } | ||
54 | |||
55 | int os_isatty(int fd) | ||
56 | { | ||
57 | return(isatty(fd)); | ||
58 | } | ||
59 | |||
60 | int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) | ||
61 | { | ||
62 | if (pollfds_num == pollfds_size) { | ||
63 | if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { | ||
64 | /* return min size needed for new pollfds area */ | ||
65 | return((pollfds_size + 1) * sizeof(pollfds[0])); | ||
66 | } | ||
67 | |||
68 | if(pollfds != NULL){ | ||
69 | memcpy(tmp_pfd, pollfds, | ||
70 | sizeof(pollfds[0]) * pollfds_size); | ||
71 | /* remove old pollfds */ | ||
72 | kfree(pollfds); | ||
73 | } | ||
74 | pollfds = tmp_pfd; | ||
75 | pollfds_size++; | ||
76 | } else { | ||
77 | /* remove not used tmp_pfd */ | ||
78 | if (tmp_pfd != NULL) | ||
79 | kfree(tmp_pfd); | ||
80 | } | ||
81 | |||
82 | pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, | ||
83 | .events = events, | ||
84 | .revents = 0 }); | ||
85 | pollfds_num++; | ||
86 | |||
87 | return(0); | ||
88 | } | ||
89 | |||
90 | void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, | ||
91 | struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2) | ||
92 | { | ||
93 | struct irq_fd **prev; | ||
94 | int i = 0; | ||
95 | |||
96 | prev = &active_fds; | ||
97 | while(*prev != NULL){ | ||
98 | if((*test)(*prev, arg)){ | ||
99 | struct irq_fd *old_fd = *prev; | ||
100 | if((pollfds[i].fd != -1) && | ||
101 | (pollfds[i].fd != (*prev)->fd)){ | ||
102 | printk("os_free_irq_by_cb - mismatch between " | ||
103 | "active_fds and pollfds, fd %d vs %d\n", | ||
104 | (*prev)->fd, pollfds[i].fd); | ||
105 | goto out; | ||
106 | } | ||
107 | |||
108 | pollfds_num--; | ||
109 | |||
110 | /* This moves the *whole* array after pollfds[i] | ||
111 | * (though it doesn't spot as such)! | ||
112 | */ | ||
113 | |||
114 | memmove(&pollfds[i], &pollfds[i + 1], | ||
115 | (pollfds_num - i) * sizeof(pollfds[0])); | ||
116 | if(*last_irq_ptr2 == &old_fd->next) | ||
117 | *last_irq_ptr2 = prev; | ||
118 | |||
119 | *prev = (*prev)->next; | ||
120 | if(old_fd->type == IRQ_WRITE) | ||
121 | ignore_sigio_fd(old_fd->fd); | ||
122 | kfree(old_fd); | ||
123 | continue; | ||
124 | } | ||
125 | prev = &(*prev)->next; | ||
126 | i++; | ||
127 | } | ||
128 | out: | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | |||
133 | int os_get_pollfd(int i) | ||
134 | { | ||
135 | return(pollfds[i].fd); | ||
136 | } | ||
137 | |||
138 | void os_set_pollfd(int i, int fd) | ||
139 | { | ||
140 | pollfds[i].fd = fd; | ||
141 | } | ||
142 | |||
143 | void os_set_ioignore(void) | ||
144 | { | ||
145 | set_handler(SIGIO, SIG_IGN, 0, -1); | ||
146 | } | ||
147 | |||
148 | void init_irq_signals(int on_sigstack) | ||
149 | { | ||
150 | __sighandler_t h; | ||
151 | int flags; | ||
152 | |||
153 | flags = on_sigstack ? SA_ONSTACK : 0; | ||
154 | if(timer_irq_inited) h = (__sighandler_t) alarm_handler; | ||
155 | else h = boot_timer_handler; | ||
156 | |||
157 | set_handler(SIGVTALRM, h, flags | SA_RESTART, | ||
158 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); | ||
159 | set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, | ||
160 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
161 | signal(SIGWINCH, SIG_IGN); | ||
162 | } | ||
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c new file mode 100644 index 000000000000..9ba942947146 --- /dev/null +++ b/arch/um/os-Linux/sigio.c | |||
@@ -0,0 +1,323 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <unistd.h> | ||
7 | #include <stdlib.h> | ||
8 | #include <termios.h> | ||
9 | #include <pty.h> | ||
10 | #include <signal.h> | ||
11 | #include <errno.h> | ||
12 | #include <string.h> | ||
13 | #include <sched.h> | ||
14 | #include <sys/socket.h> | ||
15 | #include <sys/poll.h> | ||
16 | #include "init.h" | ||
17 | #include "user.h" | ||
18 | #include "kern_util.h" | ||
19 | #include "user_util.h" | ||
20 | #include "sigio.h" | ||
21 | #include "os.h" | ||
22 | |||
23 | /* Protected by sigio_lock(), also used by sigio_cleanup, which is an | ||
24 | * exitcall. | ||
25 | */ | ||
26 | static int write_sigio_pid = -1; | ||
27 | |||
28 | /* These arrays are initialized before the sigio thread is started, and | ||
29 | * the descriptors closed after it is killed. So, it can't see them change. | ||
30 | * On the UML side, they are changed under the sigio_lock. | ||
31 | */ | ||
32 | #define SIGIO_FDS_INIT {-1, -1} | ||
33 | |||
34 | static int write_sigio_fds[2] = SIGIO_FDS_INIT; | ||
35 | static int sigio_private[2] = SIGIO_FDS_INIT; | ||
36 | |||
37 | struct pollfds { | ||
38 | struct pollfd *poll; | ||
39 | int size; | ||
40 | int used; | ||
41 | }; | ||
42 | |||
43 | /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread | ||
44 | * synchronizes with it. | ||
45 | */ | ||
46 | struct pollfds current_poll = { | ||
47 | .poll = NULL, | ||
48 | .size = 0, | ||
49 | .used = 0 | ||
50 | }; | ||
51 | |||
52 | struct pollfds next_poll = { | ||
53 | .poll = NULL, | ||
54 | .size = 0, | ||
55 | .used = 0 | ||
56 | }; | ||
57 | |||
58 | static int write_sigio_thread(void *unused) | ||
59 | { | ||
60 | struct pollfds *fds, tmp; | ||
61 | struct pollfd *p; | ||
62 | int i, n, respond_fd; | ||
63 | char c; | ||
64 | |||
65 | signal(SIGWINCH, SIG_IGN); | ||
66 | fds = ¤t_poll; | ||
67 | while(1){ | ||
68 | n = poll(fds->poll, fds->used, -1); | ||
69 | if(n < 0){ | ||
70 | if(errno == EINTR) continue; | ||
71 | printk("write_sigio_thread : poll returned %d, " | ||
72 | "errno = %d\n", n, errno); | ||
73 | } | ||
74 | for(i = 0; i < fds->used; i++){ | ||
75 | p = &fds->poll[i]; | ||
76 | if(p->revents == 0) continue; | ||
77 | if(p->fd == sigio_private[1]){ | ||
78 | n = os_read_file(sigio_private[1], &c, sizeof(c)); | ||
79 | if(n != sizeof(c)) | ||
80 | printk("write_sigio_thread : " | ||
81 | "read failed, err = %d\n", -n); | ||
82 | tmp = current_poll; | ||
83 | current_poll = next_poll; | ||
84 | next_poll = tmp; | ||
85 | respond_fd = sigio_private[1]; | ||
86 | } | ||
87 | else { | ||
88 | respond_fd = write_sigio_fds[1]; | ||
89 | fds->used--; | ||
90 | memmove(&fds->poll[i], &fds->poll[i + 1], | ||
91 | (fds->used - i) * sizeof(*fds->poll)); | ||
92 | } | ||
93 | |||
94 | n = os_write_file(respond_fd, &c, sizeof(c)); | ||
95 | if(n != sizeof(c)) | ||
96 | printk("write_sigio_thread : write failed, " | ||
97 | "err = %d\n", -n); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int need_poll(int n) | ||
105 | { | ||
106 | if(n <= next_poll.size){ | ||
107 | next_poll.used = n; | ||
108 | return(0); | ||
109 | } | ||
110 | kfree(next_poll.poll); | ||
111 | next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); | ||
112 | if(next_poll.poll == NULL){ | ||
113 | printk("need_poll : failed to allocate new pollfds\n"); | ||
114 | next_poll.size = 0; | ||
115 | next_poll.used = 0; | ||
116 | return(-1); | ||
117 | } | ||
118 | next_poll.size = n; | ||
119 | next_poll.used = n; | ||
120 | return(0); | ||
121 | } | ||
122 | |||
123 | /* Must be called with sigio_lock held, because it's needed by the marked | ||
124 | * critical section. */ | ||
125 | static void update_thread(void) | ||
126 | { | ||
127 | unsigned long flags; | ||
128 | int n; | ||
129 | char c; | ||
130 | |||
131 | flags = set_signals(0); | ||
132 | n = os_write_file(sigio_private[0], &c, sizeof(c)); | ||
133 | if(n != sizeof(c)){ | ||
134 | printk("update_thread : write failed, err = %d\n", -n); | ||
135 | goto fail; | ||
136 | } | ||
137 | |||
138 | n = os_read_file(sigio_private[0], &c, sizeof(c)); | ||
139 | if(n != sizeof(c)){ | ||
140 | printk("update_thread : read failed, err = %d\n", -n); | ||
141 | goto fail; | ||
142 | } | ||
143 | |||
144 | set_signals(flags); | ||
145 | return; | ||
146 | fail: | ||
147 | /* Critical section start */ | ||
148 | if(write_sigio_pid != -1) | ||
149 | os_kill_process(write_sigio_pid, 1); | ||
150 | write_sigio_pid = -1; | ||
151 | close(sigio_private[0]); | ||
152 | close(sigio_private[1]); | ||
153 | close(write_sigio_fds[0]); | ||
154 | close(write_sigio_fds[1]); | ||
155 | /* Critical section end */ | ||
156 | set_signals(flags); | ||
157 | } | ||
158 | |||
159 | int add_sigio_fd(int fd, int read) | ||
160 | { | ||
161 | int err = 0, i, n, events; | ||
162 | |||
163 | sigio_lock(); | ||
164 | for(i = 0; i < current_poll.used; i++){ | ||
165 | if(current_poll.poll[i].fd == fd) | ||
166 | goto out; | ||
167 | } | ||
168 | |||
169 | n = current_poll.used + 1; | ||
170 | err = need_poll(n); | ||
171 | if(err) | ||
172 | goto out; | ||
173 | |||
174 | for(i = 0; i < current_poll.used; i++) | ||
175 | next_poll.poll[i] = current_poll.poll[i]; | ||
176 | |||
177 | if(read) events = POLLIN; | ||
178 | else events = POLLOUT; | ||
179 | |||
180 | next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, | ||
181 | .events = events, | ||
182 | .revents = 0 }); | ||
183 | update_thread(); | ||
184 | out: | ||
185 | sigio_unlock(); | ||
186 | return(err); | ||
187 | } | ||
188 | |||
189 | int ignore_sigio_fd(int fd) | ||
190 | { | ||
191 | struct pollfd *p; | ||
192 | int err = 0, i, n = 0; | ||
193 | |||
194 | sigio_lock(); | ||
195 | for(i = 0; i < current_poll.used; i++){ | ||
196 | if(current_poll.poll[i].fd == fd) break; | ||
197 | } | ||
198 | if(i == current_poll.used) | ||
199 | goto out; | ||
200 | |||
201 | err = need_poll(current_poll.used - 1); | ||
202 | if(err) | ||
203 | goto out; | ||
204 | |||
205 | for(i = 0; i < current_poll.used; i++){ | ||
206 | p = ¤t_poll.poll[i]; | ||
207 | if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; | ||
208 | } | ||
209 | if(n == i){ | ||
210 | printk("ignore_sigio_fd : fd %d not found\n", fd); | ||
211 | err = -1; | ||
212 | goto out; | ||
213 | } | ||
214 | |||
215 | update_thread(); | ||
216 | out: | ||
217 | sigio_unlock(); | ||
218 | return(err); | ||
219 | } | ||
220 | |||
221 | static struct pollfd *setup_initial_poll(int fd) | ||
222 | { | ||
223 | struct pollfd *p; | ||
224 | |||
225 | p = um_kmalloc(sizeof(struct pollfd)); | ||
226 | if (p == NULL) { | ||
227 | printk("setup_initial_poll : failed to allocate poll\n"); | ||
228 | return NULL; | ||
229 | } | ||
230 | *p = ((struct pollfd) { .fd = fd, | ||
231 | .events = POLLIN, | ||
232 | .revents = 0 }); | ||
233 | return p; | ||
234 | } | ||
235 | |||
236 | void write_sigio_workaround(void) | ||
237 | { | ||
238 | unsigned long stack; | ||
239 | struct pollfd *p; | ||
240 | int err; | ||
241 | int l_write_sigio_fds[2]; | ||
242 | int l_sigio_private[2]; | ||
243 | int l_write_sigio_pid; | ||
244 | |||
245 | /* We call this *tons* of times - and most ones we must just fail. */ | ||
246 | sigio_lock(); | ||
247 | l_write_sigio_pid = write_sigio_pid; | ||
248 | sigio_unlock(); | ||
249 | |||
250 | if (l_write_sigio_pid != -1) | ||
251 | return; | ||
252 | |||
253 | err = os_pipe(l_write_sigio_fds, 1, 1); | ||
254 | if(err < 0){ | ||
255 | printk("write_sigio_workaround - os_pipe 1 failed, " | ||
256 | "err = %d\n", -err); | ||
257 | return; | ||
258 | } | ||
259 | err = os_pipe(l_sigio_private, 1, 1); | ||
260 | if(err < 0){ | ||
261 | printk("write_sigio_workaround - os_pipe 2 failed, " | ||
262 | "err = %d\n", -err); | ||
263 | goto out_close1; | ||
264 | } | ||
265 | |||
266 | p = setup_initial_poll(l_sigio_private[1]); | ||
267 | if(!p) | ||
268 | goto out_close2; | ||
269 | |||
270 | sigio_lock(); | ||
271 | |||
272 | /* Did we race? Don't try to optimize this, please, it's not so likely | ||
273 | * to happen, and no more than once at the boot. */ | ||
274 | if(write_sigio_pid != -1) | ||
275 | goto out_free; | ||
276 | |||
277 | current_poll = ((struct pollfds) { .poll = p, | ||
278 | .used = 1, | ||
279 | .size = 1 }); | ||
280 | |||
281 | if (write_sigio_irq(l_write_sigio_fds[0])) | ||
282 | goto out_clear_poll; | ||
283 | |||
284 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); | ||
285 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); | ||
286 | |||
287 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | ||
288 | CLONE_FILES | CLONE_VM, &stack, 0); | ||
289 | |||
290 | if (write_sigio_pid < 0) | ||
291 | goto out_clear; | ||
292 | |||
293 | sigio_unlock(); | ||
294 | return; | ||
295 | |||
296 | out_clear: | ||
297 | write_sigio_pid = -1; | ||
298 | write_sigio_fds[0] = -1; | ||
299 | write_sigio_fds[1] = -1; | ||
300 | sigio_private[0] = -1; | ||
301 | sigio_private[1] = -1; | ||
302 | out_clear_poll: | ||
303 | current_poll = ((struct pollfds) { .poll = NULL, | ||
304 | .size = 0, | ||
305 | .used = 0 }); | ||
306 | out_free: | ||
307 | kfree(p); | ||
308 | sigio_unlock(); | ||
309 | out_close2: | ||
310 | close(l_sigio_private[0]); | ||
311 | close(l_sigio_private[1]); | ||
312 | out_close1: | ||
313 | close(l_write_sigio_fds[0]); | ||
314 | close(l_write_sigio_fds[1]); | ||
315 | } | ||
316 | |||
317 | void sigio_cleanup(void) | ||
318 | { | ||
319 | if(write_sigio_pid != -1){ | ||
320 | os_kill_process(write_sigio_pid, 1); | ||
321 | write_sigio_pid = -1; | ||
322 | } | ||
323 | } | ||
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 829d6b0d8b02..32753131f8d8 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <pty.h> | ||
6 | #include <stdio.h> | 7 | #include <stdio.h> |
7 | #include <stddef.h> | 8 | #include <stddef.h> |
8 | #include <stdarg.h> | 9 | #include <stdarg.h> |
@@ -539,3 +540,130 @@ int __init parse_iomem(char *str, int *add) | |||
539 | return(1); | 540 | return(1); |
540 | } | 541 | } |
541 | 542 | ||
543 | |||
544 | /* Changed during early boot */ | ||
545 | int pty_output_sigio = 0; | ||
546 | int pty_close_sigio = 0; | ||
547 | |||
548 | /* Used as a flag during SIGIO testing early in boot */ | ||
549 | static volatile int got_sigio = 0; | ||
550 | |||
551 | static void __init handler(int sig) | ||
552 | { | ||
553 | got_sigio = 1; | ||
554 | } | ||
555 | |||
556 | struct openpty_arg { | ||
557 | int master; | ||
558 | int slave; | ||
559 | int err; | ||
560 | }; | ||
561 | |||
562 | static void openpty_cb(void *arg) | ||
563 | { | ||
564 | struct openpty_arg *info = arg; | ||
565 | |||
566 | info->err = 0; | ||
567 | if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) | ||
568 | info->err = -errno; | ||
569 | } | ||
570 | |||
571 | static void __init check_one_sigio(void (*proc)(int, int)) | ||
572 | { | ||
573 | struct sigaction old, new; | ||
574 | struct openpty_arg pty = { .master = -1, .slave = -1 }; | ||
575 | int master, slave, err; | ||
576 | |||
577 | initial_thread_cb(openpty_cb, &pty); | ||
578 | if(pty.err){ | ||
579 | printk("openpty failed, errno = %d\n", -pty.err); | ||
580 | return; | ||
581 | } | ||
582 | |||
583 | master = pty.master; | ||
584 | slave = pty.slave; | ||
585 | |||
586 | if((master == -1) || (slave == -1)){ | ||
587 | printk("openpty failed to allocate a pty\n"); | ||
588 | return; | ||
589 | } | ||
590 | |||
591 | /* Not now, but complain so we now where we failed. */ | ||
592 | err = raw(master); | ||
593 | if (err < 0) | ||
594 | panic("check_sigio : __raw failed, errno = %d\n", -err); | ||
595 | |||
596 | err = os_sigio_async(master, slave); | ||
597 | if(err < 0) | ||
598 | panic("tty_fds : sigio_async failed, err = %d\n", -err); | ||
599 | |||
600 | if(sigaction(SIGIO, NULL, &old) < 0) | ||
601 | panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); | ||
602 | new = old; | ||
603 | new.sa_handler = handler; | ||
604 | if(sigaction(SIGIO, &new, NULL) < 0) | ||
605 | panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); | ||
606 | |||
607 | got_sigio = 0; | ||
608 | (*proc)(master, slave); | ||
609 | |||
610 | close(master); | ||
611 | close(slave); | ||
612 | |||
613 | if(sigaction(SIGIO, &old, NULL) < 0) | ||
614 | panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); | ||
615 | } | ||
616 | |||
617 | static void tty_output(int master, int slave) | ||
618 | { | ||
619 | int n; | ||
620 | char buf[512]; | ||
621 | |||
622 | printk("Checking that host ptys support output SIGIO..."); | ||
623 | |||
624 | memset(buf, 0, sizeof(buf)); | ||
625 | |||
626 | while(os_write_file(master, buf, sizeof(buf)) > 0) ; | ||
627 | if(errno != EAGAIN) | ||
628 | panic("check_sigio : write failed, errno = %d\n", errno); | ||
629 | while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; | ||
630 | |||
631 | if(got_sigio){ | ||
632 | printk("Yes\n"); | ||
633 | pty_output_sigio = 1; | ||
634 | } | ||
635 | else if(n == -EAGAIN) printk("No, enabling workaround\n"); | ||
636 | else panic("check_sigio : read failed, err = %d\n", n); | ||
637 | } | ||
638 | |||
639 | static void tty_close(int master, int slave) | ||
640 | { | ||
641 | printk("Checking that host ptys support SIGIO on close..."); | ||
642 | |||
643 | close(slave); | ||
644 | if(got_sigio){ | ||
645 | printk("Yes\n"); | ||
646 | pty_close_sigio = 1; | ||
647 | } | ||
648 | else printk("No, enabling workaround\n"); | ||
649 | } | ||
650 | |||
651 | void __init check_sigio(void) | ||
652 | { | ||
653 | if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && | ||
654 | (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ | ||
655 | printk("No pseudo-terminals available - skipping pty SIGIO " | ||
656 | "check\n"); | ||
657 | return; | ||
658 | } | ||
659 | check_one_sigio(tty_output); | ||
660 | check_one_sigio(tty_close); | ||
661 | } | ||
662 | |||
663 | void os_check_bugs(void) | ||
664 | { | ||
665 | check_ptrace(); | ||
666 | check_sigio(); | ||
667 | check_devanon(); | ||
668 | } | ||
669 | |||
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index 919d19f11537..5461a065bbb9 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c | |||
@@ -110,6 +110,16 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | void forward_ipi(int fd, int pid) | ||
114 | { | ||
115 | int err; | ||
116 | |||
117 | err = os_set_owner(fd, pid); | ||
118 | if(err < 0) | ||
119 | printk("forward_ipi: set_owner failed, fd = %d, me = %d, " | ||
120 | "target = %d, err = %d\n", fd, os_getpid(), pid, -err); | ||
121 | } | ||
122 | |||
113 | /* | 123 | /* |
114 | *------------------------- | 124 | *------------------------- |
115 | * only for tt mode (will be deleted in future...) | 125 | * only for tt mode (will be deleted in future...) |
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 @@ | |||
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 */ | ||
21 | static char *tty_log_dir = TTY_LOG_DIR; | ||
22 | static 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 | |||
32 | struct 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 | |||
41 | int 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 | os_write_file(tty_log_fd, &data, sizeof(data)); | ||
57 | os_write_file(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 | |||
73 | void 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 | os_write_file(tty_log_fd, &data, sizeof(data)); | ||
87 | return; | ||
88 | } | ||
89 | os_close_file(fd); | ||
90 | } | ||
91 | |||
92 | static 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 = os_write_file(fd, chunk, try); | ||
102 | if(n != try) { | ||
103 | if(n < 0) | ||
104 | return(n); | ||
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 | |||
118 | int 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 | os_write_file(tty_log_fd, &data, sizeof(data)); | ||
134 | } | ||
135 | |||
136 | return(log_chunk(fd, buf, len)); | ||
137 | } | ||
138 | |||
139 | void 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 | os_write_file(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 | |||
174 | extern void register_tty_logger(int (*opener)(void *, void *), | ||
175 | int (*writer)(int, const char *, int, | ||
176 | void *, int), | ||
177 | void (*closer)(int, void *)); | ||
178 | |||
179 | static 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 | |||
187 | static 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 | |||
199 | static 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 | ); | ||
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index ecf107ae5ac8..198e59163288 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c | |||
@@ -143,8 +143,10 @@ static int not_dead_yet(char *dir) | |||
143 | goto out_close; | 143 | goto out_close; |
144 | } | 144 | } |
145 | 145 | ||
146 | if((kill(p, 0) == 0) || (errno != ESRCH)) | 146 | if((kill(p, 0) == 0) || (errno != ESRCH)){ |
147 | printk("umid \"%s\" is already in use by pid %d\n", umid, p); | ||
147 | return 1; | 148 | return 1; |
149 | } | ||
148 | 150 | ||
149 | err = actually_do_remove(dir); | 151 | err = actually_do_remove(dir); |
150 | if(err) | 152 | if(err) |
@@ -234,33 +236,44 @@ int __init make_umid(void) | |||
234 | err = mkdir(tmp, 0777); | 236 | err = mkdir(tmp, 0777); |
235 | if(err < 0){ | 237 | if(err < 0){ |
236 | err = -errno; | 238 | err = -errno; |
237 | if(errno != EEXIST) | 239 | if(err != -EEXIST) |
238 | goto err; | 240 | goto err; |
239 | 241 | ||
240 | if(not_dead_yet(tmp) < 0) | 242 | /* 1 -> this umid is already in use |
243 | * < 0 -> we couldn't remove the umid directory | ||
244 | * In either case, we can't use this umid, so return -EEXIST. | ||
245 | */ | ||
246 | if(not_dead_yet(tmp) != 0) | ||
241 | goto err; | 247 | goto err; |
242 | 248 | ||
243 | err = mkdir(tmp, 0777); | 249 | err = mkdir(tmp, 0777); |
244 | } | 250 | } |
245 | if(err < 0){ | 251 | if(err){ |
246 | printk("Failed to create '%s' - err = %d\n", umid, err); | 252 | err = -errno; |
247 | goto err_rmdir; | 253 | printk("Failed to create '%s' - err = %d\n", umid, -errno); |
254 | goto err; | ||
248 | } | 255 | } |
249 | 256 | ||
250 | umid_setup = 1; | 257 | umid_setup = 1; |
251 | 258 | ||
252 | create_pid_file(); | 259 | create_pid_file(); |
253 | 260 | ||
254 | return 0; | 261 | err = 0; |
255 | |||
256 | err_rmdir: | ||
257 | rmdir(tmp); | ||
258 | err: | 262 | err: |
259 | return err; | 263 | return err; |
260 | } | 264 | } |
261 | 265 | ||
262 | static int __init make_umid_init(void) | 266 | static int __init make_umid_init(void) |
263 | { | 267 | { |
268 | if(!make_umid()) | ||
269 | return 0; | ||
270 | |||
271 | /* If initializing with the given umid failed, then try again with | ||
272 | * a random one. | ||
273 | */ | ||
274 | printk("Failed to initialize umid \"%s\", trying with a random umid\n", | ||
275 | umid); | ||
276 | *umid = '\0'; | ||
264 | make_umid(); | 277 | make_umid(); |
265 | 278 | ||
266 | return 0; | 279 | return 0; |