]>
git.saurik.com Git - apple/network_cmds.git/blob - telnetd.tproj/sys_term.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1989, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char sccsid
[] = "@(#)sys_term.c 8.4 (Berkeley) 5/30/95";
62 #include "pathnames.h"
64 #if defined(AUTHENTICATION)
65 #include <libtelnet/auth.h>
68 #if defined(CRAY) || defined(__hpux)
69 # define PARENT_DOES_UTMP
74 int utmp_len
= MAXHOSTNAMELEN
; /* sizeof(init_request.host) */
84 int utmp_len
= sizeof(wtmp
.ut_host
);
85 # ifndef PARENT_DOES_UTMP
86 char wtmpf
[] = "/usr/adm/wtmp";
87 char utmpf
[] = "/var/run/utmp";
88 # else /* PARENT_DOES_UTMP */
89 char wtmpf
[] = "/etc/wtmp";
90 # endif /* PARENT_DOES_UTMP */
95 # if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1')
100 #include <sys/sysv.h>
101 #include <sys/secstat.h>
103 extern struct sysv sysv
;
104 # endif /* UNICOS7x */
110 #include <sys/stropts.h>
113 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
114 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
117 #include <sys/stream.h>
120 #include <sys/resource.h>
121 #include <sys/proc.h>
141 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
142 # define EXTPROC 0400
153 # define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
154 # define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
155 # define cfgetospeed(tp) (tp)->sg.sg_ospeed
156 # define cfgetispeed(tp) (tp)->sg.sg_ispeed
157 #else /* USE_TERMIO */
159 # define termios termio
163 # define TCSANOW TCSETS
164 # define TCSADRAIN TCSETSW
165 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
168 # define TCSANOW TCSETA
169 # define TCSADRAIN TCSETAW
170 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
172 # define TCSANOW TIOCSETA
173 # define TCSADRAIN TIOCSETAW
174 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
177 # define tcsetattr(f, a, t) ioctl(f, a, t)
178 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
179 (tp)->c_cflag |= (val)
180 # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
182 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
183 (tp)->c_cflag |= ((val)<<IBSHIFT)
184 # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
186 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
187 (tp)->c_cflag |= (val)
188 # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
190 # endif /* TCSANOW */
191 struct termios termbuf
, termbuf2
; /* pty control structure */
195 #endif /* USE_TERMIO */
202 * These three routines are used to get and set the "termbuf" structure
203 * to and from the kernel. init_termbuf() gets the current settings.
204 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
205 * set_termbuf() writes the structure into the kernel.
212 (void) ioctl(pty
, TIOCGETP
, (char *)&termbuf
.sg
);
213 (void) ioctl(pty
, TIOCGETC
, (char *)&termbuf
.tc
);
214 (void) ioctl(pty
, TIOCGLTC
, (char *)&termbuf
.ltc
);
216 (void) ioctl(pty
, TIOCGSTATE
, (char *)&termbuf
.state
);
220 (void) tcgetattr(ttyfd
, &termbuf
);
222 (void) tcgetattr(pty
, &termbuf
);
228 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
230 copy_termbuf(cp
, len
)
234 if (len
> sizeof(termbuf
))
235 len
= sizeof(termbuf
);
236 memmove((char *)&termbuf
, cp
, len
);
239 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
245 * Only make the necessary changes.
248 if (memcmp((char *)&termbuf
.sg
, (char *)&termbuf2
.sg
,
250 (void) ioctl(pty
, TIOCSETN
, (char *)&termbuf
.sg
);
251 if (memcmp((char *)&termbuf
.tc
, (char *)&termbuf2
.tc
,
253 (void) ioctl(pty
, TIOCSETC
, (char *)&termbuf
.tc
);
254 if (memcmp((char *)&termbuf
.ltc
, (char *)&termbuf2
.ltc
,
255 sizeof(termbuf
.ltc
)))
256 (void) ioctl(pty
, TIOCSLTC
, (char *)&termbuf
.ltc
);
257 if (termbuf
.lflags
!= termbuf2
.lflags
)
258 (void) ioctl(pty
, TIOCLSET
, (char *)&termbuf
.lflags
);
259 #else /* USE_TERMIO */
260 if (memcmp((char *)&termbuf
, (char *)&termbuf2
, sizeof(termbuf
)))
262 (void) tcsetattr(ttyfd
, TCSANOW
, &termbuf
);
264 (void) tcsetattr(pty
, TCSANOW
, &termbuf
);
266 # if defined(CRAY2) && defined(UNICOS5)
269 #endif /* USE_TERMIO */
274 * spcset(func, valp, valpp)
276 * This function takes various special characters (func), and
277 * sets *valp to the current value of that character, and
278 * *valpp to point to where in the "termbuf" structure that
281 * It returns the SLC_ level of support for this function.
286 spcset(func
, valp
, valpp
)
293 *valp
= termbuf
.tc
.t_eofc
;
294 *valpp
= (cc_t
*)&termbuf
.tc
.t_eofc
;
295 return(SLC_VARIABLE
);
297 *valp
= termbuf
.sg
.sg_erase
;
298 *valpp
= (cc_t
*)&termbuf
.sg
.sg_erase
;
299 return(SLC_VARIABLE
);
301 *valp
= termbuf
.sg
.sg_kill
;
302 *valpp
= (cc_t
*)&termbuf
.sg
.sg_kill
;
303 return(SLC_VARIABLE
);
305 *valp
= termbuf
.tc
.t_intrc
;
306 *valpp
= (cc_t
*)&termbuf
.tc
.t_intrc
;
307 return(SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
309 *valp
= termbuf
.tc
.t_quitc
;
310 *valpp
= (cc_t
*)&termbuf
.tc
.t_quitc
;
311 return(SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
313 *valp
= termbuf
.tc
.t_startc
;
314 *valpp
= (cc_t
*)&termbuf
.tc
.t_startc
;
315 return(SLC_VARIABLE
);
317 *valp
= termbuf
.tc
.t_stopc
;
318 *valpp
= (cc_t
*)&termbuf
.tc
.t_stopc
;
319 return(SLC_VARIABLE
);
321 *valp
= termbuf
.ltc
.t_flushc
;
322 *valpp
= (cc_t
*)&termbuf
.ltc
.t_flushc
;
323 return(SLC_VARIABLE
);
325 *valp
= termbuf
.ltc
.t_suspc
;
326 *valpp
= (cc_t
*)&termbuf
.ltc
.t_suspc
;
327 return(SLC_VARIABLE
);
329 *valp
= termbuf
.ltc
.t_werasc
;
330 *valpp
= (cc_t
*)&termbuf
.ltc
.t_werasc
;
331 return(SLC_VARIABLE
);
333 *valp
= termbuf
.ltc
.t_rprntc
;
334 *valpp
= (cc_t
*)&termbuf
.ltc
.t_rprntc
;
335 return(SLC_VARIABLE
);
337 *valp
= termbuf
.ltc
.t_lnextc
;
338 *valpp
= (cc_t
*)&termbuf
.ltc
.t_lnextc
;
339 return(SLC_VARIABLE
);
341 *valp
= termbuf
.tc
.t_brkc
;
342 *valpp
= (cc_t
*)&termbuf
.ltc
.t_lnextc
;
343 return(SLC_VARIABLE
);
354 return(SLC_NOSUPPORT
);
358 #else /* USE_TERMIO */
361 spcset(func
, valp
, valpp
)
367 #define setval(a, b) *valp = termbuf.c_cc[a]; \
368 *valpp = &termbuf.c_cc[a]; \
370 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
374 setval(VEOF
, SLC_VARIABLE
);
376 setval(VERASE
, SLC_VARIABLE
);
378 setval(VKILL
, SLC_VARIABLE
);
380 setval(VINTR
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
382 setval(VQUIT
, SLC_VARIABLE
|SLC_FLUSHIN
|SLC_FLUSHOUT
);
385 setval(VSTART
, SLC_VARIABLE
);
391 setval(VSTOP
, SLC_VARIABLE
);
397 setval(VWERASE
, SLC_VARIABLE
);
403 setval(VREPRINT
, SLC_VARIABLE
);
409 setval(VLNEXT
, SLC_VARIABLE
);
414 #if !defined(VDISCARD) && defined(VFLUSHO)
415 # define VDISCARD VFLUSHO
418 setval(VDISCARD
, SLC_VARIABLE
|SLC_FLUSHOUT
);
424 setval(VSUSP
, SLC_VARIABLE
|SLC_FLUSHIN
);
430 setval(VEOL
, SLC_VARIABLE
);
434 setval(VEOL2
, SLC_VARIABLE
);
438 setval(VSTATUS
, SLC_VARIABLE
);
451 return(SLC_NOSUPPORT
);
454 #endif /* USE_TERMIO */
460 * Return the number of pty's configured into the system.
468 if ((numptys
= sysconf(_SC_CRAY_NPTY
)) != -1)
471 #endif /* _SC_CRAY_NPTY */
480 * Allocate a pty. As a side effect, the external character
481 * array "line" contains the name of the slave side.
483 * Returns the file descriptor of the opened pty.
487 char *line
= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
489 static char Xline
[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
493 char *myline
= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
506 p
= open("/dev/ptmx", 2);
510 strcpy(line
, ptsname(p
));
514 #else /* ! STREAMSPTY */
516 register char *cp
, *p1
, *p2
;
518 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
523 (void) sprintf(line
, "/dev/ptyXX");
527 (void) sprintf(line
, "/dev/ptym/ptyXX");
532 for (cp
= "pqrstuvwxyzPQRST"; *cp
; cp
++) {
538 * This stat() check is just to keep us from
539 * looping through all 256 combinations if there
540 * aren't that many ptys available.
542 if (stat(line
, &stb
) < 0)
544 for (i
= 0; i
< 16; i
++) {
545 *p2
= "0123456789abcdef"[i
];
551 for (p1
= &line
[8]; *p1
; p1
++)
557 #if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
558 if (ioctl(p
, TIOCGPGRP
, &dummy
) == 0
564 #endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */
570 extern lowpty
, highpty
;
573 for (*ptynum
= lowpty
; *ptynum
<= highpty
; (*ptynum
)++) {
574 (void) sprintf(myline
, "/dev/pty/%03d", *ptynum
);
578 (void) sprintf(line
, "/dev/ttyp%03d", *ptynum
);
580 * Here are some shenanigans to make sure that there
581 * are no listeners lurking on the line.
583 if(stat(line
, &sb
) < 0) {
587 if(sb
.st_uid
|| sb
.st_gid
|| sb
.st_mode
!= 0600) {
596 * Now it should be safe...check for accessability.
598 if (access(line
, 6) == 0)
601 /* no tty side to pty so skip it */
606 #endif /* STREAMSPTY */
613 * tty_flowmode() Find out if flow control is enabled or disabled.
614 * tty_linemode() Find out if linemode (external processing) is enabled.
615 * tty_setlinemod(on) Turn on/off linemode.
616 * tty_isecho() Find out if echoing is turned on.
617 * tty_setecho(on) Enable/disable character echoing.
618 * tty_israw() Find out if terminal is in RAW mode.
619 * tty_binaryin(on) Turn on/off BINARY on input.
620 * tty_binaryout(on) Turn on/off BINARY on output.
621 * tty_isediting() Find out if line editing is enabled.
622 * tty_istrapsig() Find out if signal trapping is enabled.
623 * tty_setedit(on) Turn on/off line editing.
624 * tty_setsig(on) Turn on/off signal trapping.
625 * tty_issofttab() Find out if tab expansion is enabled.
626 * tty_setsofttab(on) Turn on/off soft tab expansion.
627 * tty_islitecho() Find out if typed control chars are echoed literally
628 * tty_setlitecho() Turn on/off literal echo of control chars
629 * tty_tspeed(val) Set transmit speed to val.
630 * tty_rspeed(val) Set receive speed to val.
634 static int linestate
;
642 return(termbuf
.state
& TS_EXTPROC
);
644 return(termbuf
.c_lflag
& EXTPROC
);
661 (void) ioctl(pty
, TIOCEXT
, (char *)&on
);
668 termbuf
.c_lflag
|= EXTPROC
;
670 termbuf
.c_lflag
&= ~EXTPROC
;
674 #endif /* LINEMODE */
680 return (termbuf
.sg
.sg_flags
& ECHO
);
682 return (termbuf
.c_lflag
& ECHO
);
690 return(((termbuf
.tc
.t_startc
) > 0 && (termbuf
.tc
.t_stopc
) > 0) ? 1 : 0);
692 return((termbuf
.c_iflag
& IXON
) ? 1 : 0);
701 return((termbuf
.lflags
& DECCTQ
) ? 0 : 1);
706 return((termbuf
.c_iflag
& IXANY
) ? 1 : 0);
716 termbuf
.sg
.sg_flags
|= ECHO
|CRMOD
;
718 termbuf
.sg
.sg_flags
&= ~(ECHO
|CRMOD
);
721 termbuf
.c_lflag
|= ECHO
;
723 termbuf
.c_lflag
&= ~ECHO
;
731 return(termbuf
.sg
.sg_flags
& RAW
);
733 return(!(termbuf
.c_lflag
& ICANON
));
737 #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
743 termbuf
.sg
.sg_flags
|= RAW
;
745 termbuf
.sg
.sg_flags
&= ~RAW
;
748 termbuf
.c_lflag
&= ~ICANON
;
750 termbuf
.c_lflag
|= ICANON
;
761 termbuf
.lflags
|= LPASS8
;
763 termbuf
.lflags
&= ~LPASS8
;
766 termbuf
.c_iflag
&= ~ISTRIP
;
768 termbuf
.c_iflag
|= ISTRIP
;
779 termbuf
.lflags
|= LLITOUT
;
781 termbuf
.lflags
&= ~LLITOUT
;
784 termbuf
.c_cflag
&= ~(CSIZE
|PARENB
);
785 termbuf
.c_cflag
|= CS8
;
786 termbuf
.c_oflag
&= ~OPOST
;
788 termbuf
.c_cflag
&= ~CSIZE
;
789 termbuf
.c_cflag
|= CS7
|PARENB
;
790 termbuf
.c_oflag
|= OPOST
;
799 return(termbuf
.lflags
& LPASS8
);
801 return(!(termbuf
.c_iflag
& ISTRIP
));
809 return(termbuf
.lflags
& LLITOUT
);
811 return(!(termbuf
.c_oflag
&OPOST
));
820 return(!(termbuf
.sg
.sg_flags
& (CBREAK
|RAW
)));
822 return(termbuf
.c_lflag
& ICANON
);
830 return(!(termbuf
.sg
.sg_flags
&RAW
));
832 return(termbuf
.c_lflag
& ISIG
);
842 termbuf
.sg
.sg_flags
&= ~CBREAK
;
844 termbuf
.sg
.sg_flags
|= CBREAK
;
847 termbuf
.c_lflag
|= ICANON
;
849 termbuf
.c_lflag
&= ~ICANON
;
862 termbuf
.c_lflag
|= ISIG
;
864 termbuf
.c_lflag
&= ~ISIG
;
867 #endif /* LINEMODE */
873 return (termbuf
.sg
.sg_flags
& XTABS
);
876 return (termbuf
.c_oflag
& OXTABS
);
879 return ((termbuf
.c_oflag
& TABDLY
) == TAB3
);
890 termbuf
.sg
.sg_flags
|= XTABS
;
892 termbuf
.sg
.sg_flags
&= ~XTABS
;
896 termbuf
.c_oflag
|= OXTABS
;
899 termbuf
.c_oflag
&= ~TABDLY
;
900 termbuf
.c_oflag
|= TAB3
;
904 termbuf
.c_oflag
&= ~OXTABS
;
907 termbuf
.c_oflag
&= ~TABDLY
;
908 termbuf
.c_oflag
|= TAB0
;
918 return (!(termbuf
.lflags
& LCTLECH
));
921 return (!(termbuf
.c_lflag
& ECHOCTL
));
924 return (!(termbuf
.c_lflag
& TCTLECH
));
926 # if !defined(ECHOCTL) && !defined(TCTLECH)
927 return (0); /* assumes ctl chars are echoed '^x' */
938 termbuf
.lflags
&= ~LCTLECH
;
940 termbuf
.lflags
|= LCTLECH
;
944 termbuf
.c_lflag
&= ~ECHOCTL
;
946 termbuf
.c_lflag
|= ECHOCTL
;
950 termbuf
.c_lflag
&= ~TCTLECH
;
952 termbuf
.c_lflag
|= TCTLECH
;
961 return (termbuf
.sg
.sg_flags
& CRMOD
);
963 return (termbuf
.c_iflag
& ICRNL
);
968 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
977 * A table of available terminal speeds
983 { 0, B0
}, { 50, B50
}, { 75, B75
},
984 { 110, B110
}, { 134, B134
}, { 150, B150
},
985 { 200, B200
}, { 300, B300
}, { 600, B600
},
986 { 1200, B1200
}, { 1800, B1800
}, { 2400, B2400
},
1008 { 115200, B115200
},
1011 { 230400, B230400
},
1015 #endif /* DECODE_BUAD */
1022 register struct termspeeds
*tp
;
1024 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
1026 if (tp
->speed
== -1) /* back up to last valid value */
1028 cfsetospeed(&termbuf
, tp
->value
);
1029 #else /* DECODE_BUAD */
1030 cfsetospeed(&termbuf
, val
);
1031 #endif /* DECODE_BUAD */
1039 register struct termspeeds
*tp
;
1041 for (tp
= termspeeds
; (tp
->speed
!= -1) && (val
> tp
->speed
); tp
++)
1043 if (tp
->speed
== -1) /* back up to last valid value */
1045 cfsetispeed(&termbuf
, tp
->value
);
1046 #else /* DECODE_BAUD */
1047 cfsetispeed(&termbuf
, val
);
1048 #endif /* DECODE_BAUD */
1051 #if defined(CRAY2) && defined(UNICOS5)
1055 return((termbuf
.c_oflag
& OPOST
) && (termbuf
.c_oflag
& ONLCR
) &&
1056 !(termbuf
.c_oflag
& ONLRET
));
1060 #ifdef PARENT_DOES_UTMP
1062 extern struct utmp wtmp
;
1063 extern char wtmpf
[];
1064 # else /* NEWINIT */
1074 # endif /* NEWINIT */
1075 #endif /* PARENT_DOES_UTMP */
1078 # ifdef PARENT_DOES_UTMP
1079 extern void utmp_sig_init
P((void));
1080 extern void utmp_sig_reset
P((void));
1081 extern void utmp_sig_wait
P((void));
1082 extern void utmp_sig_notify
P((int));
1083 # endif /* PARENT_DOES_UTMP */
1089 * Open the slave side of the pty, and do any initialization
1090 * that is necessary. The return value is a file descriptor
1091 * for the slave side.
1096 register int t
= -1;
1098 #if !defined(CRAY) || !defined(NEWINIT)
1104 extern int def_row
, def_col
;
1106 extern int def_tspeed
, def_rspeed
;
1108 * Opening the slave side may cause initilization of the
1109 * kernel tty structure. We need remember the state of
1110 * if linemode was turned on
1111 * terminal window size
1113 * so that we can re-set them if we need to.
1116 waslm
= tty_linemode();
1121 * Make sure that we don't have a controlling tty, and
1122 * that we are the session (process group) leader.
1125 t
= open(_PATH_TTY
, O_RDWR
);
1127 (void) ioctl(t
, TIOCNOTTY
, (char *)0);
1133 # ifdef PARENT_DOES_UTMP
1135 * Wait for our parent to get the utmp stuff to get done.
1140 t
= cleanopen(line
);
1142 fatalperror(net
, line
);
1148 if (ioctl(t
, I_PUSH
, "ptem") < 0)
1149 fatal(net
, "I_PUSH ptem");
1150 if (ioctl(t
, I_PUSH
, "ldterm") < 0)
1151 fatal(net
, "I_PUSH ldterm");
1152 if (ioctl(t
, I_PUSH
, "ttcompat") < 0)
1153 fatal(net
, "I_PUSH ttcompat");
1154 if (ioctl(pty
, I_PUSH
, "pckt") < 0)
1155 fatal(net
, "I_PUSH pckt");
1159 * set up the tty modes as we like them to be.
1163 if (def_row
|| def_col
) {
1164 memset((char *)&ws
, 0, sizeof(ws
));
1165 ws
.ws_col
= def_col
;
1166 ws
.ws_row
= def_row
;
1167 (void)ioctl(t
, TIOCSWINSZ
, (char *)&ws
);
1172 * Settings for sgtty based systems
1175 termbuf
.sg
.sg_flags
|= CRMOD
|ANYP
|ECHO
|XTABS
;
1176 # endif /* USE_TERMIO */
1179 * Settings for UNICOS (and HPUX)
1181 # if defined(CRAY) || defined(__hpux)
1182 termbuf
.c_oflag
= OPOST
|ONLCR
|TAB3
;
1183 termbuf
.c_iflag
= IGNPAR
|ISTRIP
|ICRNL
|IXON
;
1184 termbuf
.c_lflag
= ISIG
|ICANON
|ECHO
|ECHOE
|ECHOK
;
1185 termbuf
.c_cflag
= EXTB
|HUPCL
|CS8
;
1189 * Settings for all other termios/termio based
1190 * systems, other than 4.4BSD. In 4.4BSD the
1191 * kernel does the initial terminal setup.
1193 # if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
1197 termbuf
.c_lflag
|= ECHO
;
1198 termbuf
.c_oflag
|= ONLCR
|OXTABS
;
1199 termbuf
.c_iflag
|= ICRNL
;
1200 termbuf
.c_iflag
&= ~IXOFF
;
1201 # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
1202 tty_rspeed((def_rspeed
> 0) ? def_rspeed
: 9600);
1203 tty_tspeed((def_tspeed
> 0) ? def_tspeed
: 9600);
1207 # endif /* LINEMODE */
1210 * Set the tty modes, and make this our controlling tty.
1213 if (login_tty(t
) == -1)
1214 fatalperror(net
, "login_tty");
1215 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1218 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1220 * Leave the pty open so that we can write out the rlogin
1221 * protocol for /bin/login, if the authentication works.
1231 #if !defined(CRAY) || !defined(NEWINIT)
1236 * Open the specified slave side of the pty,
1237 * making sure that we have a clean tty.
1245 struct secstat secbuf
;
1246 #endif /* UNICOS7x */
1250 * Make sure that other people can't open the
1251 * slave side of the connection.
1253 (void) chown(line
, 0, 0);
1254 (void) chmod(line
, 0600);
1257 # if !defined(CRAY) && (BSD > 43)
1258 (void) revoke(line
);
1262 if (secstat(line
, &secbuf
) < 0)
1264 if (setulvl(secbuf
.st_slevel
) < 0)
1266 if (setucmp(secbuf
.st_compart
) < 0)
1269 #endif /* UNICOS7x */
1271 t
= open(line
, O_RDWR
|O_NOCTTY
);
1275 if (setulvl(sysv
.sy_minlvl
) < 0)
1280 #endif /* UNICOS7x */
1286 * Hangup anybody else using this ttyp, then reopen it for
1289 # if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
1290 (void) signal(SIGHUP
, SIG_IGN
);
1292 (void) signal(SIGHUP
, SIG_DFL
);
1293 t
= open(line
, O_RDWR
|O_NOCTTY
);
1297 # if defined(CRAY) && defined(TCVHUP)
1300 (void) signal(SIGHUP
, SIG_IGN
);
1301 (void) ioctl(t
, TCVHUP
, (char *)0);
1302 (void) signal(SIGHUP
, SIG_DFL
);
1306 if (secstat(line
, &secbuf
) < 0)
1308 if (setulvl(secbuf
.st_slevel
) < 0)
1310 if (setucmp(secbuf
.st_compart
) < 0)
1313 #endif /* UNICOS7x */
1315 i
= open(line
, O_RDWR
);
1319 if (setulvl(sysv
.sy_minlvl
) < 0)
1324 #endif /* UNICOS7x */
1331 # endif /* defined(CRAY) && defined(TCVHUP) */
1334 #endif /* !defined(CRAY) || !defined(NEWINIT) */
1345 * The setsid() may have failed because we
1346 * already have a pgrp == pid. Zero out
1347 * our pgrp and try again...
1349 if ((setpgrp(0, 0) < 0) || (setsid() < 0))
1351 fatalperror(net
, "setsid()");
1354 if (ioctl(t
, TIOCSCTTY
, (char *)0) < 0)
1355 fatalperror(net
, "ioctl(sctty)");
1358 * Close the hard fd to /dev/ttypXXX, and re-open through
1359 * the indirect /dev/tty interface.
1362 if ((t
= open("/dev/tty", O_RDWR
)) < 0)
1363 fatalperror(net
, "open(/dev/tty)");
1367 * We get our controlling tty assigned as a side-effect
1368 * of opening up a tty device. But on BSD based systems,
1369 * this only happens if our process group is zero. The
1370 * setsid() call above may have set our pgrp, so clear
1371 * it out before opening the tty...
1374 (void) setpgrp(0, 0);
1378 close(open(line
, O_RDWR
));
1390 #endif /* BSD <= 43 */
1393 char *gen_id
= "fe";
1399 * Given a hostname, do whatever
1400 * is necessary to startup the login process on the slave side of the pty.
1405 startslave(host
, autologin
, autoname
)
1415 struct init_request request
;
1418 #endif /* NEWINIT */
1420 #if defined(AUTHENTICATION)
1421 if (!autoname
|| !autoname
[0])
1424 if (autologin
< auth_level
) {
1425 fatal(net
, "Authorization failed");
1431 # ifdef PARENT_DOES_UTMP
1433 # endif /* PARENT_DOES_UTMP */
1435 if ((i
= fork()) < 0)
1436 fatalperror(net
, "fork");
1438 # ifdef PARENT_DOES_UTMP
1440 * Cray parent will create utmp entry for child and send
1441 * signal to child to tell when done. Child waits for signal
1442 * before doing anything important.
1444 register int pid
= i
;
1445 void sigjob
P((int));
1448 utmp_sig_reset(); /* reset handler to default */
1450 * Create utmp entry for child
1452 (void) time(&wtmp
.ut_time
);
1453 wtmp
.ut_type
= LOGIN_PROCESS
;
1455 SCPYN(wtmp
.ut_user
, "LOGIN");
1456 SCPYN(wtmp
.ut_host
, host
);
1457 SCPYN(wtmp
.ut_line
, line
+ sizeof("/dev/") - 1);
1459 SCPYN(wtmp
.ut_id
, wtmp
.ut_line
+3);
1461 SCPYN(wtmp
.ut_id
, wtmp
.ut_line
+7);
1465 if ((i
= open(wtmpf
, O_WRONLY
|O_APPEND
)) >= 0) {
1466 (void) write(i
, (char *)&wtmp
, sizeof(struct utmp
));
1470 (void) signal(WJSIGNAL
, sigjob
);
1472 utmp_sig_notify(pid
);
1473 # endif /* PARENT_DOES_UTMP */
1475 getptyslave(autologin
);
1476 start_login(host
, autologin
, autoname
);
1482 * Init will start up login process if we ask nicely. We only wait
1483 * for it to start up and begin normal telnet operation.
1485 if ((i
= open(INIT_FIFO
, O_WRONLY
)) < 0) {
1487 (void) sprintf(tbuf
, "Can't open %s\n", INIT_FIFO
);
1488 fatalperror(net
, tbuf
);
1490 memset((char *)&request
, 0, sizeof(request
));
1491 request
.magic
= INIT_MAGIC
;
1492 SCPYN(request
.gen_id
, gen_id
);
1493 SCPYN(request
.tty_id
, &line
[8]);
1494 SCPYN(request
.host
, host
);
1495 SCPYN(request
.term_type
, terminaltype
? terminaltype
: "network");
1496 #if !defined(UNICOS5)
1497 request
.signal
= SIGCLD
;
1498 request
.pid
= getpid();
1502 * Are we working as the bftp daemon?
1505 SCPYN(request
.exec_name
, BFTPPATH
);
1507 #endif /* BFTPDAEMON */
1508 if (write(i
, (char *)&request
, sizeof(request
)) < 0) {
1510 (void) sprintf(tbuf
, "Can't write to %s\n", INIT_FIFO
);
1511 fatalperror(net
, tbuf
);
1514 (void) signal(SIGALRM
, nologinproc
);
1515 for (i
= 0; ; i
++) {
1518 n
= read(pty
, ptyip
, BUFSIZ
);
1519 if (i
== 3 || n
>= 0 || !gotalarm
)
1522 sprintf(tbuf
, "telnetd: waiting for /etc/init to start login process on %s\r\n", line
);
1523 (void) write(net
, tbuf
, strlen(tbuf
));
1525 if (n
< 0 && gotalarm
)
1526 fatal(net
, "/etc/init didn't start login process");
1529 (void) signal(SIGALRM
, SIG_DFL
);
1532 #endif /* NEWINIT */
1536 extern char **environ
;
1541 extern char *getenv();
1545 if (*envp
= getenv("TZ"))
1547 #if defined(CRAY) || defined(__hpux)
1549 *envp
++ = "TZ=GMT0";
1560 * Assuming that we are now running as a child processes, this
1561 * function will turn us into the login process.
1565 start_login(host
, autologin
, name
)
1571 register char **argv
;
1573 extern char *getenv();
1575 register int pid
= getpid();
1585 * Create utmp entry for child
1588 memset(&utmpx
, 0, sizeof(utmpx
));
1589 SCPYN(utmpx
.ut_user
, ".telnet");
1590 SCPYN(utmpx
.ut_line
, line
+ sizeof("/dev/") - 1);
1592 utmpx
.ut_id
[0] = 't';
1593 utmpx
.ut_id
[1] = 'n';
1594 utmpx
.ut_id
[2] = SC_WILDC
;
1595 utmpx
.ut_id
[3] = SC_WILDC
;
1596 utmpx
.ut_type
= LOGIN_PROCESS
;
1597 (void) time(&utmpx
.ut_tv
.tv_sec
);
1598 if (pututxline(&utmpx
) == NULL
)
1599 fatal(net
, "pututxline failed");
1603 * -h : pass on name of host.
1604 * WARNING: -h is accepted by login if and only if
1606 * -p : don't clobber the environment (so terminal type stays set).
1608 * -f : force this login, he has already been authenticated
1610 argv
= addarg(0, "login");
1612 #if !defined(NO_LOGIN_H)
1614 # if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1616 * Don't add the "-h host" option if we are going
1617 * to be adding the "-r host" option down below...
1619 if ((auth_level
< 0) || (autologin
!= AUTH_VALID
))
1622 argv
= addarg(argv
, "-h");
1623 argv
= addarg(argv
, host
);
1626 * SVR4 version of -h takes TERM= as second arg, or -
1628 term
= getenv("TERM");
1629 if (term
== NULL
|| term
[0] == 0) {
1632 strcpy(termbuf
, "TERM=");
1633 strncat(termbuf
, term
, sizeof(termbuf
) - 6);
1636 argv
= addarg(argv
, term
);
1640 #if !defined(NO_LOGIN_P)
1641 argv
= addarg(argv
, "-p");
1645 * Set the environment variable "LINEMODE" to either
1646 * "real" or "kludge" if we are operating in either
1647 * real or kludge linemode.
1649 if (lmodetype
== REAL_LINEMODE
)
1650 setenv("LINEMODE", "real", 1);
1651 # ifdef KLUDGELINEMODE
1652 else if (lmodetype
== KLUDGE_LINEMODE
|| lmodetype
== KLUDGE_OK
)
1653 setenv("LINEMODE", "kludge", 1);
1658 * Are we working as the bftp daemon? If so, then ask login
1659 * to start bftp instead of shell.
1662 argv
= addarg(argv
, "-e");
1663 argv
= addarg(argv
, BFTPPATH
);
1666 #if defined (SecurID)
1668 * don't worry about the -f that might get sent.
1669 * A -s is supposed to override it anyhow.
1671 if (require_SecurID
)
1672 argv
= addarg(argv
, "-s");
1674 #if defined (AUTHENTICATION)
1675 if (auth_level
>= 0 && autologin
== AUTH_VALID
) {
1676 # if !defined(NO_LOGIN_F)
1677 argv
= addarg(argv
, "-f");
1678 argv
= addarg(argv
, name
);
1680 # if defined(LOGIN_R)
1682 * We don't have support for "login -f", but we
1683 * can fool /bin/login into thinking that we are
1684 * rlogind, and allow us to log in without a
1685 * password. The rlogin protocol expects
1686 * local-user\0remote-user\0term/speed\0
1692 int isecho
, israw
, xpty
, len
;
1693 extern int def_rspeed
;
1696 * Tell login that we are coming from "localhost".
1697 * If we passed in the real host name, then the
1698 * user would have to allow .rhost access from
1699 * every machine that they want authenticated
1700 * access to work from, which sort of defeats
1701 * the purpose of an authenticated login...
1702 * So, we tell login that the session is coming
1703 * from "localhost", and the user will only have
1704 * to have "localhost" in their .rhost file.
1706 # define LOGIN_HOST "localhost"
1708 argv
= addarg(argv
, "-r");
1709 argv
= addarg(argv
, LOGIN_HOST
);
1718 isecho
= tty_isecho();
1719 israw
= tty_israw();
1720 if (isecho
|| !israw
) {
1721 tty_setecho(0); /* Turn off echo */
1722 tty_setraw(1); /* Turn on raw */
1725 len
= strlen(name
)+1;
1726 write(xpty
, name
, len
);
1727 write(xpty
, name
, len
);
1728 sprintf(speed
, "%s/%d", (cp
= getenv("TERM")) ? cp
: "",
1729 (def_rspeed
> 0) ? def_rspeed
: 9600);
1730 len
= strlen(speed
)+1;
1731 write(xpty
, speed
, len
);
1733 if (isecho
|| !israw
) {
1735 tty_setecho(isecho
);
1740 * Write a newline to ensure
1741 * that login will be able to
1744 write(xpty
, "\n", 1);
1750 argv
= addarg(argv
, name
);
1755 if (getenv("USER")) {
1756 argv
= addarg(argv
, getenv("USER"));
1757 #if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1759 register char **cpp
;
1760 for (cpp
= environ
; *cpp
; cpp
++)
1761 argv
= addarg(argv
, *cpp
);
1765 * Assume that login will set the USER variable
1766 * correctly. For SysV systems, this means that
1767 * USER will no longer be set, just LOGNAME by
1768 * login. (The problem is that if the auto-login
1769 * fails, and the user then specifies a different
1770 * account name, he can get logged in with both
1771 * LOGNAME and USER in his environment, but the
1772 * USER value will be wrong.
1780 argv
= addarg(argv
, ""); /* no login name */
1781 for (p
= environ
; *p
; p
++) {
1782 argv
= addarg(argv
, *p
);
1785 #endif /* SOLARIS */
1786 #if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1792 * This sleep(1) is in here so that telnetd can
1793 * finish up with the tty. There's a race condition
1794 * the login banner message gets lost...
1797 execv(_PATH_LOGIN
, argv
);
1799 syslog(LOG_ERR
, "%s: %m\n", _PATH_LOGIN
);
1800 fatalperror(net
, _PATH_LOGIN
);
1806 register char **argv
;
1809 register char **cpp
;
1813 * 10 entries, a leading length, and a null
1815 argv
= (char **)malloc(sizeof(*argv
) * 12);
1818 *argv
++ = (char *)10;
1821 for (cpp
= argv
; *cpp
; cpp
++)
1823 if (cpp
== &argv
[(int)argv
[-1]]) {
1825 *argv
= (char *)((int)(*argv
) + 10);
1826 argv
= (char **)realloc(argv
, sizeof(*argv
)*((int)(*argv
) + 2));
1830 cpp
= &argv
[(int)argv
[-1] - 10];
1836 #endif /* NEWINIT */
1841 * This is the routine to call when we are all through, to
1842 * clean up anything that needs to be cleaned up.
1849 #ifndef PARENT_DOES_UTMP
1850 # if (BSD > 43) || defined(convex)
1853 p
= line
+ sizeof("/dev/") - 1;
1856 (void)chmod(line
, 0666);
1857 (void)chown(line
, 0, 0);
1859 (void)chmod(line
, 0666);
1860 (void)chown(line
, 0, 0);
1861 (void) shutdown(net
, 2);
1867 vhangup(); /* XXX */
1868 (void) shutdown(net
, 2);
1871 #else /* PARENT_DOES_UTMP */
1873 (void) shutdown(net
, 2);
1875 # else /* NEWINIT */
1877 static int incleanup
= 0;
1879 int child_status
; /* status of child process as returned by waitpid */
1880 int flags
= WNOHANG
|WUNTRACED
;
1883 * 1: Pick up the zombie, if we are being called
1884 * as the signal handler.
1885 * 2: If we are a nested cleanup(), return.
1886 * 3: Try to clean up TMPDIR.
1887 * 4: Fill in utmp with shutdown of process.
1888 * 5: Close down the network and pty connections.
1889 * 6: Finish up the TMPDIR cleanup, if needed.
1891 if (sig
== SIGCHLD
) {
1892 while (waitpid(-1, &child_status
, flags
) > 0)
1894 /* Check if the child process was stopped
1895 * rather than exited. We want cleanup only if
1896 * the child has died.
1898 if (WIFSTOPPED(child_status
)) {
1902 t
= sigblock(sigmask(SIGCHLD
));
1912 * We need to set ourselves back to a null
1913 * label to clean up.
1916 setulvl(sysv
.sy_minlvl
);
1919 #endif /* UNICOS7x */
1921 t
= cleantmp(&wtmp
);
1922 setutent(); /* just to make sure */
1926 (void) shutdown(net
, 2);
1932 # endif /* NEWINT */
1933 #endif /* PARENT_DOES_UTMP */
1936 #if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)
1941 * These three functions are used to coordinate the handling of
1942 * the utmp file between the server and the soon-to-be-login shell.
1943 * The server actually creates the utmp structure, the child calls
1944 * utmp_sig_wait(), until the server calls utmp_sig_notify() and
1945 * signals the future-login shell to proceed.
1947 static int caught
=0; /* NZ when signal intercepted */
1948 static void (*func
)(); /* address of previous handler */
1955 (void) signal(SIGUSR1
, func
);
1962 * register signal handler for UTMP creation
1964 if ((int)(func
= signal(SIGUSR1
, _utmp_sig_rcv
)) == -1)
1965 fatalperror(net
, "telnetd/signal");
1971 (void) signal(SIGUSR1
, func
); /* reset handler to default */
1975 # define sigoff() /* do nothing */
1976 # define sigon() /* do nothing */
1983 * Wait for parent to write our utmp entry.
1986 while (caught
== 0) {
1987 pause(); /* wait until we get a signal (sigon) */
1988 sigoff(); /* turn off signals while we check caught */
1990 sigon(); /* turn on signals again */
1994 utmp_sig_notify(pid
)
2000 static int gotsigjob
= 0;
2008 register struct jobtemp
*jp
;
2010 while ((jid
= waitjob(NULL
)) != -1) {
2015 jobend(jid
, NULL
, NULL
);
2021 * called by jobend() before calling cleantmp()
2022 * to find the correct $TMPDIR to cleanup.
2029 struct utmp
*cur
= NULL
;
2031 setutent(); /* just to make sure */
2032 while (cur
= getutent()) {
2033 if ( (cur
->ut_type
!= NULL
) && (jid
== cur
->ut_jid
) ) {
2042 * Clean up the TMPDIR that login created.
2043 * The first time this is called we pick up the info
2044 * from the utmp. If the job has already gone away,
2045 * then we'll clean up and be done. If not, then
2046 * when this is called the second time it will wait
2047 * for the signal that the job is done.
2051 register struct utmp
*wtp
;
2054 static int first
= 1;
2055 register int mask
, omask
, ret
;
2056 extern struct utmp
*getutid
P((const struct utmp
*_Id
));
2059 mask
= sigmask(WJSIGNAL
);
2062 omask
= sigblock(mask
);
2063 while (gotsigjob
== 0)
2068 setutent(); /* just to make sure */
2072 syslog(LOG_ERR
, "Can't get /var/run/utmp entry to clean TMPDIR");
2076 * Nothing to clean up if the user shell was never started.
2078 if (utp
->ut_type
!= USER_PROCESS
|| utp
->ut_jid
== 0)
2082 * Block the WJSIGNAL while we are in jobend().
2084 omask
= sigblock(mask
);
2085 ret
= jobend(utp
->ut_jid
, utp
->ut_tpath
, utp
->ut_user
);
2091 jobend(jid
, path
, user
)
2093 register char *path
;
2094 register char *user
;
2096 static int saved_jid
= 0;
2097 static int pty_saved_jid
= 0;
2098 static char saved_path
[sizeof(wtmp
.ut_tpath
)+1];
2099 static char saved_user
[sizeof(wtmp
.ut_user
)+1];
2102 * this little piece of code comes into play
2103 * only when ptyreconnect is used to reconnect
2104 * to an previous session.
2106 * this is the only time when the
2107 * "saved_jid != jid" code is executed.
2110 if ( saved_jid
&& saved_jid
!= jid
) {
2111 if (!path
) { /* called from signal handler */
2112 pty_saved_jid
= jid
;
2114 pty_saved_jid
= saved_jid
;
2119 strncpy(saved_path
, path
, sizeof(wtmp
.ut_tpath
));
2120 strncpy(saved_user
, user
, sizeof(wtmp
.ut_user
));
2121 saved_path
[sizeof(saved_path
)] = '\0';
2122 saved_user
[sizeof(saved_user
)] = '\0';
2124 if (saved_jid
== 0) {
2129 /* if the jid has changed, get the correct entry from the utmp file */
2131 if ( saved_jid
!= jid
) {
2132 struct utmp
*utp
= NULL
;
2133 struct utmp
*jid_getutid();
2135 utp
= jid_getutid(pty_saved_jid
);
2138 syslog(LOG_ERR
, "Can't get /var/run/utmp entry to clean TMPDIR");
2142 cleantmpdir(jid
, utp
->ut_tpath
, utp
->ut_user
);
2146 cleantmpdir(jid
, saved_path
, saved_user
);
2151 * Fork a child process to clean up the TMPDIR
2153 cleantmpdir(jid
, tpath
, user
)
2155 register char *tpath
;
2156 register char *user
;
2160 syslog(LOG_ERR
, "TMPDIR cleanup(%s): fork() failed: %m\n",
2164 execl(CLEANTMPCMD
, CLEANTMPCMD
, user
, tpath
, 0);
2165 syslog(LOG_ERR
, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
2166 tpath
, CLEANTMPCMD
);
2170 * Forget about child. We will exit, and
2171 * /etc/init will pick it up.
2177 #endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */
2182 * This is the function called by cleanup() to
2183 * remove the utmp entry for this person.
2192 struct utmp
*u
, *utmp
;
2196 struct utmpx
*utxp
, utmpx
;
2199 * This updates the utmpx and utmp entries and make a wtmp/x entry
2202 SCPYN(utmpx
.ut_line
, line
+ sizeof("/dev/") - 1);
2203 utxp
= getutxline(&utmpx
);
2205 utxp
->ut_type
= DEAD_PROCESS
;
2206 utxp
->ut_exit
.e_termination
= 0;
2207 utxp
->ut_exit
.e_exit
= 0;
2208 (void) time(&utmpx
.ut_tv
.tv_sec
);
2209 utmpx
.ut_tv
.tv_usec
= 0;
2216 #if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
2222 struct utmp
*u
, *utmp
;
2226 f
= open(utmpf
, O_RDWR
);
2228 (void) fstat(f
, &statbf
);
2229 utmp
= (struct utmp
*)malloc((unsigned)statbf
.st_size
);
2231 syslog(LOG_ERR
, "utmp malloc failed");
2232 if (statbf
.st_size
&& utmp
) {
2233 nutmp
= read(f
, (char *)utmp
, (int)statbf
.st_size
);
2234 nutmp
/= sizeof(struct utmp
);
2236 for (u
= utmp
; u
< &utmp
[nutmp
] ; u
++) {
2237 if (SCMPN(u
->ut_line
, line
+5) ||
2240 (void) lseek(f
, ((long)u
)-((long)utmp
), L_SET
);
2241 SCPYN(u
->ut_name
, "");
2242 SCPYN(u
->ut_host
, "");
2243 (void) time(&u
->ut_time
);
2244 (void) write(f
, (char *)u
, sizeof(wtmp
));
2251 f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
2253 SCPYN(wtmp
.ut_line
, line
+5);
2254 SCPYN(wtmp
.ut_name
, "");
2255 SCPYN(wtmp
.ut_host
, "");
2256 (void) time(&wtmp
.ut_time
);
2257 (void) write(f
, (char *)&wtmp
, sizeof(wtmp
));
2261 (void) chmod(line
, 0666);
2262 (void) chown(line
, 0, 0);
2263 line
[strlen("/dev/")] = 'p';
2264 (void) chmod(line
, 0666);
2265 (void) chown(line
, 0, 0);
2275 int fd
; /* for /etc/wtmp */
2277 utmp
.ut_type
= USER_PROCESS
;
2278 (void) strncpy(utmp
.ut_id
, line
+12, sizeof(utmp
.ut_id
));
2280 utptr
= getutid(&utmp
);
2281 /* write it out only if it exists */
2283 utptr
->ut_type
= DEAD_PROCESS
;
2284 utptr
->ut_time
= time((long *) 0);
2285 (void) pututline(utptr
);
2286 /* set wtmp entry if wtmp file exists */
2287 if ((fd
= open(wtmpf
, O_WRONLY
| O_APPEND
)) >= 0) {
2288 (void) write(fd
, utptr
, sizeof(utmp
));
2294 (void) chmod(line
, 0666);
2295 (void) chown(line
, 0, 0);
2296 line
[14] = line
[13];
2297 line
[13] = line
[12];
2303 (void) chmod(line
, 0666);
2304 (void) chown(line
, 0, 0);