xref: /original-bsd/libexec/telnetd/sys_term.c (revision 92ab646d)
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)sys_term.c	5.10 (Berkeley) 06/30/90";
10 #endif /* not lint */
11 
12 #include "telnetd.h"
13 #include "pathnames.h"
14 
15 #ifdef	NEWINIT
16 #include <initreq.h>
17 #else	/* NEWINIT*/
18 #include <utmp.h>
19 struct	utmp wtmp;
20 
21 # ifndef CRAY
22 char	wtmpf[]	= "/usr/adm/wtmp";
23 char	utmpf[] = "/etc/utmp";
24 # else	/* CRAY */
25 char	wtmpf[]	= "/etc/wtmp";
26 # endif	/* CRAY */
27 #endif	/* NEWINIT */
28 
29 #define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
30 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
31 
32 #ifdef	STREAMS
33 #include <sys/stream.h>
34 #endif
35 #include <sys/tty.h>
36 #ifdef	t_erase
37 #undef	t_erase
38 #undef	t_kill
39 #undef	t_intrc
40 #undef	t_quitc
41 #undef	t_startc
42 #undef	t_stopc
43 #undef	t_eofc
44 #undef	t_brkc
45 #undef	t_suspc
46 #undef	t_dsuspc
47 #undef	t_rprntc
48 #undef	t_flushc
49 #undef	t_werasc
50 #undef	t_lnextc
51 #endif
52 
53 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
54 # define EXTPROC 0400
55 #endif
56 
57 #ifndef	USE_TERMIO
58 struct termbuf {
59 	struct sgttyb sg;
60 	struct tchars tc;
61 	struct ltchars ltc;
62 	int state;
63 	int lflags;
64 } termbuf, termbuf2;
65 #else	/* USE_TERMIO */
66 # ifdef	SYSV_TERMIO
67 #	define termios termio
68 # endif
69 # ifndef TCSETA
70 #  ifdef TCSETS
71 #   define TCSETA TCSETS
72 #   define TCGETA TCGETS
73 #  else
74 #   define TCSETA TIOCSETAW
75 #   define TCGETA TIOCGETA
76 #  endif
77 # endif /* 4.4BSD */
78 struct termios termbuf, termbuf2;	/* pty control structure */
79 #endif	/* USE_TERMIO */
80 
81 /*
82  * init_termbuf()
83  * copy_termbuf(cp)
84  * set_termbuf()
85  *
86  * These three routines are used to get and set the "termbuf" structure
87  * to and from the kernel.  init_termbuf() gets the current settings.
88  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
89  * set_termbuf() writes the structure into the kernel.
90  */
91 
92 init_termbuf()
93 {
94 #ifndef	USE_TERMIO
95 	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
96 	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
97 	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
98 # ifdef	TIOCGSTATE
99 	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
100 # endif
101 #else
102 	(void) ioctl(pty, TCGETA, (char *)&termbuf);
103 #endif
104 	termbuf2 = termbuf;
105 }
106 
107 #if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
108 copy_termbuf(cp, len)
109 char *cp;
110 int len;
111 {
112 	if (len > sizeof(termbuf))
113 		len = sizeof(termbuf);
114 	bcopy(cp, (char *)&termbuf, len);
115 	termbuf2 = termbuf;
116 }
117 #endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
118 
119 set_termbuf()
120 {
121 	/*
122 	 * Only make the necessary changes.
123 	 */
124 #ifndef	USE_TERMIO
125 	if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
126 		(void) ioctl(pty, TIOCSETP, (char *)&termbuf.sg);
127 	if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
128 		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
129 	if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
130 							sizeof(termbuf.ltc)))
131 		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
132 	if (termbuf.lflags != termbuf2.lflags)
133 		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
134 #else	/* USE_TERMIO */
135 	if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
136 		(void) ioctl(pty, TCSETA, (char *)&termbuf);
137 # if	defined(CRAY2) && defined(UNCIOS5)
138 	needtermstat = 1;
139 # endif
140 #endif	/* USE_TERMIO */
141 }
142 
143 
144 /*
145  * spcset(func, valp, valpp)
146  *
147  * This function takes various special characters (func), and
148  * sets *valp to the current value of that character, and
149  * *valpp to point to where in the "termbuf" structure that
150  * value is kept.
151  *
152  * It returns the SLC_ level of support for this function.
153  */
154 
155 #ifndef	USE_TERMIO
156 spcset(func, valp, valpp)
157 int func;
158 cc_t *valp;
159 cc_t **valpp;
160 {
161 	switch(func) {
162 	case SLC_EOF:
163 		*valp = termbuf.tc.t_eofc;
164 		*valpp = (cc_t *)&termbuf.tc.t_eofc;
165 		return(SLC_VARIABLE);
166 	case SLC_EC:
167 		*valp = termbuf.sg.sg_erase;
168 		*valpp = (cc_t *)&termbuf.sg.sg_erase;
169 		return(SLC_VARIABLE);
170 	case SLC_EL:
171 		*valp = termbuf.sg.sg_kill;
172 		*valpp = (cc_t *)&termbuf.sg.sg_kill;
173 		return(SLC_VARIABLE);
174 	case SLC_IP:
175 		*valp = termbuf.tc.t_intrc;
176 		*valpp = (cc_t *)&termbuf.tc.t_intrc;
177 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
178 	case SLC_ABORT:
179 		*valp = termbuf.tc.t_quitc;
180 		*valpp = (cc_t *)&termbuf.tc.t_quitc;
181 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
182 	case SLC_XON:
183 		*valp = termbuf.tc.t_startc;
184 		*valpp = (cc_t *)&termbuf.tc.t_startc;
185 		return(SLC_VARIABLE);
186 	case SLC_XOFF:
187 		*valp = termbuf.tc.t_stopc;
188 		*valpp = (cc_t *)&termbuf.tc.t_stopc;
189 		return(SLC_VARIABLE);
190 	case SLC_AO:
191 		*valp = termbuf.ltc.t_flushc;
192 		*valpp = (cc_t *)&termbuf.ltc.t_flushc;
193 		return(SLC_VARIABLE);
194 	case SLC_SUSP:
195 		*valp = termbuf.ltc.t_suspc;
196 		*valpp = (cc_t *)&termbuf.ltc.t_suspc;
197 		return(SLC_VARIABLE);
198 	case SLC_EW:
199 		*valp = termbuf.ltc.t_werasc;
200 		*valpp = (cc_t *)&termbuf.ltc.t_werasc;
201 		return(SLC_VARIABLE);
202 	case SLC_RP:
203 		*valp = termbuf.ltc.t_rprntc;
204 		*valpp = (cc_t *)&termbuf.ltc.t_rprntc;
205 		return(SLC_VARIABLE);
206 	case SLC_LNEXT:
207 		*valp = termbuf.ltc.t_lnextc;
208 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
209 		return(SLC_VARIABLE);
210 	case SLC_FORW1:
211 		*valp = termbuf.tc.t_brkc;
212 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
213 		return(SLC_VARIABLE);
214 	case SLC_BRK:
215 	case SLC_SYNCH:
216 	case SLC_AYT:
217 	case SLC_EOR:
218 		*valp = (cc_t)0;
219 		*valpp = (cc_t *)0;
220 		return(SLC_DEFAULT);
221 	default:
222 		*valp = (cc_t)0;
223 		*valpp = (cc_t *)0;
224 		return(SLC_NOSUPPORT);
225 	}
226 }
227 
228 #else	/* USE_TERMIO */
229 
230 spcset(func, valp, valpp)
231 int func;
232 cc_t *valp;
233 cc_t **valpp;
234 {
235 
236 #define	setval(a, b)	*valp = termbuf.c_cc[a]; \
237 			*valpp = &termbuf.c_cc[a]; \
238 			return(b);
239 #define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
240 
241 	switch(func) {
242 	case SLC_EOF:
243 		setval(VEOF, SLC_VARIABLE);
244 	case SLC_EC:
245 		setval(VERASE, SLC_VARIABLE);
246 	case SLC_EL:
247 		setval(VKILL, SLC_VARIABLE);
248 	case SLC_IP:
249 		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
250 	case SLC_ABORT:
251 		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
252 	case SLC_XON:
253 #ifdef	VSTART
254 		setval(VSTART, SLC_VARIABLE);
255 #else
256 		defval(0x13);
257 #endif
258 	case SLC_XOFF:
259 #ifdef	VSTOP
260 		setval(VSTOP, SLC_VARIABLE);
261 #else
262 		defval(0x11);
263 #endif
264 	case SLC_EW:
265 #ifdef	VWERASE
266 		setval(VWERASE, SLC_VARIABLE);
267 #else
268 		defval(0);
269 #endif
270 	case SLC_RP:
271 #ifdef	VREPRINT
272 		setval(VREPRINT, SLC_VARIABLE);
273 #else
274 		defval(0);
275 #endif
276 	case SLC_LNEXT:
277 #ifdef	VLNEXT
278 		setval(VLNEXT, SLC_VARIABLE);
279 #else
280 		defval(0);
281 #endif
282 	case SLC_AO:
283 #ifdef	VFLUSHO
284 		setval(VFLUSHO, SLC_VARIABLE|SLC_FLUSHOUT);
285 #else
286 		defval(0);
287 #endif
288 	case SLC_SUSP:
289 #ifdef	VSUSP
290 		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
291 #else
292 		defval(0);
293 #endif
294 #ifdef	VEOL
295 	case SLC_FORW1:
296 		setval(VEOL, SLC_VARIABLE);
297 #endif
298 #ifdef	VEOL2
299 	case SLC_FORW2:
300 		setval(VEOL2, SLC_VARIABLE);
301 #endif
302 
303 	case SLC_BRK:
304 	case SLC_SYNCH:
305 	case SLC_AYT:
306 	case SLC_EOR:
307 		defval(0);
308 
309 	default:
310 		*valp = 0;
311 		*valpp = 0;
312 		return(SLC_NOSUPPORT);
313 	}
314 }
315 #endif	/* USE_TERMIO */
316 
317 #ifdef CRAY
318 /*
319  * getnpty()
320  *
321  * Return the number of pty's configured into the system.
322  */
323 getnpty()
324 {
325 #ifdef _SC_CRAY_NPTY
326 	return sysconf(_SC_CRAY_NPTY);
327 #else
328 	return 128;
329 #endif /* _SC_CRAY_NPTY */
330 }
331 #endif /* CRAY */
332 
333 /*
334  * getpty()
335  *
336  * Allocate a pty.  As a side effect, the external character
337  * array "line" contains the name of the slave side.
338  *
339  * Returns the file descriptor of the opened pty.
340  */
341 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
342 
343 getpty()
344 {
345 	register int p;
346 #ifndef CRAY
347 	register char c, *p1, *p2;
348 	register int i;
349 
350 	(void) sprintf(line, "/dev/ptyXX");
351 	p1 = &line[8];
352 	p2 = &line[9];
353 
354 	for (c = 'p'; c <= 's'; c++) {
355 		struct stat stb;
356 
357 		*p1 = c;
358 		*p2 = '0';
359 		if (stat(line, &stb) < 0)
360 			break;
361 		for (i = 0; i < 16; i++) {
362 			*p2 = "0123456789abcdef"[i];
363 			p = open(line, 2);
364 			if (p > 0) {
365 				line[5] = 't';
366 				return(p);
367 			}
368 		}
369 	}
370 #else	/* CRAY */
371 	register int npty;
372 	extern lowpty, highpty;
373 
374 	for (npty = lowpty; npty <= highpty; npty++) {
375 		(void) sprintf(line, "/dev/pty/%03d", npty);
376 		p = open(line, 2);
377 		if (p < 0)
378 			continue;
379 		(void) sprintf(line, "/dev/ttyp%03d", npty);
380 		if (access(line, 6) == 0)
381 			return(p);
382 		else {
383 			/* no tty side to pty so skip it */
384 			(void) close(p);
385 		}
386 	}
387 #endif	/* CRAY */
388 	return(-1);
389 }
390 
391 #ifdef	LINEMODE
392 /*
393  * tty_flowmode()	Find out if flow control is enabled or disabled.
394  * tty_linemode()	Find out if linemode (external processing) is enabled.
395  * tty_setlinemod(on)	Turn on/off linemode.
396  * tty_isecho()		Find out if echoing is turned on.
397  * tty_setecho(on)	Enable/disable character echoing.
398  * tty_israw()		Find out if terminal is in RAW mode.
399  * tty_binaryin(on)	Turn on/off BINARY on input.
400  * tty_binaryout(on)	Turn on/off BINARY on output.
401  * tty_isediting()	Find out if line editing is enabled.
402  * tty_istrapsig()	Find out if signal trapping is enabled.
403  * tty_setedit(on)	Turn on/off line editing.
404  * tty_setsig(on)	Turn on/off signal trapping.
405  * tty_issofttab()	Find out if tab expansion is enabled.
406  * tty_setsofttab(on)	Turn on/off soft tab expansion.
407  * tty_islitecho()	Find out if typed control chars are echoed literally
408  * tty_setlitecho()	Turn on/off literal echo of control chars
409  * tty_tspeed(val)	Set transmit speed to val.
410  * tty_rspeed(val)	Set receive speed to val.
411  */
412 
413 tty_flowmode()
414 {
415 #ifndef USE_TERMIO
416 	return((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0);
417 #else
418 	return(termbuf.c_iflag & IXON ? 1 : 0);
419 #endif
420 }
421 
422 tty_linemode()
423 {
424 #ifndef	USE_TERMIO
425 	return(termbuf.state & TS_EXTPROC);
426 #else
427 	return(termbuf.c_lflag & EXTPROC);
428 #endif
429 }
430 
431 tty_setlinemode(on)
432 int on;
433 {
434 #ifdef	TIOCEXT
435 	(void) ioctl(pty, TIOCEXT, (char *)&on);
436 #else	/* !TIOCEXT */
437 #ifdef	EXTPROC
438 	if (on)
439 		termbuf.c_lflag |= EXTPROC;
440 	else
441 		termbuf.c_lflag &= ~EXTPROC;
442 #endif
443 	set_termbuf();
444 #endif	/* TIOCEXT */
445 }
446 
447 tty_isecho()
448 {
449 #ifndef USE_TERMIO
450 	return (termbuf.sg.sg_flags & ECHO);
451 #else
452 	return (termbuf.c_lflag & ECHO);
453 #endif
454 }
455 #endif	/* LINEMODE */
456 
457 tty_setecho(on)
458 {
459 #ifndef	USE_TERMIO
460 	if (on)
461 		termbuf.sg.sg_flags |= ECHO|CRMOD;
462 	else
463 		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
464 #else
465 	if (on)
466 		termbuf.c_lflag |= ECHO;
467 	else
468 		termbuf.c_lflag &= ~ECHO;
469 #endif
470 }
471 
472 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
473 tty_israw()
474 {
475 #ifndef USE_TERMIO
476 	return(termbuf.sg.sg_flags & RAW);
477 #else
478 	return(!(termbuf.c_lflag & ICANON));
479 #endif
480 }
481 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
482 
483 tty_binaryin(on)
484 {
485 #ifndef	USE_TERMIO
486 	if (on)
487 		termbuf.lflags |= LPASS8;
488 	else
489 		termbuf.lflags &= ~LPASS8;
490 #else
491 	if (on) {
492 		termbuf.c_lflag &= ~ISTRIP;
493 	} else {
494 		termbuf.c_lflag |= ISTRIP;
495 	}
496 #endif
497 }
498 
499 tty_binaryout(on)
500 {
501 #ifndef	USE_TERMIO
502 	if (on)
503 		termbuf.lflags |= LLITOUT;
504 	else
505 		termbuf.lflags &= ~LLITOUT;
506 #else
507 	if (on) {
508 		termbuf.c_cflag &= ~(CSIZE|PARENB);
509 		termbuf.c_cflag |= CS8;
510 		termbuf.c_oflag &= ~OPOST;
511 	} else {
512 		termbuf.c_cflag &= ~CSIZE;
513 		termbuf.c_cflag |= CS7|PARENB;
514 		termbuf.c_oflag |= OPOST;
515 	}
516 #endif
517 }
518 
519 tty_isbinaryin()
520 {
521 #ifndef	USE_TERMIO
522 	return(termbuf.lflags & LPASS8);
523 #else
524 	return(!(termbuf.c_iflag & ISTRIP));
525 #endif
526 }
527 
528 tty_isbinaryout()
529 {
530 #ifndef	USE_TERMIO
531 	return(termbuf.lflags & LLITOUT);
532 #else
533 	return(!(termbuf.c_oflag&OPOST));
534 #endif
535 }
536 
537 #ifdef	LINEMODE
538 tty_isediting()
539 {
540 #ifndef USE_TERMIO
541 	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
542 #else
543 	return(termbuf.c_lflag & ICANON);
544 #endif
545 }
546 
547 tty_istrapsig()
548 {
549 #ifndef USE_TERMIO
550 	return(!(termbuf.sg.sg_flags&RAW));
551 #else
552 	return(termbuf.c_lflag & ISIG);
553 #endif
554 }
555 
556 tty_setedit(on)
557 int on;
558 {
559 #ifndef USE_TERMIO
560 	if (on)
561 		termbuf.sg.sg_flags &= ~CBREAK;
562 	else
563 		termbuf.sg.sg_flags |= CBREAK;
564 #else
565 	if (on)
566 		termbuf.c_lflag |= ICANON;
567 	else
568 		termbuf.c_lflag &= ~ICANON;
569 #endif
570 }
571 
572 tty_setsig(on)
573 int on;
574 {
575 #ifndef	USE_TERMIO
576 	if (on)
577 		;
578 #else
579 	if (on)
580 		termbuf.c_lflag |= ISIG;
581 	else
582 		termbuf.c_lflag &= ~ISIG;
583 #endif
584 }
585 #endif	/* LINEMODE */
586 
587 tty_issofttab()
588 {
589 #ifndef	USE_TERMIO
590 	return (termbuf.sg.sg_flags & XTABS);
591 #else
592 # ifdef	OXTABS
593 	return (termbuf.c_oflag & OXTABS);
594 # endif
595 # ifdef	TABDLY
596 	return ((termbuf.c_oflag & TABDLY) == TAB3);
597 # endif
598 #endif
599 }
600 
601 tty_setsofttab(on)
602 int on;
603 {
604 #ifndef	USE_TERMIO
605 	if (on)
606 		termbuf.sg.sg_flags |= XTABS;
607 	else
608 		termbuf.sg.sg_flags &= ~XTABS;
609 #else
610 	if (on) {
611 # ifdef	OXTABS
612 		termbuf.c_oflag |= OXTABS;
613 # endif
614 # ifdef	TABDLY
615 		termbuf.c_oflag &= ~TABDLY;
616 		termbuf.c_oflag |= TAB3;
617 # endif
618 	} else {
619 # ifdef	OXTABS
620 		termbuf.c_oflag &= ~OXTABS;
621 # endif
622 # ifdef	TABDLY
623 		termbuf.c_oflag &= ~TABDLY;
624 		termbuf.c_oflag |= TAB0;
625 # endif
626 	}
627 #endif
628 }
629 
630 tty_islitecho()
631 {
632 #ifndef	USE_TERMIO
633 	return (!(termbuf.sg.sg_flags & CTLECH));
634 #else
635 # ifdef	ECHOCTL
636 	return (!(termbuf.c_lflag & ECHOCTL));
637 # endif
638 # ifdef	TCTLECH
639 	return (!(termbuf.c_lflag & TCTLECH));
640 # endif
641 # if	!defined(ECHOCTL) && !defined(TCTLECH)
642 	return (0);	/* assumes ctl chars are echoed '^x' */
643 # endif
644 #endif
645 }
646 
647 tty_setlitecho(on)
648 int on;
649 {
650 #ifndef	USE_TERMIO
651 	if (on)
652 		termbuf.sg.sg_flags &= ~CTLECH;
653 	else
654 		termbuf.sg.sg_flags |= CTLECH;
655 #else
656 # ifdef	ECHOCTL
657 	if (on)
658 		termbuf.c_lflag &= ~ECHOCTL;
659 	else
660 		termbuf.c_lflag |= ECHOCTL;
661 # endif
662 # ifdef	TCTLECH
663 	if (on)
664 		termbuf.c_lflag &= ~TCTLECH;
665 	else
666 		termbuf.c_lflag |= TCTLECH;
667 # endif
668 #endif
669 }
670 
671 /*
672  * A table of available terminal speeds
673  */
674 struct termspeeds {
675 	int	speed;
676 	int	value;
677 } termspeeds[] = {
678 	{ 0,     B0 },    { 50,    B50 },   { 75,    B75 },
679 	{ 110,   B110 },  { 134,   B134 },  { 150,   B150 },
680 	{ 200,   B200 },  { 300,   B300 },  { 600,   B600 },
681 	{ 1200,  B1200 }, { 1800,  B1800 }, { 2400,  B2400 },
682 	{ 4800,  B4800 }, { 9600,  B9600 }, { 19200, B9600 },
683 	{ 38400, B9600 }, { -1,    B9600 }
684 };
685 
686 tty_tspeed(val)
687 {
688 	register struct termspeeds *tp;
689 
690 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
691 		;
692 #ifndef	USE_TERMIO
693 	termbuf.sg.sg_ospeed = tp->value;
694 #else
695 # ifdef	CBAUD
696 	termbuf.c_cflag &= ~CBAUD;
697 	termbuf.c_cflag |= tp->value;
698 # else
699 	termbuf.c_ospeed = tp->value;
700 # endif
701 #endif
702 }
703 
704 tty_rspeed(val)
705 {
706 	register struct termspeeds *tp;
707 
708 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
709 		;
710 #ifndef	USE_TERMIO
711 	termbuf.sg.sg_ispeed = tp->value;
712 #else
713 # ifdef	CBAUD
714 	termbuf.c_cflag &= ~CBAUD;
715 	termbuf.c_cflag |= tp->value;
716 # else
717 	termbuf.c_ispeed = tp->value;
718 # endif
719 #endif
720 }
721 
722 #if	defined(CRAY2) && defined(UNICOS5)
723 tty_isnewmap()
724 {
725 	return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
726 			!(termbuf.c_oflag & ONLRET));
727 }
728 #endif
729 
730 #ifdef	CRAY
731 # ifndef NEWINIT
732 extern	struct utmp wtmp;
733 extern char wtmpf[];
734 # else	/* NEWINIT */
735 int	gotalarm;
736 /* ARGSUSED */
737 void
738 nologinproc(sig)
739 int sig;
740 {
741 	gotalarm++;
742 }
743 # endif	/* NEWINIT */
744 #endif /* CRAY */
745 
746 /*
747  * getptyslave()
748  *
749  * Open the slave side of the pty, and do any initialization
750  * that is necessary.  The return value is a file descriptor
751  * for the slave side.
752  */
753 getptyslave()
754 {
755 	register int t = -1;
756 
757 #ifndef	CRAY
758 	/*
759 	 * Disassociate self from control terminal and open ttyp side.
760 	 * Set important flags on ttyp and ptyp.
761 	 */
762 	t = open(_PATH_TTY, O_RDWR);
763 	if (t >= 0) {
764 		(void) ioctl(t, TIOCNOTTY, (char *)0);
765 		(void) close(t);
766 	}
767 
768 	t = open(line, O_RDWR);
769 	if (t < 0)
770 		fatalperror(net, line);
771 	if (fchmod(t, 0))
772 		fatalperror(net, line);
773 #if BSD <= 43
774 	(void) signal(SIGHUP, SIG_IGN);
775 	vhangup();
776 	(void) signal(SIGHUP, SIG_DFL);
777 	t = open(line, O_RDWR);
778 	if (t < 0)
779 		fatalperror(net, line);
780 #endif
781 
782 	init_termbuf();
783 #ifndef	USE_TERMIO
784 	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
785 	termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
786 #else
787 	termbuf.c_lflag |= ECHO;
788 #ifndef	OXTABS
789 #define OXTABS	0
790 #endif
791 	termbuf.c_oflag |= ONLCR|OXTABS;
792 	termbuf.c_iflag |= ICRNL;
793 	termbuf.c_iflag &= ~IXOFF;
794 # ifdef	CBAUD
795 	termbuf.c_cflag &= ~CBAUD;
796 	termbuf.c_cflag |= B9600;
797 # else	/* CBAUD */
798 	termbuf.c_ospeed = termbuf.c_ispeed = B9600;
799 # endif	/* CBAUD */
800 #endif
801 	set_termbuf();
802 #else	/* CRAY */
803 	(void) chown(line, 0, 0);
804 	(void) chmod(line, 0600);
805 #endif	/* CRAY */
806 	return(t);
807 }
808 
809 #ifdef	NEWINIT
810 char *gen_id = "fe";
811 #endif
812 
813 /*
814  * startslave(t, host)
815  *
816  * Given a file descriptor (t) for a tty, and a hostname, do whatever
817  * is necessary to startup the login process on the slave side of the pty.
818  */
819 
820 /* ARGSUSED */
821 startslave(t, host)
822 int t;
823 char *host;
824 {
825 	register int i;
826 	long time();
827 
828 #ifndef	NEWINIT
829 # ifdef	CRAY
830 	utmp_sig_init();
831 # endif	/* CRAY */
832 
833 	if ((i = fork()) < 0)
834 		fatalperror(net, "fork");
835 	if (i) {
836 # ifdef	CRAY
837 		/*
838 		 * Cray parent will create utmp entry for child and send
839 		 * signal to child to tell when done.  Child waits for signal
840 		 * before doing anything important.
841 		 */
842 		register int pid = i;
843 
844 		setpgrp();
845 		utmp_sig_reset();		/* reset handler to default */
846 		/*
847 		 * Create utmp entry for child
848 		 */
849 		(void) time(&wtmp.ut_time);
850 		wtmp.ut_type = LOGIN_PROCESS;
851 		wtmp.ut_pid = pid;
852 		SCPYN(wtmp.ut_user, "LOGIN");
853 		SCPYN(wtmp.ut_host, host);
854 		SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
855 		SCPYN(wtmp.ut_id, wtmp.ut_line+3);
856 		pututline(&wtmp);
857 		endutent();
858 		if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
859 			(void) write(i, (char *)&wtmp, sizeof(struct utmp));
860 			(void) close(i);
861 		}
862 		utmp_sig_notify(pid);
863 # endif	/* CRAY */
864 		(void) close(t);
865 	} else {
866 		start_login(t, host);
867 		/*NOTREACHED*/
868 	}
869 #else	/* NEWINIT */
870 
871 	extern char *ptyip;
872 	struct init_request request;
873 	void nologinproc();
874 	register int n;
875 
876 	/*
877 	 * Init will start up login process if we ask nicely.  We only wait
878 	 * for it to start up and begin normal telnet operation.
879 	 */
880 	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
881 		char tbuf[128];
882 		(void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
883 		fatalperror(net, tbuf);
884 	}
885 	memset((char *)&request, 0, sizeof(request));
886 	request.magic = INIT_MAGIC;
887 	SCPYN(request.gen_id, gen_id);
888 	SCPYN(request.tty_id, &line[8]);
889 	SCPYN(request.host, host);
890 	SCPYN(request.term_type, terminaltype);
891 #if	!defined(UNICOS5)
892 	request.signal = SIGCLD;
893 	request.pid = getpid();
894 #endif
895 #ifdef BFTPDAEMON
896 	/*
897 	 * Are we working as the bftp daemon?
898 	 */
899 	if (bftpd) {
900 		SCPYN(request.exec_name, BFTPPATH);
901 	}
902 #endif /* BFTPDAEMON */
903 	if (write(i, (char *)&request, sizeof(request)) < 0) {
904 		char tbuf[128];
905 		(void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
906 		fatalperror(net, tbuf);
907 	}
908 	(void) close(i);
909 	(void) signal(SIGALRM, nologinproc);
910 	for (i = 0; ; i++) {
911 		char tbuf[128];
912 		alarm(15);
913 		n = read(pty, ptyip, BUFSIZ);
914 		if (i == 3 || n >= 0 || !gotalarm)
915 			break;
916 		gotalarm = 0;
917 		sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
918 		(void) write(net, tbuf, strlen(tbuf));
919 	}
920 	if (n < 0 && gotalarm)
921 		fatal(net, "/etc/init didn't start login process");
922 	pcc += n;
923 	alarm(0);
924 	(void) signal(SIGALRM, SIG_DFL);
925 
926 	return;
927 #endif	/* NEWINIT */
928 }
929 
930 char	*envinit[3];
931 extern char **environ;
932 
933 init_env()
934 {
935 	extern char *getenv();
936 	char **envp;
937 
938 	envp = envinit;
939 	if (*envp = getenv("TZ"))
940 		*envp++ -= 3;
941 #ifdef	CRAY
942 	else
943 		*envp++ = "TZ=GMT0";
944 #endif
945 	*envp = 0;
946 	environ = envinit;
947 }
948 
949 #ifdef	CRAY
950 /*
951  * These are environment variable that we
952  * don't put on the argument line.
953  */
954 char *invalid[] = {
955 	"USER=",	/* Set up by login */
956 	"HOME=",	/* Set up by login */
957 	"LOGNAME=",	/* Set up by login */
958 	"TMPDIR=",	/* Set up by login */
959 	"SHELL=",	/* Set up by login */
960 	"PATH=",	/* Set up by login */
961 	"MAIL=",	/* Set up by login */
962 	"TZ=",		/* Login gets it from the environment */
963 	"TERM=",	/* Login gets it from the environment */
964 	0
965 };
966 #endif
967 
968 #ifndef	NEWINIT
969 
970 /*
971  * start_login(t, host)
972  *
973  * Assuming that we are now running as a child processes, this
974  * function will turn us into the login process.
975  */
976 
977 start_login(t, host)
978 int t;
979 char *host;
980 {
981 	register char *cp;
982 	register char **argv;
983 	char **addarg();
984 #ifdef	CRAY
985 	register char **cpp, **cpp2;
986 	utmp_sig_wait();
987 # ifndef TCVHUP
988 	setpgrp();
989 # endif
990 	t = open(line, 2);	/* open ttyp */
991 	if (t < 0)
992 		fatalperror(net, line);
993 # ifdef	TCVHUP
994 	/*
995 	 * Hangup anybody else using this ttyp, then reopen it for
996 	 * ourselves.
997 	 */
998 	(void) chown(line, 0, 0);
999 	(void) chmod(line, 0600);
1000 	(void) signal(SIGHUP, SIG_IGN);
1001 	(void) ioctl(t, TCVHUP, (char *)0);
1002 	(void) signal(SIGHUP, SIG_DFL);
1003 	setpgrp();
1004 	i = open(line, 2);
1005 	if (i < 0)
1006 		fatalperror(net, line);
1007 	(void) close(t);
1008 	t = i;
1009 # endif	/* TCVHUP */
1010 	/*
1011 	 * set ttyp modes as we like them to be
1012 	 */
1013 	init_termbuf();
1014 	termbuf.c_oflag = OPOST|ONLCR|TAB3;
1015 	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1016 	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1017 	termbuf.c_cflag = EXTB|HUPCL|CS8;
1018 	set_termbuf();
1019 #endif	/* CRAY */
1020 
1021 	/*
1022 	 * set up standard paths before forking to login
1023 	 */
1024 #if BSD > 43
1025 	if (login_tty(t) == -1)
1026 		fatalperror(net, "login_tty");
1027 #else
1028 	(void) dup2(t, 0);
1029 	(void) dup2(t, 1);
1030 	(void) dup2(t, 2);
1031 	(void) close(t);
1032 #endif
1033 	if (net > 2)
1034 		(void) close(net);
1035 	if (pty > 2)
1036 		(void) close(pty);
1037 	/*
1038 	 * -h : pass on name of host.
1039 	 *		WARNING:  -h is accepted by login if and only if
1040 	 *			getuid() == 0.
1041 	 * -p : don't clobber the environment (so terminal type stays set).
1042 	 */
1043 	argv = addarg(0, "login");
1044 	argv = addarg(argv, "-h");
1045 	argv = addarg(argv, host);
1046 #if	!defined(CRAY) && !defined(NO_LOGIN_P)
1047 	argv = addarg(argv, "-p");
1048 #endif
1049 #ifdef	BFTPDAEMON
1050 	/*
1051 	 * Are we working as the bftp daemon?  If so, then ask login
1052 	 * to start bftp instead of shell.
1053 	 */
1054 	if (bftpd) {
1055 		argv = addarg(argv, "-e");
1056 		argv = addarg(argv, BFTPPATH);
1057 	} else
1058 #endif
1059 	if (getenv("USER")) {
1060 		argv = addarg(argv, getenv("USER"));
1061 	}
1062 #ifdef	CRAY
1063 	for (cpp = environ; *cpp; cpp++) {
1064 		for (cpp2 = invalid; *cpp2; cpp2++)
1065 			if (strncmp(*cpp2, *cpp, strlen(*cpp2)) == 0)
1066 				break;
1067 		if (*cpp2)
1068 			continue;
1069 		argv = addarg(argv, *cpp);
1070 	}
1071 #endif
1072 
1073 	execv(_PATH_LOGIN, argv);
1074 
1075 	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
1076 	fatalperror(net, _PATH_LOGIN);
1077 	/*NOTREACHED*/
1078 }
1079 
1080 char **
1081 addarg(argv, val)
1082 register char **argv;
1083 register char *val;
1084 {
1085 	register char **cpp;
1086 	char *malloc();
1087 
1088 	if (argv == NULL) {
1089 		/*
1090 		 * 10 entries, a leading length, and a null
1091 		 */
1092 		argv = (char **)malloc(sizeof(*argv) * 12);
1093 		if (argv == NULL)
1094 			return(NULL);
1095 		*argv++ = (char *)10;
1096 		*argv = (char *)0;
1097 	}
1098 	for (cpp = argv; *cpp; cpp++)
1099 		;
1100 	if (cpp == &argv[(int)argv[-1]]) {
1101 		--argv;
1102 		*argv = (char *)((int)(*argv) + 10);
1103 		argv = (char **)realloc(argv, (int)(*argv) + 2);
1104 		if (argv == NULL)
1105 			return(NULL);
1106 		argv++;
1107 		cpp = &argv[(int)argv[-1] - 10];
1108 	}
1109 	*cpp++ = val;
1110 	*cpp = 0;
1111 	return(argv);
1112 }
1113 #endif	NEWINIT
1114 
1115 /*
1116  * cleanup()
1117  *
1118  * This is the routine to call when we are all through, to
1119  * clean up anything that needs to be cleaned up.
1120  */
1121 cleanup()
1122 {
1123 
1124 #ifndef	CRAY
1125 # if BSD > 43
1126 	char *p;
1127 
1128 	p = line + sizeof("/dev/") - 1;
1129 	if (logout(p))
1130 		logwtmp(p, "", "");
1131 	(void)chmod(line, 0666);
1132 	(void)chown(line, 0, 0);
1133 	*p = 'p';
1134 	(void)chmod(line, 0666);
1135 	(void)chown(line, 0, 0);
1136 # else
1137 	rmut();
1138 	vhangup();	/* XXX */
1139 # endif
1140 	(void) shutdown(net, 2);
1141 #else	/* CRAY */
1142 # ifndef NEWINIT
1143 	rmut(line);
1144 	(void) shutdown(net, 2);
1145 	kill(0, SIGHUP);
1146 # else	/* NEWINIT */
1147 	(void) shutdown(net, 2);
1148 # endif	/* NEWINT */
1149 #endif	/* CRAY */
1150 	exit(1);
1151 }
1152 
1153 #if	defined(CRAY) && !defined(NEWINIT)
1154 /*
1155  * _utmp_sig_rcv
1156  * utmp_sig_init
1157  * utmp_sig_wait
1158  *	These three functions are used to coordinate the handling of
1159  *	the utmp file between the server and the soon-to-be-login shell.
1160  *	The server actually creates the utmp structure, the child calls
1161  *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
1162  *	signals the future-login shell to proceed.
1163  */
1164 static int caught=0;		/* NZ when signal intercepted */
1165 static void (*func)();		/* address of previous handler */
1166 
1167 void
1168 _utmp_sig_rcv(sig)
1169 int sig;
1170 {
1171 	caught = 1;
1172 	(void) signal(SIGUSR1, func);
1173 }
1174 
1175 utmp_sig_init()
1176 {
1177 	/*
1178 	 * register signal handler for UTMP creation
1179 	 */
1180 	if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1181 		fatalperror(net, "telnetd/signal");
1182 }
1183 
1184 utmp_sig_reset()
1185 {
1186 	(void) signal(SIGUSR1, func);	/* reset handler to default */
1187 }
1188 
1189 utmp_sig_wait()
1190 {
1191 	/*
1192 	 * Wait for parent to write our utmp entry.
1193 	 */
1194 	sigoff();
1195 	while (caught == 0) {
1196 		pause();	/* wait until we get a signal (sigon) */
1197 		sigoff();	/* turn off signals while we check caught */
1198 	}
1199 	sigon();		/* turn on signals again */
1200 }
1201 
1202 utmp_sig_notify(pid)
1203 {
1204 	kill(pid, SIGUSR1);
1205 }
1206 #endif	/* defined(CRAY) && !defined(NEWINIT) */
1207 
1208 /*
1209  * rmut()
1210  *
1211  * This is the function called by cleanup() to
1212  * remove the utmp entry for this person.
1213  */
1214 
1215 #if	!defined(CRAY) && BSD <= 43
1216 rmut()
1217 {
1218 	register f;
1219 	int found = 0;
1220 	struct utmp *u, *utmp;
1221 	int nutmp;
1222 	struct stat statbf;
1223 	char *malloc();
1224 	long time();
1225 	off_t lseek();
1226 
1227 	f = open(utmpf, O_RDWR);
1228 	if (f >= 0) {
1229 		(void) fstat(f, &statbf);
1230 		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1231 		if (!utmp)
1232 			syslog(LOG_ERR, "utmp malloc failed");
1233 		if (statbf.st_size && utmp) {
1234 			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
1235 			nutmp /= sizeof(struct utmp);
1236 
1237 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
1238 				if (SCMPN(u->ut_line, line+5) ||
1239 				    u->ut_name[0]==0)
1240 					continue;
1241 				(void) lseek(f, ((long)u)-((long)utmp), L_SET);
1242 				SCPYN(u->ut_name, "");
1243 				SCPYN(u->ut_host, "");
1244 				(void) time(&u->ut_time);
1245 				(void) write(f, (char *)u, sizeof(wtmp));
1246 				found++;
1247 			}
1248 		}
1249 		(void) close(f);
1250 	}
1251 	if (found) {
1252 		f = open(wtmpf, O_WRONLY|O_APPEND);
1253 		if (f >= 0) {
1254 			SCPYN(wtmp.ut_line, line+5);
1255 			SCPYN(wtmp.ut_name, "");
1256 			SCPYN(wtmp.ut_host, "");
1257 			(void) time(&wtmp.ut_time);
1258 			(void) write(f, (char *)&wtmp, sizeof(wtmp));
1259 			(void) close(f);
1260 		}
1261 	}
1262 	(void) chmod(line, 0666);
1263 	(void) chown(line, 0, 0);
1264 	line[strlen("/dev/")] = 'p';
1265 	(void) chmod(line, 0666);
1266 	(void) chown(line, 0, 0);
1267 }  /* end of rmut */
1268 #endif	/* CRAY */
1269