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

📄 tty_io.c

📁 gives an orthogonal feeling to tty s, be they consoles or rs-channels. It also implements echoing, c
💻 C
📖 第 1 页 / 共 4 页
字号:
	tty = (struct tty_struct *)file->private_data;	inode = file->f_dentry->d_inode;	if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))		return -EIO;	if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))		return -EIO;	/* This check not only needs to be done before reading, but also	   whenever read_chan() gets woken up after sleeping, so I've	   moved it to there.  This should only be done for the N_TTY	   line discipline, anyway.  Same goes for write_chan(). -- jlc. */#if 0	if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */	    (tty->pgrp > 0) &&	    (current->tty == tty) &&	    (tty->pgrp != current->pgrp))		if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))			return -EIO;		else {			(void) kill_pg(current->pgrp, SIGTTIN, 1);			return -ERESTARTSYS;		}#endif	lock_kernel();	if (tty->ldisc.read)		i = (tty->ldisc.read)(tty,file,buf,count);	else		i = -EIO;	unlock_kernel();	if (i > 0)		inode->i_atime = CURRENT_TIME;	return i;}/* * Split writes up in sane blocksizes to avoid * denial-of-service type attacks */static inline ssize_t do_tty_write(	ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),	struct tty_struct *tty,	struct file *file,	const unsigned char *buf,	size_t count){	ssize_t ret = 0, written = 0;		if (file->f_flags & O_NONBLOCK) {		if (down_trylock(&tty->atomic_write))			return -EAGAIN;	}	else {		if (down_interruptible(&tty->atomic_write))			return -ERESTARTSYS;	}	if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) {		lock_kernel();		written = write(tty, file, buf, count);		unlock_kernel();	} else {		for (;;) {			unsigned long size = MAX(PAGE_SIZE*2,16384);			if (size > count)				size = count;			lock_kernel();			ret = write(tty, file, buf, size);			unlock_kernel();			if (ret <= 0)				break;			written += ret;			buf += ret;			count -= ret;			if (!count)				break;			ret = -ERESTARTSYS;			if (signal_pending(current))				break;			if (current->need_resched)				schedule();		}	}	if (written) {		file->f_dentry->d_inode->i_mtime = CURRENT_TIME;		ret = written;	}	up(&tty->atomic_write);	return ret;}static ssize_t tty_write(struct file * file, const char * buf, size_t count,			 loff_t *ppos){	int is_console;	struct tty_struct * tty;	struct inode *inode;	/* Can't seek (pwrite) on ttys.  */	if (ppos != &file->f_pos)		return -ESPIPE;	/*	 *      For now, we redirect writes from /dev/console as	 *      well as /dev/tty0.	 */	inode = file->f_dentry->d_inode;	is_console = (inode->i_rdev == SYSCONS_DEV ||		      inode->i_rdev == CONSOLE_DEV);	if (is_console && redirect)		tty = redirect;	else		tty = (struct tty_struct *)file->private_data;	if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))		return -EIO;	if (!tty || !tty->driver.write || (test_bit(TTY_IO_ERROR, &tty->flags)))		return -EIO;#if 0	if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&	    (current->tty == tty) && (tty->pgrp != current->pgrp)) {		if (is_orphaned_pgrp(current->pgrp))			return -EIO;		if (!is_ignored(SIGTTOU)) {			(void) kill_pg(current->pgrp, SIGTTOU, 1);			return -ERESTARTSYS;		}	}#endif	if (!tty->ldisc.write)		return -EIO;	return do_tty_write(tty->ldisc.write, tty, file,			    (const unsigned char *)buf, count);}/* Semaphore to protect creating and releasing a tty */static DECLARE_MUTEX(tty_sem);static void down_tty_sem(int index){	down(&tty_sem);}static void up_tty_sem(int index){	up(&tty_sem);}static void release_mem(struct tty_struct *tty, int idx);/* * WSH 06/09/97: Rewritten to remove races and properly clean up after a * failed open.  The new code protects the open with a semaphore, so it's * really quite straightforward.  The semaphore locking can probably be * relaxed for the (most common) case of reopening a tty. */static int init_dev(kdev_t device, struct tty_struct **ret_tty){	struct tty_struct *tty, *o_tty;	struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;	struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;	struct tty_driver *driver;		int retval=0;	int idx;	driver = get_tty_driver(device);	if (!driver)		return -ENODEV;	idx = MINOR(device) - driver->minor_start;	/* 	 * Check whether we need to acquire the tty semaphore to avoid	 * race conditions.  For now, play it safe.	 */	down_tty_sem(idx);	/* check whether we're reopening an existing tty */	tty = driver->table[idx];	if (tty) goto fast_track;	/*	 * First time open is complex, especially for PTY devices.	 * This code guarantees that either everything succeeds and the	 * TTY is ready for operation, or else the table slots are vacated	 * and the allocated memory released.  (Except that the termios 	 * and locked termios may be retained.)	 */	o_tty = NULL;	tp = o_tp = NULL;	ltp = o_ltp = NULL;	tty = alloc_tty_struct();	if(!tty)		goto fail_no_mem;	initialize_tty_struct(tty);	tty->device = device;	tty->driver = *driver;	tp_loc = &driver->termios[idx];	if (!*tp_loc) {		tp = (struct termios *) kmalloc(sizeof(struct termios),						GFP_KERNEL);		if (!tp)			goto free_mem_out;		*tp = driver->init_termios;	}	ltp_loc = &driver->termios_locked[idx];	if (!*ltp_loc) {		ltp = (struct termios *) kmalloc(sizeof(struct termios),						 GFP_KERNEL);		if (!ltp)			goto free_mem_out;		memset(ltp, 0, sizeof(struct termios));	}	if (driver->type == TTY_DRIVER_TYPE_PTY) {		o_tty = alloc_tty_struct();		if (!o_tty)			goto free_mem_out;		initialize_tty_struct(o_tty);		o_tty->device = (kdev_t) MKDEV(driver->other->major,					driver->other->minor_start + idx);		o_tty->driver = *driver->other;		o_tp_loc  = &driver->other->termios[idx];		if (!*o_tp_loc) {			o_tp = (struct termios *)				kmalloc(sizeof(struct termios), GFP_KERNEL);			if (!o_tp)				goto free_mem_out;			*o_tp = driver->other->init_termios;		}		o_ltp_loc = &driver->other->termios_locked[idx];		if (!*o_ltp_loc) {			o_ltp = (struct termios *)				kmalloc(sizeof(struct termios), GFP_KERNEL);			if (!o_ltp)				goto free_mem_out;			memset(o_ltp, 0, sizeof(struct termios));		}		/*		 * Everything allocated ... set up the o_tty structure.		 */		driver->other->table[idx] = o_tty;		if (!*o_tp_loc)			*o_tp_loc = o_tp;		if (!*o_ltp_loc)			*o_ltp_loc = o_ltp;		o_tty->termios = *o_tp_loc;		o_tty->termios_locked = *o_ltp_loc;		(*driver->other->refcount)++;		if (driver->subtype == PTY_TYPE_MASTER)			o_tty->count++;		/* Establish the links in both directions */		tty->link   = o_tty;		o_tty->link = tty;	}	/* 	 * All structures have been allocated, so now we install them.	 * Failures after this point use release_mem to clean up, so 	 * there's no need to null out the local pointers.	 */	driver->table[idx] = tty;		if (!*tp_loc)		*tp_loc = tp;	if (!*ltp_loc)		*ltp_loc = ltp;	tty->termios = *tp_loc;	tty->termios_locked = *ltp_loc;	(*driver->refcount)++;	tty->count++;	/* 	 * Structures all installed ... call the ldisc open routines.	 * If we fail here just call release_mem to clean up.  No need	 * to decrement the use counts, as release_mem doesn't care.	 */	if (tty->ldisc.open) {		retval = (tty->ldisc.open)(tty);		if (retval)			goto release_mem_out;	}	if (o_tty && o_tty->ldisc.open) {		retval = (o_tty->ldisc.open)(o_tty);		if (retval) {			if (tty->ldisc.close)				(tty->ldisc.close)(tty);			goto release_mem_out;		}	}	goto success;	/*	 * This fast open can be used if the tty is already open.	 * No memory is allocated, and the only failures are from	 * attempting to open a closing tty or attempting multiple	 * opens on a pty master.	 */fast_track:	if (test_bit(TTY_CLOSING, &tty->flags)) {		retval = -EIO;		goto end_init;	}	if (driver->type == TTY_DRIVER_TYPE_PTY &&	    driver->subtype == PTY_TYPE_MASTER) {		/*		 * special case for PTY masters: only one open permitted, 		 * and the slave side open count is incremented as well.		 */		if (tty->count) {			retval = -EIO;			goto end_init;		}		tty->link->count++;	}	tty->count++;	tty->driver = *driver; /* N.B. why do this every time?? */success:	*ret_tty = tty;		/* All paths come through here to release the semaphore */end_init:	up_tty_sem(idx);	return retval;	/* Release locally allocated memory ... nothing placed in slots */free_mem_out:	if (o_tp)		kfree(o_tp);	if (o_tty)		free_tty_struct(o_tty);	if (ltp)		kfree(ltp);	if (tp)		kfree(tp);	free_tty_struct(tty);fail_no_mem:	retval = -ENOMEM;	goto end_init;	/* call the tty release_mem routine to clean out this slot */release_mem_out:	printk(KERN_INFO "init_dev: ldisc open failed, "			 "clearing slot %d\n", idx);	release_mem(tty, idx);	goto end_init;}/* * Releases memory associated with a tty structure, and clears out the * driver table slots. */static void release_mem(struct tty_struct *tty, int idx){	struct tty_struct *o_tty;	struct termios *tp;	if ((o_tty = tty->link) != NULL) {		o_tty->driver.table[idx] = NULL;		if (o_tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {			tp = o_tty->driver.termios[idx];			o_tty->driver.termios[idx] = NULL;			kfree(tp);		}		o_tty->magic = 0;		(*o_tty->driver.refcount)--;		list_del(&o_tty->tty_files);		free_tty_struct(o_tty);	}	tty->driver.table[idx] = NULL;	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {		tp = tty->driver.termios[idx];		tty->driver.termios[idx] = NULL;		kfree(tp);	}	tty->magic = 0;	(*tty->driver.refcount)--;	list_del(&tty->tty_files);	free_tty_struct(tty);}/* * Even releasing the tty structures is a tricky business.. We have * to be very careful that the structures are all released at the * same time, as interrupts might otherwise get the wrong pointers. * * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */static void release_dev(struct file * filp){	struct tty_struct *tty, *o_tty;	int	pty_master, tty_closing, o_tty_closing, do_sleep;	int	idx;	char	buf[64];		tty = (struct tty_struct *)filp->private_data;	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev"))		return;	check_tty_count(tty, "release_dev");	tty_fasync(-1, filp, 0);	idx = MINOR(tty->device) - tty->driver.minor_start;	pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&		      tty->driver.subtype == PTY_TYPE_MASTER);	o_tty = tty->link;#ifdef TTY_PARANOIA_CHECK	if (idx < 0 || idx >= tty->driver.num) {		printk(KERN_DEBUG "release_dev: bad idx when trying to "				  "free (%s)\n", kdevname(tty->device));		return;	}	if (tty != tty->driver.table[idx]) {		printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "				  "for (%s)\n", idx, kdevname(tty->device));		return;	}	if (tty->termios != tty->driver.termios[idx]) {		printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "		       "for (%s)\n",		       idx, kdevname(tty->device));		return;	}	if (tty->termios_locked != tty->driver.termios_locked[idx]) {		printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "		       "termios_locked for (%s)\n",		       idx, kdevname(tty->device));		return;	}#endif#ifdef TTY_DEBUG_HANGUP	printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",	       tty_name(tty, buf), tty->count);#endif#ifdef TTY_PARANOIA_CHECK	if (tty->driver.other) {		if (o_tty != tty->driver.other->table[idx]) {			printk(KERN_DEBUG "release_dev: other->table[%d] "					  "not o_tty for (%s)\n",			       idx, kdevname(tty->device));			return;		}		if (o_tty->termios != tty->driver.other->termios[idx]) {			printk(KERN_DEBUG "release_dev: other->termios[%d] "					  "not o_termios for (%s)\n",			       idx, kdevname(tty->device));			return;		}		if (o_tty->termios_locked != 		      tty->driver.other->termios_locked[idx]) {			printk(KERN_DEBUG "release_dev: other->termios_locked["					  "%d] not o_termios_locked for (%s)\n",			       idx, kdevname(tty->device));			return;		}		if (o_tty->link != tty) {			printk(KERN_DEBUG "release_dev: bad pty pointers\n");			return;		}	}#endif	if (tty->driver.close)		tty->driver.close(tty, filp);	/*	 * Sanity check: if tty->count is going to zero, there shouldn't be	 * any waiters on tty->read_wait or tty->write_wait.  We test the	 * wait queues and kick everyone out _before_ actually starting to	 * close.  This ensures that we won't block while releasing the tty	 * structure.	 *	 * The test for the o_tty closing is necessary, since the master and	 * slave sides may close in any order.  If the slave side closes out	 * first, its count will be one, since the master side holds an open.	 * Thus this test wouldn't be triggered at the time the slave closes,	 * so we do it now.	 *	 * Note that it's possible for the tty to be opened again while we're	 * flushing out waiters.  By recalculating the closing flags before	 * each iteration we avoid any problems.	 */	while (1) {		tty_closing = tty->count <= 1;		o_tty_closing = o_tty &&			(o_tty->count <= (pty_master ? 1 : 0));		do_sleep = 0;		if (tty_closing) {			if (waitqueue_active(&tty->read_wait)) {				wake_up(&tty->read_wait);				do_sleep++;			}			if (waitqueue_active(&tty->write_wait)) {				wake_up(&tty->write_wait);				do_sleep++;			}		}		if (o_tty_closing) {			if (waitqueue_active(&o_tty->read_wait)) {				wake_up(&o_tty->read_wait);				do_sleep++;			}			if (waitqueue_active(&o_tty->write_wait)) {				wake_up(&o_tty->write_wait);				do_sleep++;			}		}		if (!do_sleep)			break;		printk(KERN_WARNING "release_dev: %s: read/write wait queue "				    "active!\n", tty_name(tty, buf));		schedule();	}		/*	 * The closing flags are now consistent with the open counts on 	 * both sides, and we've completed the last operation that could 	 * block, so it's safe to proceed with closing.	 */	if (pty_master) {		if (--o_tty->count < 0) {			printk(KERN_WARNING "release_dev: bad pty slave count "					    "(%d) for %s\n",			       o_tty->count, tty_name(o_tty, buf));			o_tty->count = 0;		}	}	if (--tty->count < 0) {		printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",		       tty->count, tty_name(tty, buf));		tty->count = 0;	}	/*	 * We've decremented tty->count, so we should zero out	 * filp->private_data, to break the link between the tty and	 * the file descriptor.  Otherwise if filp_close() blocks before	 * the file descriptor is removed from the inuse_filp	 * list, check_tty_count() could observe a discrepancy and	 * printk a warning message to the user.	 */	filp->private_data = 0;	/*	 * Perform some housekeeping before deciding whether to return.	 *	 * Set the TTY_CLOSING flag if this was the last open.  In the	 * case of a pty we may have to wait around for the other side	 * to close, and TTY_CLOSING makes sure we can't be reopened.	 */	if(tty_closing)		set_bit(TTY_CLOSING, &tty->flags);	if(o_tty_closing)		set_bit(TTY_CLOSING, &o_tty->flags);	/*	 * If _either_ side is closing, make sure there aren't any	 * processes that still think tty or o_tty is their controlling	 * tty.  Also, clear redirect if it points to either tty.	 */	if (tty_closing || o_tty_closing) {		struct task_struct *p;

⌨️ 快捷键说明

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