tty_ioctl.c

来自「linux 内核源代码」· C语言 代码 · 共 983 行 · 第 1/2 页

C
983
字号
	} else {		if (user_termios_to_kernel_termios(&tmp_termios,						(struct termios2 __user *)arg))			return -EFAULT;	}#else	} else if (user_termios_to_kernel_termios(&tmp_termios,					(struct termios __user *)arg))		return -EFAULT;#endif	/* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed	   so its unconditionally usable */	tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);	tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);	ld = tty_ldisc_ref(tty);		if (ld != NULL) {		if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)			ld->flush_buffer(tty);		tty_ldisc_deref(ld);	}		if (opt & TERMIOS_WAIT) {		tty_wait_until_sent(tty, 0);		if (signal_pending(current))			return -EINTR;	}	change_termios(tty, &tmp_termios);	/* FIXME: Arguably if tmp_termios == tty->termios AND the	   actual requested termios was not tmp_termios then we may	   want to return an error as no user requested change has	   succeeded */	return 0;}static int get_termio(struct tty_struct * tty, struct termio __user * termio){	if (kernel_termios_to_user_termio(termio, tty->termios))		return -EFAULT;	return 0;}static unsigned long inq_canon(struct tty_struct * tty){	int nr, head, tail;	if (!tty->canon_data || !tty->read_buf)		return 0;	head = tty->canon_head;	tail = tty->read_tail;	nr = (head - tail) & (N_TTY_BUF_SIZE-1);	/* Skip EOF-chars.. */	while (head != tail) {		if (test_bit(tail, tty->read_flags) &&		    tty->read_buf[tail] == __DISABLED_CHAR)			nr--;		tail = (tail+1) & (N_TTY_BUF_SIZE-1);	}	return nr;}#ifdef TIOCGETP/* * These are deprecated, but there is limited support.. * * The "sg_flags" translation is a joke.. */static int get_sgflags(struct tty_struct * tty){	int flags = 0;	if (!(tty->termios->c_lflag & ICANON)) {		if (tty->termios->c_lflag & ISIG)			flags |= 0x02;		/* cbreak */		else			flags |= 0x20;		/* raw */	}	if (tty->termios->c_lflag & ECHO)		flags |= 0x08;			/* echo */	if (tty->termios->c_oflag & OPOST)		if (tty->termios->c_oflag & ONLCR)			flags |= 0x10;		/* crmod */	return flags;}static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb){	struct sgttyb tmp;	mutex_lock(&tty->termios_mutex);	tmp.sg_ispeed = tty->termios->c_ispeed;	tmp.sg_ospeed = tty->termios->c_ospeed;	tmp.sg_erase = tty->termios->c_cc[VERASE];	tmp.sg_kill = tty->termios->c_cc[VKILL];	tmp.sg_flags = get_sgflags(tty);	mutex_unlock(&tty->termios_mutex);		return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;}static void set_sgflags(struct ktermios * termios, int flags){	termios->c_iflag = ICRNL | IXON;	termios->c_oflag = 0;	termios->c_lflag = ISIG | ICANON;	if (flags & 0x02) {	/* cbreak */		termios->c_iflag = 0;		termios->c_lflag &= ~ICANON;	}	if (flags & 0x08) {		/* echo */		termios->c_lflag |= ECHO | ECHOE | ECHOK |				    ECHOCTL | ECHOKE | IEXTEN;	}	if (flags & 0x10) {		/* crmod */		termios->c_oflag |= OPOST | ONLCR;	}	if (flags & 0x20) {	/* raw */		termios->c_iflag = 0;		termios->c_lflag &= ~(ISIG | ICANON);	}	if (!(termios->c_lflag & ICANON)) {		termios->c_cc[VMIN] = 1;		termios->c_cc[VTIME] = 0;	}}/** *	set_sgttyb		-	set legacy terminal values *	@tty: tty structure *	@sgttyb: pointer to old style terminal structure * *	Updates a terminal from the legacy BSD style terminal information *	structure. * *	Locking: termios_sem */static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb){	int retval;	struct sgttyb tmp;	struct ktermios termios;	retval = tty_check_change(tty);	if (retval)		return retval;		if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))		return -EFAULT;	mutex_lock(&tty->termios_mutex);	termios = *tty->termios;	termios.c_cc[VERASE] = tmp.sg_erase;	termios.c_cc[VKILL] = tmp.sg_kill;	set_sgflags(&termios, tmp.sg_flags);	/* Try and encode into Bfoo format */#ifdef BOTHER	tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);#endif	mutex_unlock(&tty->termios_mutex);	change_termios(tty, &termios);	return 0;}#endif#ifdef TIOCGETCstatic int get_tchars(struct tty_struct * tty, struct tchars __user * tchars){	struct tchars tmp;	tmp.t_intrc = tty->termios->c_cc[VINTR];	tmp.t_quitc = tty->termios->c_cc[VQUIT];	tmp.t_startc = tty->termios->c_cc[VSTART];	tmp.t_stopc = tty->termios->c_cc[VSTOP];	tmp.t_eofc = tty->termios->c_cc[VEOF];	tmp.t_brkc = tty->termios->c_cc[VEOL2];	/* what is brkc anyway? */	return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;}static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars){	struct tchars tmp;	if (copy_from_user(&tmp, tchars, sizeof(tmp)))		return -EFAULT;	tty->termios->c_cc[VINTR] = tmp.t_intrc;	tty->termios->c_cc[VQUIT] = tmp.t_quitc;	tty->termios->c_cc[VSTART] = tmp.t_startc;	tty->termios->c_cc[VSTOP] = tmp.t_stopc;	tty->termios->c_cc[VEOF] = tmp.t_eofc;	tty->termios->c_cc[VEOL2] = tmp.t_brkc;	/* what is brkc anyway? */	return 0;}#endif#ifdef TIOCGLTCstatic int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars){	struct ltchars tmp;	tmp.t_suspc = tty->termios->c_cc[VSUSP];	tmp.t_dsuspc = tty->termios->c_cc[VSUSP];	/* what is dsuspc anyway? */	tmp.t_rprntc = tty->termios->c_cc[VREPRINT];	tmp.t_flushc = tty->termios->c_cc[VEOL2];	/* what is flushc anyway? */	tmp.t_werasc = tty->termios->c_cc[VWERASE];	tmp.t_lnextc = tty->termios->c_cc[VLNEXT];	return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;}static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars){	struct ltchars tmp;	if (copy_from_user(&tmp, ltchars, sizeof(tmp)))		return -EFAULT;	tty->termios->c_cc[VSUSP] = tmp.t_suspc;	tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;	/* what is dsuspc anyway? */	tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;	tty->termios->c_cc[VEOL2] = tmp.t_flushc;	/* what is flushc anyway? */	tty->termios->c_cc[VWERASE] = tmp.t_werasc;	tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;	return 0;}#endif/** *	send_prio_char		-	send priority character * *	Send a high priority character to the tty even if stopped * *	Locking: none for xchar method, write ordering for write method. */static int send_prio_char(struct tty_struct *tty, char ch){	int	was_stopped = tty->stopped;	if (tty->driver->send_xchar) {		tty->driver->send_xchar(tty, ch);		return 0;	}	if (tty_write_lock(tty, 0) < 0)		return -ERESTARTSYS;	if (was_stopped)		start_tty(tty);	tty->driver->write(tty, &ch, 1);	if (was_stopped)		stop_tty(tty);	tty_write_unlock(tty);	return 0;}/** *	tty_mode_ioctl		-	mode related ioctls *	@tty: tty for the ioctl *	@file: file pointer for the tty *	@cmd: command *	@arg: ioctl argument * *	Perform non line discipline specific mode control ioctls. This *	is designed to be called by line disciplines to ensure they provide *	consistent mode setting. */int tty_mode_ioctl(struct tty_struct * tty, struct file *file,			unsigned int cmd, unsigned long arg){	struct tty_struct * real_tty;	void __user *p = (void __user *)arg;	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&	    tty->driver->subtype == PTY_TYPE_MASTER)		real_tty = tty->link;	else		real_tty = tty;	switch (cmd) {#ifdef TIOCGETP		case TIOCGETP:			return get_sgttyb(real_tty, (struct sgttyb __user *) arg);		case TIOCSETP:		case TIOCSETN:			return set_sgttyb(real_tty, (struct sgttyb __user *) arg);#endif#ifdef TIOCGETC		case TIOCGETC:			return get_tchars(real_tty, p);		case TIOCSETC:			return set_tchars(real_tty, p);#endif#ifdef TIOCGLTC		case TIOCGLTC:			return get_ltchars(real_tty, p);		case TIOCSLTC:			return set_ltchars(real_tty, p);#endif		case TCSETSF:			return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);		case TCSETSW:			return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);		case TCSETS:			return set_termios(real_tty, p, TERMIOS_OLD);#ifndef TCGETS2		case TCGETS:			if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))				return -EFAULT;			return 0;#else		case TCGETS:			if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))				return -EFAULT;			return 0;		case TCGETS2:			if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))				return -EFAULT;			return 0;		case TCSETSF2:			return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);		case TCSETSW2:			return set_termios(real_tty, p, TERMIOS_WAIT);		case TCSETS2:			return set_termios(real_tty, p, 0);#endif		case TCGETA:			return get_termio(real_tty, p);		case TCSETAF:			return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);		case TCSETAW:			return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);		case TCSETA:			return set_termios(real_tty, p, TERMIOS_TERMIO);#ifndef TCGETS2		case TIOCGLCKTRMIOS:			if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))				return -EFAULT;			return 0;		case TIOCSLCKTRMIOS:			if (!capable(CAP_SYS_ADMIN))				return -EPERM;			if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))				return -EFAULT;			return 0;#else		case TIOCGLCKTRMIOS:			if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))				return -EFAULT;			return 0;		case TIOCSLCKTRMIOS:			if (!capable(CAP_SYS_ADMIN))				return -EPERM;			if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))				return -EFAULT;			return 0;#endif		case TIOCGSOFTCAR:			return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);		case TIOCSSOFTCAR:			if (get_user(arg, (unsigned int __user *) arg))				return -EFAULT;			mutex_lock(&tty->termios_mutex);			tty->termios->c_cflag =				((tty->termios->c_cflag & ~CLOCAL) |				 (arg ? CLOCAL : 0));			mutex_unlock(&tty->termios_mutex);			return 0;		default:			return -ENOIOCTLCMD;	}}EXPORT_SYMBOL_GPL(tty_mode_ioctl);int tty_perform_flush(struct tty_struct *tty, unsigned long arg){	struct tty_ldisc *ld;	int retval = tty_check_change(tty);	if (retval)		return retval;	ld = tty_ldisc_ref(tty);	switch (arg) {	case TCIFLUSH:		if (ld && ld->flush_buffer)			ld->flush_buffer(tty);		break;	case TCIOFLUSH:		if (ld && ld->flush_buffer)			ld->flush_buffer(tty);		/* fall through */	case TCOFLUSH:		if (tty->driver->flush_buffer)			tty->driver->flush_buffer(tty);		break;	default:		tty_ldisc_deref(ld);		return -EINVAL;	}	tty_ldisc_deref(ld);	return 0;}EXPORT_SYMBOL_GPL(tty_perform_flush);int n_tty_ioctl(struct tty_struct * tty, struct file * file,		       unsigned int cmd, unsigned long arg){	struct tty_struct * real_tty;	int retval;	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&	    tty->driver->subtype == PTY_TYPE_MASTER)		real_tty = tty->link;	else		real_tty = tty;	switch (cmd) {		case TCXONC:			retval = tty_check_change(tty);			if (retval)				return retval;			switch (arg) {			case TCOOFF:				if (!tty->flow_stopped) {					tty->flow_stopped = 1;					stop_tty(tty);				}				break;			case TCOON:				if (tty->flow_stopped) {					tty->flow_stopped = 0;					start_tty(tty);				}				break;			case TCIOFF:				if (STOP_CHAR(tty) != __DISABLED_CHAR)					return send_prio_char(tty, STOP_CHAR(tty));				break;			case TCION:				if (START_CHAR(tty) != __DISABLED_CHAR)					return send_prio_char(tty, START_CHAR(tty));				break;			default:				return -EINVAL;			}			return 0;		case TCFLSH:			return tty_perform_flush(tty, arg);		case TIOCOUTQ:			return put_user(tty->driver->chars_in_buffer ?					tty->driver->chars_in_buffer(tty) : 0,					(int __user *) arg);		case TIOCINQ:			retval = tty->read_cnt;			if (L_ICANON(tty))				retval = inq_canon(tty);			return put_user(retval, (unsigned int __user *) arg);		case TIOCPKT:		{			int pktmode;			if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||			    tty->driver->subtype != PTY_TYPE_MASTER)				return -ENOTTY;			if (get_user(pktmode, (int __user *) arg))				return -EFAULT;			if (pktmode) {				if (!tty->packet) {					tty->packet = 1;					tty->link->ctrl_status = 0;				}			} else				tty->packet = 0;			return 0;		}		default:			/* Try the mode commands */			return tty_mode_ioctl(tty, file, cmd, arg);		}}EXPORT_SYMBOL(n_tty_ioctl);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?