Пример #1
0
/*
 * Perform OPOST processing.  Returns -1 when the output device is
 * full and the character must be retried.
 */
static int opost(unsigned char c, struct tty_struct *tty)
{
	int	space, spaces;

	space = tty->driver.write_room(tty);
	if (!space)
		return -1;

	if (O_OPOST(tty)) {
		switch (c) {
		case '\n':
			if (O_ONLRET(tty))
				tty->column = 0;
			if (O_ONLCR(tty)) {
				if (space < 2)
					return -1;
				tty->driver.put_char(tty, '\r');
				tty->column = 0;
			}
			tty->canon_column = tty->column;
			break;
		case '\r':
			if (O_ONOCR(tty) && tty->column == 0)
				return 0;
			if (O_OCRNL(tty)) {
				c = '\n';
				if (O_ONLRET(tty))
					tty->canon_column = tty->column = 0;
				break;
			}
			tty->canon_column = tty->column = 0;
			break;
		case '\t':
			spaces = 8 - (tty->column & 7);
			if (O_TABDLY(tty) == XTABS) {
				if (space < spaces)
					return -1;
				tty->column += spaces;
				tty->driver.write(tty, 0, "        ", spaces);
				return 0;
			}
			tty->column += spaces;
			break;
		case '\b':
			if (tty->column > 0)
				tty->column--;
			break;
		default:
			if (O_OLCUC(tty))
				c = toupper(c);
			if (!iscntrl(c))
				tty->column++;
			break;
		}
	}
	tty->driver.put_char(tty, c);
	return 0;
}
Пример #2
0
static int opost(unsigned char c, struct tty_struct *tty)
{
	if (FULL(&tty->write_q))
		return -1;
	if (O_OPOST(tty)) {
		switch (c) {
		case '\n':
			if (O_ONLRET(tty))
				tty->column = 0;
			if (O_ONLCR(tty)) {
				if (LEFT(&tty->write_q) < 2)
					return -1;
				put_tty_queue('\r', &tty->write_q);
				tty->column = 0;
			}
			tty->canon_column = tty->column;
			break;
		case '\r':
			if (O_ONOCR(tty) && tty->column == 0)
				return 0;
			if (O_OCRNL(tty)) {
				c = '\n';
				if (O_ONLRET(tty))
					tty->canon_column = tty->column = 0;
				break;
			}
			tty->canon_column = tty->column = 0;
			break;
		case '\t':
			if (O_TABDLY(tty) == XTABS) {
				if (LEFT(&tty->write_q) < 8)
					return -1;
				do
					put_tty_queue(' ', &tty->write_q);
				while (++tty->column % 8);
				return 0;
			}
			tty->column = (tty->column | 7) + 1;
			break;
		case '\b':
			if (tty->column > 0)
				tty->column--;
			break;
		default:
			if (O_OLCUC(tty))
				c = toupper(c);
			if (!iscntrl(c))
				tty->column++;
			break;
		}
	}
	put_tty_queue(c, &tty->write_q);
	return 0;
}
Пример #3
0
static int write_chan(struct tty_struct * tty, struct file * file,
		      const unsigned char * buf, unsigned int nr)
{
	struct wait_queue wait = { current, NULL };
	int c;
	const unsigned char *b = buf;
	int retval = 0;

	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
	if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
		retval = tty_check_change(tty);
		if (retval)
			return retval;
	}

	add_wait_queue(&tty->write_wait, &wait);
	while (1) {
		current->state = TASK_INTERRUPTIBLE;
		if (current->signal & ~current->blocked) {
			retval = -ERESTARTSYS;
			break;
		}
		if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
			retval = -EIO;
			break;
		}
		if (O_OPOST(tty)) {
			while (nr > 0) {
				c = get_user(b);
				if (opost(c, tty) < 0)
					break;
				b++; nr--;
			}
			if (tty->driver.flush_chars)
				tty->driver.flush_chars(tty);
		} else {
			c = tty->driver.write(tty, 1, b, nr);
			b += c;
			nr -= c;
		}
		if (!nr)
			break;
		if (file->f_flags & O_NONBLOCK) {
			retval = -EAGAIN;
			break;
		}
		schedule();
	}
	current->state = TASK_RUNNING;
	remove_wait_queue(&tty->write_wait, &wait);
	return (b - buf) ? b - buf : retval;
}
Пример #4
0
static void process_echoes(struct tty_struct *tty)
{
	int	space, nr;
	unsigned char c;
	unsigned char *cp, *buf_end;

	if (!tty->echo_cnt)
		return;

	mutex_lock(&tty->output_lock);
	mutex_lock(&tty->echo_lock);

	space = tty_write_room(tty);

	buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
	cp = tty->echo_buf + tty->echo_pos;
	nr = tty->echo_cnt;
	while (nr > 0) {
		c = *cp;
		if (c == ECHO_OP_START) {
			unsigned char op;
			unsigned char *opp;
			int no_space_left = 0;

			opp = cp + 1;
			if (opp == buf_end)
				opp -= N_TTY_BUF_SIZE;
			op = *opp;

			switch (op) {
				unsigned int num_chars, num_bs;

			case ECHO_OP_ERASE_TAB:
				if (++opp == buf_end)
					opp -= N_TTY_BUF_SIZE;
				num_chars = *opp;

				if (!(num_chars & 0x80))
					num_chars += tty->canon_column;
				num_bs = 8 - (num_chars & 7);

				if (num_bs > space) {
					no_space_left = 1;
					break;
				}
				space -= num_bs;
				while (num_bs--) {
					tty_put_char(tty, '\b');
					if (tty->column > 0)
						tty->column--;
				}
				cp += 3;
				nr -= 3;
				break;

			case ECHO_OP_SET_CANON_COL:
				tty->canon_column = tty->column;
				cp += 2;
				nr -= 2;
				break;

			case ECHO_OP_MOVE_BACK_COL:
				if (tty->column > 0)
					tty->column--;
				cp += 2;
				nr -= 2;
				break;

			case ECHO_OP_START:
				
				if (!space) {
					no_space_left = 1;
					break;
				}
				tty_put_char(tty, ECHO_OP_START);
				tty->column++;
				space--;
				cp += 2;
				nr -= 2;
				break;

			default:
				if (space < 2) {
					no_space_left = 1;
					break;
				}
				tty_put_char(tty, '^');
				tty_put_char(tty, op ^ 0100);
				tty->column += 2;
				space -= 2;
				cp += 2;
				nr -= 2;
			}

			if (no_space_left)
				break;
		} else {
			if (O_OPOST(tty) &&
			    !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
				int retval = do_output_char(c, tty, space);
				if (retval < 0)
					break;
				space -= retval;
			} else {
				if (!space)
					break;
				tty_put_char(tty, c);
				space -= 1;
			}
			cp += 1;
			nr -= 1;
		}

		
		if (cp >= buf_end)
			cp -= N_TTY_BUF_SIZE;
	}

	if (nr == 0) {
		tty->echo_pos = 0;
		tty->echo_cnt = 0;
		tty->echo_overrun = 0;
	} else {
		int num_processed = tty->echo_cnt - nr;
		tty->echo_pos += num_processed;
		tty->echo_pos &= N_TTY_BUF_SIZE - 1;
		tty->echo_cnt = nr;
		if (num_processed > 0)
			tty->echo_overrun = 0;
	}

	mutex_unlock(&tty->echo_lock);
	mutex_unlock(&tty->output_lock);

	if (tty->ops->flush_chars)
		tty->ops->flush_chars(tty);
}
Пример #5
0
static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
			   const unsigned char *buf, size_t nr)
{
	const unsigned char *b = buf;
	DECLARE_WAITQUEUE(wait, current);
	int c;
	ssize_t retval = 0;

	
	if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
		retval = tty_check_change(tty);
		if (retval)
			return retval;
	}

	
	process_echoes(tty);

	add_wait_queue(&tty->write_wait, &wait);
	while (1) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			break;
		}
		if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
			retval = -EIO;
			break;
		}
		if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
			while (nr > 0) {
				ssize_t num = process_output_block(tty, b, nr);
				if (num < 0) {
					if (num == -EAGAIN)
						break;
					retval = num;
					goto break_out;
				}
				b += num;
				nr -= num;
				if (nr == 0)
					break;
				c = *b;
				if (process_output(c, tty) < 0)
					break;
				b++; nr--;
			}
			if (tty->ops->flush_chars)
				tty->ops->flush_chars(tty);
		} else {
			while (nr > 0) {
				c = tty->ops->write(tty, b, nr);
				if (c < 0) {
					retval = c;
					goto break_out;
				}
				if (!c)
					break;
				b += c;
				nr -= c;
			}
		}
		if (!nr)
			break;
		if (file->f_flags & O_NONBLOCK) {
			retval = -EAGAIN;
			break;
		}
		schedule();
	}
break_out:
	__set_current_state(TASK_RUNNING);
	remove_wait_queue(&tty->write_wait, &wait);
	if (b - buf != nr && tty->fasync)
		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
	return (b - buf) ? b - buf : retval;
}
Пример #6
0
static ssize_t write_chan(struct tty_struct * tty, struct file * file,
			  const unsigned char * buf, size_t nr)
{
	const unsigned char *b = buf;
	struct wait_queue wait = { current, NULL };
	int c;
	ssize_t retval = 0;

	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
	if (L_TOSTOP(tty) && 
	    file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
		retval = tty_check_change(tty);
		if (retval)
			return retval;
	}

	add_wait_queue(&tty->write_wait, &wait);
	while (1) {
		current->state = TASK_INTERRUPTIBLE;
		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			break;
		}
		if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
			retval = -EIO;
			break;
		}
		if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
			while (nr > 0) {
				ssize_t num = opost_block(tty, b, nr);
				if (num < 0) {
					retval = num;
					goto break_out;
				}
				b += num;
				nr -= num;
				if (nr == 0)
					break;
				current->state = TASK_RUNNING;
				get_user(c, b);
				current->state = TASK_INTERRUPTIBLE;
				if (opost(c, tty) < 0)
					break;
				b++; nr--;
			}
			if (tty->driver.flush_chars)
				tty->driver.flush_chars(tty);
		} else {
			current->state = TASK_RUNNING;
			c = tty->driver.write(tty, 1, b, nr);
			current->state = TASK_INTERRUPTIBLE;
			if (c < 0) {
				retval = c;
				goto break_out;
			}
			b += c;
			nr -= c;
		}
		if (!nr)
			break;
		if (file->f_flags & O_NONBLOCK) {
			retval = -EAGAIN;
			break;
		}
		schedule();
	}
break_out:
	current->state = TASK_RUNNING;
	remove_wait_queue(&tty->write_wait, &wait);
	return (b - buf) ? b - buf : retval;
}
Пример #7
0
static ssize_t write_chan(struct tty_struct * tty, struct file * file,
			  const unsigned char * buf, size_t nr)
{
	const unsigned char *b = buf;
	DECLARE_WAITQUEUE(wait, current);
	int c;
	ssize_t retval = 0;
	int transaction_commit = committing_transaction();

	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
	if ((!transaction_commit) && 
	    L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
		retval = tty_check_change(tty);
		if (retval)
			return retval;
	}

	add_wait_queue(&tty->write_wait, &wait);
	while (1) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			break;
		}
		if ((!transaction_commit) &&
		    (tty_hung_up_p(file) || (tty->link && !tty->link->count))) {
			retval = -EIO;
			break;
		}
		if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
			while (nr > 0) {
				ssize_t num = opost_block(tty, b, nr);
				if (num < 0) {
					if (num == -EAGAIN)
						break;
					retval = num;
					goto break_out;
				}
				b += num;
				nr -= num;
				if (nr == 0)
					break;
				c = *b;
				if (opost(c, tty) < 0)
					break;
				b++; nr--;
			}
			if (tty->driver->flush_chars)
				tty->driver->flush_chars(tty);
		} else {
			while (nr > 0) {
				c = tty->driver->write(tty, b, nr);
				if (c < 0) {
					retval = c;
					goto break_out;
				}
				if (!c)
					break;
				b += c;
				nr -= c;
			}
		}
		if (!nr)
			break;
		if ((!transaction_commit) &&
		    (tx_cache_get_file_ro(file)->f_flags & O_NONBLOCK)) {
			retval = -EAGAIN;
			break;
		}
		schedule();
	}
break_out:
	__set_current_state(TASK_RUNNING);
	remove_wait_queue(&tty->write_wait, &wait);
	return (b - buf) ? b - buf : retval;
}