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