⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty_io.c

📁 gives an orthogonal feeling to tty s, be they consoles or rs-channels. It also implements echoing, c
💻 C
📖 第 1 页 / 共 4 页
字号:
		read_lock(&tasklist_lock);		for_each_task(p) {			if (p->tty == tty || (o_tty && p->tty == o_tty))				p->tty = NULL;		}		read_unlock(&tasklist_lock);		if (redirect == tty || (o_tty && redirect == o_tty))			redirect = NULL;	}	/* check whether both sides are closing ... */	if (!tty_closing || (o_tty && !o_tty_closing))		return;	#ifdef TTY_DEBUG_HANGUP	printk(KERN_DEBUG "freeing tty structure...");#endif	/*	 * Shutdown the current line discipline, and reset it to N_TTY.	 * N.B. why reset ldisc when we're releasing the memory??	 */	if (tty->ldisc.close)		(tty->ldisc.close)(tty);	tty->ldisc = ldiscs[N_TTY];	tty->termios->c_line = N_TTY;	if (o_tty) {		if (o_tty->ldisc.close)			(o_tty->ldisc.close)(o_tty);		o_tty->ldisc = ldiscs[N_TTY];	}		/*	 * Make sure that the tty's task queue isn't activated. 	 */	run_task_queue(&tq_timer);	flush_scheduled_tasks();	/* 	 * The release_mem function takes care of the details of clearing	 * the slots and preserving the termios structure.	 */	release_mem(tty, idx);}/* * tty_open and tty_release keep up the tty count that contains the * number of opens done on a tty. We cannot use the inode-count, as * different inodes might point to the same tty. * * Open-counting is needed for pty masters, as well as for keeping * track of serial lines: DTR is dropped when the last close happens. * (This is not done solely through tty->count, now.  - Ted 1/27/92) * * The termios state of a pty is reset on first open so that * settings don't persist across reuse. */static int tty_open(struct inode * inode, struct file * filp){	struct tty_struct *tty;	int noctty, retval;	kdev_t device;	unsigned short saved_flags;	char	buf[64];	saved_flags = filp->f_flags;retry_open:	noctty = filp->f_flags & O_NOCTTY;	device = inode->i_rdev;	if (device == TTY_DEV) {		if (!current->tty)			return -ENXIO;		device = current->tty->device;		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */		/* noctty = 1; */	}#ifdef CONFIG_VT	if (device == CONSOLE_DEV) {		extern int fg_console;		device = MKDEV(TTY_MAJOR, fg_console + 1);		noctty = 1;	}#endif	if (device == SYSCONS_DEV) {		struct console *c = console_drivers;		while(c && !c->device)			c = c->next;		if (!c)                        return -ENODEV;                device = c->device(c);		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/console block */		noctty = 1;	}	if (device == PTMX_DEV) {#ifdef CONFIG_UNIX98_PTYS		/* find a free pty. */		int major, minor;		struct tty_driver *driver;		/* find a device that is not in use. */		retval = -1;		for ( major = 0 ; major < UNIX98_NR_MAJORS ; major++ ) {			driver = &ptm_driver[major];			for (minor = driver->minor_start ;			     minor < driver->minor_start + driver->num ;			     minor++) {				device = MKDEV(driver->major, minor);				if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */			}		}		return -EIO; /* no free ptys */	ptmx_found:		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */		minor -= driver->minor_start;		devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));		tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,				   pts_driver[major].minor_start + minor);		noctty = 1;		goto init_dev_done;#else   /* CONFIG_UNIX_98_PTYS */		return -ENODEV;#endif  /* CONFIG_UNIX_98_PTYS */	}	retval = init_dev(device, &tty);	if (retval)		return retval;#ifdef CONFIG_UNIX98_PTYSinit_dev_done:#endif	filp->private_data = tty;	file_move(filp, &tty->tty_files);	check_tty_count(tty, "tty_open");	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&	    tty->driver.subtype == PTY_TYPE_MASTER)		noctty = 1;#ifdef TTY_DEBUG_HANGUP	printk(KERN_DEBUG "opening %s...", tty_name(tty, buf));#endif	if (tty->driver.open)		retval = tty->driver.open(tty, filp);	else		retval = -ENODEV;	filp->f_flags = saved_flags;	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())		retval = -EBUSY;	if (retval) {#ifdef TTY_DEBUG_HANGUP		printk(KERN_DEBUG "error %d in opening %s...", retval,		       tty_name(tty, buf));#endif		release_dev(filp);		if (retval != -ERESTARTSYS)			return retval;		if (signal_pending(current))			return retval;		schedule();		/*		 * Need to reset f_op in case a hangup happened.		 */		filp->f_op = &tty_fops;		goto retry_open;	}	if (!noctty &&	    current->leader &&	    !current->tty &&	    tty->session == 0) {	    	task_lock(current);		current->tty = tty;		task_unlock(current);		current->tty_old_pgrp = 0;		tty->session = current->session;		tty->pgrp = current->pgrp;	}	if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) &&	    (tty->driver.subtype == SERIAL_TYPE_CALLOUT) &&	    (tty->count == 1)) {		static int nr_warns;		if (nr_warns < 5) {			printk(KERN_WARNING "tty_io.c: "				"process %d (%s) used obsolete /dev/%s - "				"update software to use /dev/ttyS%d\n",				current->pid, current->comm,				tty_name(tty, buf), TTY_NUMBER(tty));			nr_warns++;		}	}	return 0;}static int tty_release(struct inode * inode, struct file * filp){	lock_kernel();	release_dev(filp);	unlock_kernel();	return 0;}/* No kernel lock held - fine */static unsigned int tty_poll(struct file * filp, poll_table * wait){	struct tty_struct * tty;	tty = (struct tty_struct *)filp->private_data;	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_poll"))		return 0;	if (tty->ldisc.poll)		return (tty->ldisc.poll)(tty, filp, wait);	return 0;}static int tty_fasync(int fd, struct file * filp, int on){	struct tty_struct * tty;	int retval;	tty = (struct tty_struct *)filp->private_data;	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync"))		return 0;		retval = fasync_helper(fd, filp, on, &tty->fasync);	if (retval <= 0)		return retval;	if (on) {		if (!waitqueue_active(&tty->read_wait))			tty->minimum_to_wake = 1;		if (filp->f_owner.pid == 0) {			filp->f_owner.pid = (-tty->pgrp) ? : current->pid;			filp->f_owner.uid = current->uid;			filp->f_owner.euid = current->euid;		}	} else {		if (!tty->fasync && !waitqueue_active(&tty->read_wait))			tty->minimum_to_wake = N_TTY_BUF_SIZE;	}	return 0;}static int tiocsti(struct tty_struct *tty, char * arg){	char ch, mbz = 0;	if ((current->tty != tty) && !suser())		return -EPERM;	if (get_user(ch, arg))		return -EFAULT;	tty->ldisc.receive_buf(tty, &ch, &mbz, 1);	return 0;}static int tiocgwinsz(struct tty_struct *tty, struct winsize * arg){	if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))		return -EFAULT;	return 0;}static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,	struct winsize * arg){	struct winsize tmp_ws;	if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))		return -EFAULT;	if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))		return 0;	if (tty->pgrp > 0)		kill_pg(tty->pgrp, SIGWINCH, 1);	if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))		kill_pg(real_tty->pgrp, SIGWINCH, 1);	tty->winsize = tmp_ws;	real_tty->winsize = tmp_ws;	return 0;}static int tioccons(struct inode *inode,	struct tty_struct *tty, struct tty_struct *real_tty){	if (inode->i_rdev == SYSCONS_DEV ||	    inode->i_rdev == CONSOLE_DEV) {		if (!suser())			return -EPERM;		redirect = NULL;		return 0;	}	if (redirect)		return -EBUSY;	redirect = real_tty;	return 0;}static int fionbio(struct file *file, int *arg){	int nonblock;	if (get_user(nonblock, arg))		return -EFAULT;	if (nonblock)		file->f_flags |= O_NONBLOCK;	else		file->f_flags &= ~O_NONBLOCK;	return 0;}static int tiocsctty(struct tty_struct *tty, int arg){	if (current->leader &&	    (current->session == tty->session))		return 0;	/*	 * The process must be a session leader and	 * not have a controlling tty already.	 */	if (!current->leader || current->tty)		return -EPERM;	if (tty->session > 0) {		/*		 * This tty is already the controlling		 * tty for another session group!		 */		if ((arg == 1) && suser()) {			/*			 * Steal it away			 */			struct task_struct *p;			read_lock(&tasklist_lock);			for_each_task(p)				if (p->tty == tty)					p->tty = NULL;			read_unlock(&tasklist_lock);		} else			return -EPERM;	}	task_lock(current);	current->tty = tty;	task_unlock(current);	current->tty_old_pgrp = 0;	tty->session = current->session;	tty->pgrp = current->pgrp;	return 0;}static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg){	/*	 * (tty == real_tty) is a cheap way of	 * testing if the tty is NOT a master pty.	 */	if (tty == real_tty && current->tty != real_tty)		return -ENOTTY;	return put_user(real_tty->pgrp, arg);}static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg){	pid_t pgrp;	int retval = tty_check_change(real_tty);	if (retval == -EIO)		return -ENOTTY;	if (retval)		return retval;	if (!current->tty ||	    (current->tty != real_tty) ||	    (real_tty->session != current->session))		return -ENOTTY;	if (get_user(pgrp, (pid_t *) arg))		return -EFAULT;	if (pgrp < 0)		return -EINVAL;	if (session_of_pgrp(pgrp) != current->session)		return -EPERM;	real_tty->pgrp = pgrp;	return 0;}static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t *arg){	/*	 * (tty == real_tty) is a cheap way of	 * testing if the tty is NOT a master pty.	*/	if (tty == real_tty && current->tty != real_tty)		return -ENOTTY;	if (real_tty->session <= 0)		return -ENOTTY;	return put_user(real_tty->session, arg);}static int tiocttygstruct(struct tty_struct *tty, struct tty_struct *arg){	if (copy_to_user(arg, tty, sizeof(*arg)))		return -EFAULT;	return 0;}static int tiocsetd(struct tty_struct *tty, int *arg){	int ldisc;	if (get_user(ldisc, arg))		return -EFAULT;	return tty_set_ldisc(tty, ldisc);}static int send_break(struct tty_struct *tty, int duration){	set_current_state(TASK_INTERRUPTIBLE);	tty->driver.break_ctl(tty, -1);	if (!signal_pending(current))		schedule_timeout(duration);	tty->driver.break_ctl(tty, 0);	if (signal_pending(current))		return -EINTR;	return 0;}/* * Split this up, as gcc can choke on it otherwise.. */int tty_ioctl(struct inode * inode, struct file * file,	      unsigned int cmd, unsigned long arg){	struct tty_struct *tty, *real_tty;	int retval;		tty = (struct tty_struct *)file->private_data;	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))		return -EINVAL;	real_tty = tty;	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&	    tty->driver.subtype == PTY_TYPE_MASTER)		real_tty = tty->link;	/*	 * Break handling by driver	 */	if (!tty->driver.break_ctl) {		switch(cmd) {		case TIOCSBRK:		case TIOCCBRK:			if (tty->driver.ioctl)				return tty->driver.ioctl(tty, file, cmd, arg);			return -EINVAL;					/* These two ioctl's always return success; even if */		/* the driver doesn't support them. */		case TCSBRK:		case TCSBRKP:			if (!tty->driver.ioctl)				return 0;			retval = tty->driver.ioctl(tty, file, cmd, arg);			if (retval == -ENOIOCTLCMD)				retval = 0;			return retval;		}	}	/*	 * Factor out some common prep work	 */	switch (cmd) {	case TIOCSETD:	case TIOCSBRK:	case TIOCCBRK:	case TCSBRK:	case TCSBRKP:					retval = tty_check_change(tty);		if (retval)			return retval;		if (cmd != TIOCCBRK) {			tty_wait_until_sent(tty, 0);			if (signal_pending(current))				return -EINTR;		}		break;	}	switch (cmd) {		case TIOCSTI:			return tiocsti(tty, (char *)arg);		case TIOCGWINSZ:			return tiocgwinsz(tty, (struct winsize *) arg);		case TIOCSWINSZ:			return tiocswinsz(tty, real_tty, (struct winsize *) arg);		case TIOCCONS:			return tioccons(inode, tty, real_tty);		case FIONBIO:			return fionbio(file, (int *) arg);		case TIOCEXCL:			set_bit(TTY_EXCLUSIVE, &tty->flags);			return 0;		case TIOCNXCL:			clear_bit(TTY_EXCLUSIVE, &tty->flags);			return 0;		case TIOCNOTTY:			if (current->tty != tty)				return -ENOTTY;			if (current->leader)				disassociate_ctty(0);			task_lock(current);			current->tty = NULL;			task_unlock(current);			return 0;		case TIOCSCTTY:			return tiocsctty(tty, arg);		case TIOCGPGRP:			return tiocgpgrp(tty, real_tty, (pid_t *) arg);		case TIOCSPGRP:			return tiocspgrp(tty, real_tty, (pid_t *) arg);		case TIOCGSID:			return tiocgsid(tty, real_tty, (pid_t *) arg);		case TIOCGETD:			return put_user(tty->ldisc.num, (int *) arg);		case TIOCSETD:			return tiocsetd(tty, (int *) arg);#ifdef CONFIG_VT		case TIOCLINUX:			return tioclinux(tty, arg);#endif		case TIOCTTYGSTRUCT:			return tiocttygstruct(tty, (struct tty_struct *) arg);		/*		 * Break handling		 */		case TIOCSBRK:	/* Turn break on, unconditionally */			tty->driver.break_ctl(tty, -1);			return 0;					case TIOCCBRK:	/* Turn break off, unconditionally */			tty->driver.break_ctl(tty, 0);			return 0;		case TCSBRK:   /* SVID version: non-zero arg --> no break */			/*			 * XXX is the above comment correct, or the			 * code below correct?  Is this ioctl used at			 * all by anyone?			 */			if (!arg)				return send_break(tty, HZ/4);			return 0;		case TCSBRKP:	/* support for POSIX tcsendbreak() */				return send_break(tty, arg ? arg*(HZ/10) : HZ/4);	}	if (tty->driver.ioctl) {		int retval = (tty->driver.ioctl)(tty, file, cmd, arg);		if (retval != -ENOIOCTLCMD)			return retval;	}	if (tty->ldisc.ioctl) {		int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg);		if (retval != -ENOIOCTLCMD)			return retval;	}	return -EINVAL;}/* * This implements the "Secure Attention Key" ---  the idea is to * prevent trojan horses by killing all processes associated with this * tty when the user hits the "Secure Attention Key".  Required for * super-paranoid applications --- see the Orange Book for more details.

⌨️ 快捷键说明

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