1/* Copyright (c) 1993-2002
2 *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20 *
21 ****************************************************************
22 */
23
24/*
25 * NOTICE: tty.c is automatically generated from tty.sh
26 * Do not change anything here. If you then change tty.sh.
27 */
28
29#include <sys/types.h>
30#include <signal.h>
31#include <fcntl.h>
32#ifndef sgi
33# include <sys/file.h>
34#endif
35#if !defined(sun) || defined(SUNOS3)
36# include <sys/ioctl.h> /* collosions with termios.h */
37#else
38# ifndef TIOCEXCL
39#  include <sys/ttold.h>	/* needed for TIOCEXCL */
40# endif
41#endif
42#ifdef __hpux
43# include <sys/modem.h>
44#endif
45
46#ifdef ISC
47# include <sys/tty.h>
48# include <sys/sioctl.h>
49# include <sys/pty.h>
50#endif
51
52#include "config.h"
53#ifdef SVR4
54#include <sys/stropts.h>	/* for I_POP */
55#endif
56
57#include "screen.h"
58#include "extern.h"
59
60#if !defined(TIOCCONS) && defined(sun) && defined(SVR4)
61# include <sys/strredir.h>
62#endif
63
64extern struct display *display, *displays;
65extern int iflag;
66#if (!defined(TIOCCONS) && defined(SRIOCSREDIR)) || defined(linux)
67extern struct win *console_window;
68static void consredir_readev_fn __P((struct event *, char *));
69#endif
70
71int separate_sids = 1;
72
73static void DoSendBreak __P((int, int, int));
74static sigret_t SigAlrmDummy __P(SIGPROTOARG);
75
76
77/* Frank Schulz (fschulz@pyramid.com):
78 * I have no idea why VSTART is not defined and my fix is probably not
79 * the cleanest, but it works.
80 */
81#if !defined(VSTART) && defined(_VSTART)
82#define VSTART _VSTART
83#endif
84#if !defined(VSTOP) && defined(_VSTOP)
85#define VSTOP _VSTOP
86#endif
87
88#ifndef O_NOCTTY
89# define O_NOCTTY 0
90#endif
91
92#ifndef TTYVMIN
93# define TTYVMIN 1
94#endif
95#ifndef TTYVTIME
96#define TTYVTIME 0
97#endif
98
99
100static sigret_t
101SigAlrmDummy SIGDEFARG
102{
103  debug("SigAlrmDummy()\n");
104  SIGRETURN;
105}
106
107/*
108 *  Carefully open a charcter device. Not used to open display ttys.
109 *  The second parameter is parsed for a few stty style options.
110 */
111
112int
113OpenTTY(line, opt)
114char *line, *opt;
115{
116  int f;
117  struct mode Mode;
118  sigret_t (*sigalrm)__P(SIGPROTOARG);
119
120  sigalrm = signal(SIGALRM, SigAlrmDummy);
121  alarm(2);
122
123  /* this open only succeeds, if real uid is allowed */
124  if ((f = secopen(line, O_RDWR | O_NONBLOCK | O_NOCTTY, 0)) == -1)
125    {
126      if (errno == EINTR)
127        Msg(0, "Cannot open line '%s' for R/W: open() blocked, aborted.", line);
128      else
129        Msg(errno, "Cannot open line '%s' for R/W", line);
130      alarm(0);
131      signal(SIGALRM, sigalrm);
132      return -1;
133    }
134  if (!isatty(f))
135    {
136      Msg(0, "'%s' is not a tty", line);
137      alarm(0);
138      signal(SIGALRM, sigalrm);
139      close(f);
140      return -1;
141    }
142#if defined(I_POP) && defined(POP_TTYMODULES)
143  debug("OpenTTY I_POP\n");
144  while (ioctl(f, I_POP, (char *)0) >= 0)
145    ;
146#endif
147  /*
148   * We come here exclusively. This is to stop all kermit and cu type things
149   * accessing the same tty line.
150   * Perhaps we should better create a lock in some /usr/spool/locks directory?
151   */
152#ifdef TIOCEXCL
153 errno = 0;
154 if (ioctl(f, TIOCEXCL, (char *) 0) < 0)
155   Msg(errno, "%s: ioctl TIOCEXCL failed", line);
156 debug3("%d %d %d\n", getuid(), geteuid(), getpid());
157 debug2("%s TIOCEXCL errno %d\n", line, errno);
158#endif  /* TIOCEXCL */
159  /*
160   * We create a sane tty mode. We do not copy things from the display tty
161   */
162#if WE_REALLY_WANT_TO_COPY_THE_TTY_MODE
163  if (display)
164    {
165      debug1("OpenTTY: using mode of display for %s\n", line);
166      Mode = D_NewMode;
167    }
168  else
169#endif
170    InitTTY(&Mode, W_TYPE_PLAIN);
171
172  SttyMode(&Mode, opt);
173#ifdef DEBUG
174  DebugTTY(&Mode);
175#endif
176  SetTTY(f, &Mode);
177
178#if defined(linux) && defined(TIOCMSET)
179  {
180    int mcs = 0;
181    ioctl(f, TIOCMGET, &mcs);
182    mcs |= TIOCM_RTS;
183    ioctl(f, TIOCMSET, &mcs);
184  }
185#endif
186
187  brktty(f);
188  alarm(0);
189  signal(SIGALRM, sigalrm);
190  debug2("'%s' CONNECT fd=%d.\n", line, f);
191  return f;
192}
193
194
195/*
196 *  Tty mode handling
197 */
198
199void
200InitTTY(m, ttyflag)
201struct mode *m;
202int ttyflag;
203{
204  bzero((char *)m, sizeof(*m));
205#ifdef POSIX
206  /* struct termios tio
207   * defaults, as seen on SunOS 4.1.3
208   */
209  debug1("InitTTY: POSIX: termios defaults based on SunOS 4.1.3, but better (%d)\n", ttyflag);
210#if defined(BRKINT)
211	m->tio.c_iflag |= BRKINT;
212#endif /* BRKINT */
213#if defined(IGNPAR)
214	m->tio.c_iflag |= IGNPAR;
215#endif /* IGNPAR */
216/* IF{ISTRIP}	m->tio.c_iflag |= ISTRIP;  may be needed, let's try. jw. */
217#if defined(IXON)
218	m->tio.c_iflag |= IXON;
219#endif /* IXON */
220/* IF{IMAXBEL}	m->tio.c_iflag |= IMAXBEL; sorry, this one is ridiculus. jw */
221
222  if (!ttyflag)	/* may not even be good for ptys.. */
223    {
224#if defined(ICRNL)
225	m->tio.c_iflag |= ICRNL;
226#endif /* ICRNL */
227#if defined(ONLCR)
228	m->tio.c_oflag |= ONLCR;
229#endif /* ONLCR */
230#if defined(TAB3)
231	m->tio.c_oflag |= TAB3;
232#endif /* TAB3 */
233#if defined(OXTABS)
234      m->tio.c_oflag |= OXTABS;
235#endif /* OXTABS */
236/* IF{PARENB}	m->tio.c_cflag |= PARENB;	nah! jw. */
237#if defined(OPOST)
238	m->tio.c_oflag |= OPOST;
239#endif /* OPOST */
240    }
241
242
243/*
244 * Or-ing the speed into c_cflags is dangerous.
245 * It breaks on bsdi, where c_ispeed and c_ospeed are extra longs.
246 *
247 * IF{B9600}    m->tio.c_cflag |= B9600;
248 * IF{IBSHIFT) && defined(B9600}        m->tio.c_cflag |= B9600 << IBSHIFT;
249 *
250 * We hope that we have the posix calls to do it right:
251 * If these are not available you might try the above.
252 */
253#if defined(B9600)
254       cfsetospeed(&m->tio, B9600);
255#endif /* B9600 */
256#if defined(B9600)
257       cfsetispeed(&m->tio, B9600);
258#endif /* B9600 */
259
260#if defined(CS8)
261 	m->tio.c_cflag |= CS8;
262#endif /* CS8 */
263#if defined(CREAD)
264	m->tio.c_cflag |= CREAD;
265#endif /* CREAD */
266#if defined(CLOCAL)
267	m->tio.c_cflag |= CLOCAL;
268#endif /* CLOCAL */
269
270#if defined(ECHOCTL)
271	m->tio.c_lflag |= ECHOCTL;
272#endif /* ECHOCTL */
273#if defined(ECHOKE)
274	m->tio.c_lflag |= ECHOKE;
275#endif /* ECHOKE */
276
277  if (!ttyflag)
278    {
279#if defined(ISIG)
280	m->tio.c_lflag |= ISIG;
281#endif /* ISIG */
282#if defined(ICANON)
283	m->tio.c_lflag |= ICANON;
284#endif /* ICANON */
285#if defined(ECHO)
286	m->tio.c_lflag |= ECHO;
287#endif /* ECHO */
288    }
289#if defined(ECHOE)
290	m->tio.c_lflag |= ECHOE;
291#endif /* ECHOE */
292#if defined(ECHOK)
293	m->tio.c_lflag |= ECHOK;
294#endif /* ECHOK */
295#if defined(IEXTEN)
296	m->tio.c_lflag |= IEXTEN;
297#endif /* IEXTEN */
298
299#if defined(VINTR)
300#if (VINTR < MAXCC)
301	m->tio.c_cc[VINTR]    = Ctrl('C');
302#endif
303#endif /* VINTR */
304#if defined(VQUIT)
305#if (VQUIT < MAXCC)
306	m->tio.c_cc[VQUIT]    = Ctrl('\\');
307#endif
308#endif /* VQUIT */
309#if defined(VERASE)
310#if (VERASE < MAXCC)
311	m->tio.c_cc[VERASE]   = 0x7f; /* DEL */
312#endif
313#endif /* VERASE */
314#if defined(VKILL)
315#if (VKILL < MAXCC)
316	m->tio.c_cc[VKILL]    = Ctrl('H');
317#endif
318#endif /* VKILL */
319#if defined(VEOF)
320#if (VEOF < MAXCC)
321	m->tio.c_cc[VEOF]     = Ctrl('D');
322#endif
323#endif /* VEOF */
324#if defined(VEOL)
325#if (VEOL < MAXCC)
326	m->tio.c_cc[VEOL]     = 0000;
327#endif
328#endif /* VEOL */
329#if defined(VEOL2)
330#if (VEOL2 < MAXCC)
331	m->tio.c_cc[VEOL2]    = 0000;
332#endif
333#endif /* VEOL2 */
334#if defined(VSWTCH)
335#if (VSWTCH < MAXCC)
336	m->tio.c_cc[VSWTCH]   = 0000;
337#endif
338#endif /* VSWTCH */
339#if defined(VSTART)
340#if (VSTART < MAXCC)
341	m->tio.c_cc[VSTART]   = Ctrl('Q');
342#endif
343#endif /* VSTART */
344#if defined(VSTOP)
345#if (VSTOP < MAXCC)
346	m->tio.c_cc[VSTOP]    = Ctrl('S');
347#endif
348#endif /* VSTOP */
349#if defined(VSUSP)
350#if (VSUSP < MAXCC)
351	m->tio.c_cc[VSUSP]    = Ctrl('Z');
352#endif
353#endif /* VSUSP */
354#if defined(VDSUSP)
355#if (VDSUSP < MAXCC)
356	m->tio.c_cc[VDSUSP]   = Ctrl('Y');
357#endif
358#endif /* VDSUSP */
359#if defined(VREPRINT)
360#if (VREPRINT < MAXCC)
361	m->tio.c_cc[VREPRINT] = Ctrl('R');
362#endif
363#endif /* VREPRINT */
364#if defined(VDISCARD)
365#if (VDISCARD < MAXCC)
366	m->tio.c_cc[VDISCARD] = Ctrl('O');
367#endif
368#endif /* VDISCARD */
369#if defined(VWERASE)
370#if (VWERASE < MAXCC)
371	m->tio.c_cc[VWERASE]  = Ctrl('W');
372#endif
373#endif /* VWERASE */
374#if defined(VLNEXT)
375#if (VLNEXT < MAXCC)
376	m->tio.c_cc[VLNEXT]   = Ctrl('V');
377#endif
378#endif /* VLNEXT */
379#if defined(VSTATUS)
380#if (VSTATUS < MAXCC)
381	m->tio.c_cc[VSTATUS]  = Ctrl('T');
382#endif
383#endif /* VSTATUS */
384
385  if (ttyflag)
386    {
387      m->tio.c_cc[VMIN] = TTYVMIN;
388      m->tio.c_cc[VTIME] = TTYVTIME;
389    }
390
391# ifdef HPUX_LTCHARS_HACK
392  m->m_ltchars.t_suspc =  Ctrl('Z');
393  m->m_ltchars.t_dsuspc = Ctrl('Y');
394  m->m_ltchars.t_rprntc = Ctrl('R');
395  m->m_ltchars.t_flushc = Ctrl('O');
396  m->m_ltchars.t_werasc = Ctrl('W');
397  m->m_ltchars.t_lnextc = Ctrl('V');
398# endif /* HPUX_LTCHARS_HACK */
399
400#else /* POSIX */
401
402# ifdef TERMIO
403  debug1("InitTTY: nonPOSIX, struct termio a la Motorola SYSV68 (%d)\n", ttyflag);
404  /* struct termio tio
405   * defaults, as seen on Mototola SYSV68:
406   * input: 7bit, CR->NL, ^S/^Q flow control
407   * output: POSTprocessing: NL->NL-CR, Tabs to spaces
408   * control: 9600baud, 8bit CSIZE, enable input
409   * local: enable signals, erase/kill processing, echo on.
410   */
411#if defined(ISTRIP)
412	m->tio.c_iflag |= ISTRIP;
413#endif /* ISTRIP */
414#if defined(IXON)
415	m->tio.c_iflag |= IXON;
416#endif /* IXON */
417
418  if (!ttyflag)	/* may not even be good for ptys.. */
419    {
420#if defined(OPOST)
421	m->tio.c_oflag |= OPOST;
422#endif /* OPOST */
423#if defined(ICRNL)
424	m->tio.c_iflag |= ICRNL;
425#endif /* ICRNL */
426#if defined(ONLCR)
427	m->tio.c_oflag |= ONLCR;
428#endif /* ONLCR */
429#if defined(TAB3)
430	m->tio.c_oflag |= TAB3;
431#endif /* TAB3 */
432    }
433
434#ifdef __bsdi__
435		)-: cannot handle BSDI without POSIX
436#else
437#if defined(B9600)
438	m->tio.c_cflag  = B9600;
439#endif /* B9600 */
440#endif
441#if defined(CS8)
442 	m->tio.c_cflag |= CS8;
443#endif /* CS8 */
444#if defined(CREAD)
445	m->tio.c_cflag |= CREAD;
446#endif /* CREAD */
447
448  if (!ttyflag)
449    {
450#if defined(ISIG)
451	m->tio.c_lflag |= ISIG;
452#endif /* ISIG */
453#if defined(ICANON)
454	m->tio.c_lflag |= ICANON;
455#endif /* ICANON */
456#if defined(ECHO)
457	m->tio.c_lflag |= ECHO;
458#endif /* ECHO */
459    }
460#if defined(ECHOE)
461	m->tio.c_lflag |= ECHOE;
462#endif /* ECHOE */
463#if defined(ECHOK)
464	m->tio.c_lflag |= ECHOK;
465#endif /* ECHOK */
466
467#if defined(VINTR)
468#if (VINTR < MAXCC)
469	m->tio.c_cc[VINTR]  = Ctrl('C');
470#endif
471#endif /* VINTR */
472#if defined(VQUIT)
473#if (VQUIT < MAXCC)
474	m->tio.c_cc[VQUIT]  = Ctrl('\\');
475#endif
476#endif /* VQUIT */
477#if defined(VERASE)
478#if (VERASE < MAXCC)
479	m->tio.c_cc[VERASE] = 0177; /* DEL */
480#endif
481#endif /* VERASE */
482#if defined(VKILL)
483#if (VKILL < MAXCC)
484	m->tio.c_cc[VKILL]  = Ctrl('H');
485#endif
486#endif /* VKILL */
487#if defined(VEOF)
488#if (VEOF < MAXCC)
489	m->tio.c_cc[VEOF]   = Ctrl('D');
490#endif
491#endif /* VEOF */
492#if defined(VEOL)
493#if (VEOL < MAXCC)
494	m->tio.c_cc[VEOL]   = 0377;
495#endif
496#endif /* VEOL */
497#if defined(VEOL2)
498#if (VEOL2 < MAXCC)
499	m->tio.c_cc[VEOL2]  = 0377;
500#endif
501#endif /* VEOL2 */
502#if defined(VSWTCH)
503#if (VSWTCH < MAXCC)
504	m->tio.c_cc[VSWTCH] = 0000;
505#endif
506#endif /* VSWTCH */
507
508  if (ttyflag)
509   {
510      m->tio.c_cc[VMIN] = TTYVMIN;
511      m->tio.c_cc[VTIME] = TTYVTIME;
512    }
513
514# else /* TERMIO */
515  debug1("InitTTY: BSD: defaults a la SunOS 4.1.3 (%d)\n", ttyflag);
516  m->m_ttyb.sg_ispeed = B9600;
517  m->m_ttyb.sg_ospeed = B9600;
518  m->m_ttyb.sg_erase  = 0177; /*DEL */
519  m->m_ttyb.sg_kill   = Ctrl('H');
520  if (!ttyflag)
521    m->m_ttyb.sg_flags = CRMOD | ECHO
522#if defined(ANYP)
523	| ANYP
524#endif /* ANYP */
525    ;
526  else
527    m->m_ttyb.sg_flags = CBREAK
528#if defined(ANYP)
529	| ANYP
530#endif /* ANYP */
531    ;
532
533  m->m_tchars.t_intrc   = Ctrl('C');
534  m->m_tchars.t_quitc   = Ctrl('\\');
535  m->m_tchars.t_startc  = Ctrl('Q');
536  m->m_tchars.t_stopc   = Ctrl('S');
537  m->m_tchars.t_eofc    = Ctrl('D');
538  m->m_tchars.t_brkc    = -1;
539
540  m->m_ltchars.t_suspc  = Ctrl('Z');
541  m->m_ltchars.t_dsuspc = Ctrl('Y');
542  m->m_ltchars.t_rprntc = Ctrl('R');
543  m->m_ltchars.t_flushc = Ctrl('O');
544  m->m_ltchars.t_werasc = Ctrl('W');
545  m->m_ltchars.t_lnextc = Ctrl('V');
546
547#if defined(NTTYDISC)
548	m->m_ldisc = NTTYDISC;
549#endif /* NTTYDISC */
550
551  m->m_lmode = 0
552#if defined(LDECCTQ)
553	| LDECCTQ
554#endif /* LDECCTQ */
555#if defined(LCTLECH)
556	| LCTLECH
557#endif /* LCTLECH */
558#if defined(LPASS8)
559	| LPASS8
560#endif /* LPASS8 */
561#if defined(LCRTKIL)
562	| LCRTKIL
563#endif /* LCRTKIL */
564#if defined(LCRTERA)
565	| LCRTERA
566#endif /* LCRTERA */
567#if defined(LCRTBS)
568	| LCRTBS
569#endif /* LCRTBS */
570  ;
571# endif /* TERMIO */
572#endif /* POSIX */
573
574#if defined(ENCODINGS) && defined(TIOCKSET)
575  m->m_jtchars.t_ascii = 'J';
576  m->m_jtchars.t_kanji = 'B';
577  m->m_knjmode = KM_ASCII | KM_SYSSJIS;
578#endif
579}
580
581void
582SetTTY(fd, mp)
583int fd;
584struct mode *mp;
585{
586  errno = 0;
587#ifdef POSIX
588  tcsetattr(fd, TCSADRAIN, &mp->tio);
589# ifdef HPUX_LTCHARS_HACK
590  ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars);
591# endif
592#else
593# ifdef TERMIO
594  ioctl(fd, TCSETAW, (char *)&mp->tio);
595#  ifdef CYTERMIO
596  if (mp->tio.c_line == 3)
597    {
598      ioctl(fd, LDSETMAPKEY, (char *)&mp->m_mapkey);
599      ioctl(fd, LDSETMAPSCREEN, (char *)&mp->m_mapscreen);
600      ioctl(fd, LDSETBACKSPACE, (char *)&mp->m_backspace);
601    }
602#  endif
603# else
604  /* ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb); */
605  ioctl(fd, TIOCSETC, (char *)&mp->m_tchars);
606  ioctl(fd, TIOCLSET, (char *)&mp->m_lmode);
607  ioctl(fd, TIOCSETD, (char *)&mp->m_ldisc);
608  ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb);
609  ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars); /* moved here for apollo. jw */
610# endif
611#endif
612#if defined(ENCODINGS) && defined(TIOCKSET)
613  ioctl(fd, TIOCKSETC, &mp->m_jtchars);
614  ioctl(fd, TIOCKSET, &mp->m_knjmode);
615#endif
616  if (errno)
617    Msg(errno, "SetTTY (fd %d): ioctl failed", fd);
618}
619
620void
621GetTTY(fd, mp)
622int fd;
623struct mode *mp;
624{
625  errno = 0;
626#ifdef POSIX
627  tcgetattr(fd, &mp->tio);
628# ifdef HPUX_LTCHARS_HACK
629  ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
630# endif
631#else
632# ifdef TERMIO
633  ioctl(fd, TCGETA, (char *)&mp->tio);
634#  ifdef CYTERMIO
635  if (mp->tio.c_line == 3)
636    {
637      ioctl(fd, LDGETMAPKEY, (char *)&mp->m_mapkey);
638      ioctl(fd, LDGETMAPSCREEN, (char *)&mp->m_mapscreen);
639      ioctl(fd, LDGETBACKSPACE, (char *)&mp->m_backspace);
640    }
641  else
642    {
643      mp->m_mapkey = NOMAPKEY;
644      mp->m_mapscreen = NOMAPSCREEN;
645      mp->m_backspace = '\b';
646    }
647#  endif
648# else
649  ioctl(fd, TIOCGETP, (char *)&mp->m_ttyb);
650  ioctl(fd, TIOCGETC, (char *)&mp->m_tchars);
651  ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
652  ioctl(fd, TIOCLGET, (char *)&mp->m_lmode);
653  ioctl(fd, TIOCGETD, (char *)&mp->m_ldisc);
654# endif
655#endif
656#if defined(ENCODINGS) && defined(TIOCKSET)
657  ioctl(fd, TIOCKGETC, &mp->m_jtchars);
658  ioctl(fd, TIOCKGET, &mp->m_knjmode);
659#endif
660  if (errno)
661    Msg(errno, "GetTTY (fd %d): ioctl failed", fd);
662}
663
664/*
665 * needs interrupt = iflag and flow = d->d_flow
666 */
667void
668SetMode(op, np, flow, interrupt)
669struct mode *op, *np;
670int flow, interrupt;
671{
672  *np = *op;
673
674  ASSERT(display);
675#if defined(TERMIO) || defined(POSIX)
676# ifdef CYTERMIO
677  np->m_mapkey = NOMAPKEY;
678  np->m_mapscreen = NOMAPSCREEN;
679  np->tio.c_line = 0;
680# endif
681#if defined(ICRNL)
682  np->tio.c_iflag &= ~ICRNL;
683#endif /* ICRNL */
684#if defined(ISTRIP)
685  np->tio.c_iflag &= ~ISTRIP;
686#endif /* ISTRIP */
687#if defined(ONLCR)
688  np->tio.c_oflag &= ~ONLCR;
689#endif /* ONLCR */
690  np->tio.c_lflag &= ~(ICANON | ECHO);
691  /*
692   * From Andrew Myers (andru@tonic.lcs.mit.edu)
693   * to avoid ^V^V-Problem on OSF1
694   */
695#if defined(IEXTEN)
696  np->tio.c_lflag &= ~IEXTEN;
697#endif /* IEXTEN */
698
699  /*
700   * Unfortunately, the master process never will get SIGINT if the real
701   * terminal is different from the one on which it was originaly started
702   * (process group membership has not been restored or the new tty could not
703   * be made controlling again). In my solution, it is the attacher who
704   * receives SIGINT (because it is always correctly associated with the real
705   * tty) and forwards it to the master [kill(MasterPid, SIGINT)].
706   * Marc Boucher (marc@CAM.ORG)
707   */
708  if (interrupt)
709    np->tio.c_lflag |= ISIG;
710  else
711    np->tio.c_lflag &= ~ISIG;
712  /*
713   * careful, careful catche monkey..
714   * never set VMIN and VTIME to zero, if you want blocking io.
715   *
716   * We may want to do a VMIN > 0, VTIME > 0 read on the ptys too, to
717   * reduce interrupt frequency.  But then we would not know how to
718   * handle read returning 0. jw.
719   */
720  np->tio.c_cc[VMIN] = 1;
721  np->tio.c_cc[VTIME] = 0;
722  if (!interrupt || !flow)
723    np->tio.c_cc[VINTR] = VDISABLE;
724  np->tio.c_cc[VQUIT] = VDISABLE;
725  if (flow == 0)
726    {
727#if defined(VSTART)
728#if (VSTART < MAXCC)
729	np->tio.c_cc[VSTART] = VDISABLE;
730#endif
731#endif /* VSTART */
732#if defined(VSTOP)
733#if (VSTOP < MAXCC)
734	np->tio.c_cc[VSTOP] = VDISABLE;
735#endif
736#endif /* VSTOP */
737      np->tio.c_iflag &= ~IXON;
738    }
739#if defined(VDISCARD)
740#if (VDISCARD < MAXCC)
741	np->tio.c_cc[VDISCARD] = VDISABLE;
742#endif
743#endif /* VDISCARD */
744#if defined(VLNEXT)
745#if (VLNEXT < MAXCC)
746	np->tio.c_cc[VLNEXT] = VDISABLE;
747#endif
748#endif /* VLNEXT */
749#if defined(VSTATUS)
750#if (VSTATUS < MAXCC)
751	np->tio.c_cc[VSTATUS] = VDISABLE;
752#endif
753#endif /* VSTATUS */
754#if defined(VSUSP)
755#if (VSUSP < MAXCC)
756	np->tio.c_cc[VSUSP] = VDISABLE;
757#endif
758#endif /* VSUSP */
759#if defined(VERASE)
760#if (VERASE < MAXCC)
761	np->tio.c_cc[VERASE] = VDISABLE;
762#endif
763#endif /* VERASE */
764#if defined(VKILL)
765#if (VKILL < MAXCC)
766	np->tio.c_cc[VKILL] = VDISABLE;
767#endif
768#endif /* VKILL */
769# ifdef HPUX_LTCHARS_HACK
770  np->m_ltchars.t_suspc  = VDISABLE;
771  np->m_ltchars.t_dsuspc = VDISABLE;
772  np->m_ltchars.t_rprntc = VDISABLE;
773  np->m_ltchars.t_flushc = VDISABLE;
774  np->m_ltchars.t_werasc = VDISABLE;
775  np->m_ltchars.t_lnextc = VDISABLE;
776# else /* HPUX_LTCHARS_HACK */
777#if defined(VDSUSP)
778#if (VDSUSP < MAXCC)
779	np->tio.c_cc[VDSUSP] = VDISABLE;
780#endif
781#endif /* VDSUSP */
782#if defined(VREPRINT)
783#if (VREPRINT < MAXCC)
784	np->tio.c_cc[VREPRINT] = VDISABLE;
785#endif
786#endif /* VREPRINT */
787#if defined(VWERASE)
788#if (VWERASE < MAXCC)
789	np->tio.c_cc[VWERASE] = VDISABLE;
790#endif
791#endif /* VWERASE */
792# endif /* HPUX_LTCHARS_HACK */
793#else /* TERMIO || POSIX */
794  if (!interrupt || !flow)
795    np->m_tchars.t_intrc = -1;
796  np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
797  np->m_ttyb.sg_flags |= CBREAK;
798# if defined(CYRILL) && defined(CSTYLE) && defined(CS_8BITS)
799  np->m_ttyb.sg_flags &= ~CSTYLE;
800  np->m_ttyb.sg_flags |= CS_8BITS;
801# endif
802  np->m_tchars.t_quitc = -1;
803  if (flow == 0)
804    {
805      np->m_tchars.t_startc = -1;
806      np->m_tchars.t_stopc = -1;
807    }
808  np->m_ltchars.t_suspc = -1;
809  np->m_ltchars.t_dsuspc = -1;
810  np->m_ltchars.t_flushc = -1;
811  np->m_ltchars.t_lnextc = -1;
812#endif /* defined(TERMIO) || defined(POSIX) */
813}
814
815/* operates on display */
816void
817SetFlow(on)
818int on;
819{
820  ASSERT(display);
821  if (D_flow == on)
822    return;
823#if defined(TERMIO) || defined(POSIX)
824  if (on)
825    {
826      D_NewMode.tio.c_cc[VINTR] = iflag ? D_OldMode.tio.c_cc[VINTR] : VDISABLE;
827#if defined(VSTART)
828#if (VSTART < MAXCC)
829	D_NewMode.tio.c_cc[VSTART] = D_OldMode.tio.c_cc[VSTART];
830#endif
831#endif /* VSTART */
832#if defined(VSTOP)
833#if (VSTOP < MAXCC)
834	D_NewMode.tio.c_cc[VSTOP] = D_OldMode.tio.c_cc[VSTOP];
835#endif
836#endif /* VSTOP */
837      D_NewMode.tio.c_iflag |= D_OldMode.tio.c_iflag & IXON;
838    }
839  else
840    {
841      D_NewMode.tio.c_cc[VINTR] = VDISABLE;
842#if defined(VSTART)
843#if (VSTART < MAXCC)
844	D_NewMode.tio.c_cc[VSTART] = VDISABLE;
845#endif
846#endif /* VSTART */
847#if defined(VSTOP)
848#if (VSTOP < MAXCC)
849	D_NewMode.tio.c_cc[VSTOP] = VDISABLE;
850#endif
851#endif /* VSTOP */
852      D_NewMode.tio.c_iflag &= ~IXON;
853    }
854# ifdef POSIX
855  if (tcsetattr(D_userfd, TCSANOW, &D_NewMode.tio))
856# else
857  if (ioctl(D_userfd, TCSETAW, (char *)&D_NewMode.tio) != 0)
858# endif
859    debug1("SetFlow: ioctl errno %d\n", errno);
860#else /* POSIX || TERMIO */
861  if (on)
862    {
863      D_NewMode.m_tchars.t_intrc = iflag ? D_OldMode.m_tchars.t_intrc : -1;
864      D_NewMode.m_tchars.t_startc = D_OldMode.m_tchars.t_startc;
865      D_NewMode.m_tchars.t_stopc = D_OldMode.m_tchars.t_stopc;
866    }
867  else
868    {
869      D_NewMode.m_tchars.t_intrc = -1;
870      D_NewMode.m_tchars.t_startc = -1;
871      D_NewMode.m_tchars.t_stopc = -1;
872    }
873  if (ioctl(D_userfd, TIOCSETC, (char *)&D_NewMode.m_tchars) != 0)
874    debug1("SetFlow: ioctl errno %d\n", errno);
875#endif /* POSIX || TERMIO */
876  D_flow = on;
877}
878
879/* parse commands from opt and modify m */
880int
881SttyMode(m, opt)
882struct mode *m;
883char *opt;
884{
885  static const char sep[] = " \t:;,";
886
887  if (!opt)
888    return 0;
889
890  while (*opt)
891    {
892      while (index(sep, *opt)) opt++;
893      if (*opt >= '0' && *opt <= '9')
894        {
895	  if (SetBaud(m, atoi(opt), atoi(opt)))
896	    return -1;
897	}
898      else if (!strncmp("cs7", opt, 3))
899        {
900#if defined(POSIX) || defined(TERMIO)
901	  m->tio.c_cflag &= ~CSIZE;
902	  m->tio.c_cflag |= CS7;
903#else
904	  m->m_lmode &= ~LPASS8;
905#endif
906	}
907      else if (!strncmp("cs8", opt, 3))
908	{
909#if defined(POSIX) || defined(TERMIO)
910	  m->tio.c_cflag &= ~CSIZE;
911	  m->tio.c_cflag |= CS8;
912#else
913	  m->m_lmode |= LPASS8;
914#endif
915	}
916      else if (!strncmp("istrip", opt, 6))
917	{
918#if defined(POSIX) || defined(TERMIO)
919	  m->tio.c_iflag |= ISTRIP;
920#else
921	  m->m_lmode &= ~LPASS8;
922#endif
923        }
924      else if (!strncmp("-istrip", opt, 7))
925	{
926#if defined(POSIX) || defined(TERMIO)
927	  m->tio.c_iflag &= ~ISTRIP;
928#else
929	  m->m_lmode |= LPASS8;
930#endif
931        }
932      else if (!strncmp("ixon", opt, 4))
933	{
934#if defined(POSIX) || defined(TERMIO)
935	  m->tio.c_iflag |= IXON;
936#else
937	  debug("SttyMode: no ixon in old bsd land.\n");
938#endif
939        }
940      else if (!strncmp("-ixon", opt, 5))
941	{
942#if defined(POSIX) || defined(TERMIO)
943	  m->tio.c_iflag &= ~IXON;
944#else
945	  debug("SttyMode: no -ixon in old bsd land.\n");
946#endif
947        }
948      else if (!strncmp("ixoff", opt, 5))
949	{
950#if defined(POSIX) || defined(TERMIO)
951	  m->tio.c_iflag |= IXOFF;
952#else
953	  m->m_ttyb.sg_flags |= TANDEM;
954#endif
955        }
956      else if (!strncmp("-ixoff", opt, 6))
957	{
958#if defined(POSIX) || defined(TERMIO)
959	  m->tio.c_iflag &= ~IXOFF;
960#else
961	  m->m_ttyb.sg_flags &= ~TANDEM;
962#endif
963        }
964      else if (!strncmp("crtscts", opt, 7))
965	{
966#if (defined(POSIX) || defined(TERMIO)) && defined(CRTSCTS)
967	  m->tio.c_cflag |= CRTSCTS;
968#endif
969	}
970      else if (!strncmp("-crtscts", opt, 8))
971        {
972#if (defined(POSIX) || defined(TERMIO)) && defined(CRTSCTS)
973	  m->tio.c_cflag &= ~CRTSCTS;
974#endif
975	}
976      else
977        return -1;
978      while (*opt && !index(sep, *opt)) opt++;
979    }
980  return 0;
981}
982
983/*
984 *  Job control handling
985 *
986 *  Somehow the ultrix session handling is broken, so use
987 *  the bsdish variant.
988 */
989
990/*ARGSUSED*/
991void
992brktty(fd)
993int fd;
994{
995#if defined(POSIX) && !defined(ultrix)
996  if (separate_sids)
997    setsid();		/* will break terminal affiliation */
998  /* GNU added for Hurd systems 2001-10-10 */
999# if defined(BSD) && defined(TIOCSCTTY) && !defined(__GNU__)
1000  ioctl(fd, TIOCSCTTY, (char *)0);
1001# endif /* BSD && TIOCSCTTY */
1002#else /* POSIX */
1003# ifdef SYSV
1004  if (separate_sids)
1005    setpgrp();		/* will break terminal affiliation */
1006# else /* SYSV */
1007#  ifdef BSDJOBS
1008  int devtty;
1009
1010  if ((devtty = open("/dev/tty", O_RDWR | O_NONBLOCK)) >= 0)
1011    {
1012      if (ioctl(devtty, TIOCNOTTY, (char *)0))
1013        debug2("brktty: ioctl(devtty=%d, TIOCNOTTY, 0) = %d\n", devtty, errno);
1014      close(devtty);
1015    }
1016#  endif /* BSDJOBS */
1017# endif /* SYSV */
1018#endif /* POSIX */
1019}
1020
1021int
1022fgtty(fd)
1023int fd;
1024{
1025#ifdef BSDJOBS
1026  int mypid;
1027
1028  mypid = getpid();
1029
1030  /* The next lines should be obsolete. Can anybody check if they
1031   * are really needed on the BSD platforms?
1032   *
1033   * this is to avoid the message:
1034   *	fgtty: Not a typewriter (25)
1035   */
1036# if defined(__osf__) || (BSD >= 199103) || defined(ISC)
1037  if (separate_sids)
1038    setsid();	/* should be already done */
1039#  ifdef TIOCSCTTY
1040  ioctl(fd, TIOCSCTTY, (char *)0);
1041#  endif
1042# endif
1043
1044# ifdef POSIX
1045  if (separate_sids)
1046    if (tcsetpgrp(fd, mypid))
1047      {
1048        debug1("fgtty: tcsetpgrp: %d\n", errno);
1049        return -1;
1050      }
1051# else /* POSIX */
1052  if (ioctl(fd, TIOCSPGRP, (char *)&mypid) != 0)
1053    debug1("fgtty: TIOSETPGRP: %d\n", errno);
1054#  ifndef SYSV	/* Already done in brktty():setpgrp() */
1055  if (separate_sids)
1056    if (setpgrp(fd, mypid))
1057      debug1("fgtty: setpgrp: %d\n", errno);
1058#  endif
1059# endif /* POSIX */
1060#endif /* BSDJOBS */
1061  return 0;
1062}
1063
1064/*
1065 * The alm boards on our sparc center 1000 have a lousy driver.
1066 * We cannot generate long breaks unless we use the most ugly form
1067 * of ioctls. jw.
1068 */
1069#ifdef POSIX
1070int breaktype = 2;
1071#else /* POSIX */
1072# ifdef TCSBRK
1073int breaktype = 1;
1074# else
1075int breaktype = 0;
1076# endif
1077#endif /* POSIX */
1078
1079#if defined(sun) && !defined(SVR4)
1080# define HAVE_SUPER_TCSENDBREAK
1081#endif
1082
1083/*
1084 * type:
1085 *  0:	TIOCSBRK / TIOCCBRK
1086 *  1:	TCSBRK
1087 *  2:	tcsendbreak()
1088 * n: approximate duration in 1/4 seconds.
1089 */
1090static void
1091DoSendBreak(fd, n, type)
1092int fd, n, type;
1093{
1094  switch (type)
1095    {
1096    case 2:	/* tcsendbreak() =============================== */
1097#ifdef POSIX
1098# ifdef HAVE_SUPER_TCSENDBREAK
1099      /* There is one rare case that I have tested, where tcsendbreak works
1100       * really great: this was an alm driver that came with SunOS 4.1.3
1101       * If you have this one, define the above symbol.
1102       * here we can use the second parameter to specify the duration.
1103       */
1104      debug2("tcsendbreak(fd=%d, %d)\n", fd, n);
1105      if (tcsendbreak(fd, n) < 0)
1106        Msg(errno, "cannot send BREAK (tcsendbreak)");
1107# else
1108      /*
1109       * here we hope, that multiple calls to tcsendbreak() can
1110       * be concatenated to form a long break, as we do not know
1111       * what exact interpretation the second parameter has:
1112       *
1113       * - sunos 4: duration in quarter seconds
1114       * - sunos 5: 0 a short break, nonzero a tcdrain()
1115       * - hpux, irix: ignored
1116       * - mot88: duration in milliseconds
1117       * - aix: duration in milliseconds, but 0 is 25 milliseconds.
1118       */
1119      debug2("%d * tcsendbreak(fd=%d, 0)\n", n, fd);
1120	{
1121	  int i;
1122
1123	  if (!n)
1124	    n++;
1125	  for (i = 0; i < n; i++)
1126	    if (tcsendbreak(fd, 0) < 0)
1127	      {
1128		Msg(errno, "cannot send BREAK (tcsendbreak SVR4)");
1129		return;
1130	      }
1131	}
1132# endif
1133#else /* POSIX */
1134      Msg(0, "tcsendbreak() not available, change breaktype");
1135#endif /* POSIX */
1136      break;
1137
1138    case 1:	/* TCSBRK ======================================= */
1139#ifdef TCSBRK
1140      if (!n)
1141        n++;
1142      /*
1143       * Here too, we assume that short breaks can be concatenated to
1144       * perform long breaks. But for SOLARIS, this is not true, of course.
1145       */
1146      debug2("%d * TCSBRK fd=%d\n", n, fd);
1147	{
1148	  int i;
1149
1150	  for (i = 0; i < n; i++)
1151	    if (ioctl(fd, TCSBRK, (char *)0) < 0)
1152	      {
1153		Msg(errno, "Cannot send BREAK (TCSBRK)");
1154		return;
1155	      }
1156	}
1157#else /* TCSBRK */
1158      Msg(0, "TCSBRK not available, change breaktype");
1159#endif /* TCSBRK */
1160      break;
1161
1162    case 0:	/* TIOCSBRK / TIOCCBRK ========================== */
1163#if defined(TIOCSBRK) && defined(TIOCCBRK)
1164      /*
1165       * This is very rude. Screen actively celebrates the break.
1166       * But it may be the only save way to issue long breaks.
1167       */
1168      debug("TIOCSBRK TIOCCBRK\n");
1169      if (ioctl(fd, TIOCSBRK, (char *)0) < 0)
1170        {
1171	  Msg(errno, "Can't send BREAK (TIOCSBRK)");
1172	  return;
1173	}
1174      sleep1000(n ? n * 250 : 250);
1175      if (ioctl(fd, TIOCCBRK, (char *)0) < 0)
1176        {
1177	  Msg(errno, "BREAK stuck!!! -- HELP! (TIOCCBRK)");
1178	  return;
1179	}
1180#else /* TIOCSBRK && TIOCCBRK */
1181      Msg(0, "TIOCSBRK/CBRK not available, change breaktype");
1182#endif /* TIOCSBRK && TIOCCBRK */
1183      break;
1184
1185    default:	/* unknown ========================== */
1186      Msg(0, "Internal SendBreak error: method %d unknown", type);
1187    }
1188}
1189
1190/*
1191 * Send a break for n * 0.25 seconds. Tty must be PLAIN.
1192 * The longest possible break allowed here is 15 seconds.
1193 */
1194
1195void
1196SendBreak(wp, n, closeopen)
1197struct win *wp;
1198int n, closeopen;
1199{
1200  sigret_t (*sigalrm)__P(SIGPROTOARG);
1201
1202#ifdef BUILTIN_TELNET
1203  if (wp->w_type == W_TYPE_TELNET)
1204    {
1205      TelBreak(wp);
1206      return;
1207    }
1208#endif
1209  if (wp->w_type != W_TYPE_PLAIN)
1210    return;
1211
1212  debug3("break(%d, %d) fd %d\n", n, closeopen, wp->w_ptyfd);
1213
1214#ifdef POSIX
1215  (void) tcflush(wp->w_ptyfd, TCIOFLUSH);
1216#else
1217# ifdef TIOCFLUSH
1218  (void) ioctl(wp->w_ptyfd, TIOCFLUSH, (char *)0);
1219# endif /* TIOCFLUSH */
1220#endif /* POSIX */
1221
1222  if (closeopen)
1223    {
1224      close(wp->w_ptyfd);
1225      sleep1000(n ? n * 250 : 250);
1226      if ((wp->w_ptyfd = OpenTTY(wp->w_tty, wp->w_cmdargs[1])) < 1)
1227	{
1228	  Msg(0, "Ouch, cannot reopen line %s, please try harder", wp->w_tty);
1229	  return;
1230	}
1231      (void) fcntl(wp->w_ptyfd, F_SETFL, FNBLOCK);
1232    }
1233  else
1234    {
1235      sigalrm = signal(SIGALRM, SigAlrmDummy);
1236      alarm(15);
1237
1238      DoSendBreak(wp->w_ptyfd, n, breaktype);
1239
1240      alarm(0);
1241      signal(SIGALRM, sigalrm);
1242    }
1243  debug("            broken.\n");
1244}
1245
1246/*
1247 *  Console grabbing
1248 */
1249
1250#if (!defined(TIOCCONS) && defined(SRIOCSREDIR)) || defined(linux)
1251
1252static struct event consredir_ev;
1253static int consredirfd[2] = {-1, -1};
1254
1255static void
1256consredir_readev_fn(ev, data)
1257struct event *ev;
1258char *data;
1259{
1260  char *p, *n, buf[256];
1261  int l;
1262
1263  if (!console_window || (l = read(consredirfd[0], buf, sizeof(buf))) <= 0)
1264    {
1265      close(consredirfd[0]);
1266      close(consredirfd[1]);
1267      consredirfd[0] = consredirfd[1] = -1;
1268      evdeq(ev);
1269      return;
1270    }
1271  for (p = n = buf; l > 0; n++, l--)
1272    if (*n == '\n')
1273      {
1274        if (n > p)
1275	  WriteString(console_window, p, n - p);
1276        WriteString(console_window, "\r\n", 2);
1277        p = n + 1;
1278      }
1279  if (n > p)
1280    WriteString(console_window, p, n - p);
1281}
1282
1283#endif
1284
1285/*ARGSUSED*/
1286int
1287TtyGrabConsole(fd, on, rc_name)
1288int fd, on;
1289char *rc_name;
1290{
1291#if defined(TIOCCONS) && !defined(linux)
1292  struct display *d;
1293  int ret = 0;
1294  int sfd = -1;
1295
1296  if (on < 0)
1297    return 0;		/* pty close will ungrab */
1298  if (on)
1299    {
1300      if (displays == 0)
1301	{
1302	  Msg(0, "I need a display");
1303	  return -1;
1304	}
1305      for (d = displays; d; d = d->d_next)
1306	if (strcmp(d->d_usertty, "/dev/console") == 0)
1307	  break;
1308      if (d)
1309	{
1310	  Msg(0, "too dangerous - screen is running on /dev/console");
1311	  return -1;
1312	}
1313    }
1314
1315  if (!on)
1316    {
1317      char *slave;
1318      if ((fd = OpenPTY(&slave)) < 0)
1319	{
1320	  Msg(errno, "%s: could not open detach pty master", rc_name);
1321	  return -1;
1322	}
1323      if ((sfd = open(slave, O_RDWR | O_NOCTTY)) < 0)
1324	{
1325	  Msg(errno, "%s: could not open detach pty slave", rc_name);
1326	  close(fd);
1327	  return -1;
1328	}
1329    }
1330  if (UserContext() == 1)
1331    UserReturn(ioctl(fd, TIOCCONS, (char *)&on));
1332  ret = UserStatus();
1333  if (ret)
1334    Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
1335  if (!on)
1336    {
1337      close(sfd);
1338      close(fd);
1339    }
1340  return ret;
1341
1342#else
1343# if defined(SRIOCSREDIR) || defined(linux)
1344  struct display *d;
1345#  ifdef SRIOCSREDIR
1346  int cfd;
1347#  else
1348  struct mode new1, new2;
1349  char *slave;
1350#  endif
1351
1352  if (on > 0)
1353    {
1354      if (displays == 0)
1355	{
1356	  Msg(0, "I need a display");
1357	  return -1;
1358	}
1359      for (d = displays; d; d = d->d_next)
1360	if (strcmp(d->d_usertty, "/dev/console") == 0)
1361	  break;
1362      if (d)
1363	{
1364	  Msg(0, "too dangerous - screen is running on /dev/console");
1365	  return -1;
1366	}
1367    }
1368  if (consredirfd[0] >= 0)
1369    {
1370      evdeq(&consredir_ev);
1371      close(consredirfd[0]);
1372      close(consredirfd[1]);
1373      consredirfd[0] = consredirfd[1] = -1;
1374    }
1375  if (on <= 0)
1376    return 0;
1377#  ifdef SRIOCSREDIR
1378  if ((cfd = secopen("/dev/console", O_RDWR|O_NOCTTY, 0)) == -1)
1379    {
1380      Msg(errno, "/dev/console");
1381      return -1;
1382    }
1383  if (pipe(consredirfd))
1384    {
1385      Msg(errno, "pipe");
1386      close(cfd);
1387      consredirfd[0] = consredirfd[1] = -1;
1388      return -1;
1389    }
1390  if (ioctl(cfd, SRIOCSREDIR, consredirfd[1]))
1391    {
1392      Msg(errno, "SRIOCSREDIR ioctl");
1393      close(cfd);
1394      close(consredirfd[0]);
1395      close(consredirfd[1]);
1396      consredirfd[0] = consredirfd[1] = -1;
1397      return -1;
1398    }
1399  close(cfd);
1400#  else
1401  /* special linux workaround for a too restrictive kernel */
1402  if ((consredirfd[0] = OpenPTY(&slave)) < 0)
1403    {
1404      Msg(errno, "%s: could not open detach pty master", rc_name);
1405      return -1;
1406    }
1407  if ((consredirfd[1] = open(slave, O_RDWR | O_NOCTTY)) < 0)
1408    {
1409      Msg(errno, "%s: could not open detach pty slave", rc_name);
1410      close(consredirfd[0]);
1411      return -1;
1412    }
1413  InitTTY(&new1, 0);
1414  SetMode(&new1, &new2, 0, 0);
1415  SetTTY(consredirfd[1], &new2);
1416  if (UserContext() == 1)
1417    UserReturn(ioctl(consredirfd[1], TIOCCONS, (char *)&on));
1418  if (UserStatus())
1419    {
1420      Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
1421      close(consredirfd[0]);
1422      close(consredirfd[1]);
1423      return -1;
1424    }
1425#  endif
1426  consredir_ev.fd = consredirfd[0];
1427  consredir_ev.type = EV_READ;
1428  consredir_ev.handler = consredir_readev_fn;
1429  evenq(&consredir_ev);
1430  return 0;
1431# else
1432  if (on > 0)
1433    Msg(0, "%s: don't know how to grab the console", rc_name);
1434  return -1;
1435# endif
1436#endif
1437}
1438
1439/*
1440 * Read modem control lines of a physical tty and write them to buf
1441 * in a readable format.
1442 * Will not write more than 256 characters to buf.
1443 * Returns buf;
1444 */
1445char *
1446TtyGetModemStatus(fd, buf)
1447int fd;
1448char *buf;
1449{
1450  char *p = buf;
1451#ifdef TIOCGSOFTCAR
1452  unsigned int softcar;
1453#endif
1454#if defined(TIOCMGET) || defined(TIOCMODG)
1455  unsigned int mflags;
1456#else
1457# ifdef MCGETA
1458  /* this is yet another interface, found on hpux. grrr */
1459  mflag mflags;
1460#if defined(MDTR)
1461#  define TIOCM_DTR MDTR
1462#endif /* MDTR */
1463#if defined(MRTS)
1464#  define TIOCM_RTS MRTS
1465#endif /* MRTS */
1466#if defined(MDSR)
1467#  define TIOCM_DSR MDSR
1468#endif /* MDSR */
1469#if defined(MDCD)
1470#  define TIOCM_CAR MDCD
1471#endif /* MDCD */
1472#if defined(MRI)
1473#  define TIOCM_RNG MRI
1474#endif /* MRI */
1475#if defined(MCTS)
1476#  define TIOCM_CTS MCTS
1477#endif /* MCTS */
1478# endif
1479#endif
1480#if defined(CLOCAL) || defined(CRTSCTS)
1481  struct mode mtio;	/* screen.h */
1482#endif
1483#if defined(CRTSCTS) || defined(TIOCM_CTS)
1484  int rtscts;
1485#endif
1486  int clocal;
1487
1488#if defined(CLOCAL) || defined(CRTSCTS)
1489  GetTTY(fd, &mtio);
1490#endif
1491  clocal = 0;
1492#ifdef CLOCAL
1493  if (mtio.tio.c_cflag & CLOCAL)
1494    {
1495      clocal = 1;
1496      *p++ = '{';
1497    }
1498#endif
1499
1500#ifdef TIOCM_CTS
1501# ifdef CRTSCTS
1502  if (!(mtio.tio.c_cflag & CRTSCTS))
1503    rtscts = 0;
1504  else
1505# endif /* CRTSCTS */
1506    rtscts = 1;
1507#endif /* TIOCM_CTS */
1508
1509#ifdef TIOCGSOFTCAR
1510  if (ioctl(fd, TIOCGSOFTCAR, (char *)&softcar) < 0)
1511    softcar = 0;
1512#endif
1513
1514#if defined(TIOCMGET) || defined(TIOCMODG) || defined(MCGETA)
1515# ifdef TIOCMGET
1516  if (ioctl(fd, TIOCMGET, (char *)&mflags) < 0)
1517# else
1518#  ifdef TIOCMODG
1519  if (ioctl(fd, TIOCMODG, (char *)&mflags) < 0)
1520#  else
1521  if (ioctl(fd, MCGETA, &mflags) < 0)
1522#  endif
1523# endif
1524    {
1525#ifdef TIOCGSOFTCAR
1526      sprintf(p, "NO-TTY? %s", softcar ? "(CD)" : "CD");
1527#else
1528      sprintf(p, "NO-TTY?");
1529#endif
1530      p += strlen(p);
1531    }
1532  else
1533    {
1534      char *s;
1535# ifdef FANCY_MODEM
1536#  ifdef TIOCM_LE
1537      if (!(mflags & TIOCM_LE))
1538        for (s = "!LE "; *s; *p++ = *s++);
1539#  endif
1540# endif /* FANCY_MODEM */
1541
1542# ifdef TIOCM_RTS
1543      s = "!RTS "; if (mflags & TIOCM_RTS) s++;
1544      while (*s) *p++ = *s++;
1545# endif
1546# ifdef TIOCM_CTS
1547      s = "!CTS ";
1548      if (!rtscts)
1549        {
1550          *p++ = '(';
1551          s = "!CTS) ";
1552	}
1553      if (mflags & TIOCM_CTS) s++;
1554      while (*s) *p++ = *s++;
1555# endif
1556
1557# ifdef TIOCM_DTR
1558      s = "!DTR "; if (mflags & TIOCM_DTR) s++;
1559      while (*s) *p++ = *s++;
1560# endif
1561# ifdef TIOCM_DSR
1562      s = "!DSR "; if (mflags & TIOCM_DSR) s++;
1563      while (*s) *p++ = *s++;
1564# endif
1565# if defined(TIOCM_CD) || defined(TIOCM_CAR)
1566      s = "!CD ";
1567#  ifdef TIOCGSOFTCAR
1568      if (softcar)
1569	 {
1570	  *p++ = '(';
1571	  s = "!CD) ";
1572	 }
1573#  endif
1574#  ifdef TIOCM_CD
1575      if (mflags & TIOCM_CD) s++;
1576#  else
1577      if (mflags & TIOCM_CAR) s++;
1578#  endif
1579      while (*s) *p++ = *s++;
1580# endif
1581# if defined(TIOCM_RI) || defined(TIOCM_RNG)
1582#  ifdef TIOCM_RI
1583      if (mflags & TIOCM_RI)
1584#  else
1585      if (mflags & TIOCM_RNG)
1586#  endif
1587	for (s = "RI "; *s; *p++ = *s++);
1588# endif
1589# ifdef FANCY_MODEM
1590#  ifdef TIOCM_ST
1591      s = "!ST "; if (mflags & TIOCM_ST) s++;
1592      while (*s) *p++ = *s++;
1593#  endif
1594#  ifdef TIOCM_SR
1595      s = "!SR "; if (mflags & TIOCM_SR) s++;
1596      while (*s) *p++ = *s++;
1597#  endif
1598# endif /* FANCY_MODEM */
1599      if (p > buf && p[-1] == ' ')
1600        p--;
1601      *p = '\0';
1602    }
1603#else
1604# ifdef TIOCGSOFTCAR
1605  sprintf(p, " %s", softcar ? "(CD)", "CD");
1606  p += strlen(p);
1607# endif
1608#endif
1609  if (clocal)
1610    *p++ = '}';
1611  *p = '\0';
1612  return buf;
1613}
1614
1615/*
1616 * Old bsd-ish machines may not have any of the baudrate B... symbols.
1617 * We hope to detect them here, so that the btable[] below always has
1618 * many entries.
1619 */
1620#ifndef POSIX
1621# ifndef TERMIO
1622#  if !defined(B9600) && !defined(B2400) && !defined(B1200) && !defined(B300)
1623#if !defined(B0)
1624#define		B0	0
1625#endif /* B0 */
1626#if !defined(B50)
1627#define  	B50	1
1628#endif /* B50 */
1629#if !defined(B75)
1630#define  	B75	2
1631#endif /* B75 */
1632#if !defined(B110)
1633#define 	B110	3
1634#endif /* B110 */
1635#if !defined(B134)
1636#define 	B134	4
1637#endif /* B134 */
1638#if !defined(B150)
1639#define 	B150	5
1640#endif /* B150 */
1641#if !defined(B200)
1642#define 	B200	6
1643#endif /* B200 */
1644#if !defined(B300)
1645#define 	B300	7
1646#endif /* B300 */
1647#if !defined(B600)
1648#define 	B600	8
1649#endif /* B600 */
1650#if !defined(B1200)
1651#define	B1200	9
1652#endif /* B1200 */
1653#if !defined(B1800)
1654#define	B1800	10
1655#endif /* B1800 */
1656#if !defined(B2400)
1657#define	B2400	11
1658#endif /* B2400 */
1659#if !defined(B4800)
1660#define	B4800	12
1661#endif /* B4800 */
1662#if !defined(B9600)
1663#define	B9600	13
1664#endif /* B9600 */
1665#if !defined(EXTA)
1666#define	EXTA	14
1667#endif /* EXTA */
1668#if !defined(EXTB)
1669#define	EXTB	15
1670#endif /* EXTB */
1671#  endif
1672# endif
1673#endif
1674
1675/*
1676 * On hpux, idx and sym will be different.
1677 * Rumor has it that, we need idx in D_dospeed to make tputs
1678 * padding correct.
1679 * Frequently used entries come first.
1680 */
1681static struct baud_values btable[] =
1682{
1683#if defined(B9600)
1684	{	13,	9600,	B9600	},
1685#endif /* B9600 */
1686#if defined(B19200)
1687	{	14,	19200,	B19200	},
1688#endif /* B19200 */
1689#if defined(EXTA)
1690	{	14,	19200,	EXTA	},
1691#endif /* EXTA */
1692#if defined(B38400)
1693	{	15,	38400,	B38400	},
1694#endif /* B38400 */
1695#if defined(EXTB)
1696	{	15,	38400,	EXTB	},
1697#endif /* EXTB */
1698#if defined(B57600)
1699	{	16,	57600,	B57600	},
1700#endif /* B57600 */
1701#if defined(B115200)
1702	{	17,	115200,	B115200	},
1703#endif /* B115200 */
1704#if defined(B230400)
1705	{	18,	230400,	B230400	},
1706#endif /* B230400 */
1707#if defined(B460800)
1708	{	19,	460800,	B460800	},
1709#endif /* B460800 */
1710#if defined(B7200)
1711	{	13,	7200,	B7200	},
1712#endif /* B7200 */
1713#if defined(B4800)
1714	{	12,	4800,	B4800	},
1715#endif /* B4800 */
1716#if defined(B3600)
1717	{	12,	3600,	B3600	},
1718#endif /* B3600 */
1719#if defined(B2400)
1720	{	11,	2400,	B2400	},
1721#endif /* B2400 */
1722#if defined(B1800)
1723	{	10,	1800,	B1800	},
1724#endif /* B1800 */
1725#if defined(B1200)
1726	{	9,	1200,	B1200	},
1727#endif /* B1200 */
1728#if defined(B900)
1729 	{	9,	900,	B900	},
1730#endif /* B900 */
1731#if defined(B600)
1732 	{	8,	600,	B600	},
1733#endif /* B600 */
1734#if defined(B300)
1735 	{	7,	300, 	B300	},
1736#endif /* B300 */
1737#if defined(B200)
1738 	{	6,	200, 	B200	},
1739#endif /* B200 */
1740#if defined(B150)
1741 	{	5,	150,	B150	},
1742#endif /* B150 */
1743#if defined(B134)
1744 	{	4,	134,	B134	},
1745#endif /* B134 */
1746#if defined(B110)
1747 	{	3,	110,	B110	},
1748#endif /* B110 */
1749#if defined(B75)
1750  	{	2,	75,	B75	},
1751#endif /* B75 */
1752#if defined(B50)
1753  	{	1,	50,	B50	},
1754#endif /* B50 */
1755#if defined(B0)
1756   	{	0,	0,	B0	},
1757#endif /* B0 */
1758		{	-1,	-1,	-1	}
1759};
1760
1761/*
1762 * baud may either be a bits-per-second value or a symbolic
1763 * value as returned by cfget?speed()
1764 */
1765struct baud_values *
1766lookup_baud(baud)
1767int baud;
1768{
1769  struct baud_values *p;
1770
1771  for (p = btable; p->idx >= 0; p++)
1772    if (baud == p->bps || baud == p->sym)
1773      return p;
1774  return NULL;
1775}
1776
1777/*
1778 * change the baud rate in a mode structure.
1779 * ibaud and obaud are given in bit/second, or at your option as
1780 * termio B... symbols as defined in e.g. suns sys/ttydev.h
1781 * -1 means don't change.
1782 */
1783int
1784SetBaud(m, ibaud, obaud)
1785struct mode *m;
1786int ibaud, obaud;
1787{
1788  struct baud_values *ip, *op;
1789
1790  if ((!(ip = lookup_baud(ibaud)) && ibaud != -1) ||
1791      (!(op = lookup_baud(obaud)) && obaud != -1))
1792    return -1;
1793
1794#ifdef POSIX
1795  if (ip) cfsetispeed(&m->tio, ip->sym);
1796  if (op) cfsetospeed(&m->tio, op->sym);
1797#else /* POSIX */
1798# ifdef TERMIO
1799  if (ip)
1800    {
1801#  ifdef IBSHIFT
1802      m->tio.c_cflag &= ~(CBAUD << IBSHIFT);
1803      m->tio.c_cflag |= (ip->sym & CBAUD) << IBSHIFT;
1804#  else /* IBSHIFT */
1805      if (ibaud != obaud)
1806        return -1;
1807#  endif /* IBSHIFT */
1808    }
1809  if (op)
1810    {
1811      m->tio.c_cflag &= ~CBAUD;
1812      m->tio.c_cflag |= op->sym & CBAUD;
1813    }
1814# else /* TERMIO */
1815  if (ip) m->m_ttyb.sg_ispeed = ip->idx;
1816  if (op) m->m_ttyb.sg_ospeed = op->idx;
1817# endif /* TERMIO */
1818#endif /* POSIX */
1819  return 0;
1820}
1821
1822/*
1823 *  Write out the mode struct in a readable form
1824 */
1825
1826#ifdef DEBUG
1827void
1828DebugTTY(m)
1829struct mode *m;
1830{
1831  int i;
1832
1833#ifdef POSIX
1834  debug("struct termios tio:\n");
1835  debug1("c_iflag = %#x\n", (unsigned int)m->tio.c_iflag);
1836  debug1("c_oflag = %#x\n", (unsigned int)m->tio.c_oflag);
1837  debug1("c_cflag = %#x\n", (unsigned int)m->tio.c_cflag);
1838  debug1("c_lflag = %#x\n", (unsigned int)m->tio.c_lflag);
1839  debug1("cfgetospeed() = %d\n", (int)cfgetospeed(&m->tio));
1840  debug1("cfgetispeed() = %d\n", (int)cfgetispeed(&m->tio));
1841  for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
1842    {
1843      debug2("c_cc[%d] = %#x\n", i, m->tio.c_cc[i]);
1844    }
1845# ifdef HPUX_LTCHARS_HACK
1846  debug1("suspc     = %#02x\n", m->m_ltchars.t_suspc);
1847  debug1("dsuspc    = %#02x\n", m->m_ltchars.t_dsuspc);
1848  debug1("rprntc    = %#02x\n", m->m_ltchars.t_rprntc);
1849  debug1("flushc    = %#02x\n", m->m_ltchars.t_flushc);
1850  debug1("werasc    = %#02x\n", m->m_ltchars.t_werasc);
1851  debug1("lnextc    = %#02x\n", m->m_ltchars.t_lnextc);
1852# endif /* HPUX_LTCHARS_HACK */
1853#else /* POSIX */
1854# ifdef TERMIO
1855  debug("struct termio tio:\n");
1856  debug1("c_iflag = %04o\n", m->tio.c_iflag);
1857  debug1("c_oflag = %04o\n", m->tio.c_oflag);
1858  debug1("c_cflag = %04o\n", m->tio.c_cflag);
1859  debug1("c_lflag = %04o\n", m->tio.c_lflag);
1860  for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
1861    {
1862      debug2("c_cc[%d] = %04o\n", i, m->tio.c_cc[i]);
1863    }
1864# else /* TERMIO */
1865  debug1("sg_ispeed = %d\n",    m->m_ttyb.sg_ispeed);
1866  debug1("sg_ospeed = %d\n",    m->m_ttyb.sg_ospeed);
1867  debug1("sg_erase  = %#02x\n", m->m_ttyb.sg_erase);
1868  debug1("sg_kill   = %#02x\n", m->m_ttyb.sg_kill);
1869  debug1("sg_flags  = %#04x\n", (unsigned short)m->m_ttyb.sg_flags);
1870  debug1("intrc     = %#02x\n", m->m_tchars.t_intrc);
1871  debug1("quitc     = %#02x\n", m->m_tchars.t_quitc);
1872  debug1("startc    = %#02x\n", m->m_tchars.t_startc);
1873  debug1("stopc     = %#02x\n", m->m_tchars.t_stopc);
1874  debug1("eofc      = %#02x\n", m->m_tchars.t_eofc);
1875  debug1("brkc      = %#02x\n", m->m_tchars.t_brkc);
1876  debug1("suspc     = %#02x\n", m->m_ltchars.t_suspc);
1877  debug1("dsuspc    = %#02x\n", m->m_ltchars.t_dsuspc);
1878  debug1("rprntc    = %#02x\n", m->m_ltchars.t_rprntc);
1879  debug1("flushc    = %#02x\n", m->m_ltchars.t_flushc);
1880  debug1("werasc    = %#02x\n", m->m_ltchars.t_werasc);
1881  debug1("lnextc    = %#02x\n", m->m_ltchars.t_lnextc);
1882  debug1("ldisc     = %d\n",    m->m_ldisc);
1883  debug1("lmode     = %#x\n",   m->m_lmode);
1884# endif /* TERMIO */
1885#endif /* POSIX */
1886}
1887#endif /* DEBUG */
1888