diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/drivers/chan_user.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/um/drivers/chan_user.c')
-rw-r--r-- | arch/um/drivers/chan_user.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c new file mode 100644 index 00000000000..583b8e137c3 --- /dev/null +++ b/arch/um/drivers/chan_user.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <unistd.h> | ||
7 | #include <stdlib.h> | ||
8 | #include <errno.h> | ||
9 | #include <termios.h> | ||
10 | #include <string.h> | ||
11 | #include <signal.h> | ||
12 | #include <sys/stat.h> | ||
13 | #include <sys/ioctl.h> | ||
14 | #include <sys/socket.h> | ||
15 | #include "kern_util.h" | ||
16 | #include "user_util.h" | ||
17 | #include "chan_user.h" | ||
18 | #include "user.h" | ||
19 | #include "helper.h" | ||
20 | #include "os.h" | ||
21 | #include "choose-mode.h" | ||
22 | #include "mode.h" | ||
23 | |||
24 | int generic_console_write(int fd, const char *buf, int n, void *unused) | ||
25 | { | ||
26 | struct termios save, new; | ||
27 | int err; | ||
28 | |||
29 | if(isatty(fd)){ | ||
30 | CATCH_EINTR(err = tcgetattr(fd, &save)); | ||
31 | if (err) | ||
32 | goto error; | ||
33 | new = save; | ||
34 | /* The terminal becomes a bit less raw, to handle \n also as | ||
35 | * "Carriage Return", not only as "New Line". Otherwise, the new | ||
36 | * line won't start at the first column.*/ | ||
37 | new.c_oflag |= OPOST; | ||
38 | CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new)); | ||
39 | if (err) | ||
40 | goto error; | ||
41 | } | ||
42 | err = generic_write(fd, buf, n, NULL); | ||
43 | /* Restore raw mode, in any case; we *must* ignore any error apart | ||
44 | * EINTR, except for debug.*/ | ||
45 | if(isatty(fd)) | ||
46 | CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save)); | ||
47 | return(err); | ||
48 | error: | ||
49 | return(-errno); | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * UML SIGWINCH handling | ||
54 | * | ||
55 | * The point of this is to handle SIGWINCH on consoles which have host ttys and | ||
56 | * relay them inside UML to whatever might be running on the console and cares | ||
57 | * about the window size (since SIGWINCH notifies about terminal size changes). | ||
58 | * | ||
59 | * So, we have a separate thread for each host tty attached to a UML device | ||
60 | * (side-issue - I'm annoyed that one thread can't have multiple controlling | ||
61 | * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons | ||
62 | * that doesn't make any sense). | ||
63 | * | ||
64 | * SIGWINCH can't be received synchronously, so you have to set up to receive it | ||
65 | * as a signal. That being the case, if you are going to wait for it, it is | ||
66 | * convenient to sit in a pause() and wait for the signal to bounce you out of | ||
67 | * it (see below for how we make sure to exit only on SIGWINCH). | ||
68 | */ | ||
69 | |||
70 | static void winch_handler(int sig) | ||
71 | { | ||
72 | } | ||
73 | |||
74 | struct winch_data { | ||
75 | int pty_fd; | ||
76 | int pipe_fd; | ||
77 | int close_me; | ||
78 | }; | ||
79 | |||
80 | static int winch_thread(void *arg) | ||
81 | { | ||
82 | struct winch_data *data = arg; | ||
83 | sigset_t sigs; | ||
84 | int pty_fd, pipe_fd; | ||
85 | int count, err; | ||
86 | char c = 1; | ||
87 | |||
88 | os_close_file(data->close_me); | ||
89 | pty_fd = data->pty_fd; | ||
90 | pipe_fd = data->pipe_fd; | ||
91 | count = os_write_file(pipe_fd, &c, sizeof(c)); | ||
92 | if(count != sizeof(c)) | ||
93 | printk("winch_thread : failed to write synchronization " | ||
94 | "byte, err = %d\n", -count); | ||
95 | |||
96 | /* We are not using SIG_IGN on purpose, so don't fix it as I thought to | ||
97 | * do! If using SIG_IGN, the pause() call below would not stop on | ||
98 | * SIGWINCH. */ | ||
99 | |||
100 | signal(SIGWINCH, winch_handler); | ||
101 | sigfillset(&sigs); | ||
102 | sigdelset(&sigs, SIGWINCH); | ||
103 | /* Block anything else than SIGWINCH. */ | ||
104 | if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){ | ||
105 | printk("winch_thread : sigprocmask failed, errno = %d\n", | ||
106 | errno); | ||
107 | exit(1); | ||
108 | } | ||
109 | |||
110 | if(setsid() < 0){ | ||
111 | printk("winch_thread : setsid failed, errno = %d\n", errno); | ||
112 | exit(1); | ||
113 | } | ||
114 | |||
115 | err = os_new_tty_pgrp(pty_fd, os_getpid()); | ||
116 | if(err < 0){ | ||
117 | printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); | ||
118 | exit(1); | ||
119 | } | ||
120 | |||
121 | /* These are synchronization calls between various UML threads on the | ||
122 | * host - since they are not different kernel threads, we cannot use | ||
123 | * kernel semaphores. We don't use SysV semaphores because they are | ||
124 | * persistant. */ | ||
125 | count = os_read_file(pipe_fd, &c, sizeof(c)); | ||
126 | if(count != sizeof(c)) | ||
127 | printk("winch_thread : failed to read synchronization byte, " | ||
128 | "err = %d\n", -count); | ||
129 | |||
130 | while(1){ | ||
131 | /* This will be interrupted by SIGWINCH only, since other signals | ||
132 | * are blocked.*/ | ||
133 | pause(); | ||
134 | |||
135 | count = os_write_file(pipe_fd, &c, sizeof(c)); | ||
136 | if(count != sizeof(c)) | ||
137 | printk("winch_thread : write failed, err = %d\n", | ||
138 | -count); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) | ||
143 | { | ||
144 | struct winch_data data; | ||
145 | unsigned long stack; | ||
146 | int fds[2], pid, n, err; | ||
147 | char c; | ||
148 | |||
149 | err = os_pipe(fds, 1, 1); | ||
150 | if(err < 0){ | ||
151 | printk("winch_tramp : os_pipe failed, err = %d\n", -err); | ||
152 | return(err); | ||
153 | } | ||
154 | |||
155 | data = ((struct winch_data) { .pty_fd = fd, | ||
156 | .pipe_fd = fds[1], | ||
157 | .close_me = fds[0] } ); | ||
158 | pid = run_helper_thread(winch_thread, &data, 0, &stack, 0); | ||
159 | if(pid < 0){ | ||
160 | printk("fork of winch_thread failed - errno = %d\n", errno); | ||
161 | return(pid); | ||
162 | } | ||
163 | |||
164 | os_close_file(fds[1]); | ||
165 | *fd_out = fds[0]; | ||
166 | n = os_read_file(fds[0], &c, sizeof(c)); | ||
167 | if(n != sizeof(c)){ | ||
168 | printk("winch_tramp : failed to read synchronization byte\n"); | ||
169 | printk("read failed, err = %d\n", -n); | ||
170 | printk("fd %d will not support SIGWINCH\n", fd); | ||
171 | *fd_out = -1; | ||
172 | } | ||
173 | return(pid); | ||
174 | } | ||
175 | |||
176 | void register_winch(int fd, struct tty_struct *tty) | ||
177 | { | ||
178 | int pid, thread, thread_fd; | ||
179 | int count; | ||
180 | char c = 1; | ||
181 | |||
182 | if(!isatty(fd)) | ||
183 | return; | ||
184 | |||
185 | pid = tcgetpgrp(fd); | ||
186 | if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, | ||
187 | tty) && (pid == -1)){ | ||
188 | thread = winch_tramp(fd, tty, &thread_fd); | ||
189 | if(fd != -1){ | ||
190 | register_winch_irq(thread_fd, fd, thread, tty); | ||
191 | |||
192 | count = os_write_file(thread_fd, &c, sizeof(c)); | ||
193 | if(count != sizeof(c)) | ||
194 | printk("register_winch : failed to write " | ||
195 | "synchronization byte, err = %d\n", | ||
196 | -count); | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
203 | * Emacs will notice this stuff at the end of the file and automatically | ||
204 | * adjust the settings for this buffer only. This must remain at the end | ||
205 | * of the file. | ||
206 | * --------------------------------------------------------------------------- | ||
207 | * Local variables: | ||
208 | * c-file-style: "linux" | ||
209 | * End: | ||
210 | */ | ||