📄 tty.c
字号:
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 + -