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

📄 tty_io.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}int tty_hung_up_p(struct file * filp){	return (filp->f_op == &hung_up_tty_fops);}/* * This function is typically called only by the session leader, when * it wants to disassociate itself from its controlling tty. * * It performs the following functions: * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group * 	(2)  Clears the tty from being controlling the session * 	(3)  Clears the controlling tty for all processes in the * 		session group. * * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. */void disassociate_ctty(int on_exit){	struct tty_struct *tty = current->tty;	struct task_struct *p;	int tty_pgrp = -1;	if (tty) {		tty_pgrp = tty->pgrp;		if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)			tty_vhangup(tty);	} else {		if (current->tty_old_pgrp) {			kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);			kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);		}		return;	}	if (tty_pgrp > 0) {		kill_pg(tty_pgrp, SIGHUP, on_exit);		if (!on_exit)			kill_pg(tty_pgrp, SIGCONT, on_exit);	}	current->tty_old_pgrp = 0;	tty->session = 0;	tty->pgrp = -1;	for_each_task(p)	  	if (p->session == current->session)			p->tty = NULL;}void wait_for_keypress(void){	sleep_on(&keypress_wait);}void stop_tty(struct tty_struct *tty){	if (tty->stopped)		return;	tty->stopped = 1;	if (tty->link && tty->link->packet) {		tty->ctrl_status &= ~TIOCPKT_START;		tty->ctrl_status |= TIOCPKT_STOP;		wake_up_interruptible(&tty->link->read_wait);	}	if (tty->driver.stop)		(tty->driver.stop)(tty);}void start_tty(struct tty_struct *tty){	if (!tty->stopped)		return;	tty->stopped = 0;	if (tty->link && tty->link->packet) {		tty->ctrl_status &= ~TIOCPKT_STOP;		tty->ctrl_status |= TIOCPKT_START;		wake_up_interruptible(&tty->link->read_wait);	}	if (tty->driver.start)		(tty->driver.start)(tty);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);	wake_up_interruptible(&tty->write_wait);}static int tty_read(struct inode * inode, struct file * file, char * buf, int count){	int i;	struct tty_struct * tty;	tty = (struct tty_struct *)file->private_data;	if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))		return -EIO;	if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))		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	if (tty->ldisc.read)		/* XXX casts are for what kernel-wide prototypes should be. */		i = (tty->ldisc.read)(tty,file,(unsigned char *)buf,(unsigned int)count);	else		i = -EIO;	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 int do_tty_write(	int (*write)(struct tty_struct *, struct file *, const unsigned char *, unsigned int),	struct inode *inode,	struct tty_struct *tty,	struct file *file,	const unsigned char *buf,	unsigned int count){	int ret = 0, written = 0;	for (;;) {		/* why should this depend on the page size? (PAGE_SIZE*2) */		unsigned int size = 8192;		if (size > count)			size = count;		ret = write(tty, file, buf, size);		if (ret <= 0)			break;		written += ret;		buf += ret;		count -= ret;		if (!count)			break;		ret = -ERESTARTSYS;		if (current->signal & ~current->blocked)			break;		if (need_resched)			schedule();	}	if (written) {		inode->i_mtime = CURRENT_TIME;		ret = written;	}	return ret;}static int tty_write(struct inode * inode, struct file * file, const char * buf, int count){	int is_console;	struct tty_struct * tty;	is_console = (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 || (tty->flags & (1 << TTY_IO_ERROR)))		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,		inode, tty, file,		(const unsigned char *)buf,		(unsigned int)count);}/* Semaphore to protect creating and releasing a tty */static struct semaphore tty_sem = MUTEX;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);/* * 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;	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 (GFP_KERNEL);	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 (GFP_KERNEL);		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:	retval = -EIO;	if (test_bit(TTY_CLOSING, &tty->flags))		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)			goto end_init;		tty->link->count++;	}	tty->count++;	tty->driver = *driver; /* N.B. why do this every time?? */success:	retval = 0;	*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_s(o_tp, sizeof(struct termios));	if (o_tty)		free_tty_struct(o_tty);	if (ltp)		kfree_s(ltp, sizeof(struct termios));	if (tp)		kfree_s(tp, sizeof(struct termios));	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("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_s(tp, sizeof(struct termios));		}		o_tty->magic = 0;		(*o_tty->driver.refcount)--;		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_s(tp, sizeof(struct termios));	}	tty->magic = 0;	(*tty->driver.refcount)--;	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. */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;		tty = (struct tty_struct *)filp->private_data;	if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev"))		return;	check_tty_count(tty, "release_dev");	tty_fasync(filp->f_inode, 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;

⌨️ 快捷键说明

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