Blame view
arch/um/drivers/chan_user.c
6.95 KB
cb8fa61c2 uml: arch/um/driv... |
1 |
/* |
e99525f97 uml: console subs... |
2 |
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) |
1da177e4c Linux-2.6.12-rc2 |
3 4 |
* Licensed under the GPL */ |
1da177e4c Linux-2.6.12-rc2 |
5 |
#include <stdlib.h> |
e99525f97 uml: console subs... |
6 |
#include <unistd.h> |
1da177e4c Linux-2.6.12-rc2 |
7 |
#include <errno.h> |
1d2ddcfb1 [PATCH] uml: clos... |
8 |
#include <sched.h> |
e99525f97 uml: console subs... |
9 10 |
#include <signal.h> #include <termios.h> |
1da177e4c Linux-2.6.12-rc2 |
11 |
#include <sys/ioctl.h> |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include "chan_user.h" |
37185b332 um: get rid of po... |
13 14 |
#include <os.h> #include <um_malloc.h> |
89fe64766 uml: move userspa... |
15 16 17 |
void generic_close(int fd, void *unused) { |
8e2d10e1e uml: tidy recentl... |
18 |
close(fd); |
89fe64766 uml: move userspa... |
19 20 21 22 23 |
} int generic_read(int fd, char *c_out, void *unused) { int n; |
8e2d10e1e uml: tidy recentl... |
24 25 26 27 |
n = read(fd, c_out, sizeof(*c_out)); if (n > 0) return n; else if (errno == EAGAIN) |
89fe64766 uml: move userspa... |
28 |
return 0; |
8e2d10e1e uml: tidy recentl... |
29 |
else if (n == 0) |
89fe64766 uml: move userspa... |
30 |
return -EIO; |
8e2d10e1e uml: tidy recentl... |
31 |
return -errno; |
89fe64766 uml: move userspa... |
32 |
} |
8e2d10e1e uml: tidy recentl... |
33 |
/* XXX Trivial wrapper around write */ |
89fe64766 uml: move userspa... |
34 35 36 |
int generic_write(int fd, const char *buf, int n, void *unused) { |
c59dbcadd uml: fix console ... |
37 38 39 40 41 42 43 44 45 46 |
int err; err = write(fd, buf, n); if (err > 0) return err; else if (errno == EAGAIN) return 0; else if (err == 0) return -EIO; return -errno; |
89fe64766 uml: move userspa... |
47 48 49 50 51 |
} int generic_window_size(int fd, void *unused, unsigned short *rows_out, unsigned short *cols_out) { |
8e2d10e1e uml: tidy recentl... |
52 |
struct winsize size; |
89fe64766 uml: move userspa... |
53 |
int ret; |
e99525f97 uml: console subs... |
54 |
if (ioctl(fd, TIOCGWINSZ, &size) < 0) |
8e2d10e1e uml: tidy recentl... |
55 |
return -errno; |
89fe64766 uml: move userspa... |
56 |
|
8e2d10e1e uml: tidy recentl... |
57 |
ret = ((*rows_out != size.ws_row) || (*cols_out != size.ws_col)); |
89fe64766 uml: move userspa... |
58 |
|
8e2d10e1e uml: tidy recentl... |
59 60 |
*rows_out = size.ws_row; *cols_out = size.ws_col; |
89fe64766 uml: move userspa... |
61 62 63 64 65 66 67 68 |
return ret; } void generic_free(void *data) { kfree(data); } |
1da177e4c Linux-2.6.12-rc2 |
69 |
|
55c033c1f [PATCH] uml conso... |
70 |
int generic_console_write(int fd, const char *buf, int n) |
1da177e4c Linux-2.6.12-rc2 |
71 |
{ |
ce3b642d4 uml: work around ... |
72 |
sigset_t old, no_sigio; |
1da177e4c Linux-2.6.12-rc2 |
73 74 |
struct termios save, new; int err; |
e99525f97 uml: console subs... |
75 |
if (isatty(fd)) { |
ce3b642d4 uml: work around ... |
76 77 78 79 |
sigemptyset(&no_sigio); sigaddset(&no_sigio, SIGIO); if (sigprocmask(SIG_BLOCK, &no_sigio, &old)) goto error; |
1da177e4c Linux-2.6.12-rc2 |
80 81 82 83 |
CATCH_EINTR(err = tcgetattr(fd, &save)); if (err) goto error; new = save; |
cb8fa61c2 uml: arch/um/driv... |
84 85 86 |
/* * The terminal becomes a bit less raw, to handle also as |
1da177e4c Linux-2.6.12-rc2 |
87 |
* "Carriage Return", not only as "New Line". Otherwise, the new |
cb8fa61c2 uml: arch/um/driv... |
88 89 |
* line won't start at the first column. */ |
1da177e4c Linux-2.6.12-rc2 |
90 91 92 93 94 95 |
new.c_oflag |= OPOST; CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new)); if (err) goto error; } err = generic_write(fd, buf, n, NULL); |
cb8fa61c2 uml: arch/um/driv... |
96 97 98 99 |
/* * Restore raw mode, in any case; we *must* ignore any error apart * EINTR, except for debug. */ |
ce3b642d4 uml: work around ... |
100 |
if (isatty(fd)) { |
1da177e4c Linux-2.6.12-rc2 |
101 |
CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save)); |
ce3b642d4 uml: work around ... |
102 103 |
sigprocmask(SIG_SETMASK, &old, NULL); } |
e99525f97 uml: console subs... |
104 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
105 |
error: |
e99525f97 uml: console subs... |
106 |
return -errno; |
1da177e4c Linux-2.6.12-rc2 |
107 108 109 110 111 |
} /* * UML SIGWINCH handling * |
42a359e31 uml: SIGIO suppor... |
112 113 114 115 |
* The point of this is to handle SIGWINCH on consoles which have host * ttys and relay them inside UML to whatever might be running on the * console and cares about the window size (since SIGWINCH notifies * about terminal size changes). |
1da177e4c Linux-2.6.12-rc2 |
116 |
* |
42a359e31 uml: SIGIO suppor... |
117 118 119 120 |
* So, we have a separate thread for each host tty attached to a UML * device (side-issue - I'm annoyed that one thread can't have * multiple controlling ttys for the purpose of handling SIGWINCH, but * I imagine there are other reasons that doesn't make any sense). |
1da177e4c Linux-2.6.12-rc2 |
121 |
* |
42a359e31 uml: SIGIO suppor... |
122 123 124 125 126 |
* SIGWINCH can't be received synchronously, so you have to set up to * receive it as a signal. That being the case, if you are going to * wait for it, it is convenient to sit in sigsuspend() and wait for * the signal to bounce you out of it (see below for how we make sure * to exit only on SIGWINCH). |
1da177e4c Linux-2.6.12-rc2 |
127 128 129 130 131 132 133 134 135 |
*/ static void winch_handler(int sig) { } struct winch_data { int pty_fd; int pipe_fd; |
1da177e4c Linux-2.6.12-rc2 |
136 137 138 139 140 141 142 |
}; static int winch_thread(void *arg) { struct winch_data *data = arg; sigset_t sigs; int pty_fd, pipe_fd; |
8ca842c4b uml: remove os_* ... |
143 |
int count; |
1da177e4c Linux-2.6.12-rc2 |
144 |
char c = 1; |
1da177e4c Linux-2.6.12-rc2 |
145 146 |
pty_fd = data->pty_fd; pipe_fd = data->pipe_fd; |
8ca842c4b uml: remove os_* ... |
147 |
count = write(pipe_fd, &c, sizeof(c)); |
e99525f97 uml: console subs... |
148 149 150 151 |
if (count != sizeof(c)) printk(UM_KERN_ERR "winch_thread : failed to write " "synchronization byte, err = %d ", -count); |
1da177e4c Linux-2.6.12-rc2 |
152 |
|
e99525f97 uml: console subs... |
153 154 |
/* * We are not using SIG_IGN on purpose, so don't fix it as I thought to |
ed1b58d8b [PATCH] uml: fix ... |
155 |
* do! If using SIG_IGN, the sigsuspend() call below would not stop on |
e99525f97 uml: console subs... |
156 157 |
* SIGWINCH. */ |
1da177e4c Linux-2.6.12-rc2 |
158 159 160 |
signal(SIGWINCH, winch_handler); sigfillset(&sigs); |
ed1b58d8b [PATCH] uml: fix ... |
161 |
/* Block all signals possible. */ |
e99525f97 uml: console subs... |
162 163 164 165 |
if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) { printk(UM_KERN_ERR "winch_thread : sigprocmask failed, " "errno = %d ", errno); |
1da177e4c Linux-2.6.12-rc2 |
166 167 |
exit(1); } |
ed1b58d8b [PATCH] uml: fix ... |
168 169 |
/* In sigsuspend(), block anything else than SIGWINCH. */ sigdelset(&sigs, SIGWINCH); |
1da177e4c Linux-2.6.12-rc2 |
170 |
|
e99525f97 uml: console subs... |
171 172 173 174 |
if (setsid() < 0) { printk(UM_KERN_ERR "winch_thread : setsid failed, errno = %d ", errno); |
1da177e4c Linux-2.6.12-rc2 |
175 176 |
exit(1); } |
cb8fa61c2 uml: arch/um/driv... |
177 |
if (ioctl(pty_fd, TIOCSCTTY, 0) < 0) { |
8ca842c4b uml: remove os_* ... |
178 179 180 181 182 |
printk(UM_KERN_ERR "winch_thread : TIOCSCTTY failed on " "fd %d err = %d ", pty_fd, errno); exit(1); } |
cb8fa61c2 uml: arch/um/driv... |
183 |
if (tcsetpgrp(pty_fd, os_getpid()) < 0) { |
8ca842c4b uml: remove os_* ... |
184 185 186 |
printk(UM_KERN_ERR "winch_thread : tcsetpgrp failed on " "fd %d err = %d ", pty_fd, errno); |
1da177e4c Linux-2.6.12-rc2 |
187 188 |
exit(1); } |
e99525f97 uml: console subs... |
189 190 |
/* * These are synchronization calls between various UML threads on the |
1da177e4c Linux-2.6.12-rc2 |
191 192 |
* host - since they are not different kernel threads, we cannot use * kernel semaphores. We don't use SysV semaphores because they are |
e99525f97 uml: console subs... |
193 194 |
* persistent. */ |
8ca842c4b uml: remove os_* ... |
195 |
count = read(pipe_fd, &c, sizeof(c)); |
e99525f97 uml: console subs... |
196 197 |
if (count != sizeof(c)) printk(UM_KERN_ERR "winch_thread : failed to read " |
8ca842c4b uml: remove os_* ... |
198 199 |
"synchronization byte, err = %d ", errno); |
1da177e4c Linux-2.6.12-rc2 |
200 |
|
e99525f97 uml: console subs... |
201 202 203 |
while(1) { /* * This will be interrupted by SIGWINCH only, since |
42a359e31 uml: SIGIO suppor... |
204 205 |
* other signals are blocked. */ |
ed1b58d8b [PATCH] uml: fix ... |
206 |
sigsuspend(&sigs); |
1da177e4c Linux-2.6.12-rc2 |
207 |
|
8ca842c4b uml: remove os_* ... |
208 |
count = write(pipe_fd, &c, sizeof(c)); |
e99525f97 uml: console subs... |
209 210 |
if (count != sizeof(c)) printk(UM_KERN_ERR "winch_thread : write failed, " |
8ca842c4b uml: remove os_* ... |
211 212 |
"err = %d ", errno); |
1da177e4c Linux-2.6.12-rc2 |
213 214 |
} } |
2116bda6a um: Use tty_port ... |
215 |
static int winch_tramp(int fd, struct tty_port *port, int *fd_out, |
42a359e31 uml: SIGIO suppor... |
216 |
unsigned long *stack_out) |
1da177e4c Linux-2.6.12-rc2 |
217 218 |
{ struct winch_data data; |
1f96ddb4f [PATCH] uml: clea... |
219 |
int fds[2], n, err; |
1da177e4c Linux-2.6.12-rc2 |
220 221 222 |
char c; err = os_pipe(fds, 1, 1); |
e99525f97 uml: console subs... |
223 224 225 226 |
if (err < 0) { printk(UM_KERN_ERR "winch_tramp : os_pipe failed, err = %d ", -err); |
1f96ddb4f [PATCH] uml: clea... |
227 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
228 229 230 |
} data = ((struct winch_data) { .pty_fd = fd, |
1d2ddcfb1 [PATCH] uml: clos... |
231 |
.pipe_fd = fds[1] } ); |
e99525f97 uml: console subs... |
232 233 |
/* * CLONE_FILES so this thread doesn't hold open files which are open |
42a359e31 uml: SIGIO suppor... |
234 235 236 |
* now, but later closed in a different thread. This is a * problem with /dev/net/tun, which if held open by this * thread, prevents the TUN/TAP device from being reused. |
1d2ddcfb1 [PATCH] uml: clos... |
237 |
*/ |
c43990162 uml: simplify hel... |
238 |
err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); |
e99525f97 uml: console subs... |
239 240 241 242 |
if (err < 0) { printk(UM_KERN_ERR "fork of winch_thread failed - errno = %d ", -err); |
1f96ddb4f [PATCH] uml: clea... |
243 |
goto out_close; |
1da177e4c Linux-2.6.12-rc2 |
244 |
} |
1da177e4c Linux-2.6.12-rc2 |
245 |
*fd_out = fds[0]; |
8ca842c4b uml: remove os_* ... |
246 |
n = read(fds[0], &c, sizeof(c)); |
e99525f97 uml: console subs... |
247 248 249 250 |
if (n != sizeof(c)) { printk(UM_KERN_ERR "winch_tramp : failed to read " "synchronization byte "); |
8ca842c4b uml: remove os_* ... |
251 252 |
printk(UM_KERN_ERR "read failed, err = %d ", errno); |
e99525f97 uml: console subs... |
253 254 255 |
printk(UM_KERN_ERR "fd %d will not support SIGWINCH ", fd); err = -EINVAL; |
1d2ddcfb1 [PATCH] uml: clos... |
256 |
goto out_close; |
1da177e4c Linux-2.6.12-rc2 |
257 |
} |
89df6bfc0 uml: DEBUG_SHIRQ ... |
258 259 |
if (os_set_fd_block(*fd_out, 0)) { |
e99525f97 uml: console subs... |
260 261 262 |
printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd " "non-blocking. "); |
89df6bfc0 uml: DEBUG_SHIRQ ... |
263 264 265 266 |
goto out_close; } return err; |
1f96ddb4f [PATCH] uml: clea... |
267 268 |
out_close: |
8ca842c4b uml: remove os_* ... |
269 270 |
close(fds[1]); close(fds[0]); |
1f96ddb4f [PATCH] uml: clea... |
271 272 |
out: return err; |
1da177e4c Linux-2.6.12-rc2 |
273 |
} |
2116bda6a um: Use tty_port ... |
274 |
void register_winch(int fd, struct tty_port *port) |
1da177e4c Linux-2.6.12-rc2 |
275 |
{ |
42a359e31 uml: SIGIO suppor... |
276 277 |
unsigned long stack; int pid, thread, count, thread_fd = -1; |
1da177e4c Linux-2.6.12-rc2 |
278 |
char c = 1; |
e99525f97 uml: console subs... |
279 |
if (!isatty(fd)) |
1da177e4c Linux-2.6.12-rc2 |
280 281 282 |
return; pid = tcgetpgrp(fd); |
2116bda6a um: Use tty_port ... |
283 284 |
if (is_skas_winch(pid, fd, port)) { register_winch_irq(-1, fd, -1, port, 0); |
17e052093 um: take register... |
285 286 287 288 |
return; } if (pid == -1) { |
2116bda6a um: Use tty_port ... |
289 |
thread = winch_tramp(fd, port, &thread_fd, &stack); |
42a359e31 uml: SIGIO suppor... |
290 291 |
if (thread < 0) return; |
2116bda6a um: Use tty_port ... |
292 |
register_winch_irq(thread_fd, fd, thread, port, stack); |
42a359e31 uml: SIGIO suppor... |
293 |
|
8ca842c4b uml: remove os_* ... |
294 |
count = write(thread_fd, &c, sizeof(c)); |
e99525f97 uml: console subs... |
295 296 |
if (count != sizeof(c)) printk(UM_KERN_ERR "register_winch : failed to write " |
8ca842c4b uml: remove os_* ... |
297 298 |
"synchronization byte, err = %d ", errno); |
1da177e4c Linux-2.6.12-rc2 |
299 300 |
} } |