1f206aabbSJeff Dike /* 2f206aabbSJeff Dike * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 3f206aabbSJeff Dike * Licensed under the GPL 4f206aabbSJeff Dike */ 5f206aabbSJeff Dike 6f206aabbSJeff Dike #include <unistd.h> 7f206aabbSJeff Dike #include <stdlib.h> 8f206aabbSJeff Dike #include <termios.h> 9f206aabbSJeff Dike #include <pty.h> 10f206aabbSJeff Dike #include <signal.h> 11c65badbdSJeff Dike #include <fcntl.h> 12f206aabbSJeff Dike #include <errno.h> 13f206aabbSJeff Dike #include <string.h> 14f206aabbSJeff Dike #include <sched.h> 15f206aabbSJeff Dike #include <sys/socket.h> 16f206aabbSJeff Dike #include <sys/poll.h> 17f206aabbSJeff Dike #include "init.h" 18f206aabbSJeff Dike #include "user.h" 19f206aabbSJeff Dike #include "kern_util.h" 20f206aabbSJeff Dike #include "sigio.h" 21f206aabbSJeff Dike #include "os.h" 22c13e5690SPaolo 'Blaisorblade' Giarrusso #include "um_malloc.h" 23c65badbdSJeff Dike #include "init.h" 24f206aabbSJeff Dike 25f206aabbSJeff Dike /* Protected by sigio_lock(), also used by sigio_cleanup, which is an 26f206aabbSJeff Dike * exitcall. 27f206aabbSJeff Dike */ 28f206aabbSJeff Dike static int write_sigio_pid = -1; 29*c4399016SJeff Dike static unsigned long write_sigio_stack; 30f206aabbSJeff Dike 31f206aabbSJeff Dike /* These arrays are initialized before the sigio thread is started, and 32f206aabbSJeff Dike * the descriptors closed after it is killed. So, it can't see them change. 33f206aabbSJeff Dike * On the UML side, they are changed under the sigio_lock. 34f206aabbSJeff Dike */ 355f4e8fd0SJeff Dike #define SIGIO_FDS_INIT {-1, -1} 365f4e8fd0SJeff Dike 375f4e8fd0SJeff Dike static int write_sigio_fds[2] = SIGIO_FDS_INIT; 385f4e8fd0SJeff Dike static int sigio_private[2] = SIGIO_FDS_INIT; 39f206aabbSJeff Dike 40f206aabbSJeff Dike struct pollfds { 41f206aabbSJeff Dike struct pollfd *poll; 42f206aabbSJeff Dike int size; 43f206aabbSJeff Dike int used; 44f206aabbSJeff Dike }; 45f206aabbSJeff Dike 46f206aabbSJeff Dike /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread 47f206aabbSJeff Dike * synchronizes with it. 48f206aabbSJeff Dike */ 4919bdf040SJeff Dike static struct pollfds current_poll; 5019bdf040SJeff Dike static struct pollfds next_poll; 5119bdf040SJeff Dike static struct pollfds all_sigio_fds; 52f206aabbSJeff Dike 53f206aabbSJeff Dike static int write_sigio_thread(void *unused) 54f206aabbSJeff Dike { 55f206aabbSJeff Dike struct pollfds *fds, tmp; 56f206aabbSJeff Dike struct pollfd *p; 57f206aabbSJeff Dike int i, n, respond_fd; 58f206aabbSJeff Dike char c; 59f206aabbSJeff Dike 60f206aabbSJeff Dike signal(SIGWINCH, SIG_IGN); 61f206aabbSJeff Dike fds = ¤t_poll; 62f206aabbSJeff Dike while(1){ 63f206aabbSJeff Dike n = poll(fds->poll, fds->used, -1); 64f206aabbSJeff Dike if(n < 0){ 65f206aabbSJeff Dike if(errno == EINTR) continue; 66f206aabbSJeff Dike printk("write_sigio_thread : poll returned %d, " 67f206aabbSJeff Dike "errno = %d\n", n, errno); 68f206aabbSJeff Dike } 69f206aabbSJeff Dike for(i = 0; i < fds->used; i++){ 70f206aabbSJeff Dike p = &fds->poll[i]; 71f206aabbSJeff Dike if(p->revents == 0) continue; 72f206aabbSJeff Dike if(p->fd == sigio_private[1]){ 73a61f334fSJeff Dike CATCH_EINTR(n = read(sigio_private[1], &c, 74a61f334fSJeff Dike sizeof(c))); 75f206aabbSJeff Dike if(n != sizeof(c)) 76f206aabbSJeff Dike printk("write_sigio_thread : " 7719bdf040SJeff Dike "read on socket failed, " 78a61f334fSJeff Dike "err = %d\n", errno); 79f206aabbSJeff Dike tmp = current_poll; 80f206aabbSJeff Dike current_poll = next_poll; 81f206aabbSJeff Dike next_poll = tmp; 82f206aabbSJeff Dike respond_fd = sigio_private[1]; 83f206aabbSJeff Dike } 84f206aabbSJeff Dike else { 85f206aabbSJeff Dike respond_fd = write_sigio_fds[1]; 86f206aabbSJeff Dike fds->used--; 87f206aabbSJeff Dike memmove(&fds->poll[i], &fds->poll[i + 1], 88f206aabbSJeff Dike (fds->used - i) * sizeof(*fds->poll)); 89f206aabbSJeff Dike } 90f206aabbSJeff Dike 91a61f334fSJeff Dike CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); 92f206aabbSJeff Dike if(n != sizeof(c)) 9319bdf040SJeff Dike printk("write_sigio_thread : write on socket " 94a61f334fSJeff Dike "failed, err = %d\n", errno); 95f206aabbSJeff Dike } 96f206aabbSJeff Dike } 97f206aabbSJeff Dike 98f206aabbSJeff Dike return 0; 99f206aabbSJeff Dike } 100f206aabbSJeff Dike 10119bdf040SJeff Dike static int need_poll(struct pollfds *polls, int n) 102f206aabbSJeff Dike { 103838e56a1SJeff Dike struct pollfd *new; 104838e56a1SJeff Dike 105838e56a1SJeff Dike if(n <= polls->size) 10619bdf040SJeff Dike return 0; 107838e56a1SJeff Dike 108838e56a1SJeff Dike new = um_kmalloc_atomic(n * sizeof(struct pollfd)); 109838e56a1SJeff Dike if(new == NULL){ 110f206aabbSJeff Dike printk("need_poll : failed to allocate new pollfds\n"); 11119bdf040SJeff Dike return -ENOMEM; 112f206aabbSJeff Dike } 113838e56a1SJeff Dike 114838e56a1SJeff Dike memcpy(new, polls->poll, polls->used * sizeof(struct pollfd)); 115838e56a1SJeff Dike kfree(polls->poll); 116838e56a1SJeff Dike 117838e56a1SJeff Dike polls->poll = new; 11819bdf040SJeff Dike polls->size = n; 11919bdf040SJeff Dike return 0; 120f206aabbSJeff Dike } 121f206aabbSJeff Dike 122f206aabbSJeff Dike /* Must be called with sigio_lock held, because it's needed by the marked 12319bdf040SJeff Dike * critical section. 12419bdf040SJeff Dike */ 125f206aabbSJeff Dike static void update_thread(void) 126f206aabbSJeff Dike { 127f206aabbSJeff Dike unsigned long flags; 128f206aabbSJeff Dike int n; 129f206aabbSJeff Dike char c; 130f206aabbSJeff Dike 131f206aabbSJeff Dike flags = set_signals(0); 132a61f334fSJeff Dike n = write(sigio_private[0], &c, sizeof(c)); 133f206aabbSJeff Dike if(n != sizeof(c)){ 134a61f334fSJeff Dike printk("update_thread : write failed, err = %d\n", errno); 135f206aabbSJeff Dike goto fail; 136f206aabbSJeff Dike } 137f206aabbSJeff Dike 138a61f334fSJeff Dike CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); 139f206aabbSJeff Dike if(n != sizeof(c)){ 140a61f334fSJeff Dike printk("update_thread : read failed, err = %d\n", errno); 141f206aabbSJeff Dike goto fail; 142f206aabbSJeff Dike } 143f206aabbSJeff Dike 144f206aabbSJeff Dike set_signals(flags); 145f206aabbSJeff Dike return; 146f206aabbSJeff Dike fail: 147f206aabbSJeff Dike /* Critical section start */ 148*c4399016SJeff Dike if (write_sigio_pid != -1) { 149f206aabbSJeff Dike os_kill_process(write_sigio_pid, 1); 150*c4399016SJeff Dike free_stack(write_sigio_stack, 0); 151*c4399016SJeff Dike } 152f206aabbSJeff Dike write_sigio_pid = -1; 153f206aabbSJeff Dike close(sigio_private[0]); 154f206aabbSJeff Dike close(sigio_private[1]); 155f206aabbSJeff Dike close(write_sigio_fds[0]); 156f206aabbSJeff Dike close(write_sigio_fds[1]); 157f206aabbSJeff Dike /* Critical section end */ 158f206aabbSJeff Dike set_signals(flags); 159f206aabbSJeff Dike } 160f206aabbSJeff Dike 16119bdf040SJeff Dike int add_sigio_fd(int fd) 162f206aabbSJeff Dike { 16319bdf040SJeff Dike struct pollfd *p; 16419bdf040SJeff Dike int err = 0, i, n; 165f206aabbSJeff Dike 166f206aabbSJeff Dike sigio_lock(); 16719bdf040SJeff Dike for(i = 0; i < all_sigio_fds.used; i++){ 16819bdf040SJeff Dike if(all_sigio_fds.poll[i].fd == fd) 16919bdf040SJeff Dike break; 17019bdf040SJeff Dike } 17119bdf040SJeff Dike if(i == all_sigio_fds.used) 17219bdf040SJeff Dike goto out; 17319bdf040SJeff Dike 17419bdf040SJeff Dike p = &all_sigio_fds.poll[i]; 17519bdf040SJeff Dike 176f206aabbSJeff Dike for(i = 0; i < current_poll.used; i++){ 177f206aabbSJeff Dike if(current_poll.poll[i].fd == fd) 178f206aabbSJeff Dike goto out; 179f206aabbSJeff Dike } 180f206aabbSJeff Dike 181838e56a1SJeff Dike n = current_poll.used; 182838e56a1SJeff Dike err = need_poll(&next_poll, n + 1); 183f206aabbSJeff Dike if(err) 184f206aabbSJeff Dike goto out; 185f206aabbSJeff Dike 186838e56a1SJeff Dike memcpy(next_poll.poll, current_poll.poll, 187838e56a1SJeff Dike current_poll.used * sizeof(struct pollfd)); 188838e56a1SJeff Dike next_poll.poll[n] = *p; 189838e56a1SJeff Dike next_poll.used = n + 1; 190f206aabbSJeff Dike update_thread(); 191f206aabbSJeff Dike out: 192f206aabbSJeff Dike sigio_unlock(); 19319bdf040SJeff Dike return err; 194f206aabbSJeff Dike } 195f206aabbSJeff Dike 196f206aabbSJeff Dike int ignore_sigio_fd(int fd) 197f206aabbSJeff Dike { 198f206aabbSJeff Dike struct pollfd *p; 199f206aabbSJeff Dike int err = 0, i, n = 0; 200f206aabbSJeff Dike 20161232f2fSJeff Dike /* This is called from exitcalls elsewhere in UML - if 20261232f2fSJeff Dike * sigio_cleanup has already run, then update_thread will hang 20361232f2fSJeff Dike * or fail because the thread is no longer running. 20461232f2fSJeff Dike */ 20561232f2fSJeff Dike if(write_sigio_pid == -1) 20661232f2fSJeff Dike return -EIO; 20761232f2fSJeff Dike 208f206aabbSJeff Dike sigio_lock(); 209f206aabbSJeff Dike for(i = 0; i < current_poll.used; i++){ 210f206aabbSJeff Dike if(current_poll.poll[i].fd == fd) break; 211f206aabbSJeff Dike } 212f206aabbSJeff Dike if(i == current_poll.used) 213f206aabbSJeff Dike goto out; 214f206aabbSJeff Dike 21519bdf040SJeff Dike err = need_poll(&next_poll, current_poll.used - 1); 216f206aabbSJeff Dike if(err) 217f206aabbSJeff Dike goto out; 218f206aabbSJeff Dike 219f206aabbSJeff Dike for(i = 0; i < current_poll.used; i++){ 220f206aabbSJeff Dike p = ¤t_poll.poll[i]; 22119bdf040SJeff Dike if(p->fd != fd) 22219bdf040SJeff Dike next_poll.poll[n++] = *p; 223f206aabbSJeff Dike } 224838e56a1SJeff Dike next_poll.used = current_poll.used - 1; 225f206aabbSJeff Dike 226f206aabbSJeff Dike update_thread(); 227f206aabbSJeff Dike out: 228f206aabbSJeff Dike sigio_unlock(); 22961232f2fSJeff Dike return err; 230f206aabbSJeff Dike } 231f206aabbSJeff Dike 232f206aabbSJeff Dike static struct pollfd *setup_initial_poll(int fd) 233f206aabbSJeff Dike { 234f206aabbSJeff Dike struct pollfd *p; 235f206aabbSJeff Dike 236f206aabbSJeff Dike p = um_kmalloc(sizeof(struct pollfd)); 237f206aabbSJeff Dike if (p == NULL) { 238f206aabbSJeff Dike printk("setup_initial_poll : failed to allocate poll\n"); 239f206aabbSJeff Dike return NULL; 240f206aabbSJeff Dike } 241f206aabbSJeff Dike *p = ((struct pollfd) { .fd = fd, 242f206aabbSJeff Dike .events = POLLIN, 243f206aabbSJeff Dike .revents = 0 }); 244f206aabbSJeff Dike return p; 245f206aabbSJeff Dike } 246f206aabbSJeff Dike 2478e64d96aSJeff Dike static void write_sigio_workaround(void) 248f206aabbSJeff Dike { 249f206aabbSJeff Dike struct pollfd *p; 250f206aabbSJeff Dike int err; 251f206aabbSJeff Dike int l_write_sigio_fds[2]; 252f206aabbSJeff Dike int l_sigio_private[2]; 253f206aabbSJeff Dike int l_write_sigio_pid; 254f206aabbSJeff Dike 255f206aabbSJeff Dike /* We call this *tons* of times - and most ones we must just fail. */ 256f206aabbSJeff Dike sigio_lock(); 257f206aabbSJeff Dike l_write_sigio_pid = write_sigio_pid; 258f206aabbSJeff Dike sigio_unlock(); 259f206aabbSJeff Dike 260f206aabbSJeff Dike if (l_write_sigio_pid != -1) 261f206aabbSJeff Dike return; 262f206aabbSJeff Dike 263f206aabbSJeff Dike err = os_pipe(l_write_sigio_fds, 1, 1); 264f206aabbSJeff Dike if(err < 0){ 265f206aabbSJeff Dike printk("write_sigio_workaround - os_pipe 1 failed, " 266f206aabbSJeff Dike "err = %d\n", -err); 267f206aabbSJeff Dike return; 268f206aabbSJeff Dike } 269f206aabbSJeff Dike err = os_pipe(l_sigio_private, 1, 1); 270f206aabbSJeff Dike if(err < 0){ 271f206aabbSJeff Dike printk("write_sigio_workaround - os_pipe 2 failed, " 272f206aabbSJeff Dike "err = %d\n", -err); 273f206aabbSJeff Dike goto out_close1; 274f206aabbSJeff Dike } 275f206aabbSJeff Dike 276f206aabbSJeff Dike p = setup_initial_poll(l_sigio_private[1]); 277f206aabbSJeff Dike if(!p) 278f206aabbSJeff Dike goto out_close2; 279f206aabbSJeff Dike 280f206aabbSJeff Dike sigio_lock(); 281f206aabbSJeff Dike 282f206aabbSJeff Dike /* Did we race? Don't try to optimize this, please, it's not so likely 283f206aabbSJeff Dike * to happen, and no more than once at the boot. */ 284f206aabbSJeff Dike if(write_sigio_pid != -1) 2855f4e8fd0SJeff Dike goto out_free; 2865f4e8fd0SJeff Dike 2875f4e8fd0SJeff Dike current_poll = ((struct pollfds) { .poll = p, 2885f4e8fd0SJeff Dike .used = 1, 2895f4e8fd0SJeff Dike .size = 1 }); 2905f4e8fd0SJeff Dike 2915f4e8fd0SJeff Dike if (write_sigio_irq(l_write_sigio_fds[0])) 2925f4e8fd0SJeff Dike goto out_clear_poll; 2935f4e8fd0SJeff Dike 2945f4e8fd0SJeff Dike memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); 2955f4e8fd0SJeff Dike memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); 296f206aabbSJeff Dike 297f206aabbSJeff Dike write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 298*c4399016SJeff Dike CLONE_FILES | CLONE_VM, 299*c4399016SJeff Dike &write_sigio_stack); 300f206aabbSJeff Dike 301f206aabbSJeff Dike if (write_sigio_pid < 0) 302f206aabbSJeff Dike goto out_clear; 303f206aabbSJeff Dike 304f206aabbSJeff Dike sigio_unlock(); 305f206aabbSJeff Dike return; 306f206aabbSJeff Dike 307f206aabbSJeff Dike out_clear: 308f206aabbSJeff Dike write_sigio_pid = -1; 3095f4e8fd0SJeff Dike write_sigio_fds[0] = -1; 3105f4e8fd0SJeff Dike write_sigio_fds[1] = -1; 3115f4e8fd0SJeff Dike sigio_private[0] = -1; 3125f4e8fd0SJeff Dike sigio_private[1] = -1; 3135f4e8fd0SJeff Dike out_clear_poll: 3145f4e8fd0SJeff Dike current_poll = ((struct pollfds) { .poll = NULL, 3155f4e8fd0SJeff Dike .size = 0, 3165f4e8fd0SJeff Dike .used = 0 }); 317f206aabbSJeff Dike out_free: 3185f4e8fd0SJeff Dike sigio_unlock(); 319e6fb54abSPaolo 'Blaisorblade' Giarrusso kfree(p); 320f206aabbSJeff Dike out_close2: 321f206aabbSJeff Dike close(l_sigio_private[0]); 322f206aabbSJeff Dike close(l_sigio_private[1]); 323f206aabbSJeff Dike out_close1: 324f206aabbSJeff Dike close(l_write_sigio_fds[0]); 325f206aabbSJeff Dike close(l_write_sigio_fds[1]); 326f206aabbSJeff Dike } 327f206aabbSJeff Dike 328c65badbdSJeff Dike /* Changed during early boot */ 329c65badbdSJeff Dike static int pty_output_sigio = 0; 330c65badbdSJeff Dike static int pty_close_sigio = 0; 331c65badbdSJeff Dike 3328e64d96aSJeff Dike void maybe_sigio_broken(int fd, int read) 3338e64d96aSJeff Dike { 33419bdf040SJeff Dike int err; 33519bdf040SJeff Dike 3368e64d96aSJeff Dike if(!isatty(fd)) 3378e64d96aSJeff Dike return; 3388e64d96aSJeff Dike 3398e64d96aSJeff Dike if((read || pty_output_sigio) && (!read || pty_close_sigio)) 3408e64d96aSJeff Dike return; 3418e64d96aSJeff Dike 3428e64d96aSJeff Dike write_sigio_workaround(); 34319bdf040SJeff Dike 34419bdf040SJeff Dike sigio_lock(); 34519bdf040SJeff Dike err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); 34604a51e66SJeff Dike if(err){ 34704a51e66SJeff Dike printk("maybe_sigio_broken - failed to add pollfd for " 34804a51e66SJeff Dike "descriptor %d\n", fd); 34919bdf040SJeff Dike goto out; 35004a51e66SJeff Dike } 351838e56a1SJeff Dike 35219bdf040SJeff Dike all_sigio_fds.poll[all_sigio_fds.used++] = 35319bdf040SJeff Dike ((struct pollfd) { .fd = fd, 35419bdf040SJeff Dike .events = read ? POLLIN : POLLOUT, 35519bdf040SJeff Dike .revents = 0 }); 35619bdf040SJeff Dike out: 35719bdf040SJeff Dike sigio_unlock(); 3588e64d96aSJeff Dike } 3598e64d96aSJeff Dike 36029ac1c21SJeff Dike static void sigio_cleanup(void) 361f206aabbSJeff Dike { 362*c4399016SJeff Dike if (write_sigio_pid == -1) 363*c4399016SJeff Dike return; 364*c4399016SJeff Dike 365f206aabbSJeff Dike os_kill_process(write_sigio_pid, 1); 366*c4399016SJeff Dike free_stack(write_sigio_stack, 0); 367f206aabbSJeff Dike write_sigio_pid = -1; 368f206aabbSJeff Dike } 36929ac1c21SJeff Dike 37029ac1c21SJeff Dike __uml_exitcall(sigio_cleanup); 371c65badbdSJeff Dike 372c65badbdSJeff Dike /* Used as a flag during SIGIO testing early in boot */ 373c65badbdSJeff Dike static volatile int got_sigio = 0; 374c65badbdSJeff Dike 375c65badbdSJeff Dike static void __init handler(int sig) 376c65badbdSJeff Dike { 377c65badbdSJeff Dike got_sigio = 1; 378c65badbdSJeff Dike } 379c65badbdSJeff Dike 380c65badbdSJeff Dike struct openpty_arg { 381c65badbdSJeff Dike int master; 382c65badbdSJeff Dike int slave; 383c65badbdSJeff Dike int err; 384c65badbdSJeff Dike }; 385c65badbdSJeff Dike 386c65badbdSJeff Dike static void openpty_cb(void *arg) 387c65badbdSJeff Dike { 388c65badbdSJeff Dike struct openpty_arg *info = arg; 389c65badbdSJeff Dike 390c65badbdSJeff Dike info->err = 0; 391c65badbdSJeff Dike if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) 392c65badbdSJeff Dike info->err = -errno; 393c65badbdSJeff Dike } 394c65badbdSJeff Dike 395c65badbdSJeff Dike static int async_pty(int master, int slave) 396c65badbdSJeff Dike { 397c65badbdSJeff Dike int flags; 398c65badbdSJeff Dike 399c65badbdSJeff Dike flags = fcntl(master, F_GETFL); 400c65badbdSJeff Dike if(flags < 0) 401c65badbdSJeff Dike return -errno; 402c65badbdSJeff Dike 403c65badbdSJeff Dike if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || 404c65badbdSJeff Dike (fcntl(master, F_SETOWN, os_getpid()) < 0)) 405c65badbdSJeff Dike return -errno; 406c65badbdSJeff Dike 407c65badbdSJeff Dike if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) 408c65badbdSJeff Dike return -errno; 409c65badbdSJeff Dike 410c65badbdSJeff Dike return(0); 411c65badbdSJeff Dike } 412c65badbdSJeff Dike 413c65badbdSJeff Dike static void __init check_one_sigio(void (*proc)(int, int)) 414c65badbdSJeff Dike { 415c65badbdSJeff Dike struct sigaction old, new; 416c65badbdSJeff Dike struct openpty_arg pty = { .master = -1, .slave = -1 }; 417c65badbdSJeff Dike int master, slave, err; 418c65badbdSJeff Dike 419c65badbdSJeff Dike initial_thread_cb(openpty_cb, &pty); 420c65badbdSJeff Dike if(pty.err){ 421c65badbdSJeff Dike printk("openpty failed, errno = %d\n", -pty.err); 422c65badbdSJeff Dike return; 423c65badbdSJeff Dike } 424c65badbdSJeff Dike 425c65badbdSJeff Dike master = pty.master; 426c65badbdSJeff Dike slave = pty.slave; 427c65badbdSJeff Dike 428c65badbdSJeff Dike if((master == -1) || (slave == -1)){ 429c65badbdSJeff Dike printk("openpty failed to allocate a pty\n"); 430c65badbdSJeff Dike return; 431c65badbdSJeff Dike } 432c65badbdSJeff Dike 433c65badbdSJeff Dike /* Not now, but complain so we now where we failed. */ 434c65badbdSJeff Dike err = raw(master); 435c65badbdSJeff Dike if (err < 0) 436c65badbdSJeff Dike panic("check_sigio : __raw failed, errno = %d\n", -err); 437c65badbdSJeff Dike 438c65badbdSJeff Dike err = async_pty(master, slave); 439c65badbdSJeff Dike if(err < 0) 440c65badbdSJeff Dike panic("tty_fds : sigio_async failed, err = %d\n", -err); 441c65badbdSJeff Dike 442c65badbdSJeff Dike if(sigaction(SIGIO, NULL, &old) < 0) 443c65badbdSJeff Dike panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); 444c65badbdSJeff Dike new = old; 445c65badbdSJeff Dike new.sa_handler = handler; 446c65badbdSJeff Dike if(sigaction(SIGIO, &new, NULL) < 0) 447c65badbdSJeff Dike panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); 448c65badbdSJeff Dike 449c65badbdSJeff Dike got_sigio = 0; 450c65badbdSJeff Dike (*proc)(master, slave); 451c65badbdSJeff Dike 452c65badbdSJeff Dike close(master); 453c65badbdSJeff Dike close(slave); 454c65badbdSJeff Dike 455c65badbdSJeff Dike if(sigaction(SIGIO, &old, NULL) < 0) 456c65badbdSJeff Dike panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); 457c65badbdSJeff Dike } 458c65badbdSJeff Dike 459c65badbdSJeff Dike static void tty_output(int master, int slave) 460c65badbdSJeff Dike { 461c65badbdSJeff Dike int n; 462c65badbdSJeff Dike char buf[512]; 463c65badbdSJeff Dike 464c65badbdSJeff Dike printk("Checking that host ptys support output SIGIO..."); 465c65badbdSJeff Dike 466c65badbdSJeff Dike memset(buf, 0, sizeof(buf)); 467c65badbdSJeff Dike 468a61f334fSJeff Dike while(write(master, buf, sizeof(buf)) > 0) ; 469c65badbdSJeff Dike if(errno != EAGAIN) 470ef0470c0SJeff Dike panic("tty_output : write failed, errno = %d\n", errno); 471a61f334fSJeff Dike while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; 472c65badbdSJeff Dike 473c65badbdSJeff Dike if(got_sigio){ 474c65badbdSJeff Dike printk("Yes\n"); 475c65badbdSJeff Dike pty_output_sigio = 1; 476c65badbdSJeff Dike } 477ef0470c0SJeff Dike else if(n == -EAGAIN) 478ef0470c0SJeff Dike printk("No, enabling workaround\n"); 479ef0470c0SJeff Dike else panic("tty_output : read failed, err = %d\n", n); 480c65badbdSJeff Dike } 481c65badbdSJeff Dike 482c65badbdSJeff Dike static void tty_close(int master, int slave) 483c65badbdSJeff Dike { 484c65badbdSJeff Dike printk("Checking that host ptys support SIGIO on close..."); 485c65badbdSJeff Dike 486c65badbdSJeff Dike close(slave); 487c65badbdSJeff Dike if(got_sigio){ 488c65badbdSJeff Dike printk("Yes\n"); 489c65badbdSJeff Dike pty_close_sigio = 1; 490c65badbdSJeff Dike } 491c65badbdSJeff Dike else printk("No, enabling workaround\n"); 492c65badbdSJeff Dike } 493c65badbdSJeff Dike 494c65badbdSJeff Dike void __init check_sigio(void) 495c65badbdSJeff Dike { 496c65badbdSJeff Dike if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && 497c65badbdSJeff Dike (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ 498c65badbdSJeff Dike printk("No pseudo-terminals available - skipping pty SIGIO " 499c65badbdSJeff Dike "check\n"); 500c65badbdSJeff Dike return; 501c65badbdSJeff Dike } 502c65badbdSJeff Dike check_one_sigio(tty_output); 503c65badbdSJeff Dike check_one_sigio(tty_close); 504c65badbdSJeff Dike } 505c65badbdSJeff Dike 506c65badbdSJeff Dike /* Here because it only does the SIGIO testing for now */ 507c65badbdSJeff Dike void __init os_check_bugs(void) 508c65badbdSJeff Dike { 509c65badbdSJeff Dike check_sigio(); 510c65badbdSJeff Dike } 511