pty library
[unix-history] / usr / src / libexec / telnetd / sys_term.c
CommitLineData
ea139302
PB
1/*
2 * Copyright (c) 1989 Regents of the University of California.
3 * All rights reserved.
4 *
836fe169 5 * %sccs.include.redist.c%
ea139302
PB
6 */
7
8#ifndef lint
9633556e 9static char sccsid[] = "@(#)sys_term.c 5.9 (Berkeley) %G%";
ea139302
PB
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>
19struct utmp wtmp;
20
21# ifndef CRAY
22char wtmpf[] = "/usr/adm/wtmp";
23char utmpf[] = "/etc/utmp";
24# else /* CRAY */
25char 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
4a8a7128
PB
32#ifdef STREAMS
33#include <sys/stream.h>
34#endif
ea139302
PB
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
4a8a7128
PB
53#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
54# define EXTPROC 0400
55#endif
56
ea139302
PB
57#ifndef USE_TERMIO
58struct 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 */
ea139302
PB
66# ifdef SYSV_TERMIO
67# define termios termio
68# endif
7308c4e5 69# ifndef TCSETA
4a8a7128
PB
70# ifdef TCSETS
71# define TCSETA TCSETS
72# define TCGETA TCGETS
73# else
74# define TCSETA TIOCSETA
75# define TCGETA TIOCGETA
76# endif
7308c4e5 77# endif /* 4.4BSD */
ea139302
PB
78struct 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
92init_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)
108copy_termbuf(cp, len)
109char *cp;
110int 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
119set_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);
ed8f31c1 137# if defined(CRAY2) && defined(UNCIOS5)
ea139302
PB
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
156spcset(func, valp, valpp)
157int func;
ed8f31c1
PB
158cc_t *valp;
159cc_t **valpp;
ea139302
PB
160{
161 switch(func) {
162 case SLC_EOF:
163 *valp = termbuf.tc.t_eofc;
ed8f31c1 164 *valpp = (cc_t *)&termbuf.tc.t_eofc;
ea139302
PB
165 return(SLC_VARIABLE);
166 case SLC_EC:
167 *valp = termbuf.sg.sg_erase;
ed8f31c1 168 *valpp = (cc_t *)&termbuf.sg.sg_erase;
ea139302
PB
169 return(SLC_VARIABLE);
170 case SLC_EL:
171 *valp = termbuf.sg.sg_kill;
ed8f31c1 172 *valpp = (cc_t *)&termbuf.sg.sg_kill;
ea139302
PB
173 return(SLC_VARIABLE);
174 case SLC_IP:
175 *valp = termbuf.tc.t_intrc;
ed8f31c1 176 *valpp = (cc_t *)&termbuf.tc.t_intrc;
ea139302
PB
177 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
178 case SLC_ABORT:
179 *valp = termbuf.tc.t_quitc;
ed8f31c1 180 *valpp = (cc_t *)&termbuf.tc.t_quitc;
ea139302
PB
181 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
182 case SLC_XON:
183 *valp = termbuf.tc.t_startc;
ed8f31c1 184 *valpp = (cc_t *)&termbuf.tc.t_startc;
ea139302
PB
185 return(SLC_VARIABLE);
186 case SLC_XOFF:
187 *valp = termbuf.tc.t_stopc;
ed8f31c1 188 *valpp = (cc_t *)&termbuf.tc.t_stopc;
ea139302
PB
189 return(SLC_VARIABLE);
190 case SLC_AO:
191 *valp = termbuf.ltc.t_flushc;
ed8f31c1 192 *valpp = (cc_t *)&termbuf.ltc.t_flushc;
ea139302
PB
193 return(SLC_VARIABLE);
194 case SLC_SUSP:
195 *valp = termbuf.ltc.t_suspc;
ed8f31c1 196 *valpp = (cc_t *)&termbuf.ltc.t_suspc;
ea139302
PB
197 return(SLC_VARIABLE);
198 case SLC_EW:
199 *valp = termbuf.ltc.t_werasc;
ed8f31c1 200 *valpp = (cc_t *)&termbuf.ltc.t_werasc;
ea139302
PB
201 return(SLC_VARIABLE);
202 case SLC_RP:
203 *valp = termbuf.ltc.t_rprntc;
ed8f31c1 204 *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
ea139302
PB
205 return(SLC_VARIABLE);
206 case SLC_LNEXT:
207 *valp = termbuf.ltc.t_lnextc;
ed8f31c1
PB
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;
ea139302
PB
213 return(SLC_VARIABLE);
214 case SLC_BRK:
215 case SLC_SYNCH:
216 case SLC_AYT:
217 case SLC_EOR:
ed8f31c1
PB
218 *valp = (cc_t)0;
219 *valpp = (cc_t *)0;
ea139302
PB
220 return(SLC_DEFAULT);
221 default:
ed8f31c1
PB
222 *valp = (cc_t)0;
223 *valpp = (cc_t *)0;
ea139302
PB
224 return(SLC_NOSUPPORT);
225 }
226}
227
228#else /* USE_TERMIO */
229
230spcset(func, valp, valpp)
231int func;
ed8f31c1
PB
232cc_t *valp;
233cc_t **valpp;
ea139302 234{
053fd49d
PB
235
236#define setval(a, b) *valp = termbuf.c_cc[a]; \
237 *valpp = &termbuf.c_cc[a]; \
238 return(b);
ed8f31c1 239#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
053fd49d 240
ea139302
PB
241 switch(func) {
242 case SLC_EOF:
053fd49d 243 setval(VEOF, SLC_VARIABLE);
ea139302 244 case SLC_EC:
053fd49d 245 setval(VERASE, SLC_VARIABLE);
ea139302 246 case SLC_EL:
053fd49d 247 setval(VKILL, SLC_VARIABLE);
ea139302 248 case SLC_IP:
053fd49d 249 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
ea139302 250 case SLC_ABORT:
053fd49d 251 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
ea139302 252 case SLC_XON:
053fd49d
PB
253#ifdef VSTART
254 setval(VSTART, SLC_VARIABLE);
255#else
256 defval(0x13);
257#endif
ea139302 258 case SLC_XOFF:
053fd49d
PB
259#ifdef VSTOP
260 setval(VSTOP, SLC_VARIABLE);
261#else
262 defval(0x11);
263#endif
ea139302 264 case SLC_EW:
053fd49d
PB
265#ifdef VWERASE
266 setval(VWERASE, SLC_VARIABLE);
267#else
268 defval(0);
269#endif
ea139302 270 case SLC_RP:
053fd49d
PB
271#ifdef VREPRINT
272 setval(VREPRINT, SLC_VARIABLE);
273#else
274 defval(0);
275#endif
ea139302 276 case SLC_LNEXT:
053fd49d
PB
277#ifdef VLNEXT
278 setval(VLNEXT, SLC_VARIABLE);
279#else
280 defval(0);
281#endif
282 case SLC_AO:
4a8a7128
PB
283#ifdef VFLUSHO
284 setval(VFLUSHO, SLC_VARIABLE|SLC_FLUSHOUT);
053fd49d
PB
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
ed8f31c1
PB
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
053fd49d 302
ea139302
PB
303 case SLC_BRK:
304 case SLC_SYNCH:
305 case SLC_AYT:
306 case SLC_EOR:
053fd49d
PB
307 defval(0);
308
ea139302
PB
309 default:
310 *valp = 0;
311 *valpp = 0;
312 return(SLC_NOSUPPORT);
313 }
314}
315#endif /* USE_TERMIO */
316
ed8f31c1
PB
317#ifdef CRAY
318/*
319 * getnpty()
320 *
321 * Return the number of pty's configured into the system.
322 */
323getnpty()
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
ea139302
PB
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 */
341char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
342
343getpty()
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.
4a8a7128
PB
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
ea139302
PB
409 * tty_tspeed(val) Set transmit speed to val.
410 * tty_rspeed(val) Set receive speed to val.
411 */
412
413tty_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
422tty_linemode()
423{
424#ifndef USE_TERMIO
425 return(termbuf.state & TS_EXTPROC);
426#else
427 return(termbuf.c_lflag & EXTPROC);
428#endif
429}
430
431tty_setlinemode(on)
432int 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
447tty_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
457tty_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)
473tty_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
483tty_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
499tty_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
519tty_isbinaryin()
520{
521#ifndef USE_TERMIO
522 return(termbuf.lflags & LPASS8);
523#else
053fd49d 524 return(!(termbuf.c_iflag & ISTRIP));
ea139302
PB
525#endif
526}
527
528tty_isbinaryout()
529{
530#ifndef USE_TERMIO
531 return(termbuf.lflags & LLITOUT);
532#else
053fd49d 533 return(!(termbuf.c_oflag&OPOST));
ea139302
PB
534#endif
535}
536
537#ifdef LINEMODE
538tty_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
547tty_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
556tty_setedit(on)
557int 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
572tty_setsig(on)
573int 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
4a8a7128
PB
587tty_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
601tty_setsofttab(on)
602int 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
630tty_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
647tty_setlitecho(on)
648int 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
ea139302
PB
671/*
672 * A table of available terminal speeds
673 */
674struct 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
686tty_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
4a8a7128 695# ifdef CBAUD
ea139302
PB
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
704tty_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
4a8a7128 713# ifdef CBAUD
ea139302
PB
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
ed8f31c1 722#if defined(CRAY2) && defined(UNICOS5)
ea139302
PB
723tty_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
732extern struct utmp wtmp;
733extern char wtmpf[];
734# else /* NEWINIT */
735int gotalarm;
ed8f31c1
PB
736/* ARGSUSED */
737void
738nologinproc(sig)
739int sig;
ea139302
PB
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 */
753getptyslave()
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);
4a8a7128 773#if BSD <= 43
ea139302
PB
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);
4a8a7128 780#endif
ea139302
PB
781
782 init_termbuf();
783#ifndef USE_TERMIO
ed8f31c1 784 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
ea139302
PB
785 termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
786#else
787 termbuf.c_lflag |= ECHO;
4a8a7128
PB
788#ifndef OXTABS
789#define OXTABS 0
790#endif
ea139302
PB
791 termbuf.c_oflag |= ONLCR|OXTABS;
792 termbuf.c_iflag |= ICRNL;
793 termbuf.c_iflag &= ~IXOFF;
4a8a7128
PB
794# ifdef CBAUD
795 termbuf.c_cflag &= ~CBAUD;
796 termbuf.c_cflag |= B9600;
797# else /* CBAUD */
ea139302 798 termbuf.c_ospeed = termbuf.c_ispeed = B9600;
4a8a7128 799# endif /* CBAUD */
ea139302
PB
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
810char *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 */
821startslave(t, host)
822int t;
823char *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();
4a8a7128 845 utmp_sig_reset(); /* reset handler to default */
ea139302
PB
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;
ed8f31c1 873 void nologinproc();
ea139302
PB
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);
4a8a7128
PB
890 SCPYN(request.term_type, terminaltype);
891#if !defined(UNICOS5)
ed8f31c1
PB
892 request.signal = SIGCLD;
893 request.pid = getpid();
894#endif
4a8a7128
PB
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 */
ea139302
PB
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++) {
ed8f31c1 911 char tbuf[128];
ea139302
PB
912 alarm(15);
913 n = read(pty, ptyip, BUFSIZ);
914 if (i == 3 || n >= 0 || !gotalarm)
915 break;
916 gotalarm = 0;
ed8f31c1
PB
917 sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
918 (void) write(net, tbuf, strlen(tbuf));
ea139302
PB
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
ea139302
PB
926 return;
927#endif /* NEWINIT */
928}
929
ea139302 930char *envinit[3];
4a8a7128
PB
931extern char **environ;
932
933init_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 */
954char *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
ea139302
PB
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
977start_login(t, host)
978int t;
979char *host;
980{
4a8a7128
PB
981 register char *cp;
982 register char **argv;
983 char **addarg();
ea139302 984#ifdef CRAY
4a8a7128 985 register char **cpp, **cpp2;
ea139302
PB
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();
ed8f31c1 1014 termbuf.c_oflag = OPOST|ONLCR|TAB3;
ea139302
PB
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 */
9633556e
MT
1024#if BSD > 43
1025 if (login_tty(t) == -1)
1026 fatalperror(net, "login_tty");
1027#else
ea139302
PB
1028 (void) dup2(t, 0);
1029 (void) dup2(t, 1);
1030 (void) dup2(t, 2);
1031 (void) close(t);
9633556e
MT
1032#endif
1033 if (net > 2)
1034 (void) close(net);
1035 if (pty > 2)
1036 (void) close(pty);
ea139302
PB
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 */
4a8a7128
PB
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 }
ea139302 1071#endif
4a8a7128
PB
1072
1073 execv(_PATH_LOGIN, argv);
1074
ea139302
PB
1075 syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
1076 fatalperror(net, _PATH_LOGIN);
1077 /*NOTREACHED*/
1078}
4a8a7128
PB
1079
1080char **
1081addarg(argv, val)
1082register char **argv;
1083register 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}
ea139302
PB
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 */
1121cleanup()
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);
ea139302
PB
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 */
1164static int caught=0; /* NZ when signal intercepted */
1165static void (*func)(); /* address of previous handler */
1166
1167void
1168_utmp_sig_rcv(sig)
1169int sig;
1170{
1171 caught = 1;
1172 (void) signal(SIGUSR1, func);
1173}
1174
1175utmp_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
4a8a7128
PB
1184utmp_sig_reset()
1185{
1186 (void) signal(SIGUSR1, func); /* reset handler to default */
1187}
1188
ea139302
PB
1189utmp_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
1202utmp_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
1216rmut()
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 */