/* * linux/kernel/chr_drv/pty.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * pty.c * * This module exports the following pty function: * * int pty_open(struct tty_struct * tty, struct file * filp); */ #include #include #include #include #include #include #include static void pty_close(struct tty_struct * tty, struct file * filp) { if (!tty) return; if (IS_A_PTY_MASTER(tty->line)) { if (tty->count > 1) return; } else { if (tty->count > 2) return; } wake_up_interruptible(&tty->secondary.proc_list); wake_up_interruptible(&tty->read_q.proc_list); wake_up_interruptible(&tty->write_q.proc_list); if (!tty->link) return; wake_up_interruptible(&tty->link->secondary.proc_list); wake_up_interruptible(&tty->link->read_q.proc_list); wake_up_interruptible(&tty->link->write_q.proc_list); if (IS_A_PTY_MASTER(tty->line)) { tty_hangup(tty->link); flush_input(tty); flush_output(tty); } } static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) { int c; while (!from->stopped && !EMPTY(&from->write_q)) { if (FULL(&to->read_q)) { TTY_READ_FLUSH(to); if (FULL(&to->read_q)) break; continue; } c = get_tty_queue(&from->write_q); put_tty_queue(c, &to->read_q); if (current->signal & ~current->blocked) break; } TTY_READ_FLUSH(to); if (!FULL(&from->write_q)) wake_up_interruptible(&from->write_q.proc_list); if (from->write_data_cnt) { set_bit(from->line, &tty_check_write); mark_bh(TTY_BH); } } /* * This routine gets called when tty_write has put something into * the write_queue. It copies the input to the output-queue of it's * slave. */ static void pty_write(struct tty_struct * tty) { if (tty->link) pty_copy(tty,tty->link); } int pty_open(struct tty_struct *tty, struct file * filp) { if (!tty || !tty->link) return -ENODEV; if (IS_A_PTY_MASTER(tty->line)) clear_bit(TTY_SLAVE_OPENED, &tty->flags); else set_bit(TTY_SLAVE_OPENED, &tty->link->flags); tty->write = tty->link->write = pty_write; tty->close = tty->link->close = pty_close; wake_up_interruptible(&tty->read_q.proc_list); if (filp->f_flags & O_NDELAY) return 0; while (!tty->link->count && !(current->signal & ~current->blocked)) interruptible_sleep_on(&tty->link->read_q.proc_list); if (!tty->link->count) return -ERESTARTSYS; return 0; }