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

📄 tty_io.c

📁 unix/linux 编程实践一书的所有源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		kfree_s(o_tp, sizeof(struct termios));	if (o_tty)		free_page((unsigned long) o_tty);	if (ltp)		kfree_s(ltp, sizeof(struct termios));	if (tp)		kfree_s(tp, sizeof(struct termios));	free_page((unsigned long) 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_page((unsigned long) 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_page((unsigned long) 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;#ifdef TTY_PARANOIA_CHECK	if (idx < 0 || idx >= tty->driver.num) {		printk("release_dev: bad idx when trying to free (%s)\n",		       kdevname(tty->device));		return;	}	if (tty != tty->driver.table[idx]) {		printk("release_dev: driver.table[%d] not tty for (%s)\n",		       idx, kdevname(tty->device));		return;	}	if (tty->termios != tty->driver.termios[idx]) {		printk("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("release_dev: driver.termios_locked[%d] not "		       "termios_locked for (%s)\n",		       idx, kdevname(tty->device));		return;	}#endif#ifdef TTY_DEBUG_HANGUP	printk("release_dev of %s (tty count=%d)...", tty_name(tty),	       tty->count);#endif#ifdef TTY_PARANOIA_CHECK	if (tty->driver.other) {		if (o_tty != tty->driver.other->table[idx]) {			printk("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("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("release_dev: other->termios_locked[%d] not "			       "o_termios_locked for (%s)\n",			       idx, kdevname(tty->device));			return;		}		if (o_tty->link != tty) {			printk("release_dev: bad pty pointers\n");			return;		}	}#endif	/*	 * 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("release_dev: %s: read/write wait queue active!\n",		       tty_name(tty));		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 (tty->driver.close)		tty->driver.close(tty, filp);	if (pty_master) {		if (--o_tty->count < 0) {			printk("release_dev: bad pty slave count (%d) for %s\n",			       o_tty->count, tty_name(o_tty));			o_tty->count = 0;		}	}	if (--tty->count < 0) {		printk("release_dev: bad tty->count (%d) for %s\n",		       tty->count, tty_name(tty));		tty->count = 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;		for_each_task(p) {			if (p->tty == tty || (o_tty && p->tty == o_tty))				p->tty = NULL;		}		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;	filp->private_data = 0;	#ifdef TTY_DEBUG_HANGUP	printk("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.  If it	 * is, take it out of the linked list.  The tqueue isn't used by	 * pty's, so skip the test for them.	 */	if (tty->driver.type != TTY_DRIVER_TYPE_PTY) {		cli();		if (tty->flip.tqueue.sync) {			struct tq_struct *tq, *prev;			for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {				if (tq == &tty->flip.tqueue) {					if (prev)						prev->next = tq->next;					else						tq_timer = tq->next;					break;				}			}		}		sti();	}	/* 	 * 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 minor;	int noctty, retval;	kdev_t device;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;		/* noctty = 1; */	}	if (device == CONSOLE_DEV) {		device = MKDEV(TTY_MAJOR, fg_console+1);		noctty = 1;	}	minor = MINOR(device);		retval = init_dev(device, &tty);	if (retval)		return retval;	filp->private_data = tty;	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("opening %s...", tty_name(tty));#endif	if (tty->driver.open)		retval = tty->driver.open(tty, filp);	else		retval = -ENODEV;	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())		retval = -EBUSY;	if (retval) {#ifdef TTY_DEBUG_HANGUP		printk("error %d in opening %s...", retval, tty_name(tty));#endif		release_dev(filp);		if (retval != -ERESTARTSYS)			return retval;		if (current->signal & ~current->blocked)			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) {		current->tty = tty;		current->tty_old_pgrp = 0;		tty->session = current->session;		tty->pgrp = current->pgrp;	}	return 0;}static void tty_release(struct inode * inode, struct file * filp){	release_dev(filp);}static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait){	struct tty_struct * tty;	tty = (struct tty_struct *)filp->private_data;	if (tty_paranoia_check(tty, inode->i_rdev, "tty_select"))		return 0;	if (tty->ldisc.select)		return (tty->ldisc.select)(tty, inode, filp, sel_type, wait);	return 0;}/* * fasync_helper() is used by some character device drivers (mainly mice) * to set up the fasync queue. It returns negative on error, 0 if it did * no changes and positive if it added/deleted the entry. */int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasync_struct **fapp){	struct fasync_struct *fa, **fp;	unsigned long flags;	for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {		if (fa->fa_file == filp)			break;	}	if (on) {		if (fa)			return 0;		fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);		if (!fa)			return -ENOMEM;		fa->magic = FASYNC_MAGIC;		fa->fa_file = filp;		save_flags(flags);		cli();		fa->fa_next = *fapp;		*fapp = fa;		restore_flags(flags);		return 1;	}	if (!fa)		return 0;	save_flags(flags);	cli();	*fp = fa->fa_next;	restore_flags(flags);	kfree(fa);	return 1;}static int tty_fasync(struct inode * inode, struct file * filp, int on){	struct tty_struct * tty;	int retval;	tty = (struct tty_struct *)filp->private_data;	if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))		return 0;		retval = fasync_helper(inode, 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;}#if 0/* * XXX does anyone use this anymore?!? */static int do_get_ps_info(unsigned long arg){	struct tstruct {		int flag;		int present[NR_TASKS];		struct task_struct tasks[NR_TASKS];	};	struct tstruct *ts = (struct tstruct *)arg;	struct task_struct **p;	char *c, *d;	int i, n = 0;		i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));	if (i)		return i;	for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)		if (*p)		{			c = (char *)(*p);			d = (char *)(ts->tasks+n);			for (i=0 ; i<sizeof(struct task_struct) ; i++)				put_user(*c++, d++);			put_user(1, ts->present+n);		}		else				put_user(0, ts->present+n);	return(0);			}#endifstatic int tty_ioctl(struct inode * inode, struct file * file,		     unsigned int cmd, unsigned long arg){	int	retval;	struct tty_struct * tty;	struct tty_struct * real_tty;	struct winsize tmp_ws;	pid_t pgrp;	unsigned char	ch;	char	mbz = 0;		tty = (struct tty_struct *)file->private_data;	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))		return -EINVAL;	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 TIOCSTI:			if ((current->tty != tty) && !suser())				return -EPERM;			retval = verify_area(VERIFY_READ, (void *) arg, 1);

⌨️ 快捷键说明

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