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

📄 tty.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	case OTIOCSETD:	case  TIOCSETN:	case  TIOCSETP:	case  TIOCSLTC:#endif		while (isbackground(curproc, tp) &&		    p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&		    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&		    (p->p_sigmask & sigmask(SIGTTOU)) == 0) {			pgsignal(p->p_pgrp, SIGTTOU, 1);			if (error = ttysleep(tp,			    &lbolt, TTOPRI | PCATCH, ttybg, 0))				return (error);		}		break;	}	switch (cmd) {			/* Process the ioctl. */	case FIOASYNC:			/* set/clear async i/o */		s = spltty();		if (*(int *)data)			SET(tp->t_state, TS_ASYNC);		else			CLR(tp->t_state, TS_ASYNC);		splx(s);		break;	case FIONBIO:			/* set/clear non-blocking i/o */		break;			/* XXX: delete. */	case FIONREAD:			/* get # bytes to read */		*(int *)data = ttnread(tp);		break;	case TIOCEXCL:			/* set exclusive use of tty */		s = spltty();		SET(tp->t_state, TS_XCLUDE);		splx(s);		break;	case TIOCFLUSH: {		/* flush buffers */		register int flags = *(int *)data;		if (flags == 0)			flags = FREAD | FWRITE;		else			flags &= FREAD | FWRITE;		ttyflush(tp, flags);		break;	}	case TIOCCONS:			/* become virtual console */		if (*(int *)data) {			if (constty && constty != tp &&			    ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==			    (TS_CARR_ON | TS_ISOPEN))				return (EBUSY);#ifndef	UCONSOLE			if (error = suser(p->p_ucred, &p->p_acflag))				return (error);#endif			constty = tp;		} else if (tp == constty)			constty = NULL;		break;	case TIOCDRAIN:			/* wait till output drained */		if (error = ttywait(tp))			return (error);		break;	case TIOCGETA: {		/* get termios struct */		struct termios *t = (struct termios *)data;		bcopy(&tp->t_termios, t, sizeof(struct termios));		break;	}	case TIOCGETD:			/* get line discipline */		*(int *)data = tp->t_line;		break;	case TIOCGWINSZ:		/* get window size */		*(struct winsize *)data = tp->t_winsize;		break;	case TIOCGPGRP:			/* get pgrp of tty */		if (!isctty(p, tp))			return (ENOTTY);		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;		break;#ifdef TIOCHPCL	case TIOCHPCL:			/* hang up on last close */		s = spltty();		SET(tp->t_cflag, HUPCL);		splx(s);		break;#endif	case TIOCNXCL:			/* reset exclusive use of tty */		s = spltty();		CLR(tp->t_state, TS_XCLUDE);		splx(s);		break;	case TIOCOUTQ:			/* output queue size */		*(int *)data = tp->t_outq.c_cc;		break;	case TIOCSETA:			/* set termios struct */	case TIOCSETAW:			/* drain output, set */	case TIOCSETAF: {		/* drn out, fls in, set */		register struct termios *t = (struct termios *)data;		s = spltty();		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {			if (error = ttywait(tp)) {				splx(s);				return (error);			}			if (cmd == TIOCSETAF)				ttyflush(tp, FREAD);		}		if (!ISSET(t->c_cflag, CIGNORE)) {			/*			 * Set device hardware.			 */			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {				splx(s);				return (error);			} else {				if (!ISSET(tp->t_state, TS_CARR_ON) &&				    ISSET(tp->t_cflag, CLOCAL) &&				    !ISSET(t->c_cflag, CLOCAL)) {					CLR(tp->t_state, TS_ISOPEN);					SET(tp->t_state, TS_WOPEN);					ttwakeup(tp);				}				tp->t_cflag = t->c_cflag;				tp->t_ispeed = t->c_ispeed;				tp->t_ospeed = t->c_ospeed;			}			ttsetwater(tp);		}		if (cmd != TIOCSETAF) {			if (ISSET(t->c_lflag, ICANON) !=			    ISSET(tp->t_lflag, ICANON))				if (ISSET(t->c_lflag, ICANON)) {					SET(tp->t_lflag, PENDIN);					ttwakeup(tp);				} else {					struct clist tq;					catq(&tp->t_rawq, &tp->t_canq);					tq = tp->t_rawq;					tp->t_rawq = tp->t_canq;					tp->t_canq = tq;					CLR(tp->t_lflag, PENDIN);				}		}		tp->t_iflag = t->c_iflag;		tp->t_oflag = t->c_oflag;		/*		 * Make the EXTPROC bit read only.		 */		if (ISSET(tp->t_lflag, EXTPROC))			SET(t->c_lflag, EXTPROC);		else			CLR(t->c_lflag, EXTPROC);		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));		splx(s);		break;	}	case TIOCSETD: {		/* set line discipline */		register int t = *(int *)data;		dev_t device = tp->t_dev;		if ((u_int)t >= nlinesw)			return (ENXIO);		if (t != tp->t_line) {			s = spltty();			(*linesw[tp->t_line].l_close)(tp, flag);			error = (*linesw[t].l_open)(device, tp);			if (error) {				(void)(*linesw[tp->t_line].l_open)(device, tp);				splx(s);				return (error);			}			tp->t_line = t;			splx(s);		}		break;	}	case TIOCSTART:			/* start output, like ^Q */		s = spltty();		if (ISSET(tp->t_state, TS_TTSTOP) ||		    ISSET(tp->t_lflag, FLUSHO)) {			CLR(tp->t_lflag, FLUSHO);			CLR(tp->t_state, TS_TTSTOP);			ttstart(tp);		}		splx(s);		break;	case TIOCSTI:			/* simulate terminal input */		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)			return (EPERM);		if (p->p_ucred->cr_uid && !isctty(p, tp))			return (EACCES);		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);		break;	case TIOCSTOP:			/* stop output, like ^S */		s = spltty();		if (!ISSET(tp->t_state, TS_TTSTOP)) {			SET(tp->t_state, TS_TTSTOP);#ifdef sun4c				/* XXX */			(*tp->t_stop)(tp, 0);#else			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);#endif		}		splx(s);		break;	case TIOCSCTTY:			/* become controlling tty */		/* Session ctty vnode pointer set in vnode layer. */		if (!SESS_LEADER(p) ||		    (p->p_session->s_ttyvp || tp->t_session) &&		    (tp->t_session != p->p_session))			return (EPERM);		tp->t_session = p->p_session;		tp->t_pgrp = p->p_pgrp;		p->p_session->s_ttyp = tp;		p->p_flag |= P_CONTROLT;		break;	case TIOCSPGRP: {		/* set pgrp of tty */		register struct pgrp *pgrp = pgfind(*(int *)data);		if (!isctty(p, tp))			return (ENOTTY);		else if (pgrp == NULL || pgrp->pg_session != p->p_session)			return (EPERM);		tp->t_pgrp = pgrp;		break;	}	case TIOCSWINSZ:		/* set window size */		if (bcmp((caddr_t)&tp->t_winsize, data,		    sizeof (struct winsize))) {			tp->t_winsize = *(struct winsize *)data;			pgsignal(tp->t_pgrp, SIGWINCH, 1);		}		break;	default:#if defined(COMPAT_43) || defined(COMPAT_SUNOS)		return (ttcompat(tp, cmd, data, flag));#else		return (-1);#endif	}	return (0);}intttselect(device, rw, p)	dev_t device;	int rw;	struct proc *p;{	register struct tty *tp;	int nread, s;	tp = &cdevsw[major(device)].d_ttys[minor(device)];	s = spltty();	switch (rw) {	case FREAD:		nread = ttnread(tp);		if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&		    !ISSET(tp->t_state, TS_CARR_ON))			goto win;		selrecord(p, &tp->t_rsel);		break;	case FWRITE:		if (tp->t_outq.c_cc <= tp->t_lowat) {win:			splx(s);			return (1);		}		selrecord(p, &tp->t_wsel);		break;	}	splx(s);	return (0);}static intttnread(tp)	struct tty *tp;{	int nread;	if (ISSET(tp->t_lflag, PENDIN))		ttypend(tp);	nread = tp->t_canq.c_cc;	if (!ISSET(tp->t_lflag, ICANON))		nread += tp->t_rawq.c_cc;	return (nread);}/* * Wait for output to drain. */intttywait(tp)	register struct tty *tp;{	int error, s;	error = 0;	s = spltty();	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&	    (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))	    && tp->t_oproc) {		(*tp->t_oproc)(tp);		SET(tp->t_state, TS_ASLEEP);		if (error = ttysleep(tp,		    &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))			break;	}	splx(s);	return (error);}/* * Flush if successfully wait. */intttywflush(tp)	struct tty *tp;{	int error;	if ((error = ttywait(tp)) == 0)		ttyflush(tp, FREAD);	return (error);}/* * Flush tty read and/or write queues, notifying anyone waiting. */voidttyflush(tp, rw)	register struct tty *tp;	int rw;{	register int s;	s = spltty();	if (rw & FREAD) {		FLUSHQ(&tp->t_canq);		FLUSHQ(&tp->t_rawq);		tp->t_rocount = 0;		tp->t_rocol = 0;		CLR(tp->t_state, TS_LOCAL);		ttwakeup(tp);	}	if (rw & FWRITE) {		CLR(tp->t_state, TS_TTSTOP);#ifdef sun4c						/* XXX */		(*tp->t_stop)(tp, rw);#else		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);#endif		FLUSHQ(&tp->t_outq);		wakeup((caddr_t)&tp->t_outq);		selwakeup(&tp->t_wsel);	}	splx(s);}/* * Copy in the default termios characters. */voidttychars(tp)	struct tty *tp;{	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));}/* * Send stop character on input overflow. */static voidttyblock(tp)	register struct tty *tp;{	register int total;	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;	if (tp->t_rawq.c_cc > TTYHOG) {		ttyflush(tp, FREAD | FWRITE);		CLR(tp->t_state, TS_TBLOCK);	}	/*	 * Block further input iff: current input > threshold	 * AND input is available to user program.	 */	if (total >= TTYHOG / 2 &&	    !ISSET(tp->t_state, TS_TBLOCK) &&	    !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {			SET(tp->t_state, TS_TBLOCK);			ttstart(tp);		}	}}voidttrstrt(tp_arg)	void *tp_arg;{	struct tty *tp;	int s;#ifdef DIAGNOSTIC	if (tp_arg == NULL)		panic("ttrstrt");#endif	tp = tp_arg;	s = spltty();	CLR(tp->t_state, TS_TIMEOUT);	ttstart(tp);	splx(s);}intttstart(tp)	struct tty *tp;{	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */		(*tp->t_oproc)(tp);	return (0);}/* * "close" a line discipline */intttylclose(tp, flag)	struct tty *tp;	int flag;{	if (flag & IO_NDELAY)		ttyflush(tp, FREAD | FWRITE);	else		ttywflush(tp);	return (0);}/* * Handle modem control transition on a tty. * Flag indicates new state of carrier. * Returns 0 if the line should be turned off, otherwise 1. */intttymodem(tp, flag)	register struct tty *tp;	int flag;{	if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {		/*		 * MDMBUF: do flow control according to carrier flag		 */		if (flag) {			CLR(tp->t_state, TS_TTSTOP);			ttstart(tp);		} else if (!ISSET(tp->t_state, TS_TTSTOP)) {			SET(tp->t_state, TS_TTSTOP);#ifdef sun4c						/* XXX */			(*tp->t_stop)(tp, 0);#else			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);#endif		}	} else if (flag == 0) {		/*		 * Lost carrier.		 */		CLR(tp->t_state, TS_CARR_ON);		if (ISSET(tp->t_state, TS_ISOPEN) &&		    !ISSET(tp->t_cflag, CLOCAL)) {			if (tp->t_session && tp->t_session->s_leader)				psignal(tp->t_session->s_leader, SIGHUP);			ttyflush(tp, FREAD | FWRITE);			return (0);		}	} else {		/*		 * Carrier now on.		 */		SET(tp->t_state, TS_CARR_ON);		ttwakeup(tp);	}	return (1);}/* * Default modem control routine (for other line disciplines). * Return argument flag, to turn off device on carrier drop. */intnullmodem(tp, flag)	register struct tty *tp;	int flag;{	if (flag)		SET(tp->t_state, TS_CARR_ON);	else {		CLR(tp->t_state, TS_CARR_ON);		if (!ISSET(tp->t_cflag, CLOCAL)) {			if (tp->t_session && tp->t_session->s_leader)				psignal(tp->t_session->s_leader, SIGHUP);			return (0);		}	}	return (1);}/* * Reinput pending characters after state switch * call at spltty(). */voidttypend(tp)	register struct tty *tp;{	struct clist tq;	register c;	CLR(tp->t_lflag, PENDIN);	SET(tp->t_state, TS_TYPEN);	tq = tp->t_rawq;	tp->t_rawq.c_cc = 0;	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;	while ((c = getc(&tq)) >= 0)		ttyinput(c, tp);	CLR(tp->t_state, TS_TYPEN);}/* * Process a read call on a tty device. */intttread(tp, uio, flag)	register struct tty *tp;	struct uio *uio;	int flag;{	register struct clist *qp;	register int c;	register long lflag;	register u_char *cc = tp->t_cc;	register struct proc *p = curproc;	int s, first, error = 0;loop:	lflag = tp->t_lflag;	s = spltty();	/*	 * take pending input first	 */	if (ISSET(lflag, PENDIN))		ttypend(tp);	splx(s);	/*	 * Hang process if it's in the background.	 */	if (isbackground(p, tp)) {		if ((p->p_sigignore & sigmask(SIGTTIN)) ||		   (p->p_sigmask & sigmask(SIGTTIN)) ||		    p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)			return (EIO);		pgsignal(p->p_pgrp, SIGTTIN, 1);		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))			return (error);		goto loop;	}	/*	 * If canonical, use the canonical queue,	 * else use the raw queue.	 *	 * (should get rid of clists...)	 */	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;	/*	 * If there is no input, sleep on rawq	 * awaiting hardware receipt and notification.	 * If we have data, we don't need to check for carrier.	 */	s = spltty();	if (qp->c_cc <= 0) {		int carrier;		carrier = ISSET(tp->t_state, TS_CARR_ON) ||		    ISSET(tp->t_cflag, CLOCAL);		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {			splx(s);			return (0);	/* EOF */		}		if (flag & IO_NDELAY) {			splx(s);			return (EWOULDBLOCK);		}		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,		    carrier ? ttyin : ttopen, 0);		splx(s);		if (error)			return (error);		goto loop;	}	splx(s);	/*	 * Input present, check for input mapping and processing.	 */	first = 1;	while ((c = getc(qp)) >= 0) {		/*		 * delayed suspend (^Y)		 */		if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {			pgsignal(tp->t_pgrp, SIGTSTP, 1);			if (first) {				if (error = ttysleep(tp,				    &lbolt, TTIPRI | PCATCH, ttybg, 0))					break;				goto loop;			}			break;		}		/*		 * Interpret EOF only in canonical mode.		 */		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))			break;		/*

⌨️ 快捷键说明

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