int generic_write(int fd, const __u8 *buf, size_t n, void *unused)
{ int written = 0; int err;
/* The FD may be in blocking mode, as such, need to retry short writes, * they may have been interrupted by a signal.
*/ do {
errno = 0;
err = write(fd, buf + written, n - written); if (err > 0) {
written += err; continue;
}
} while (err < 0 && errno == EINTR);
int generic_window_size(int fd, void *unused, unsignedshort *rows_out, unsignedshort *cols_out)
{ struct winsize size; int ret;
if (ioctl(fd, TIOCGWINSZ, &size) < 0) return -errno;
ret = ((*rows_out != size.ws_row) || (*cols_out != size.ws_col));
*rows_out = size.ws_row;
*cols_out = size.ws_col;
return ret;
}
void generic_free(void *data)
{
kfree(data);
}
int generic_console_write(int fd, constchar *buf, int n)
{
sigset_t old, no_sigio; struct termios save, new; int err;
if (isatty(fd)) {
sigemptyset(&no_sigio);
sigaddset(&no_sigio, SIGIO); if (sigprocmask(SIG_BLOCK, &no_sigio, &old)) goto error;
CATCH_EINTR(err = tcgetattr(fd, &save)); if (err) goto error; new = save; /* * The terminal becomes a bit less raw, to handle \n also as * "Carriage Return", not only as "New Line". Otherwise, the new * line won't start at the first column.
*/ new.c_oflag |= OPOST;
CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new)); if (err) goto error;
}
err = generic_write(fd, buf, n, NULL); /* * Restore raw mode, in any case; we *must* ignore any error apart * EINTR, except for debug.
*/ if (isatty(fd)) {
CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save));
sigprocmask(SIG_SETMASK, &old, NULL);
}
return err;
error: return -errno;
}
/* * UML SIGWINCH handling * * 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). * * 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). * * 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).
*/
staticvoid winch_handler(int sig)
{
}
struct winch_data { int pty_fd; int pipe_fd;
};
static __noreturn int winch_thread(void *arg)
{ struct winch_data *data = arg;
sigset_t sigs; int pty_fd, pipe_fd; int count; char c = 1;
/* * We are not using SIG_IGN on purpose, so don't fix it as I thought to * do! If using SIG_IGN, the sigsuspend() call below would not stop on * SIGWINCH.
*/
signal(SIGWINCH, winch_handler);
sigfillset(&sigs); /* Block all signals possible. */ if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) {
os_info("winch_thread : sigprocmask failed, errno = %d\n",
errno); goto wait_kill;
} /* In sigsuspend(), block anything else than SIGWINCH. */
sigdelset(&sigs, SIGWINCH);
/* * These are synchronization calls between various UML threads on the * host - since they are not different kernel threads, we cannot use * kernel semaphores. We don't use SysV semaphores because they are * persistent.
*/
count = read(pipe_fd, &c, sizeof(c)); if (count != sizeof(c))
os_info("winch_thread : failed to read synchronization byte, err = %d\n",
errno);
while(1) { /* * This will be interrupted by SIGWINCH only, since * other signals are blocked.
*/
sigsuspend(&sigs);
data = ((struct winch_data) { .pty_fd = fd,
.pipe_fd = fds[1] } ); /* * CLONE_FILES so this thread doesn't hold open files which are open * 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.
*/
pid = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); if (pid < 0) {
err = pid;
printk(UM_KERN_ERR "fork of winch_thread failed - errno = %d\n",
-err); goto out_close;
}
*fd_out = fds[0];
n = read(fds[0], &c, sizeof(c)); if (n != sizeof(c)) {
printk(UM_KERN_ERR "winch_tramp : failed to read " "synchronization byte\n");
printk(UM_KERN_ERR "read failed, err = %d\n", errno);
printk(UM_KERN_ERR "fd %d will not support SIGWINCH\n", fd);
err = -EINVAL; goto out_close;
}
err = os_set_fd_block(*fd_out, 0); if (err) {
printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd " "non-blocking.\n"); goto out_close;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.10Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.