1cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike/* 2e99525f9706900417f37721e601d2b414d41bfeeJeff Dike * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the GPL 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <stdlib.h> 7e99525f9706900417f37721e601d2b414d41bfeeJeff Dike#include <unistd.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <errno.h> 91d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike#include <sched.h> 10e99525f9706900417f37721e601d2b414d41bfeeJeff Dike#include <signal.h> 11e99525f9706900417f37721e601d2b414d41bfeeJeff Dike#include <termios.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/ioctl.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "chan_user.h" 1437185b33240870719b6b5913a46e6a441f1ae96fAl Viro#include <os.h> 1537185b33240870719b6b5913a46e6a441f1ae96fAl Viro#include <um_malloc.h> 1689fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 1789fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dikevoid generic_close(int fd, void *unused) 1889fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike{ 198e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike close(fd); 2089fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike} 2189fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 2289fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dikeint generic_read(int fd, char *c_out, void *unused) 2389fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike{ 2489fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike int n; 2589fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 268e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike n = read(fd, c_out, sizeof(*c_out)); 278e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike if (n > 0) 288e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike return n; 298e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike else if (errno == EAGAIN) 3089fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike return 0; 318e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike else if (n == 0) 3289fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike return -EIO; 338e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike return -errno; 3489fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike} 3589fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 368e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike/* XXX Trivial wrapper around write */ 3789fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 3889fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dikeint generic_write(int fd, const char *buf, int n, void *unused) 3989fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike{ 40c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike int err; 41c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike 42c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike err = write(fd, buf, n); 43c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike if (err > 0) 44c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike return err; 45c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike else if (errno == EAGAIN) 46c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike return 0; 47c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike else if (err == 0) 48c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike return -EIO; 49c59dbcadd5d125ba40595612dc91ab18924164d3Jeff Dike return -errno; 5089fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike} 5189fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 5289fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dikeint generic_window_size(int fd, void *unused, unsigned short *rows_out, 5389fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike unsigned short *cols_out) 5489fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike{ 558e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike struct winsize size; 5689fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike int ret; 5789fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 58e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (ioctl(fd, TIOCGWINSZ, &size) < 0) 598e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike return -errno; 6089fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 618e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike ret = ((*rows_out != size.ws_row) || (*cols_out != size.ws_col)); 6289fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 638e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike *rows_out = size.ws_row; 648e2d10e1e76d894ec73d66dd63b641ccf5f5fb67Jeff Dike *cols_out = size.ws_col; 6589fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 6689fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike return ret; 6789fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike} 6889fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike 6989fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dikevoid generic_free(void *data) 7089fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike{ 7189fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike kfree(data); 7289fe64766ab76b02c65a806b8b5a864652493bd6Jeff Dike} 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7455c033c1f6cdedc350c79c3198b542e3ab496899Paolo 'Blaisorblade' Giarrussoint generic_console_write(int fd, const char *buf, int n) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 76ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike sigset_t old, no_sigio; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct termios save, new; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (isatty(fd)) { 81ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike sigemptyset(&no_sigio); 82ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike sigaddset(&no_sigio, SIGIO); 83ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike if (sigprocmask(SIG_BLOCK, &no_sigio, &old)) 84ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike goto error; 85ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CATCH_EINTR(err = tcgetattr(fd, &save)); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new = save; 90cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike /* 91cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike * The terminal becomes a bit less raw, to handle \n also as 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "Carriage Return", not only as "New Line". Otherwise, the new 93cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike * line won't start at the first column. 94cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new.c_oflag |= OPOST; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new)); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = generic_write(fd, buf, n, NULL); 101cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike /* 102cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike * Restore raw mode, in any case; we *must* ignore any error apart 103cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike * EINTR, except for debug. 104cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike */ 105ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike if (isatty(fd)) { 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save)); 107ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike sigprocmask(SIG_SETMASK, &old, NULL); 108ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike } 109ce3b642d42f36406112ab474c03d81c5941d9398Jeff Dike 110e99525f9706900417f37721e601d2b414d41bfeeJeff Dike return err; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 112e99525f9706900417f37721e601d2b414d41bfeeJeff Dike return -errno; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UML SIGWINCH handling 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11842a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * The point of this is to handle SIGWINCH on consoles which have host 11942a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * ttys and relay them inside UML to whatever might be running on the 12042a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * console and cares about the window size (since SIGWINCH notifies 12142a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * about terminal size changes). 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12342a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * So, we have a separate thread for each host tty attached to a UML 12442a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * device (side-issue - I'm annoyed that one thread can't have 12542a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * multiple controlling ttys for the purpose of handling SIGWINCH, but 12642a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * I imagine there are other reasons that doesn't make any sense). 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12842a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * SIGWINCH can't be received synchronously, so you have to set up to 12942a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * receive it as a signal. That being the case, if you are going to 13042a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * wait for it, it is convenient to sit in sigsuspend() and wait for 13142a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * the signal to bounce you out of it (see below for how we make sure 13242a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * to exit only on SIGWINCH). 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void winch_handler(int sig) 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct winch_data { 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pty_fd; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pipe_fd; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int winch_thread(void *arg) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct winch_data *data = arg; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigset_t sigs; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pty_fd, pipe_fd; 1498ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike int count; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c = 1; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pty_fd = data->pty_fd; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pipe_fd = data->pipe_fd; 1548ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike count = write(pipe_fd, &c, sizeof(c)); 155e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (count != sizeof(c)) 156e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_thread : failed to write " 157e99525f9706900417f37721e601d2b414d41bfeeJeff Dike "synchronization byte, err = %d\n", -count); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 159e99525f9706900417f37721e601d2b414d41bfeeJeff Dike /* 160e99525f9706900417f37721e601d2b414d41bfeeJeff Dike * We are not using SIG_IGN on purpose, so don't fix it as I thought to 161ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser * do! If using SIG_IGN, the sigsuspend() call below would not stop on 162e99525f9706900417f37721e601d2b414d41bfeeJeff Dike * SIGWINCH. 163e99525f9706900417f37721e601d2b414d41bfeeJeff Dike */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds signal(SIGWINCH, winch_handler); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigfillset(&sigs); 167ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser /* Block all signals possible. */ 168e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) { 169e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_thread : sigprocmask failed, " 170e99525f9706900417f37721e601d2b414d41bfeeJeff Dike "errno = %d\n", errno); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit(1); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 173ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser /* In sigsuspend(), block anything else than SIGWINCH. */ 174ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser sigdelset(&sigs, SIGWINCH); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 176e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (setsid() < 0) { 177e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_thread : setsid failed, errno = %d\n", 178e99525f9706900417f37721e601d2b414d41bfeeJeff Dike errno); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit(1); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 182cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike if (ioctl(pty_fd, TIOCSCTTY, 0) < 0) { 1838ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike printk(UM_KERN_ERR "winch_thread : TIOCSCTTY failed on " 1848ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike "fd %d err = %d\n", pty_fd, errno); 1858ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike exit(1); 1868ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike } 1878ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike 188cb8fa61c2b8b29d422d7310f064d60022f18f89bJeff Dike if (tcsetpgrp(pty_fd, os_getpid()) < 0) { 1898ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike printk(UM_KERN_ERR "winch_thread : tcsetpgrp failed on " 1908ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike "fd %d err = %d\n", pty_fd, errno); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exit(1); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 194e99525f9706900417f37721e601d2b414d41bfeeJeff Dike /* 195e99525f9706900417f37721e601d2b414d41bfeeJeff Dike * These are synchronization calls between various UML threads on the 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * host - since they are not different kernel threads, we cannot use 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kernel semaphores. We don't use SysV semaphores because they are 198e99525f9706900417f37721e601d2b414d41bfeeJeff Dike * persistent. 199e99525f9706900417f37721e601d2b414d41bfeeJeff Dike */ 2008ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike count = read(pipe_fd, &c, sizeof(c)); 201e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (count != sizeof(c)) 202e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_thread : failed to read " 2038ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike "synchronization byte, err = %d\n", errno); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 205e99525f9706900417f37721e601d2b414d41bfeeJeff Dike while(1) { 206e99525f9706900417f37721e601d2b414d41bfeeJeff Dike /* 207e99525f9706900417f37721e601d2b414d41bfeeJeff Dike * This will be interrupted by SIGWINCH only, since 20842a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * other signals are blocked. 20942a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike */ 210ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser sigsuspend(&sigs); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2128ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike count = write(pipe_fd, &c, sizeof(c)); 213e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (count != sizeof(c)) 214e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_thread : write failed, " 2158ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike "err = %d\n", errno); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2192116bda6ad937d7acb6e2316fd9e65ad6ca01d42Richard Weinbergerstatic int winch_tramp(int fd, struct tty_port *port, int *fd_out, 22042a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike unsigned long *stack_out) 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct winch_data data; 2231f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike int fds[2], n, err; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = os_pipe(fds, 1, 1); 227e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (err < 0) { 228e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_tramp : os_pipe failed, err = %d\n", 229e99525f9706900417f37721e601d2b414d41bfeeJeff Dike -err); 2301f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike goto out; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = ((struct winch_data) { .pty_fd = fd, 2341d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike .pipe_fd = fds[1] } ); 235e99525f9706900417f37721e601d2b414d41bfeeJeff Dike /* 236e99525f9706900417f37721e601d2b414d41bfeeJeff Dike * CLONE_FILES so this thread doesn't hold open files which are open 23742a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * now, but later closed in a different thread. This is a 23842a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * problem with /dev/net/tun, which if held open by this 23942a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike * thread, prevents the TUN/TAP device from being reused. 2401d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike */ 241c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); 242e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (err < 0) { 243e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "fork of winch_thread failed - errno = %d\n", 244e99525f9706900417f37721e601d2b414d41bfeeJeff Dike -err); 2451f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike goto out_close; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *fd_out = fds[0]; 2498ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike n = read(fds[0], &c, sizeof(c)); 250e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (n != sizeof(c)) { 251e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_tramp : failed to read " 252e99525f9706900417f37721e601d2b414d41bfeeJeff Dike "synchronization byte\n"); 2538ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike printk(UM_KERN_ERR "read failed, err = %d\n", errno); 254e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "fd %d will not support SIGWINCH\n", fd); 255e99525f9706900417f37721e601d2b414d41bfeeJeff Dike err = -EINVAL; 2561d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike goto out_close; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25889df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu 25989df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu if (os_set_fd_block(*fd_out, 0)) { 260e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd " 261e99525f9706900417f37721e601d2b414d41bfeeJeff Dike "non-blocking.\n"); 26289df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu goto out_close; 26389df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu } 26489df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu 26589df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu return err; 2661f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike 2671f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike out_close: 2688ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike close(fds[1]); 2698ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike close(fds[0]); 2701f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike out: 2711f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike return err; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2742116bda6ad937d7acb6e2316fd9e65ad6ca01d42Richard Weinbergervoid register_winch(int fd, struct tty_port *port) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27642a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike unsigned long stack; 27742a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike int pid, thread, count, thread_fd = -1; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c = 1; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 280e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (!isatty(fd)) 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pid = tcgetpgrp(fd); 2842116bda6ad937d7acb6e2316fd9e65ad6ca01d42Richard Weinberger if (is_skas_winch(pid, fd, port)) { 2852116bda6ad937d7acb6e2316fd9e65ad6ca01d42Richard Weinberger register_winch_irq(-1, fd, -1, port, 0); 28617e052093bcd21eaf9eb6e792cd76fdc4f0e3505Al Viro return; 28717e052093bcd21eaf9eb6e792cd76fdc4f0e3505Al Viro } 28817e052093bcd21eaf9eb6e792cd76fdc4f0e3505Al Viro 28917e052093bcd21eaf9eb6e792cd76fdc4f0e3505Al Viro if (pid == -1) { 2902116bda6ad937d7acb6e2316fd9e65ad6ca01d42Richard Weinberger thread = winch_tramp(fd, port, &thread_fd, &stack); 29142a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike if (thread < 0) 29242a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike return; 29342a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike 2942116bda6ad937d7acb6e2316fd9e65ad6ca01d42Richard Weinberger register_winch_irq(thread_fd, fd, thread, port, stack); 29542a359e31a0e438b5b978a8f0fecdbd3c86bb033Jeff Dike 2968ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike count = write(thread_fd, &c, sizeof(c)); 297e99525f9706900417f37721e601d2b414d41bfeeJeff Dike if (count != sizeof(c)) 298e99525f9706900417f37721e601d2b414d41bfeeJeff Dike printk(UM_KERN_ERR "register_winch : failed to write " 2998ca842c4b5cbc70b9180617e9f26b6ac9f40dbb9Jeff Dike "synchronization byte, err = %d\n", errno); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 302