xref: /titanic_53/usr/src/cmd/bnu/cu.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate /*
26*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000, 2001 by Sun Microsystems, Inc.
27*7c478bd9Sstevel@tonic-gate  * All rights reserved.
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #ident	"%Z%%M%	%I%	%E% SMI"	/* from SVR4 cu:cu.c 2.46.2.2 */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  * cu [-cdevice] [-sspeed] [-lline] [-bbits] [-h] [-t] [-d] [-n]
35*7c478bd9Sstevel@tonic-gate  *		[-o|-e] [-L] [-C] telno | systemname [local-cmd]
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  *	legal baud rates: 300, 1200, 2400, 4800, 9600, 19200, 38400.
38*7c478bd9Sstevel@tonic-gate  *
39*7c478bd9Sstevel@tonic-gate  *	-c is used to specify which device will be used for making the
40*7c478bd9Sstevel@tonic-gate  *		call.  The device argument is compared to the Type (first)
41*7c478bd9Sstevel@tonic-gate  *		field in the Devices file, and only those records that
42*7c478bd9Sstevel@tonic-gate  *		match will be used to make the call.  Either -d or -t
43*7c478bd9Sstevel@tonic-gate  *		would be more intuitive options designations, but they
44*7c478bd9Sstevel@tonic-gate  *		are already in use.
45*7c478bd9Sstevel@tonic-gate  *	-l is for specifying a line unit from the file whose
46*7c478bd9Sstevel@tonic-gate  *		name is defined in /etc/uucp/Devices.
47*7c478bd9Sstevel@tonic-gate  *	-b is for forcing the number of bits per character processed on
48*7c478bd9Sstevel@tonic-gate  *		the connection. Valid values are '7' or '8'.
49*7c478bd9Sstevel@tonic-gate  *	-h is for half-duplex (local echoing).
50*7c478bd9Sstevel@tonic-gate  *	-t is for adding CR to LF on output to remote (for terminals).
51*7c478bd9Sstevel@tonic-gate  *	-d can be used  to get some tracing & diagnostics.
52*7c478bd9Sstevel@tonic-gate  *	-o or -e is for odd or even parity on transmission to remote.
53*7c478bd9Sstevel@tonic-gate  *	-n will request the phone number from the user.
54*7c478bd9Sstevel@tonic-gate  *	-L will cause cu to go through the login chat sequence in the
55*7c478bd9Sstevel@tonic-gate  *		Systems file.
56*7c478bd9Sstevel@tonic-gate  *	-C will cause cu to run the local command specified at the end
57*7c478bd9Sstevel@tonic-gate  *		of the command line, instead of entering interactive mode.
58*7c478bd9Sstevel@tonic-gate  *	Telno is a telephone number with `=' for secondary dial-tone.
59*7c478bd9Sstevel@tonic-gate  *	If "-l dev" is used, speed is taken from /etc/uucp/Devices.
60*7c478bd9Sstevel@tonic-gate  *	Only systemnames that are included in /etc/uucp/Systems may
61*7c478bd9Sstevel@tonic-gate  *	be used.
62*7c478bd9Sstevel@tonic-gate  *
63*7c478bd9Sstevel@tonic-gate  *	Escape with `~' at beginning of line:
64*7c478bd9Sstevel@tonic-gate  *
65*7c478bd9Sstevel@tonic-gate  *	~.	quit,
66*7c478bd9Sstevel@tonic-gate  *
67*7c478bd9Sstevel@tonic-gate  *	~![cmd]			execute shell (or 'cmd') locally,
68*7c478bd9Sstevel@tonic-gate  *
69*7c478bd9Sstevel@tonic-gate  *	~$cmd			execute 'cmd' locally, stdout to remote,
70*7c478bd9Sstevel@tonic-gate  *
71*7c478bd9Sstevel@tonic-gate  *	~%break	(alias ~%b)	transmit BREAK to remote,
72*7c478bd9Sstevel@tonic-gate  *	~%cd [dir]		change directory to $HOME (or 'dir'),
73*7c478bd9Sstevel@tonic-gate  *	~%debug (alias ~%d)	toggles on/off the program debug trace,
74*7c478bd9Sstevel@tonic-gate  *	~%divert		allow unsolicited diversions to files,
75*7c478bd9Sstevel@tonic-gate  *	~%ifc (alias ~%nostop)	toggles on/off the DC3/DC1 input control,
76*7c478bd9Sstevel@tonic-gate  *	~%ofc (alias ~%noostop)	toggles on/off the DC3/DC1 output control,
77*7c478bd9Sstevel@tonic-gate  *		(certain remote systems cannot cope with DC3 or DC1).
78*7c478bd9Sstevel@tonic-gate  *	~%old			recognize old style silent diversions,
79*7c478bd9Sstevel@tonic-gate  *	~%put from [to]		put file from local to remote,
80*7c478bd9Sstevel@tonic-gate  *	~%take from [to]	take file from remote to local,
81*7c478bd9Sstevel@tonic-gate  *
82*7c478bd9Sstevel@tonic-gate  *	~l			dump communication line ioctl settings,
83*7c478bd9Sstevel@tonic-gate  *	~t			dump terminal ioctl settings.
84*7c478bd9Sstevel@tonic-gate  *
85*7c478bd9Sstevel@tonic-gate  *	Silent diversions are enabled only for use with the ~%take
86*7c478bd9Sstevel@tonic-gate  *	command by default for security reasons. Unsolicited diversions
87*7c478bd9Sstevel@tonic-gate  *	may be enabled using the ~%divert toggle. The 'new-style'
88*7c478bd9Sstevel@tonic-gate  *	diversion syntax is "~[local]>:filename", and is terminaled
89*7c478bd9Sstevel@tonic-gate  *	by "~[local]>", where 'local' is the nodename of the local
90*7c478bd9Sstevel@tonic-gate  *	system. This enables ~%take to operate properly when cu
91*7c478bd9Sstevel@tonic-gate  *	is used over multiple hops. 'old-style' diversion syntax may
92*7c478bd9Sstevel@tonic-gate  *	be enabled using the ~%old toggle. ('old-style' diversion
93*7c478bd9Sstevel@tonic-gate  *	should be avoided!)
94*7c478bd9Sstevel@tonic-gate  *
95*7c478bd9Sstevel@tonic-gate  *	Cu no longer uses dial.c to reach the remote.  Instead, cu places
96*7c478bd9Sstevel@tonic-gate  *	a telephone call to a remote system through the uucp conn() routine
97*7c478bd9Sstevel@tonic-gate  *	when the user picks the systemname option or through altconn()--
98*7c478bd9Sstevel@tonic-gate  *	which bypasses /etc/uucp/Systems -- if a telno or direct
99*7c478bd9Sstevel@tonic-gate  *	line is chosen. The line termio attributes are set in fixline(),
100*7c478bd9Sstevel@tonic-gate  *	before the remote connection is made.  As a device-lockout semaphore
101*7c478bd9Sstevel@tonic-gate  *	mechanism, uucp creates an entry in /var/spool/locks whose name is
102*7c478bd9Sstevel@tonic-gate  *	LK.<MAJ>.<maj>.<min> where MAJ is the major device of the
103*7c478bd9Sstevel@tonic-gate  *	filesystem containing the device, and <maj> and <min> are the
104*7c478bd9Sstevel@tonic-gate  *	major and minor of the device.
105*7c478bd9Sstevel@tonic-gate  *	When cu terminates, for whatever reason, cleanup() must be
106*7c478bd9Sstevel@tonic-gate  *	called to "release" the device, and clean up entries from
107*7c478bd9Sstevel@tonic-gate  *	the locks directory.  Cu runs with uucp ownership, and thus provides
108*7c478bd9Sstevel@tonic-gate  *	extra insurance that lock files will not be left around.
109*7c478bd9Sstevel@tonic-gate  */
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #include "uucp.h"
112*7c478bd9Sstevel@tonic-gate #include <locale.h>
113*7c478bd9Sstevel@tonic-gate #include <stropts.h>
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate #define	MID	BUFSIZ/2	/* mnemonic */
116*7c478bd9Sstevel@tonic-gate #define	RUB	'\177'		/* mnemonic */
117*7c478bd9Sstevel@tonic-gate #define	XON	'\21'		/* mnemonic */
118*7c478bd9Sstevel@tonic-gate #define	XOFF	'\23'		/* mnemonic */
119*7c478bd9Sstevel@tonic-gate #define	TTYIN	0		/* mnemonic */
120*7c478bd9Sstevel@tonic-gate #define	TTYOUT	1		/* mnemonic */
121*7c478bd9Sstevel@tonic-gate #define	TTYERR	2		/* mnemonic */
122*7c478bd9Sstevel@tonic-gate #define	HUNGUP  2
123*7c478bd9Sstevel@tonic-gate #define	YES	1		/* mnemonic */
124*7c478bd9Sstevel@tonic-gate #define	NO	0		/* mnemonic */
125*7c478bd9Sstevel@tonic-gate #define	IOERR	4		/* exit code */
126*7c478bd9Sstevel@tonic-gate #define	MAXPATH	100
127*7c478bd9Sstevel@tonic-gate #define	NPL	50
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate int Sflag=0;
130*7c478bd9Sstevel@tonic-gate int Cn;				/*fd for remote comm line */
131*7c478bd9Sstevel@tonic-gate jmp_buf Sjbuf;			/*needed by uucp routines*/
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate /*	io buffering	*/
134*7c478bd9Sstevel@tonic-gate /*	Wiobuf contains, in effect, 3 write buffers (to remote, to tty	*/
135*7c478bd9Sstevel@tonic-gate /*	stdout, and to tty stderr) and Riobuf contains 2 read buffers	*/
136*7c478bd9Sstevel@tonic-gate /*	(from remote, from tty).  [WR]IOFD decides which one to use.	*/
137*7c478bd9Sstevel@tonic-gate /*	[RW]iop holds current position in each.				*/
138*7c478bd9Sstevel@tonic-gate #define	WIOFD(fd)	(fd == TTYOUT ? 0 : (fd == Cn ? 1 : 2))
139*7c478bd9Sstevel@tonic-gate #define	RIOFD(fd)	(fd == TTYIN ? 0 : 1)
140*7c478bd9Sstevel@tonic-gate #define	WMASK(fd)	(fd == Cn ? line_mask : term_mask)
141*7c478bd9Sstevel@tonic-gate #define	RMASK(fd)	(fd == Cn ? line_mask : term_mask)
142*7c478bd9Sstevel@tonic-gate #define	WRIOBSZ 256
143*7c478bd9Sstevel@tonic-gate static char Riobuf[2*WRIOBSZ];
144*7c478bd9Sstevel@tonic-gate static char Wiobuf[3*WRIOBSZ];
145*7c478bd9Sstevel@tonic-gate static int Riocnt[2] = {0, 0};
146*7c478bd9Sstevel@tonic-gate static char *Riop[2];
147*7c478bd9Sstevel@tonic-gate static char *Wiop[3];
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate extern int optind;		/* variable in getopt() */
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate extern char
152*7c478bd9Sstevel@tonic-gate 	*optarg;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate static struct call Cucall;	/* call structure for altconn()	*/
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate static int Saved_tty;		/* was TCGETAW of _Tv0 successful?	*/
157*7c478bd9Sstevel@tonic-gate static int Saved_termios;	/* was TCGETSW of _Tv0 successful?	*/
158*7c478bd9Sstevel@tonic-gate static struct termio _Tv, _Tv0;	/* for saving, changing TTY atributes */
159*7c478bd9Sstevel@tonic-gate static struct termios _Tv0s;	/* for saving, changing TTY atributes */
160*7c478bd9Sstevel@tonic-gate static struct termio _Lv;	/* attributes for the line to remote */
161*7c478bd9Sstevel@tonic-gate static struct termios _Lvs;	/* attributes for the line to remote */
162*7c478bd9Sstevel@tonic-gate static char prompt[BUFSIZ]= "[";
163*7c478bd9Sstevel@tonic-gate static struct utsname utsn;
164*7c478bd9Sstevel@tonic-gate static int command_line_hups = 0;
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate static char filename[BUFSIZ] = "/dev/null";
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate static char
169*7c478bd9Sstevel@tonic-gate 	_Cxc,			/* place into which we do character io*/
170*7c478bd9Sstevel@tonic-gate 	_Tintr,			/* current input INTR */
171*7c478bd9Sstevel@tonic-gate 	_Tquit,			/* current input QUIT */
172*7c478bd9Sstevel@tonic-gate 	_Terase,		/* current input ERASE */
173*7c478bd9Sstevel@tonic-gate 	_Tkill,			/* current input KILL */
174*7c478bd9Sstevel@tonic-gate 	_Teol,			/* current secondary input EOL */
175*7c478bd9Sstevel@tonic-gate 	_Myeof,			/* current input EOF */
176*7c478bd9Sstevel@tonic-gate 	term_mask,		/* mask value for local terminal */
177*7c478bd9Sstevel@tonic-gate 	line_mask;		/* mask value for remote line */
178*7c478bd9Sstevel@tonic-gate 				/* either '0177' or '0377' */
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate int
181*7c478bd9Sstevel@tonic-gate 	Echoe,			/* save users ECHOE bit */
182*7c478bd9Sstevel@tonic-gate 	Echok,			/* save users ECHOK bit */
183*7c478bd9Sstevel@tonic-gate 	Intrupt=NO,		/* interrupt indicator */
184*7c478bd9Sstevel@tonic-gate 	Ifc=YES,		/* NO means remote can't XON/XOFF */
185*7c478bd9Sstevel@tonic-gate 	Ofc=YES,		/* NO means local can't XON/XOFF */
186*7c478bd9Sstevel@tonic-gate 	Rtn_code=0,		/* default return code */
187*7c478bd9Sstevel@tonic-gate 	Divert=NO,		/* don't allow unsolicited redirection */
188*7c478bd9Sstevel@tonic-gate 	OldStyle=NO,		/* don't handle old '~>:filename' syntax */
189*7c478bd9Sstevel@tonic-gate 				/* this will be mandatory in SVR4.1 */
190*7c478bd9Sstevel@tonic-gate 	Takeflag=NO,		/* indicates a ~%take is in progress */
191*7c478bd9Sstevel@tonic-gate 	Dologin=NO,		/* go through the login chat sequence */
192*7c478bd9Sstevel@tonic-gate 	Docmd=NO;		/* execute command instead of interactive cu */
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate EXTERN int			/* These are initialized in line.c */
195*7c478bd9Sstevel@tonic-gate 	Terminal,		/* flag; remote is a terminal */
196*7c478bd9Sstevel@tonic-gate 	Oddflag,		/* flag- odd parity option*/
197*7c478bd9Sstevel@tonic-gate 	Evenflag,		/* flag- even parity option*/
198*7c478bd9Sstevel@tonic-gate 	Duplex,			/* Unix= full duplex=YES; half = NO */
199*7c478bd9Sstevel@tonic-gate 	term_8bit,		/* is terminal set for 8 bit processing */
200*7c478bd9Sstevel@tonic-gate 	line_8bit;		/* is line set for 8 bit processing */
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate EXTERN int clear_hup();
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate pid_t
205*7c478bd9Sstevel@tonic-gate 	Child,			/* pid for receive process */
206*7c478bd9Sstevel@tonic-gate 	Shell;			/* pid for escape process */
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate static pid_t
209*7c478bd9Sstevel@tonic-gate 	dofork();		/* fork and return pid */
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate static int
212*7c478bd9Sstevel@tonic-gate 	r_char(),		/* local io routine */
213*7c478bd9Sstevel@tonic-gate 	w_char(),		/* local io routine */
214*7c478bd9Sstevel@tonic-gate 	wioflsh();
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate static void
217*7c478bd9Sstevel@tonic-gate 	_onintrpt(),		/* interrupt routines */
218*7c478bd9Sstevel@tonic-gate 	_rcvdead(),
219*7c478bd9Sstevel@tonic-gate 	_quit(),
220*7c478bd9Sstevel@tonic-gate 	_bye();
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate extern void	cleanup();
223*7c478bd9Sstevel@tonic-gate extern void	tdmp();
224*7c478bd9Sstevel@tonic-gate extern int conn(), altconn(), transmit(), tilda();
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate static void
227*7c478bd9Sstevel@tonic-gate 	recfork(),
228*7c478bd9Sstevel@tonic-gate 	sysname(),
229*7c478bd9Sstevel@tonic-gate 	blckcnt(),
230*7c478bd9Sstevel@tonic-gate 	_flush(),
231*7c478bd9Sstevel@tonic-gate 	_shell(),
232*7c478bd9Sstevel@tonic-gate 	_dopercen(),
233*7c478bd9Sstevel@tonic-gate 	_receive(),
234*7c478bd9Sstevel@tonic-gate 	_mode(),
235*7c478bd9Sstevel@tonic-gate 	_w_str();
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate extern char *Myline;	/* flag to force the requested line to be used  */
238*7c478bd9Sstevel@tonic-gate extern char *Mytype;	/* flag to force requested line type to be used
239*7c478bd9Sstevel@tonic-gate 			 * rddev() will compare the string to the D_TYPE
240*7c478bd9Sstevel@tonic-gate 			 * (first) field of the Devices record and skip any
241*7c478bd9Sstevel@tonic-gate 			 * records where they are not equal. Mytype is set
242*7c478bd9Sstevel@tonic-gate 			 * to point to the argument of the -c option from
243*7c478bd9Sstevel@tonic-gate 			 * the command line. */
244*7c478bd9Sstevel@tonic-gate static char *P_USAGE= "Usage: %s [-dhtnLC] [-c device] [-s speed] [-l line] [-b 7|8]\n\t[-o | -e] telno | systemname [local-cmd]\n";
245*7c478bd9Sstevel@tonic-gate static char *P_CON_FAILED = "Connect failed: %s\r\n";
246*7c478bd9Sstevel@tonic-gate static char *P_Ct_OPEN = "Cannot open: %s\r\n";
247*7c478bd9Sstevel@tonic-gate static char *P_LINE_GONE = "Remote line gone\r\n";
248*7c478bd9Sstevel@tonic-gate static char *P_Ct_EXSH = "Can't execute shell\r\n";
249*7c478bd9Sstevel@tonic-gate static char *P_Ct_DIVERT = "Can't divert to %s\r\n";
250*7c478bd9Sstevel@tonic-gate static char *P_Ct_UNDIVERT = "Can't end diversion to %s\r\n";
251*7c478bd9Sstevel@tonic-gate static char *P_Bad_DIVERT = "Won't divert to %s. Unsolicited.\r\n";
252*7c478bd9Sstevel@tonic-gate static char *P_STARTWITH = "Use `~~' to start line with `~'\r\n";
253*7c478bd9Sstevel@tonic-gate static char *P_CNTAFTER = "File transmission interrupted after %ld bytes.\r\n";
254*7c478bd9Sstevel@tonic-gate static char *P_CNTLINES = "%d lines/";
255*7c478bd9Sstevel@tonic-gate static char *P_CNTCHAR = "%ld characters\r\n";
256*7c478bd9Sstevel@tonic-gate static char *P_FILEINTR = "File transmission interrupted\r\n";
257*7c478bd9Sstevel@tonic-gate static char *P_Ct_FK = "Can't fork -- try later\r\n";
258*7c478bd9Sstevel@tonic-gate static char *P_Ct_SPECIAL = "r\nCan't transmit special character `%#o'\r\n";
259*7c478bd9Sstevel@tonic-gate static char *P_TOOLONG = "\nLine too long\r\n";
260*7c478bd9Sstevel@tonic-gate static char *P_IOERR = "r\nIO error\r\n";
261*7c478bd9Sstevel@tonic-gate static char *P_USECMD = "Use `~$'cmd \r\n";
262*7c478bd9Sstevel@tonic-gate #ifdef forfutureuse
263*7c478bd9Sstevel@tonic-gate static char *P_USEPLUSCMD ="Use `~+'cmd \r\n";
264*7c478bd9Sstevel@tonic-gate #endif
265*7c478bd9Sstevel@tonic-gate #ifdef u3b
266*7c478bd9Sstevel@tonic-gate static char *P_NOTERMSTAT = "Can't get terminal status\r\n";
267*7c478bd9Sstevel@tonic-gate static char *P_3BCONSOLE = "Sorry, you can't cu from a 3B console\r\n";
268*7c478bd9Sstevel@tonic-gate #endif
269*7c478bd9Sstevel@tonic-gate static char *P_TELLENGTH = "Telno cannot exceed 58 digits!\r\n";
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate /***************************************************************
272*7c478bd9Sstevel@tonic-gate  *	main: get command line args, establish connection, and fork.
273*7c478bd9Sstevel@tonic-gate  *	Child invokes "receive" to read from remote & write to TTY.
274*7c478bd9Sstevel@tonic-gate  *	Main line invokes "transmit" to read TTY & write to remote.
275*7c478bd9Sstevel@tonic-gate  ***************************************************************/
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate main(argc, argv)
278*7c478bd9Sstevel@tonic-gate char *argv[];
279*7c478bd9Sstevel@tonic-gate {
280*7c478bd9Sstevel@tonic-gate     extern void setservice();
281*7c478bd9Sstevel@tonic-gate     extern int sysaccess();
282*7c478bd9Sstevel@tonic-gate     char s[MAXPH];
283*7c478bd9Sstevel@tonic-gate     char *string;
284*7c478bd9Sstevel@tonic-gate     int i;
285*7c478bd9Sstevel@tonic-gate     int errflag=0;
286*7c478bd9Sstevel@tonic-gate     int lflag=0;
287*7c478bd9Sstevel@tonic-gate     int nflag=0;
288*7c478bd9Sstevel@tonic-gate     int systemname = 0;
289*7c478bd9Sstevel@tonic-gate     char vdisable;
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate     /* Set locale environment variables local definitions */
292*7c478bd9Sstevel@tonic-gate     (void) setlocale(LC_ALL, "");
293*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
294*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it wasn't */
295*7c478bd9Sstevel@tonic-gate #endif
296*7c478bd9Sstevel@tonic-gate     (void) textdomain(TEXT_DOMAIN);
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate     Riop[0] = &Riobuf[0];
299*7c478bd9Sstevel@tonic-gate     Riop[1] = &Riobuf[WRIOBSZ];
300*7c478bd9Sstevel@tonic-gate     Wiop[0] = &Wiobuf[0];
301*7c478bd9Sstevel@tonic-gate     Wiop[1] = &Wiobuf[WRIOBSZ];
302*7c478bd9Sstevel@tonic-gate     Wiop[2] = &Wiobuf[2*WRIOBSZ];
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate     Verbose = 1;		/*for uucp callers,  dialers feedback*/
305*7c478bd9Sstevel@tonic-gate     if ((string = strrchr(argv[0], '/')) != NULL)
306*7c478bd9Sstevel@tonic-gate 	string++;
307*7c478bd9Sstevel@tonic-gate     else
308*7c478bd9Sstevel@tonic-gate 	string = argv[0];
309*7c478bd9Sstevel@tonic-gate     if (strlcpy(Progname, string, NAMESIZE) >= NAMESIZE) {
310*7c478bd9Sstevel@tonic-gate 	errno = ENAMETOOLONG;
311*7c478bd9Sstevel@tonic-gate 	perror("cu");
312*7c478bd9Sstevel@tonic-gate 	exit(1);
313*7c478bd9Sstevel@tonic-gate     }
314*7c478bd9Sstevel@tonic-gate     setservice(Progname);
315*7c478bd9Sstevel@tonic-gate     if ( sysaccess(EACCESS_SYSTEMS) != 0 ) {
316*7c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
317*7c478bd9Sstevel@tonic-gate 	     gettext("%s: Cannot read Systems files\n"), Progname);
318*7c478bd9Sstevel@tonic-gate 	exit(1);
319*7c478bd9Sstevel@tonic-gate     }
320*7c478bd9Sstevel@tonic-gate     if ( sysaccess(EACCESS_DEVICES) != 0 ) {
321*7c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
322*7c478bd9Sstevel@tonic-gate 	     gettext("%s: Cannot read Devices files\n"), Progname);
323*7c478bd9Sstevel@tonic-gate 	exit(1);
324*7c478bd9Sstevel@tonic-gate     }
325*7c478bd9Sstevel@tonic-gate     if ( sysaccess(EACCESS_DIALERS) != 0 ) {
326*7c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr,
327*7c478bd9Sstevel@tonic-gate 	    gettext("%s: Cannot read Dialers files\n"), Progname);
328*7c478bd9Sstevel@tonic-gate 	exit(1);
329*7c478bd9Sstevel@tonic-gate     }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate     Cucall.speed = "Any";	/*default speed*/
332*7c478bd9Sstevel@tonic-gate     Cucall.line = CNULL;
333*7c478bd9Sstevel@tonic-gate     Cucall.telno = CNULL;
334*7c478bd9Sstevel@tonic-gate     Cucall.type = CNULL;
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate /*Flags for -h, -t, -e, and -o options set here; corresponding line attributes*/
337*7c478bd9Sstevel@tonic-gate /*are set in fixline() in culine.c before remote connection is made	   */
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate     while((i = getopt(argc, argv, "dhteons:l:c:b:LCH")) != EOF)
340*7c478bd9Sstevel@tonic-gate 	switch(i) {
341*7c478bd9Sstevel@tonic-gate 	    case 'd':
342*7c478bd9Sstevel@tonic-gate 		Debug = 9; /*turns on uucp debugging-level 9*/
343*7c478bd9Sstevel@tonic-gate 		break;
344*7c478bd9Sstevel@tonic-gate 	    case 'h':
345*7c478bd9Sstevel@tonic-gate 		Duplex  = NO;
346*7c478bd9Sstevel@tonic-gate 		Ifc = NO;
347*7c478bd9Sstevel@tonic-gate 		Ofc = NO;
348*7c478bd9Sstevel@tonic-gate 		break;
349*7c478bd9Sstevel@tonic-gate 	    case 't':
350*7c478bd9Sstevel@tonic-gate 		Terminal = YES;
351*7c478bd9Sstevel@tonic-gate 		break;
352*7c478bd9Sstevel@tonic-gate 	    case 'e':
353*7c478bd9Sstevel@tonic-gate 		if ( Oddflag ) {
354*7c478bd9Sstevel@tonic-gate 		    (void)fprintf(stderr,
355*7c478bd9Sstevel@tonic-gate 			gettext("%s: Cannot have both even and odd parity\n"),
356*7c478bd9Sstevel@tonic-gate 			argv[0]);
357*7c478bd9Sstevel@tonic-gate 		    exit(1);
358*7c478bd9Sstevel@tonic-gate 		}
359*7c478bd9Sstevel@tonic-gate 		Evenflag = 1;
360*7c478bd9Sstevel@tonic-gate 		break;
361*7c478bd9Sstevel@tonic-gate 	    case 'o':
362*7c478bd9Sstevel@tonic-gate 		if ( Evenflag ) {
363*7c478bd9Sstevel@tonic-gate 		    (void)fprintf(stderr,
364*7c478bd9Sstevel@tonic-gate 			gettext("%s: Cannot have both even and odd parity\n"),
365*7c478bd9Sstevel@tonic-gate 			argv[0]);
366*7c478bd9Sstevel@tonic-gate 		    exit(1);
367*7c478bd9Sstevel@tonic-gate 		}
368*7c478bd9Sstevel@tonic-gate 		Oddflag = 1;
369*7c478bd9Sstevel@tonic-gate 		break;
370*7c478bd9Sstevel@tonic-gate 	    case 'n':
371*7c478bd9Sstevel@tonic-gate 		nflag++;
372*7c478bd9Sstevel@tonic-gate 		printf(gettext("Please enter the number: "));
373*7c478bd9Sstevel@tonic-gate 		/* Read line from stdin, remove trailing newline, if any */
374*7c478bd9Sstevel@tonic-gate 		if (fgets(s, sizeof(s), stdin) != NULL &&
375*7c478bd9Sstevel@tonic-gate 			strchr(s, '\n') != NULL)
376*7c478bd9Sstevel@tonic-gate 		   s[strlen(s)-1] = '\0';
377*7c478bd9Sstevel@tonic-gate 		break;
378*7c478bd9Sstevel@tonic-gate 	    case 's':
379*7c478bd9Sstevel@tonic-gate 		Sflag++;
380*7c478bd9Sstevel@tonic-gate 		Cucall.speed = optarg;
381*7c478bd9Sstevel@tonic-gate 		break;
382*7c478bd9Sstevel@tonic-gate 	    case 'l':
383*7c478bd9Sstevel@tonic-gate 		lflag++;
384*7c478bd9Sstevel@tonic-gate 		Cucall.line = optarg;
385*7c478bd9Sstevel@tonic-gate 		break;
386*7c478bd9Sstevel@tonic-gate 	    case 'c':
387*7c478bd9Sstevel@tonic-gate 		Cucall.type = optarg;
388*7c478bd9Sstevel@tonic-gate 		Mytype = optarg;
389*7c478bd9Sstevel@tonic-gate 		break;
390*7c478bd9Sstevel@tonic-gate 	    case 'b':
391*7c478bd9Sstevel@tonic-gate 		line_8bit = ((*optarg=='7') ? NO : ((*optarg=='8') ? YES : -1));
392*7c478bd9Sstevel@tonic-gate 		if ( line_8bit == -1 ) {
393*7c478bd9Sstevel@tonic-gate 		    (void) fprintf(stderr,
394*7c478bd9Sstevel@tonic-gate 			gettext("%s: b option value must be '7' or '8'\n"),
395*7c478bd9Sstevel@tonic-gate 			argv[0]);
396*7c478bd9Sstevel@tonic-gate 		    exit(1);
397*7c478bd9Sstevel@tonic-gate 		}
398*7c478bd9Sstevel@tonic-gate 		break;
399*7c478bd9Sstevel@tonic-gate 	    case 'L':
400*7c478bd9Sstevel@tonic-gate 		Dologin++;
401*7c478bd9Sstevel@tonic-gate 		break;
402*7c478bd9Sstevel@tonic-gate 	    case 'C':
403*7c478bd9Sstevel@tonic-gate 		Docmd++;
404*7c478bd9Sstevel@tonic-gate 		break;
405*7c478bd9Sstevel@tonic-gate 	    case 'H':
406*7c478bd9Sstevel@tonic-gate 		command_line_hups++;
407*7c478bd9Sstevel@tonic-gate 		break;
408*7c478bd9Sstevel@tonic-gate 	    case '?':
409*7c478bd9Sstevel@tonic-gate 		++errflag;
410*7c478bd9Sstevel@tonic-gate 	}
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate #ifdef  u3b
413*7c478bd9Sstevel@tonic-gate     {
414*7c478bd9Sstevel@tonic-gate     struct stat buff;
415*7c478bd9Sstevel@tonic-gate     if(fstat(TTYIN, &buff) < 0) {
416*7c478bd9Sstevel@tonic-gate 	VERBOSE(gettext(P_NOTERMSTAT),"");
417*7c478bd9Sstevel@tonic-gate 	exit(1);
418*7c478bd9Sstevel@tonic-gate     } else if ( (buff.st_mode & S_IFMT) == S_IFCHR && buff.st_rdev == 0 ) {
419*7c478bd9Sstevel@tonic-gate 	VERBOSE(gettext(P_3BCONSOLE),"");
420*7c478bd9Sstevel@tonic-gate 	exit(1);
421*7c478bd9Sstevel@tonic-gate 	}
422*7c478bd9Sstevel@tonic-gate     }
423*7c478bd9Sstevel@tonic-gate #endif
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate     if((optind < argc && optind > 0) || (nflag && optind > 0)) {
426*7c478bd9Sstevel@tonic-gate 	if(nflag)
427*7c478bd9Sstevel@tonic-gate 	    string=s;
428*7c478bd9Sstevel@tonic-gate 	else
429*7c478bd9Sstevel@tonic-gate 	    string = strdup(argv[optind++]);
430*7c478bd9Sstevel@tonic-gate 	Cucall.telno = string;
431*7c478bd9Sstevel@tonic-gate 	if ( strlen(string) != strspn(string, "0123456789=-*#") ) {
432*7c478bd9Sstevel@tonic-gate 	    /* if it's not a legitimate telno, then it should be a systemname */
433*7c478bd9Sstevel@tonic-gate 	    if ( nflag ) {
434*7c478bd9Sstevel@tonic-gate 		(void)fprintf(stderr, gettext("%s: Bad phone number %s\n"),
435*7c478bd9Sstevel@tonic-gate 				argv[0], string);
436*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Phone numbers may contain "
437*7c478bd9Sstevel@tonic-gate 		    "only the digits 0 through 9 and the special\n"
438*7c478bd9Sstevel@tonic-gate 		    "characters =, -, * and #.\n"));
439*7c478bd9Sstevel@tonic-gate 		exit(1);
440*7c478bd9Sstevel@tonic-gate 	    }
441*7c478bd9Sstevel@tonic-gate 	    systemname++;
442*7c478bd9Sstevel@tonic-gate 	}
443*7c478bd9Sstevel@tonic-gate     } else
444*7c478bd9Sstevel@tonic-gate 	if(Cucall.line == CNULL)   /*if none of above, must be direct */
445*7c478bd9Sstevel@tonic-gate 	    ++errflag;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate     if(errflag) {
448*7c478bd9Sstevel@tonic-gate 	VERBOSE(gettext(P_USAGE), argv[0]);
449*7c478bd9Sstevel@tonic-gate 	exit(1);
450*7c478bd9Sstevel@tonic-gate     }
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate     if ((Cucall.telno != CNULL) &&
453*7c478bd9Sstevel@tonic-gate 		(strlen(Cucall.telno) >= (size_t)(MAXPH - 1))) {
454*7c478bd9Sstevel@tonic-gate 	VERBOSE(gettext(P_TELLENGTH),"");
455*7c478bd9Sstevel@tonic-gate 	exit(0);
456*7c478bd9Sstevel@tonic-gate     }
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate     /* save initial tty state */
459*7c478bd9Sstevel@tonic-gate     if (!(Saved_termios = ( ioctl(TTYIN, TCGETS, &_Tv0s) >= 0 ))) {
460*7c478bd9Sstevel@tonic-gate 	Saved_tty = ( ioctl(TTYIN, TCGETA, &_Tv0) == 0 );
461*7c478bd9Sstevel@tonic-gate 	_Tv0s.c_lflag = _Tv0.c_lflag;
462*7c478bd9Sstevel@tonic-gate 	_Tv0s.c_oflag = _Tv0.c_oflag;
463*7c478bd9Sstevel@tonic-gate 	_Tv0s.c_iflag = _Tv0.c_iflag;
464*7c478bd9Sstevel@tonic-gate 	_Tv0s.c_cflag = _Tv0.c_cflag;
465*7c478bd9Sstevel@tonic-gate 	for(i = 0; i < NCC; i++)
466*7c478bd9Sstevel@tonic-gate 		_Tv0s.c_cc[i] = _Tv0.c_cc[i];
467*7c478bd9Sstevel@tonic-gate     }
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate     if (Saved_termios || Saved_tty) {
470*7c478bd9Sstevel@tonic-gate 	char *p;
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	/*
473*7c478bd9Sstevel@tonic-gate 	 * We consider the terminal to be in 8 bit mode only if cs8 is set,
474*7c478bd9Sstevel@tonic-gate 	 * istrip is not set, and we're not in the "C" locale.  The "C"
475*7c478bd9Sstevel@tonic-gate 	 * locale is by definition 7 bit only.  This provides reasonable
476*7c478bd9Sstevel@tonic-gate 	 * compatibility when running in the "C" locale (currently the default)
477*7c478bd9Sstevel@tonic-gate 	 * and connecting to other systems, which are most often 7 bit systems.
478*7c478bd9Sstevel@tonic-gate 	 */
479*7c478bd9Sstevel@tonic-gate 	term_8bit = ( (_Tv0s.c_cflag & CS8) && !(_Tv0s.c_iflag & ISTRIP) &&
480*7c478bd9Sstevel@tonic-gate 	  ((p = setlocale(LC_CTYPE, NULL)) != NULL) && (strcmp(p, "C") != 0) );
481*7c478bd9Sstevel@tonic-gate 	if ( !Oddflag && !Evenflag )
482*7c478bd9Sstevel@tonic-gate 	    if (_Tv0s.c_cflag & PARENB)
483*7c478bd9Sstevel@tonic-gate 		if (_Tv0s.c_cflag & PARODD)
484*7c478bd9Sstevel@tonic-gate 		    Oddflag = 1;
485*7c478bd9Sstevel@tonic-gate 		else
486*7c478bd9Sstevel@tonic-gate 		    Evenflag = 1;
487*7c478bd9Sstevel@tonic-gate     }
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate     if (line_8bit == -1)
490*7c478bd9Sstevel@tonic-gate 	line_8bit = term_8bit;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate     term_mask = ( term_8bit ? 0377 : 0177 );
493*7c478bd9Sstevel@tonic-gate     line_mask = ( line_8bit ? 0377 : 0177 );
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate     /* if not set, use the POSIX disabled designation */
496*7c478bd9Sstevel@tonic-gate #ifdef _POSIX_VDISABLE
497*7c478bd9Sstevel@tonic-gate     vdisable = _POSIX_VDISABLE;
498*7c478bd9Sstevel@tonic-gate #else
499*7c478bd9Sstevel@tonic-gate     vdisable = fpathconf(TTYIN, _PC_VDISABLE);
500*7c478bd9Sstevel@tonic-gate #endif
501*7c478bd9Sstevel@tonic-gate     _Tintr = _Tv0s.c_cc[VINTR] ? _Tv0s.c_cc[VINTR] : vdisable;
502*7c478bd9Sstevel@tonic-gate     _Tquit = _Tv0s.c_cc[VQUIT] ? _Tv0s.c_cc[VQUIT] : vdisable;
503*7c478bd9Sstevel@tonic-gate     _Terase = _Tv0s.c_cc[VERASE] ? _Tv0s.c_cc[VERASE] : vdisable;
504*7c478bd9Sstevel@tonic-gate     _Tkill = _Tv0s.c_cc[VKILL] ? _Tv0s.c_cc[VKILL] : vdisable;
505*7c478bd9Sstevel@tonic-gate     _Teol = _Tv0s.c_cc[VEOL] ? _Tv0s.c_cc[VEOL] : vdisable;
506*7c478bd9Sstevel@tonic-gate     _Myeof = _Tv0s.c_cc[VEOF] ? _Tv0s.c_cc[VEOF] : '\04';
507*7c478bd9Sstevel@tonic-gate     Echoe = _Tv0s.c_lflag & ECHOE;
508*7c478bd9Sstevel@tonic-gate     Echok = _Tv0s.c_lflag & ECHOK;
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate     (void)signal(SIGHUP, cleanup);
511*7c478bd9Sstevel@tonic-gate     (void)signal(SIGQUIT, cleanup);
512*7c478bd9Sstevel@tonic-gate     (void)signal(SIGINT, cleanup);
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate /* place call to system; if "cu systemname", use conn() from uucp
515*7c478bd9Sstevel@tonic-gate    directly.  Otherwise, use altconn() which dummies in the
516*7c478bd9Sstevel@tonic-gate    Systems file line.
517*7c478bd9Sstevel@tonic-gate */
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate     if(systemname) {
520*7c478bd9Sstevel@tonic-gate 	if ( lflag )
521*7c478bd9Sstevel@tonic-gate 	    (void)fprintf(stderr,
522*7c478bd9Sstevel@tonic-gate 	        gettext("%s: Warning: -l flag ignored when system name used\n"),
523*7c478bd9Sstevel@tonic-gate 	        argv[0]);
524*7c478bd9Sstevel@tonic-gate 	if ( Sflag )
525*7c478bd9Sstevel@tonic-gate 	    (void)fprintf(stderr,
526*7c478bd9Sstevel@tonic-gate 	        gettext("%s: Warning: -s flag ignored when system name used\n"),
527*7c478bd9Sstevel@tonic-gate 	        argv[0]);
528*7c478bd9Sstevel@tonic-gate 	Cn = conn(string);
529*7c478bd9Sstevel@tonic-gate 	if ( (Cn < 0) && (Cucall.type != CNULL) )
530*7c478bd9Sstevel@tonic-gate 	    Cn = altconn(&Cucall);
531*7c478bd9Sstevel@tonic-gate     } else
532*7c478bd9Sstevel@tonic-gate 	Cn = altconn(&Cucall);
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate     if(Cn < 0) {
535*7c478bd9Sstevel@tonic-gate 	VERBOSE(gettext(P_CON_FAILED),UERRORTEXT);
536*7c478bd9Sstevel@tonic-gate 	cleanup(-Cn);
537*7c478bd9Sstevel@tonic-gate     } else {
538*7c478bd9Sstevel@tonic-gate 	struct stat Cnsbuf;
539*7c478bd9Sstevel@tonic-gate 	if ( fstat(Cn, &Cnsbuf) == 0 )
540*7c478bd9Sstevel@tonic-gate 	    Dev_mode = Cnsbuf.st_mode;
541*7c478bd9Sstevel@tonic-gate 	else
542*7c478bd9Sstevel@tonic-gate 	    Dev_mode = R_DEVICEMODE;
543*7c478bd9Sstevel@tonic-gate 	fchmod(Cn, M_DEVICEMODE);
544*7c478bd9Sstevel@tonic-gate     }
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate     if ((Docmd) && (argv[optind] == NULL)) {
547*7c478bd9Sstevel@tonic-gate         (void) fprintf(stderr,gettext("cu: local cmd is required, -C is ignored.\n"));
548*7c478bd9Sstevel@tonic-gate         VERBOSE(gettext(P_USAGE), argv[0]);
549*7c478bd9Sstevel@tonic-gate         Docmd=NO;
550*7c478bd9Sstevel@tonic-gate     }
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate     if (!Docmd) {
553*7c478bd9Sstevel@tonic-gate 	Euid = geteuid();
554*7c478bd9Sstevel@tonic-gate 	if((setuid(getuid()) < 0) || (setgid(getgid()) < 0)) {
555*7c478bd9Sstevel@tonic-gate 	    VERBOSE("Unable to setuid/gid\n%s", "");
556*7c478bd9Sstevel@tonic-gate 	    cleanup(101);
557*7c478bd9Sstevel@tonic-gate 	}
558*7c478bd9Sstevel@tonic-gate     }
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate     if(Debug)
561*7c478bd9Sstevel@tonic-gate 	tdmp(Cn);
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate     /* At this point succeeded in getting an open communication line	*/
564*7c478bd9Sstevel@tonic-gate     /* Conn() takes care of closing the Systems file			*/
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate     if (!Docmd) {
567*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGINT,_onintrpt);
568*7c478bd9Sstevel@tonic-gate 	_mode(1);			/* put terminal in `raw' mode */
569*7c478bd9Sstevel@tonic-gate 	VERBOSE("Connected\007\r\n%s", "");	/*bell!*/
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	/* must catch signals before fork.  if not and if _receive()	*/
572*7c478bd9Sstevel@tonic-gate 	/* fails in just the right (wrong?) way, _rcvdead() can be	*/
573*7c478bd9Sstevel@tonic-gate 	/* called and do "kill(getppid(),SIGUSR1);" before parent	*/
574*7c478bd9Sstevel@tonic-gate 	/* has done calls to signal() after recfork().			*/
575*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGUSR1, _bye);
576*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGHUP, cleanup);
577*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGQUIT, _onintrpt);
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	sysname(&prompt[1]);	/* set up system name prompt */
580*7c478bd9Sstevel@tonic-gate 	(void) strcat(prompt, "]");
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	recfork();		/* checks for child == 0 */
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	if(Child > 0) {
585*7c478bd9Sstevel@tonic-gate 	    /*
586*7c478bd9Sstevel@tonic-gate 	     * Because the child counts hangups for the -H flag,
587*7c478bd9Sstevel@tonic-gate 	     * and because we fork a new child when doing (e.g.)
588*7c478bd9Sstevel@tonic-gate 	     * ~%take, we assume the first child we fork has
589*7c478bd9Sstevel@tonic-gate 	     * processed all the hangups and we reset the count here.
590*7c478bd9Sstevel@tonic-gate 	     * We really should pass the remaining count back from
591*7c478bd9Sstevel@tonic-gate 	     * the child to the parent when we kill the child.
592*7c478bd9Sstevel@tonic-gate 	     */
593*7c478bd9Sstevel@tonic-gate 	    command_line_hups = 0;
594*7c478bd9Sstevel@tonic-gate 	    Rtn_code = transmit();
595*7c478bd9Sstevel@tonic-gate 	    _quit(Rtn_code);
596*7c478bd9Sstevel@tonic-gate 	    /*NOTREACHED*/
597*7c478bd9Sstevel@tonic-gate 	}
598*7c478bd9Sstevel@tonic-gate     } else {
599*7c478bd9Sstevel@tonic-gate 	/*
600*7c478bd9Sstevel@tonic-gate 	 * Fork a child to run the specified command,
601*7c478bd9Sstevel@tonic-gate 	 * wait for it to finish, and clean up.
602*7c478bd9Sstevel@tonic-gate 	 */
603*7c478bd9Sstevel@tonic-gate 	Child = dofork();
604*7c478bd9Sstevel@tonic-gate 	if (Child == 0) {
605*7c478bd9Sstevel@tonic-gate 	    close(0);
606*7c478bd9Sstevel@tonic-gate 	    close(1);
607*7c478bd9Sstevel@tonic-gate 	    dup(Cn);
608*7c478bd9Sstevel@tonic-gate 	    dup(Cn);
609*7c478bd9Sstevel@tonic-gate 	    close(Cn);
610*7c478bd9Sstevel@tonic-gate 	    setgid(getgid());
611*7c478bd9Sstevel@tonic-gate 	    setuid(getuid());
612*7c478bd9Sstevel@tonic-gate 	    execvp(argv[optind], &argv[optind]);
613*7c478bd9Sstevel@tonic-gate 	    exit(-1);
614*7c478bd9Sstevel@tonic-gate 	    /* NOTREACHED */
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 	wait(0);
617*7c478bd9Sstevel@tonic-gate 	/* XXX - should return wait status as our exit code */
618*7c478bd9Sstevel@tonic-gate     }
619*7c478bd9Sstevel@tonic-gate     cleanup(Cn);
620*7c478bd9Sstevel@tonic-gate     /*NOTREACHED*/
621*7c478bd9Sstevel@tonic-gate }
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate /*
624*7c478bd9Sstevel@tonic-gate  *	Kill the present child, if it exists, then fork a new one.
625*7c478bd9Sstevel@tonic-gate  */
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate static void
628*7c478bd9Sstevel@tonic-gate recfork()
629*7c478bd9Sstevel@tonic-gate {
630*7c478bd9Sstevel@tonic-gate     int ret, status;
631*7c478bd9Sstevel@tonic-gate     if (Child) {
632*7c478bd9Sstevel@tonic-gate 	kill(Child, SIGKILL);
633*7c478bd9Sstevel@tonic-gate 	while ( (ret = wait(&status)) != Child )
634*7c478bd9Sstevel@tonic-gate 	    if (ret == -1 && errno != EINTR)
635*7c478bd9Sstevel@tonic-gate 		break;
636*7c478bd9Sstevel@tonic-gate     }
637*7c478bd9Sstevel@tonic-gate     Child = dofork();
638*7c478bd9Sstevel@tonic-gate     if(Child == 0) {
639*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGUSR1, SIG_DFL);
640*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGHUP, _rcvdead);
641*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGQUIT, SIG_IGN);
642*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGINT, SIG_IGN);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	_receive();	/* This should run until killed */
645*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
646*7c478bd9Sstevel@tonic-gate     }
647*7c478bd9Sstevel@tonic-gate     return;
648*7c478bd9Sstevel@tonic-gate }
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate /***************************************************************
651*7c478bd9Sstevel@tonic-gate  *	transmit: copy stdin to remote fd, except:
652*7c478bd9Sstevel@tonic-gate  *	~.	terminate
653*7c478bd9Sstevel@tonic-gate  *	~!	local login-style shell
654*7c478bd9Sstevel@tonic-gate  *	~!cmd	execute cmd locally
655*7c478bd9Sstevel@tonic-gate  *	~$proc	execute proc locally, send output to line
656*7c478bd9Sstevel@tonic-gate  *	~%cmd	execute builtin cmd (put, take, or break)
657*7c478bd9Sstevel@tonic-gate  ****************************************************************/
658*7c478bd9Sstevel@tonic-gate #ifdef forfutureuse
659*7c478bd9Sstevel@tonic-gate  /*****************************************************************
660*7c478bd9Sstevel@tonic-gate   *	~+proc	execute locally, with stdout to and stdin from line.
661*7c478bd9Sstevel@tonic-gate   ******************************************************************/
662*7c478bd9Sstevel@tonic-gate #endif
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate int
665*7c478bd9Sstevel@tonic-gate transmit()
666*7c478bd9Sstevel@tonic-gate {
667*7c478bd9Sstevel@tonic-gate     char b[BUFSIZ];
668*7c478bd9Sstevel@tonic-gate     register char *p;
669*7c478bd9Sstevel@tonic-gate     register int escape;
670*7c478bd9Sstevel@tonic-gate     register int id = 0;  /*flag for systemname prompt on tilda escape*/
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"transmit started\n\r%s", "");
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate     /* In main loop, always waiting to read characters from	*/
675*7c478bd9Sstevel@tonic-gate     /* keyboard; writes characters to remote, or to TTYOUT	*/
676*7c478bd9Sstevel@tonic-gate     /* on a tilda escape					*/
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate     for (;;) {
679*7c478bd9Sstevel@tonic-gate 	p = b;
680*7c478bd9Sstevel@tonic-gate 	while(r_char(TTYIN) == YES) {
681*7c478bd9Sstevel@tonic-gate 	    if(p == b)  	/* Escape on leading  ~    */
682*7c478bd9Sstevel@tonic-gate 		escape = (_Cxc == '~');
683*7c478bd9Sstevel@tonic-gate 	    if(p == b+1)   	/* But not on leading ~~   */
684*7c478bd9Sstevel@tonic-gate 		escape &= (_Cxc != '~');
685*7c478bd9Sstevel@tonic-gate 	    if(escape) {
686*7c478bd9Sstevel@tonic-gate 		 if(_Cxc == '\n' || _Cxc == '\r' || _Cxc == _Teol) {
687*7c478bd9Sstevel@tonic-gate 		    *p = '\0';
688*7c478bd9Sstevel@tonic-gate 		    if(tilda(b+1) == YES)
689*7c478bd9Sstevel@tonic-gate 			return(0);
690*7c478bd9Sstevel@tonic-gate 		    id = 0;
691*7c478bd9Sstevel@tonic-gate 		    break;
692*7c478bd9Sstevel@tonic-gate 		}
693*7c478bd9Sstevel@tonic-gate 		if(_Cxc == _Tintr || _Cxc == _Tkill || _Cxc == _Tquit ||
694*7c478bd9Sstevel@tonic-gate 			(Intrupt && _Cxc == '\0')) {
695*7c478bd9Sstevel@tonic-gate 		    if(_Cxc == _Tkill) {
696*7c478bd9Sstevel@tonic-gate 			if(Echok)
697*7c478bd9Sstevel@tonic-gate 			    VERBOSE("\r\n%s", "");
698*7c478bd9Sstevel@tonic-gate 		    } else {
699*7c478bd9Sstevel@tonic-gate 			_Cxc = '\r';
700*7c478bd9Sstevel@tonic-gate 			if( w_char(Cn) == NO) {
701*7c478bd9Sstevel@tonic-gate 			    VERBOSE(gettext(P_LINE_GONE),"");
702*7c478bd9Sstevel@tonic-gate 			    return(IOERR);
703*7c478bd9Sstevel@tonic-gate 			}
704*7c478bd9Sstevel@tonic-gate 			id=0;
705*7c478bd9Sstevel@tonic-gate 		    }
706*7c478bd9Sstevel@tonic-gate 		    break;
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 		if((p == b+1) && (_Cxc != _Terase) && (!id)) {
709*7c478bd9Sstevel@tonic-gate 		    id = 1;
710*7c478bd9Sstevel@tonic-gate 		    VERBOSE("%s", prompt);
711*7c478bd9Sstevel@tonic-gate 		}
712*7c478bd9Sstevel@tonic-gate 		if(_Cxc == _Terase) {
713*7c478bd9Sstevel@tonic-gate 		    p = (--p < b)? b:p;
714*7c478bd9Sstevel@tonic-gate 		    if(p > b)
715*7c478bd9Sstevel@tonic-gate 			if(Echoe) {
716*7c478bd9Sstevel@tonic-gate 			    VERBOSE("\b \b%s", "");
717*7c478bd9Sstevel@tonic-gate 			} else
718*7c478bd9Sstevel@tonic-gate 			    (void)w_char(TTYOUT);
719*7c478bd9Sstevel@tonic-gate 		} else {
720*7c478bd9Sstevel@tonic-gate 		    (void)w_char(TTYOUT);
721*7c478bd9Sstevel@tonic-gate 		    if(p-b < BUFSIZ)
722*7c478bd9Sstevel@tonic-gate 			*p++ = _Cxc;
723*7c478bd9Sstevel@tonic-gate 		    else {
724*7c478bd9Sstevel@tonic-gate 			VERBOSE(gettext(P_TOOLONG),"");
725*7c478bd9Sstevel@tonic-gate 			break;
726*7c478bd9Sstevel@tonic-gate 		    }
727*7c478bd9Sstevel@tonic-gate 		}
728*7c478bd9Sstevel@tonic-gate     /*not a tilda escape command*/
729*7c478bd9Sstevel@tonic-gate 	    } else {
730*7c478bd9Sstevel@tonic-gate 		if(Intrupt && _Cxc == '\0') {
731*7c478bd9Sstevel@tonic-gate 		    CDEBUG(4,"got break in transmit\n\r%s", "");
732*7c478bd9Sstevel@tonic-gate 		    Intrupt = NO;
733*7c478bd9Sstevel@tonic-gate 		    (*genbrk)(Cn);
734*7c478bd9Sstevel@tonic-gate 		    _flush();
735*7c478bd9Sstevel@tonic-gate 		    break;
736*7c478bd9Sstevel@tonic-gate 		}
737*7c478bd9Sstevel@tonic-gate 		if(w_char(Cn) == NO) {
738*7c478bd9Sstevel@tonic-gate 		    VERBOSE(gettext(P_LINE_GONE),"");
739*7c478bd9Sstevel@tonic-gate 		    return(IOERR);
740*7c478bd9Sstevel@tonic-gate 		}
741*7c478bd9Sstevel@tonic-gate 		if(Duplex == NO) {
742*7c478bd9Sstevel@tonic-gate 		    if((w_char(TTYERR) == NO) || (wioflsh(TTYERR) == NO))
743*7c478bd9Sstevel@tonic-gate 			return(IOERR);
744*7c478bd9Sstevel@tonic-gate 		}
745*7c478bd9Sstevel@tonic-gate 		if ((_Cxc == _Tintr) || (_Cxc == _Tquit) ||
746*7c478bd9Sstevel@tonic-gate 		     ( (p==b) && (_Cxc == _Myeof) ) ) {
747*7c478bd9Sstevel@tonic-gate 		    CDEBUG(4,"got a tintr\n\r%s", "");
748*7c478bd9Sstevel@tonic-gate 		    _flush();
749*7c478bd9Sstevel@tonic-gate 		    break;
750*7c478bd9Sstevel@tonic-gate 		}
751*7c478bd9Sstevel@tonic-gate 		if(_Cxc == '\n' || _Cxc == '\r' ||
752*7c478bd9Sstevel@tonic-gate 		    _Cxc == _Teol || _Cxc == _Tkill) {
753*7c478bd9Sstevel@tonic-gate 		    id=0;
754*7c478bd9Sstevel@tonic-gate 		    Takeflag = NO;
755*7c478bd9Sstevel@tonic-gate 		    break;
756*7c478bd9Sstevel@tonic-gate 		}
757*7c478bd9Sstevel@tonic-gate 		p = (char*)0;
758*7c478bd9Sstevel@tonic-gate 	    }
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate     }
761*7c478bd9Sstevel@tonic-gate }
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate /***************************************************************
764*7c478bd9Sstevel@tonic-gate  *	routine to halt input from remote and flush buffers
765*7c478bd9Sstevel@tonic-gate  ***************************************************************/
766*7c478bd9Sstevel@tonic-gate static void
767*7c478bd9Sstevel@tonic-gate _flush()
768*7c478bd9Sstevel@tonic-gate {
769*7c478bd9Sstevel@tonic-gate     (void)ioctl(TTYOUT, TCXONC, 0);	/* stop tty output */
770*7c478bd9Sstevel@tonic-gate     (void)ioctl(Cn, TCFLSH, 0);		/* flush remote input */
771*7c478bd9Sstevel@tonic-gate     (void)ioctl(TTYOUT, TCFLSH, 1);	/* flush tty output */
772*7c478bd9Sstevel@tonic-gate     (void)ioctl(TTYOUT, TCXONC, 1);	/* restart tty output */
773*7c478bd9Sstevel@tonic-gate     if(Takeflag == NO) {
774*7c478bd9Sstevel@tonic-gate 	return;		/* didn't interupt file transmission */
775*7c478bd9Sstevel@tonic-gate     }
776*7c478bd9Sstevel@tonic-gate     VERBOSE(gettext(P_FILEINTR),"");
777*7c478bd9Sstevel@tonic-gate     (void)sleep(3);
778*7c478bd9Sstevel@tonic-gate     _w_str("echo '\n~>\n';mesg y;stty echo\n");
779*7c478bd9Sstevel@tonic-gate     Takeflag = NO;
780*7c478bd9Sstevel@tonic-gate     return;
781*7c478bd9Sstevel@tonic-gate }
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate /**************************************************************
784*7c478bd9Sstevel@tonic-gate  *	command interpreter for escape lines
785*7c478bd9Sstevel@tonic-gate  **************************************************************/
786*7c478bd9Sstevel@tonic-gate int
787*7c478bd9Sstevel@tonic-gate tilda(cmd)
788*7c478bd9Sstevel@tonic-gate register char	*cmd;
789*7c478bd9Sstevel@tonic-gate {
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate     VERBOSE("\r\n%s", "");
792*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call tilda(%s)\r\n", cmd);
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate     switch(cmd[0]) {
795*7c478bd9Sstevel@tonic-gate 	case CSUSP:
796*7c478bd9Sstevel@tonic-gate 	case CDSUSP:
797*7c478bd9Sstevel@tonic-gate 	    _mode(0);
798*7c478bd9Sstevel@tonic-gate 	    kill(cmd[0] == CDSUSP ? getpid() : (pid_t) 0, SIGTSTP);
799*7c478bd9Sstevel@tonic-gate 	    _mode(1);
800*7c478bd9Sstevel@tonic-gate 	    break;
801*7c478bd9Sstevel@tonic-gate 	case '.':
802*7c478bd9Sstevel@tonic-gate 	    if(Cucall.telno == CNULL)
803*7c478bd9Sstevel@tonic-gate 		if(cmd[1] != '.') {
804*7c478bd9Sstevel@tonic-gate 		    _w_str("\04\04\04\04\04");
805*7c478bd9Sstevel@tonic-gate 		    if (Child)
806*7c478bd9Sstevel@tonic-gate 			kill(Child, SIGKILL);
807*7c478bd9Sstevel@tonic-gate 		    if (ioctl (Cn, TCGETS, &_Lvs) < 0) {
808*7c478bd9Sstevel@tonic-gate 		    	(void) ioctl (Cn, TCGETA, &_Lv);
809*7c478bd9Sstevel@tonic-gate 		    	/* speed to zero for hangup */
810*7c478bd9Sstevel@tonic-gate 		    	_Lv.c_cflag = 0;
811*7c478bd9Sstevel@tonic-gate 		    	(void) ioctl (Cn, TCSETAW, &_Lv);
812*7c478bd9Sstevel@tonic-gate 		    } else {
813*7c478bd9Sstevel@tonic-gate 		    	/* speed to zero for hangup */
814*7c478bd9Sstevel@tonic-gate 			_Lvs.c_cflag &= 0xffff0000;
815*7c478bd9Sstevel@tonic-gate 			cfsetospeed(&_Lvs, B0);
816*7c478bd9Sstevel@tonic-gate 		    	(void) ioctl (Cn, TCSETSW, &_Lvs);
817*7c478bd9Sstevel@tonic-gate 		    }
818*7c478bd9Sstevel@tonic-gate 		    (void) sleep (2);
819*7c478bd9Sstevel@tonic-gate 		}
820*7c478bd9Sstevel@tonic-gate 	    return(YES);
821*7c478bd9Sstevel@tonic-gate 	case '!':
822*7c478bd9Sstevel@tonic-gate 	    _shell(cmd);	/* local shell */
823*7c478bd9Sstevel@tonic-gate 	    VERBOSE("\r%c\r\n", *cmd);
824*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
825*7c478bd9Sstevel@tonic-gate 	    break;
826*7c478bd9Sstevel@tonic-gate 	case '$':
827*7c478bd9Sstevel@tonic-gate 	    if(cmd[1] == '\0') {
828*7c478bd9Sstevel@tonic-gate 		VERBOSE(gettext(P_USECMD),"");
829*7c478bd9Sstevel@tonic-gate 		VERBOSE("(continue)%s", "");
830*7c478bd9Sstevel@tonic-gate 	    } else {
831*7c478bd9Sstevel@tonic-gate 		_shell(cmd);	/*Local shell  */
832*7c478bd9Sstevel@tonic-gate 		VERBOSE("\r%c\r\n", *cmd);
833*7c478bd9Sstevel@tonic-gate 	    }
834*7c478bd9Sstevel@tonic-gate 	    break;
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate #ifdef forfutureuse
837*7c478bd9Sstevel@tonic-gate 	case '+':
838*7c478bd9Sstevel@tonic-gate 	    if(cmd[1] == '\0') {
839*7c478bd9Sstevel@tonic-gate 		VERBOSE(gettext(P_USEPLUSCMD), "");
840*7c478bd9Sstevel@tonic-gate 		VERBOSE("(continue)%s", "");
841*7c478bd9Sstevel@tonic-gate 	    } else {
842*7c478bd9Sstevel@tonic-gate 		if (*cmd == '+')
843*7c478bd9Sstevel@tonic-gate 			  /* must suspend receive to give*/
844*7c478bd9Sstevel@tonic-gate 			  /*remote out to stdin of cmd */
845*7c478bd9Sstevel@tonic-gate 		    kill(Child, SIGKILL);
846*7c478bd9Sstevel@tonic-gate 		    _shell(cmd);	/* Local shell */
847*7c478bd9Sstevel@tonic-gate 		if (*cmd == '+')
848*7c478bd9Sstevel@tonic-gate 		    recfork();
849*7c478bd9Sstevel@tonic-gate 		VERBOSE("\r%c\r\n", *cmd);
850*7c478bd9Sstevel@tonic-gate 	    }
851*7c478bd9Sstevel@tonic-gate 	    break;
852*7c478bd9Sstevel@tonic-gate #endif
853*7c478bd9Sstevel@tonic-gate 	case '%':
854*7c478bd9Sstevel@tonic-gate 	    _dopercen(++cmd);
855*7c478bd9Sstevel@tonic-gate 	    break;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	case 't':
858*7c478bd9Sstevel@tonic-gate 	    tdmp(TTYIN);
859*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
860*7c478bd9Sstevel@tonic-gate 	    break;
861*7c478bd9Sstevel@tonic-gate 	case 'l':
862*7c478bd9Sstevel@tonic-gate 	    tdmp(Cn);
863*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
864*7c478bd9Sstevel@tonic-gate 	    break;
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	default:
867*7c478bd9Sstevel@tonic-gate 	    VERBOSE(gettext(P_STARTWITH),"");
868*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
869*7c478bd9Sstevel@tonic-gate 	    break;
870*7c478bd9Sstevel@tonic-gate     }
871*7c478bd9Sstevel@tonic-gate     return(NO);
872*7c478bd9Sstevel@tonic-gate }
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate /***************************************************************
875*7c478bd9Sstevel@tonic-gate  *	The routine "shell" takes an argument starting with
876*7c478bd9Sstevel@tonic-gate  *	either "!" or "$", and terminated with '\0'.
877*7c478bd9Sstevel@tonic-gate  *	If $arg, arg is the name of a local shell file which
878*7c478bd9Sstevel@tonic-gate  *	is executed and its output is passed to the remote.
879*7c478bd9Sstevel@tonic-gate  *	If !arg, we escape to a local shell to execute arg
880*7c478bd9Sstevel@tonic-gate  *	with output to TTY, and if arg is null, escape to
881*7c478bd9Sstevel@tonic-gate  *	a local shell and blind the remote line.  In either
882*7c478bd9Sstevel@tonic-gate  *	case, '^D' will kill the escape status.
883*7c478bd9Sstevel@tonic-gate  **************************************************************/
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate #ifdef forfutureuse
886*7c478bd9Sstevel@tonic-gate /***************************************************************
887*7c478bd9Sstevel@tonic-gate  *	Another argument to the routine "shell" may be +.  If +arg,
888*7c478bd9Sstevel@tonic-gate  *	arg is the name of a local shell file which is executed with
889*7c478bd9Sstevel@tonic-gate  *	stdin from and stdout to the remote.
890*7c478bd9Sstevel@tonic-gate  **************************************************************/
891*7c478bd9Sstevel@tonic-gate #endif
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate static void
894*7c478bd9Sstevel@tonic-gate _shell(str)
895*7c478bd9Sstevel@tonic-gate char	*str;
896*7c478bd9Sstevel@tonic-gate {
897*7c478bd9Sstevel@tonic-gate     pid_t	fk, w_ret;
898*7c478bd9Sstevel@tonic-gate     void	(*xx)(), (*yy)();
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call _shell(%s)\r\n", str);
901*7c478bd9Sstevel@tonic-gate     fk = dofork();
902*7c478bd9Sstevel@tonic-gate     if(fk < 0)
903*7c478bd9Sstevel@tonic-gate 	return;
904*7c478bd9Sstevel@tonic-gate     Shell = fk;
905*7c478bd9Sstevel@tonic-gate     _mode(0);	/* restore normal tty attributes */
906*7c478bd9Sstevel@tonic-gate     xx = signal(SIGINT, SIG_IGN);
907*7c478bd9Sstevel@tonic-gate     yy = signal(SIGQUIT, SIG_IGN);
908*7c478bd9Sstevel@tonic-gate     if(fk == 0) {
909*7c478bd9Sstevel@tonic-gate 	char *shell;
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 	if( (shell = getenv("SHELL")) == NULL)
912*7c478bd9Sstevel@tonic-gate 	    /* use default if user's shell is not set */
913*7c478bd9Sstevel@tonic-gate 	    shell = SHELL;
914*7c478bd9Sstevel@tonic-gate 	(void)close(TTYOUT);
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	/***********************************************
917*7c478bd9Sstevel@tonic-gate 	 * Hook-up our "standard output"
918*7c478bd9Sstevel@tonic-gate 	 * to either the tty for '!' or the line
919*7c478bd9Sstevel@tonic-gate 	 * for '$'  as appropriate
920*7c478bd9Sstevel@tonic-gate 	 ***********************************************/
921*7c478bd9Sstevel@tonic-gate #ifdef forfutureuse
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	/************************************************
924*7c478bd9Sstevel@tonic-gate 	 * Or to the line for '+'.
925*7c478bd9Sstevel@tonic-gate 	 **********************************************/
926*7c478bd9Sstevel@tonic-gate #endif
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	(void)fcntl((*str == '!')? TTYERR:Cn,F_DUPFD,TTYOUT);
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate #ifdef forfutureuse
931*7c478bd9Sstevel@tonic-gate 	/*************************************************
932*7c478bd9Sstevel@tonic-gate 	 * Hook-up "standard input" to the line for '+'.
933*7c478bd9Sstevel@tonic-gate 	 * **********************************************/
934*7c478bd9Sstevel@tonic-gate 	if (*str == '+') {
935*7c478bd9Sstevel@tonic-gate 	    (void)close(TTYIN);
936*7c478bd9Sstevel@tonic-gate 	    (void)fcntl(Cn,F_DUPFD,TTYIN);
937*7c478bd9Sstevel@tonic-gate 	    }
938*7c478bd9Sstevel@tonic-gate #endif
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	/***********************************************
941*7c478bd9Sstevel@tonic-gate 	 * Hook-up our "standard input"
942*7c478bd9Sstevel@tonic-gate 	 * to the tty for '!' and '$'.
943*7c478bd9Sstevel@tonic-gate 	 ***********************************************/
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	(void)close(Cn);   	/*parent still has Cn*/
946*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGINT, SIG_DFL);
947*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGHUP, SIG_DFL);
948*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGQUIT, SIG_DFL);
949*7c478bd9Sstevel@tonic-gate 	(void)signal(SIGUSR1, SIG_DFL);
950*7c478bd9Sstevel@tonic-gate 	if(*++str == '\0')
951*7c478bd9Sstevel@tonic-gate 	    (void)execl(shell,shell,(char*) 0,(char*) 0,(char *) 0);
952*7c478bd9Sstevel@tonic-gate 	else
953*7c478bd9Sstevel@tonic-gate 	    (void)execl(shell,"sh","-c",str,(char *) 0);
954*7c478bd9Sstevel@tonic-gate 	VERBOSE(gettext(P_Ct_EXSH),"");
955*7c478bd9Sstevel@tonic-gate 	exit(0);
956*7c478bd9Sstevel@tonic-gate     }
957*7c478bd9Sstevel@tonic-gate     while ((w_ret = wait((int*)0)) != fk)
958*7c478bd9Sstevel@tonic-gate 	if (w_ret == -1 && errno != EINTR)
959*7c478bd9Sstevel@tonic-gate 	    break;
960*7c478bd9Sstevel@tonic-gate     Shell = 0;
961*7c478bd9Sstevel@tonic-gate     (void)signal(SIGINT, xx);
962*7c478bd9Sstevel@tonic-gate     (void)signal(SIGQUIT, yy);
963*7c478bd9Sstevel@tonic-gate     _mode(1);
964*7c478bd9Sstevel@tonic-gate     return;
965*7c478bd9Sstevel@tonic-gate }
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate /***************************************************************
969*7c478bd9Sstevel@tonic-gate  *	This function implements the 'put', 'take', 'break',
970*7c478bd9Sstevel@tonic-gate  *	'ifc' (aliased to nostop) and 'ofc' (aliased to noostop)
971*7c478bd9Sstevel@tonic-gate  *	commands which are internal to cu.
972*7c478bd9Sstevel@tonic-gate  ***************************************************************/
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate static void
975*7c478bd9Sstevel@tonic-gate _dopercen(cmd)
976*7c478bd9Sstevel@tonic-gate register char *cmd;
977*7c478bd9Sstevel@tonic-gate {
978*7c478bd9Sstevel@tonic-gate     char	*arg[5];
979*7c478bd9Sstevel@tonic-gate     char	*getpath;
980*7c478bd9Sstevel@tonic-gate     char	mypath[MAXPATH];
981*7c478bd9Sstevel@tonic-gate     int	narg;
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate     blckcnt((long)(-1));
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call _dopercen(\"%s\")\r\n", cmd);
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate     arg[narg=0] = strtok(cmd, " \t\n");
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate     /* following loop breaks out the command and args */
990*7c478bd9Sstevel@tonic-gate     while((arg[++narg] = strtok((char*) NULL, " \t\n")) != NULL) {
991*7c478bd9Sstevel@tonic-gate 	if(narg < 4)
992*7c478bd9Sstevel@tonic-gate 	    continue;
993*7c478bd9Sstevel@tonic-gate 	else
994*7c478bd9Sstevel@tonic-gate 	    break;
995*7c478bd9Sstevel@tonic-gate     }
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate     /* ~%take file option */
998*7c478bd9Sstevel@tonic-gate     if(EQUALS(arg[0], "take")) {
999*7c478bd9Sstevel@tonic-gate 	if(narg < 2 || narg > 3) {
1000*7c478bd9Sstevel@tonic-gate 	    VERBOSE("usage: ~%%take from [to]\r\n%s", "");
1001*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
1002*7c478bd9Sstevel@tonic-gate 	    return;
1003*7c478bd9Sstevel@tonic-gate 	}
1004*7c478bd9Sstevel@tonic-gate 	if(narg == 2)
1005*7c478bd9Sstevel@tonic-gate 	    arg[2] = arg[1];
1006*7c478bd9Sstevel@tonic-gate 	(void) strcpy(filename, arg[2]);
1007*7c478bd9Sstevel@tonic-gate 	recfork();	/* fork so child (receive) knows filename */
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	/*
1010*7c478bd9Sstevel@tonic-gate 	 * be sure that the remote file (arg[1]) exists before
1011*7c478bd9Sstevel@tonic-gate 	 * you try to take it.   otherwise, the error message from
1012*7c478bd9Sstevel@tonic-gate 	 * cat will wind up in the local file (arg[2])
1013*7c478bd9Sstevel@tonic-gate 	 *
1014*7c478bd9Sstevel@tonic-gate 	 * what we're doing is:
1015*7c478bd9Sstevel@tonic-gate 	 *	stty -echo; \
1016*7c478bd9Sstevel@tonic-gate 	 *	if test -r arg1
1017*7c478bd9Sstevel@tonic-gate 	 *	then (echo '~[local]'>arg2; cat arg1; echo '~[local]'>)
1018*7c478bd9Sstevel@tonic-gate 	 *	else echo can't open: arg1
1019*7c478bd9Sstevel@tonic-gate 	 *	fi; \
1020*7c478bd9Sstevel@tonic-gate 	 *	stty echo
1021*7c478bd9Sstevel@tonic-gate 	 *
1022*7c478bd9Sstevel@tonic-gate 	 */
1023*7c478bd9Sstevel@tonic-gate 	_w_str("stty -echo;if test -r ");
1024*7c478bd9Sstevel@tonic-gate 	_w_str(arg[1]);
1025*7c478bd9Sstevel@tonic-gate 	_w_str("; then (echo '~");
1026*7c478bd9Sstevel@tonic-gate 	_w_str(prompt);
1027*7c478bd9Sstevel@tonic-gate 	_w_str(">'");
1028*7c478bd9Sstevel@tonic-gate 	_w_str(arg[2]);
1029*7c478bd9Sstevel@tonic-gate 	_w_str(";cat ");
1030*7c478bd9Sstevel@tonic-gate 	_w_str(arg[1]);
1031*7c478bd9Sstevel@tonic-gate 	_w_str(";echo '~");
1032*7c478bd9Sstevel@tonic-gate 	_w_str(prompt);
1033*7c478bd9Sstevel@tonic-gate 	_w_str(">'); else echo cant\\'t open: ");
1034*7c478bd9Sstevel@tonic-gate 	_w_str(arg[1]);
1035*7c478bd9Sstevel@tonic-gate 	_w_str("; fi;stty echo\n");
1036*7c478bd9Sstevel@tonic-gate 	Takeflag = YES;
1037*7c478bd9Sstevel@tonic-gate 	return;
1038*7c478bd9Sstevel@tonic-gate     }
1039*7c478bd9Sstevel@tonic-gate     /* ~%put file option*/
1040*7c478bd9Sstevel@tonic-gate     if(EQUALS(arg[0], "put")) {
1041*7c478bd9Sstevel@tonic-gate 	FILE	*file;
1042*7c478bd9Sstevel@tonic-gate 	char	ch, buf[BUFSIZ], spec[NCC+1], *b, *p, *q;
1043*7c478bd9Sstevel@tonic-gate 	int	i, j, len, tc=0, lines=0;
1044*7c478bd9Sstevel@tonic-gate 	long	chars=0L;
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	if(narg < 2 || narg > 3) {
1047*7c478bd9Sstevel@tonic-gate 	    VERBOSE("usage: ~%%put from [to]\r\n%s", "");
1048*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
1049*7c478bd9Sstevel@tonic-gate 	    return;
1050*7c478bd9Sstevel@tonic-gate 	}
1051*7c478bd9Sstevel@tonic-gate 	if(narg == 2)
1052*7c478bd9Sstevel@tonic-gate 	    arg[2] = arg[1];
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 	if((file = fopen(arg[1], "r")) == NULL) {
1055*7c478bd9Sstevel@tonic-gate 	    VERBOSE(gettext(P_Ct_OPEN), arg[1]);
1056*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
1057*7c478bd9Sstevel@tonic-gate 	    return;
1058*7c478bd9Sstevel@tonic-gate 	}
1059*7c478bd9Sstevel@tonic-gate 	/*
1060*7c478bd9Sstevel@tonic-gate 	 * if cannot write into file on remote machine, write into
1061*7c478bd9Sstevel@tonic-gate 	 * /dev/null
1062*7c478bd9Sstevel@tonic-gate 	 *
1063*7c478bd9Sstevel@tonic-gate 	 * what we're doing is:
1064*7c478bd9Sstevel@tonic-gate 	 *	stty -echo
1065*7c478bd9Sstevel@tonic-gate 	 *	(cat - > arg2) || cat - > /dev/null
1066*7c478bd9Sstevel@tonic-gate 	 *	stty echo
1067*7c478bd9Sstevel@tonic-gate 	 */
1068*7c478bd9Sstevel@tonic-gate 	_w_str("stty -echo;(cat - >");
1069*7c478bd9Sstevel@tonic-gate 	_w_str(arg[2]);
1070*7c478bd9Sstevel@tonic-gate 	_w_str(")||cat - >/dev/null;stty echo\n");
1071*7c478bd9Sstevel@tonic-gate 	Intrupt = NO;
1072*7c478bd9Sstevel@tonic-gate 	for(i=0,j=0; i < NCC; ++i)
1073*7c478bd9Sstevel@tonic-gate 	    if((ch=_Tv0s.c_cc[i]) != '\0')
1074*7c478bd9Sstevel@tonic-gate 		spec[j++] = ch;
1075*7c478bd9Sstevel@tonic-gate 	spec[j] = '\0';
1076*7c478bd9Sstevel@tonic-gate 	_mode(2);	/*accept interrupts from keyboard*/
1077*7c478bd9Sstevel@tonic-gate 	(void)sleep(5);	/*hope that w_str info digested*/
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	/* Read characters line by line into buf to write to	*/
1080*7c478bd9Sstevel@tonic-gate 	/* remote with character and line count for blckcnt	*/
1081*7c478bd9Sstevel@tonic-gate 	while(Intrupt == NO &&
1082*7c478bd9Sstevel@tonic-gate 		fgets(b= &buf[MID],MID,file) != NULL) {
1083*7c478bd9Sstevel@tonic-gate 	    /* worse case is each char must be escaped*/
1084*7c478bd9Sstevel@tonic-gate 	    len = strlen(b);
1085*7c478bd9Sstevel@tonic-gate 	    chars += len;		/* character count */
1086*7c478bd9Sstevel@tonic-gate 	    p = b;
1087*7c478bd9Sstevel@tonic-gate 	    while(q = strpbrk(p, spec)) {
1088*7c478bd9Sstevel@tonic-gate 		if(*q == _Tintr || *q == _Tquit || *q == _Teol) {
1089*7c478bd9Sstevel@tonic-gate 		    VERBOSE(gettext(P_Ct_SPECIAL), *q);
1090*7c478bd9Sstevel@tonic-gate 		    (void)strcpy(q, q+1);
1091*7c478bd9Sstevel@tonic-gate 		    Intrupt = YES;
1092*7c478bd9Sstevel@tonic-gate 		} else {
1093*7c478bd9Sstevel@tonic-gate 		    b = strncpy(b-1, b, q-b);
1094*7c478bd9Sstevel@tonic-gate 		    *(q-1) = '\\';
1095*7c478bd9Sstevel@tonic-gate 		}
1096*7c478bd9Sstevel@tonic-gate 		p = q+1;
1097*7c478bd9Sstevel@tonic-gate 	    }
1098*7c478bd9Sstevel@tonic-gate 	    if((tc += len) >= MID) {
1099*7c478bd9Sstevel@tonic-gate 		(void)sleep(1);
1100*7c478bd9Sstevel@tonic-gate 		tc = len;
1101*7c478bd9Sstevel@tonic-gate 	    }
1102*7c478bd9Sstevel@tonic-gate 	    if(write(Cn, b, (unsigned)strlen(b)) < 0) {
1103*7c478bd9Sstevel@tonic-gate 		VERBOSE(gettext(P_IOERR),"");
1104*7c478bd9Sstevel@tonic-gate 		Intrupt = YES;
1105*7c478bd9Sstevel@tonic-gate 		break;
1106*7c478bd9Sstevel@tonic-gate 	    }
1107*7c478bd9Sstevel@tonic-gate 	    ++lines;		/* line count */
1108*7c478bd9Sstevel@tonic-gate 	    blckcnt((long)chars);
1109*7c478bd9Sstevel@tonic-gate 	}
1110*7c478bd9Sstevel@tonic-gate 	_mode(1);
1111*7c478bd9Sstevel@tonic-gate 	blckcnt((long)(-2));		/* close */
1112*7c478bd9Sstevel@tonic-gate 	(void)fclose(file);
1113*7c478bd9Sstevel@tonic-gate 	if(Intrupt == YES) {
1114*7c478bd9Sstevel@tonic-gate 	    Intrupt = NO;
1115*7c478bd9Sstevel@tonic-gate 	    _w_str("\n");
1116*7c478bd9Sstevel@tonic-gate 	    VERBOSE(gettext(P_CNTAFTER), ++chars);
1117*7c478bd9Sstevel@tonic-gate 	} else {
1118*7c478bd9Sstevel@tonic-gate 	    VERBOSE(gettext(P_CNTLINES), lines);
1119*7c478bd9Sstevel@tonic-gate 	    VERBOSE(gettext(P_CNTCHAR),chars);
1120*7c478bd9Sstevel@tonic-gate 	}
1121*7c478bd9Sstevel@tonic-gate 	(void)sleep(3);
1122*7c478bd9Sstevel@tonic-gate 	_w_str("\04");
1123*7c478bd9Sstevel@tonic-gate 	return;
1124*7c478bd9Sstevel@tonic-gate     }
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	/*  ~%b or ~%break  */
1127*7c478bd9Sstevel@tonic-gate     if(EQUALS(arg[0], "b") || EQUALS(arg[0], "break")) {
1128*7c478bd9Sstevel@tonic-gate 	(*genbrk)(Cn);
1129*7c478bd9Sstevel@tonic-gate 	return;
1130*7c478bd9Sstevel@tonic-gate     }
1131*7c478bd9Sstevel@tonic-gate 	/*  ~%d or ~%debug toggle  */
1132*7c478bd9Sstevel@tonic-gate     if(EQUALS(arg[0], "d") || EQUALS(arg[0], "debug")) {
1133*7c478bd9Sstevel@tonic-gate 	if(Debug == 0)
1134*7c478bd9Sstevel@tonic-gate 	    Debug = 9;
1135*7c478bd9Sstevel@tonic-gate 	else
1136*7c478bd9Sstevel@tonic-gate 	    Debug = 0;
1137*7c478bd9Sstevel@tonic-gate 	VERBOSE("(continue)%s", "");
1138*7c478bd9Sstevel@tonic-gate 	return;
1139*7c478bd9Sstevel@tonic-gate     }
1140*7c478bd9Sstevel@tonic-gate 	/*  ~%[ifc|nostop]  toggles start/stop input control  */
1141*7c478bd9Sstevel@tonic-gate     if( EQUALS(arg[0], "ifc") || EQUALS(arg[0], "nostop") ) {
1142*7c478bd9Sstevel@tonic-gate 	(void)ioctl(Cn, TCGETA, &_Tv);
1143*7c478bd9Sstevel@tonic-gate 	Ifc = !Ifc;
1144*7c478bd9Sstevel@tonic-gate 	if(Ifc == YES)
1145*7c478bd9Sstevel@tonic-gate 	    _Tv.c_iflag |= IXOFF;
1146*7c478bd9Sstevel@tonic-gate 	else
1147*7c478bd9Sstevel@tonic-gate 	    _Tv.c_iflag &= ~IXOFF;
1148*7c478bd9Sstevel@tonic-gate 	(void)ioctl(Cn, TCSETAW, &_Tv);
1149*7c478bd9Sstevel@tonic-gate 	_mode(1);
1150*7c478bd9Sstevel@tonic-gate 	VERBOSE("(ifc %s)", (Ifc ? "enabled" : "disabled"));
1151*7c478bd9Sstevel@tonic-gate 	VERBOSE("(continue)%s", "");
1152*7c478bd9Sstevel@tonic-gate 	return;
1153*7c478bd9Sstevel@tonic-gate     }
1154*7c478bd9Sstevel@tonic-gate 	/*  ~%[ofc|noostop]  toggles start/stop output control  */
1155*7c478bd9Sstevel@tonic-gate     if( EQUALS(arg[0], "ofc") || EQUALS(arg[0], "noostop") ) {
1156*7c478bd9Sstevel@tonic-gate 	(void)ioctl(Cn, TCGETA, &_Tv);
1157*7c478bd9Sstevel@tonic-gate 	Ofc = !Ofc;
1158*7c478bd9Sstevel@tonic-gate 	if(Ofc == YES)
1159*7c478bd9Sstevel@tonic-gate 	    _Tv.c_iflag |= IXON;
1160*7c478bd9Sstevel@tonic-gate 	else
1161*7c478bd9Sstevel@tonic-gate 	    _Tv.c_iflag &= ~IXON;
1162*7c478bd9Sstevel@tonic-gate 	(void)ioctl(Cn, TCSETAW, &_Tv);
1163*7c478bd9Sstevel@tonic-gate 	_mode(1);
1164*7c478bd9Sstevel@tonic-gate 	VERBOSE("(ofc %s)", (Ofc ? "enabled" : "disabled"));
1165*7c478bd9Sstevel@tonic-gate 	VERBOSE("(continue)%s", "");
1166*7c478bd9Sstevel@tonic-gate 	return;
1167*7c478bd9Sstevel@tonic-gate     }
1168*7c478bd9Sstevel@tonic-gate 	/*  ~%divert toggles unsolicited redirection security */
1169*7c478bd9Sstevel@tonic-gate     if( EQUALS(arg[0], "divert") ) {
1170*7c478bd9Sstevel@tonic-gate 	Divert = !Divert;
1171*7c478bd9Sstevel@tonic-gate 	recfork();	/* fork a new child so it knows about change */
1172*7c478bd9Sstevel@tonic-gate 	VERBOSE("(unsolicited diversion %s)", (Divert ? "enabled" : "disabled"));
1173*7c478bd9Sstevel@tonic-gate 	VERBOSE("(continue)%s", "");
1174*7c478bd9Sstevel@tonic-gate 	return;
1175*7c478bd9Sstevel@tonic-gate     }
1176*7c478bd9Sstevel@tonic-gate 	/*  ~%old toggles recognition of old-style '~>:filename' */
1177*7c478bd9Sstevel@tonic-gate     if( EQUALS(arg[0], "old") ) {
1178*7c478bd9Sstevel@tonic-gate 	OldStyle = !OldStyle;
1179*7c478bd9Sstevel@tonic-gate 	recfork();	/* fork a new child so it knows about change */
1180*7c478bd9Sstevel@tonic-gate 	VERBOSE("(old-style diversion %s)", (OldStyle ? "enabled" : "disabled"));
1181*7c478bd9Sstevel@tonic-gate 	VERBOSE("(continue)%s", "");
1182*7c478bd9Sstevel@tonic-gate 	return;
1183*7c478bd9Sstevel@tonic-gate     }
1184*7c478bd9Sstevel@tonic-gate 	/* Change local current directory */
1185*7c478bd9Sstevel@tonic-gate     if(EQUALS(arg[0], "cd")) {
1186*7c478bd9Sstevel@tonic-gate 	if (narg < 2) {
1187*7c478bd9Sstevel@tonic-gate 	    getpath = getenv("HOME");
1188*7c478bd9Sstevel@tonic-gate 	    strlcpy(mypath, getpath, sizeof (mypath));
1189*7c478bd9Sstevel@tonic-gate 	    if(chdir(mypath) < 0) {
1190*7c478bd9Sstevel@tonic-gate 		VERBOSE("Cannot change to %s\r\n", mypath);
1191*7c478bd9Sstevel@tonic-gate 		VERBOSE("(continue)%s", "");
1192*7c478bd9Sstevel@tonic-gate 		return;
1193*7c478bd9Sstevel@tonic-gate 	    }
1194*7c478bd9Sstevel@tonic-gate 	} else if (chdir(arg[1]) < 0) {
1195*7c478bd9Sstevel@tonic-gate 	    VERBOSE("Cannot change to %s\r\n", arg[1]);
1196*7c478bd9Sstevel@tonic-gate 	    VERBOSE("(continue)%s", "");
1197*7c478bd9Sstevel@tonic-gate 	    return;
1198*7c478bd9Sstevel@tonic-gate 	}
1199*7c478bd9Sstevel@tonic-gate 	recfork();	/* fork a new child so it knows about change */
1200*7c478bd9Sstevel@tonic-gate 	VERBOSE("(continue)%s", "");
1201*7c478bd9Sstevel@tonic-gate 	return;
1202*7c478bd9Sstevel@tonic-gate     }
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate    if (arg[0] == (char *) NULL)
1205*7c478bd9Sstevel@tonic-gate        arg[0] = "";
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate     VERBOSE("~%%%s unknown to cu\r\n", arg[0]);
1208*7c478bd9Sstevel@tonic-gate     VERBOSE("(continue)%s", "");
1209*7c478bd9Sstevel@tonic-gate     return;
1210*7c478bd9Sstevel@tonic-gate }
1211*7c478bd9Sstevel@tonic-gate 
1212*7c478bd9Sstevel@tonic-gate /***************************************************************
1213*7c478bd9Sstevel@tonic-gate  *	receive: read from remote line, write to fd=1 (TTYOUT)
1214*7c478bd9Sstevel@tonic-gate  *	catch:
1215*7c478bd9Sstevel@tonic-gate  *	~>[>]:file
1216*7c478bd9Sstevel@tonic-gate  *	.
1217*7c478bd9Sstevel@tonic-gate  *	. stuff for file
1218*7c478bd9Sstevel@tonic-gate  *	.
1219*7c478bd9Sstevel@tonic-gate  *	~>	(ends diversion)
1220*7c478bd9Sstevel@tonic-gate  ***************************************************************/
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate static void
1223*7c478bd9Sstevel@tonic-gate _receive()
1224*7c478bd9Sstevel@tonic-gate {
1225*7c478bd9Sstevel@tonic-gate     register silent = NO, file = -1;
1226*7c478bd9Sstevel@tonic-gate     register char *p;
1227*7c478bd9Sstevel@tonic-gate     int	tic;
1228*7c478bd9Sstevel@tonic-gate     int for_me = NO;
1229*7c478bd9Sstevel@tonic-gate     char	b[BUFSIZ];
1230*7c478bd9Sstevel@tonic-gate     char	*b_p;
1231*7c478bd9Sstevel@tonic-gate     long	count;
1232*7c478bd9Sstevel@tonic-gate     int		line_ok = 1, rval;
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"_receive started\r\n%s", "");
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate     b[0] = '\0';
1237*7c478bd9Sstevel@tonic-gate     b_p = p = b;
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate     while(line_ok) {
1240*7c478bd9Sstevel@tonic-gate 	rval = r_char(Cn);
1241*7c478bd9Sstevel@tonic-gate 	if (rval == NO) {
1242*7c478bd9Sstevel@tonic-gate 	    line_ok = 0;
1243*7c478bd9Sstevel@tonic-gate 	    continue;
1244*7c478bd9Sstevel@tonic-gate 	}
1245*7c478bd9Sstevel@tonic-gate 	if (rval == HUNGUP) {
1246*7c478bd9Sstevel@tonic-gate 	    if (command_line_hups > 0) {
1247*7c478bd9Sstevel@tonic-gate 		CDEBUG(4, "Ignoring device hangup\n%s", "");
1248*7c478bd9Sstevel@tonic-gate 		command_line_hups--;
1249*7c478bd9Sstevel@tonic-gate 		(void) setuid(Euid);	/* reacquire privileges */
1250*7c478bd9Sstevel@tonic-gate 		if (clear_hup(Cn) != SUCCESS) {
1251*7c478bd9Sstevel@tonic-gate 		    DEBUG(4, "Unable to clear hup on device\n%s", "");
1252*7c478bd9Sstevel@tonic-gate 		    line_ok = 0;
1253*7c478bd9Sstevel@tonic-gate 		}
1254*7c478bd9Sstevel@tonic-gate 		(void) setuid(getuid());  /* relinquish privileges */
1255*7c478bd9Sstevel@tonic-gate 	    } else
1256*7c478bd9Sstevel@tonic-gate 		line_ok = 0;
1257*7c478bd9Sstevel@tonic-gate 	    continue;
1258*7c478bd9Sstevel@tonic-gate 	}
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 	if(silent == NO)    /* ie., if not redirecting from screen */
1261*7c478bd9Sstevel@tonic-gate 	    if(w_char(TTYOUT) == NO)
1262*7c478bd9Sstevel@tonic-gate 		_rcvdead(IOERR);    /* this will exit */
1263*7c478bd9Sstevel@tonic-gate 	/* remove CR's and fill inserted by remote */
1264*7c478bd9Sstevel@tonic-gate 	if(_Cxc == '\0' || _Cxc == RUB || _Cxc == '\r')
1265*7c478bd9Sstevel@tonic-gate 	    continue;
1266*7c478bd9Sstevel@tonic-gate 	*p++ = _Cxc;
1267*7c478bd9Sstevel@tonic-gate 	if(_Cxc != '\n' && (p-b) < BUFSIZ)
1268*7c478bd9Sstevel@tonic-gate 	    continue;
1269*7c478bd9Sstevel@tonic-gate 	/* ****************************************** */
1270*7c478bd9Sstevel@tonic-gate 	/* This code deals with ~%take file diversion */
1271*7c478bd9Sstevel@tonic-gate 	/* ****************************************** */
1272*7c478bd9Sstevel@tonic-gate 	if (b[0] == '~') {
1273*7c478bd9Sstevel@tonic-gate 	    int    append;
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate 	    if (EQUALSN(&b[1],prompt,strlen(prompt))) {
1276*7c478bd9Sstevel@tonic-gate 		b_p = b + 1 + strlen(prompt);
1277*7c478bd9Sstevel@tonic-gate 		for_me = YES;
1278*7c478bd9Sstevel@tonic-gate 	    } else {
1279*7c478bd9Sstevel@tonic-gate 		b_p = b + 1;
1280*7c478bd9Sstevel@tonic-gate 		for_me = NO;
1281*7c478bd9Sstevel@tonic-gate 	    }
1282*7c478bd9Sstevel@tonic-gate 	    if ( (for_me || OldStyle) && (*b_p == '>') ) {
1283*7c478bd9Sstevel@tonic-gate 		/* This is an acceptable '~[uname]>' line */
1284*7c478bd9Sstevel@tonic-gate 		b_p++;
1285*7c478bd9Sstevel@tonic-gate 		if ( (*b_p == '\n') && (silent == YES) ) {
1286*7c478bd9Sstevel@tonic-gate 		    /* end of diversion */
1287*7c478bd9Sstevel@tonic-gate 		    *b_p = '\0';
1288*7c478bd9Sstevel@tonic-gate 		    (void) strcpy(filename, "/dev/null");
1289*7c478bd9Sstevel@tonic-gate 		    if ( file >= 0 && close(file) ) {
1290*7c478bd9Sstevel@tonic-gate 			VERBOSE(gettext(P_Ct_UNDIVERT), b_p);
1291*7c478bd9Sstevel@tonic-gate 			perror(gettext("cu: close failed"));
1292*7c478bd9Sstevel@tonic-gate 			VERBOSE("%s","\r");
1293*7c478bd9Sstevel@tonic-gate 		    }
1294*7c478bd9Sstevel@tonic-gate 		    silent = NO;
1295*7c478bd9Sstevel@tonic-gate 		    blckcnt((long)(-2));
1296*7c478bd9Sstevel@tonic-gate 		    VERBOSE("%s\r\n", b);
1297*7c478bd9Sstevel@tonic-gate 		    VERBOSE(gettext(P_CNTLINES), tic);
1298*7c478bd9Sstevel@tonic-gate 		    VERBOSE(gettext(P_CNTCHAR), count);
1299*7c478bd9Sstevel@tonic-gate 		    file = -1;
1300*7c478bd9Sstevel@tonic-gate 		    p = b;
1301*7c478bd9Sstevel@tonic-gate 		    continue;
1302*7c478bd9Sstevel@tonic-gate 		} else if (*b_p != '\n') {
1303*7c478bd9Sstevel@tonic-gate 		    if ( *b_p == '>' ) {
1304*7c478bd9Sstevel@tonic-gate 			append = 1;
1305*7c478bd9Sstevel@tonic-gate 			b_p++;
1306*7c478bd9Sstevel@tonic-gate 		    }
1307*7c478bd9Sstevel@tonic-gate 		    if ( (for_me || (OldStyle && (*b_p == ':'))) && (silent == NO) ) {
1308*7c478bd9Sstevel@tonic-gate 			/* terminate filename string */
1309*7c478bd9Sstevel@tonic-gate 			*(p-1) = '\0';
1310*7c478bd9Sstevel@tonic-gate 			if ( *b_p == ':' )
1311*7c478bd9Sstevel@tonic-gate 			    b_p++;
1312*7c478bd9Sstevel@tonic-gate 			if ( !EQUALS(filename, b_p) ) {
1313*7c478bd9Sstevel@tonic-gate 			    if ( !Divert  || !EQUALS(filename, "/dev/null") ) {
1314*7c478bd9Sstevel@tonic-gate 				VERBOSE(gettext(P_Bad_DIVERT), b_p);
1315*7c478bd9Sstevel@tonic-gate 				(void) strcpy(filename, "/dev/null");
1316*7c478bd9Sstevel@tonic-gate 				append = 1;
1317*7c478bd9Sstevel@tonic-gate 			    } else {
1318*7c478bd9Sstevel@tonic-gate 				(void) strcpy(filename, b_p);
1319*7c478bd9Sstevel@tonic-gate 			    }
1320*7c478bd9Sstevel@tonic-gate 			}
1321*7c478bd9Sstevel@tonic-gate 			if ( append && ((file=open(filename,O_WRONLY)) >= 0) )
1322*7c478bd9Sstevel@tonic-gate 			    (void)lseek(file, 0L, 2);
1323*7c478bd9Sstevel@tonic-gate 			else
1324*7c478bd9Sstevel@tonic-gate 			    file = creat(filename, PUB_FILEMODE);
1325*7c478bd9Sstevel@tonic-gate 			if (file < 0) {
1326*7c478bd9Sstevel@tonic-gate 			    VERBOSE(gettext(P_Ct_DIVERT), filename);
1327*7c478bd9Sstevel@tonic-gate 			    perror(gettext("cu: open|creat failed"));
1328*7c478bd9Sstevel@tonic-gate 			    VERBOSE("%s","\r");
1329*7c478bd9Sstevel@tonic-gate 			    (void)sleep(5); /* 10 seemed too long*/
1330*7c478bd9Sstevel@tonic-gate 			}
1331*7c478bd9Sstevel@tonic-gate 			silent = YES;
1332*7c478bd9Sstevel@tonic-gate 			count = tic = 0;
1333*7c478bd9Sstevel@tonic-gate 			p = b;
1334*7c478bd9Sstevel@tonic-gate 			continue;
1335*7c478bd9Sstevel@tonic-gate 		    }
1336*7c478bd9Sstevel@tonic-gate 		}
1337*7c478bd9Sstevel@tonic-gate 	    }
1338*7c478bd9Sstevel@tonic-gate 	}
1339*7c478bd9Sstevel@tonic-gate 	/* Regular data, divert if appropriate */
1340*7c478bd9Sstevel@tonic-gate 	if ( silent == YES ) {
1341*7c478bd9Sstevel@tonic-gate 	    if ( file >= 0)
1342*7c478bd9Sstevel@tonic-gate 		(void)write(file, b, (unsigned)(p-b));
1343*7c478bd9Sstevel@tonic-gate 	    count += p-b;	/* tally char count */
1344*7c478bd9Sstevel@tonic-gate 	    ++tic;		/* tally lines */
1345*7c478bd9Sstevel@tonic-gate 	    blckcnt((long)count);
1346*7c478bd9Sstevel@tonic-gate 	}
1347*7c478bd9Sstevel@tonic-gate 	p = b;
1348*7c478bd9Sstevel@tonic-gate     }
1349*7c478bd9Sstevel@tonic-gate     /*
1350*7c478bd9Sstevel@tonic-gate      * we used to tell of lost carrier here, but now
1351*7c478bd9Sstevel@tonic-gate      * defer to _bye() so that escape processes are
1352*7c478bd9Sstevel@tonic-gate      * not interrupted.
1353*7c478bd9Sstevel@tonic-gate      */
1354*7c478bd9Sstevel@tonic-gate     _rcvdead(IOERR);
1355*7c478bd9Sstevel@tonic-gate     return;
1356*7c478bd9Sstevel@tonic-gate }
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate /***************************************************************
1359*7c478bd9Sstevel@tonic-gate  *	change the TTY attributes of the users terminal:
1360*7c478bd9Sstevel@tonic-gate  *	0 means restore attributes to pre-cu status.
1361*7c478bd9Sstevel@tonic-gate  *	1 means set `raw' mode for use during cu session.
1362*7c478bd9Sstevel@tonic-gate  *	2 means like 1 but accept interrupts from the keyboard.
1363*7c478bd9Sstevel@tonic-gate  ***************************************************************/
1364*7c478bd9Sstevel@tonic-gate static void
1365*7c478bd9Sstevel@tonic-gate _mode(arg)
1366*7c478bd9Sstevel@tonic-gate {
1367*7c478bd9Sstevel@tonic-gate     int i;
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call _mode(%d)\r\n", arg);
1370*7c478bd9Sstevel@tonic-gate     if(arg == 0) {
1371*7c478bd9Sstevel@tonic-gate 	if ( Saved_termios )
1372*7c478bd9Sstevel@tonic-gate 		(void)ioctl(TTYIN, TCSETSW, &_Tv0s);
1373*7c478bd9Sstevel@tonic-gate 	else if ( Saved_tty ) {
1374*7c478bd9Sstevel@tonic-gate 		_Tv0.c_lflag = _Tv0s.c_lflag;
1375*7c478bd9Sstevel@tonic-gate 		_Tv0.c_oflag = _Tv0s.c_oflag;
1376*7c478bd9Sstevel@tonic-gate 		_Tv0.c_iflag = _Tv0s.c_iflag;
1377*7c478bd9Sstevel@tonic-gate 		_Tv0.c_cflag = _Tv0s.c_cflag;
1378*7c478bd9Sstevel@tonic-gate 		for(i = 0; i < NCC; i++)
1379*7c478bd9Sstevel@tonic-gate 			_Tv0.c_cc[i] = _Tv0s.c_cc[i];
1380*7c478bd9Sstevel@tonic-gate 		(void)ioctl(TTYIN, TCSETAW, &_Tv0);
1381*7c478bd9Sstevel@tonic-gate 	}
1382*7c478bd9Sstevel@tonic-gate     } else {
1383*7c478bd9Sstevel@tonic-gate 	(void)ioctl(TTYIN, TCGETA, &_Tv);
1384*7c478bd9Sstevel@tonic-gate 	if(arg == 1) {
1385*7c478bd9Sstevel@tonic-gate 	    _Tv.c_iflag &= ~(INLCR | ICRNL | IGNCR | IUCLC);
1386*7c478bd9Sstevel@tonic-gate 	    if ( !term_8bit )
1387*7c478bd9Sstevel@tonic-gate 		_Tv.c_iflag |= ISTRIP;
1388*7c478bd9Sstevel@tonic-gate 	    _Tv.c_oflag |= OPOST;
1389*7c478bd9Sstevel@tonic-gate 	    _Tv.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET);
1390*7c478bd9Sstevel@tonic-gate 	    _Tv.c_lflag &= ~(ICANON | ISIG | ECHO);
1391*7c478bd9Sstevel@tonic-gate 	    if(Ifc == NO)
1392*7c478bd9Sstevel@tonic-gate 		_Tv.c_iflag &= ~IXON;
1393*7c478bd9Sstevel@tonic-gate 	    else
1394*7c478bd9Sstevel@tonic-gate 		_Tv.c_iflag |= IXON;
1395*7c478bd9Sstevel@tonic-gate 	    if(Ofc == NO)
1396*7c478bd9Sstevel@tonic-gate 		_Tv.c_iflag &= ~IXOFF;
1397*7c478bd9Sstevel@tonic-gate 	    else
1398*7c478bd9Sstevel@tonic-gate 		_Tv.c_iflag |= IXOFF;
1399*7c478bd9Sstevel@tonic-gate 	    if(Terminal) {
1400*7c478bd9Sstevel@tonic-gate 		_Tv.c_oflag |= ONLCR;
1401*7c478bd9Sstevel@tonic-gate 		_Tv.c_iflag |= ICRNL;
1402*7c478bd9Sstevel@tonic-gate 	    }
1403*7c478bd9Sstevel@tonic-gate 	    _Tv.c_cc[VEOF] = '\01';
1404*7c478bd9Sstevel@tonic-gate 	    _Tv.c_cc[VEOL] = '\0';
1405*7c478bd9Sstevel@tonic-gate 	}
1406*7c478bd9Sstevel@tonic-gate 	if(arg == 2) {
1407*7c478bd9Sstevel@tonic-gate 	    _Tv.c_iflag |= IXON;
1408*7c478bd9Sstevel@tonic-gate 	    _Tv.c_lflag |= ISIG;
1409*7c478bd9Sstevel@tonic-gate 	}
1410*7c478bd9Sstevel@tonic-gate 	(void)ioctl(TTYIN, TCSETAW, &_Tv);
1411*7c478bd9Sstevel@tonic-gate     }
1412*7c478bd9Sstevel@tonic-gate     return;
1413*7c478bd9Sstevel@tonic-gate }
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate static pid_t
1417*7c478bd9Sstevel@tonic-gate dofork()
1418*7c478bd9Sstevel@tonic-gate {
1419*7c478bd9Sstevel@tonic-gate     register int i;
1420*7c478bd9Sstevel@tonic-gate     pid_t x;
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate     for(i = 0; i < 6; ++i) {
1423*7c478bd9Sstevel@tonic-gate 	if((x = fork()) >= 0) {
1424*7c478bd9Sstevel@tonic-gate 	    return(x);
1425*7c478bd9Sstevel@tonic-gate 	}
1426*7c478bd9Sstevel@tonic-gate     }
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate     if(Debug) perror("dofork");
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate     VERBOSE(gettext(P_Ct_FK),"");
1431*7c478bd9Sstevel@tonic-gate     return(x);
1432*7c478bd9Sstevel@tonic-gate }
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate static int
1435*7c478bd9Sstevel@tonic-gate r_char(fd)
1436*7c478bd9Sstevel@tonic-gate {
1437*7c478bd9Sstevel@tonic-gate     int rtn = 1, rfd;
1438*7c478bd9Sstevel@tonic-gate     char *riobuf;
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate     /* find starting pos in correct buffer in Riobuf	*/
1441*7c478bd9Sstevel@tonic-gate     rfd = RIOFD(fd);
1442*7c478bd9Sstevel@tonic-gate     riobuf = &Riobuf[rfd*WRIOBSZ];
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate     if (Riop[rfd] >= &riobuf[Riocnt[rfd]]) {
1445*7c478bd9Sstevel@tonic-gate 	/* empty read buffer - refill it	*/
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	/*	flush any waiting output	*/
1448*7c478bd9Sstevel@tonic-gate 	if ( (wioflsh(Cn) == NO ) || (wioflsh(TTYOUT) == NO) )
1449*7c478bd9Sstevel@tonic-gate 	    return(NO);
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate 	while((rtn = read(fd, riobuf, WRIOBSZ)) < 0){
1452*7c478bd9Sstevel@tonic-gate 	    if(errno == EINTR) {
1453*7c478bd9Sstevel@tonic-gate 		/* onintrpt() called asynchronously before this line */
1454*7c478bd9Sstevel@tonic-gate 		if(Intrupt == YES) {
1455*7c478bd9Sstevel@tonic-gate 		    /* got a BREAK */
1456*7c478bd9Sstevel@tonic-gate 		    _Cxc = '\0';
1457*7c478bd9Sstevel@tonic-gate 		    return(YES);
1458*7c478bd9Sstevel@tonic-gate 		} else {
1459*7c478bd9Sstevel@tonic-gate 		    /*a signal other than interrupt*/
1460*7c478bd9Sstevel@tonic-gate 		    /*received during read*/
1461*7c478bd9Sstevel@tonic-gate 		    continue;
1462*7c478bd9Sstevel@tonic-gate 		}
1463*7c478bd9Sstevel@tonic-gate 	    } else {
1464*7c478bd9Sstevel@tonic-gate 		CDEBUG(4,"got read error, not EINTR\n\r%s", "");
1465*7c478bd9Sstevel@tonic-gate 		break;			/* something wrong */
1466*7c478bd9Sstevel@tonic-gate 	    }
1467*7c478bd9Sstevel@tonic-gate 	}
1468*7c478bd9Sstevel@tonic-gate 	if (rtn > 0) {
1469*7c478bd9Sstevel@tonic-gate 	    /* reset current position in buffer	*/
1470*7c478bd9Sstevel@tonic-gate 	    /* and count of available chars		*/
1471*7c478bd9Sstevel@tonic-gate 	    Riop[rfd] = riobuf;
1472*7c478bd9Sstevel@tonic-gate 	    Riocnt[rfd] = rtn;
1473*7c478bd9Sstevel@tonic-gate 	}
1474*7c478bd9Sstevel@tonic-gate     }
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate     if ( rtn > 0 ) {
1477*7c478bd9Sstevel@tonic-gate 	_Cxc = *(Riop[rfd]++) & RMASK(fd);	/* mask off appropriate bits */
1478*7c478bd9Sstevel@tonic-gate 	return(YES);
1479*7c478bd9Sstevel@tonic-gate     } else if (rtn == 0) {
1480*7c478bd9Sstevel@tonic-gate 	_Cxc = '\0';
1481*7c478bd9Sstevel@tonic-gate 	return (HUNGUP);
1482*7c478bd9Sstevel@tonic-gate     } else {
1483*7c478bd9Sstevel@tonic-gate 	_Cxc = '\0';
1484*7c478bd9Sstevel@tonic-gate 	return(NO);
1485*7c478bd9Sstevel@tonic-gate     }
1486*7c478bd9Sstevel@tonic-gate }
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate static int
1489*7c478bd9Sstevel@tonic-gate w_char(fd)
1490*7c478bd9Sstevel@tonic-gate {
1491*7c478bd9Sstevel@tonic-gate     int wfd;
1492*7c478bd9Sstevel@tonic-gate     char *wiobuf;
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate     /* find starting pos in correct buffer in Wiobuf	*/
1495*7c478bd9Sstevel@tonic-gate     wfd = WIOFD(fd);
1496*7c478bd9Sstevel@tonic-gate     wiobuf = &Wiobuf[wfd*WRIOBSZ];
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate     if (Wiop[wfd] >= &wiobuf[WRIOBSZ]) {
1499*7c478bd9Sstevel@tonic-gate 	/* full output buffer - flush it */
1500*7c478bd9Sstevel@tonic-gate 	if ( wioflsh(fd) == NO )
1501*7c478bd9Sstevel@tonic-gate 	    return(NO);
1502*7c478bd9Sstevel@tonic-gate     }
1503*7c478bd9Sstevel@tonic-gate     *(Wiop[wfd]++) = _Cxc & WMASK(fd);	/* mask off appropriate bits */
1504*7c478bd9Sstevel@tonic-gate     return(YES);
1505*7c478bd9Sstevel@tonic-gate }
1506*7c478bd9Sstevel@tonic-gate 
1507*7c478bd9Sstevel@tonic-gate /* wioflsh	flush output buffer	*/
1508*7c478bd9Sstevel@tonic-gate static int
1509*7c478bd9Sstevel@tonic-gate wioflsh(fd)
1510*7c478bd9Sstevel@tonic-gate int fd;
1511*7c478bd9Sstevel@tonic-gate {
1512*7c478bd9Sstevel@tonic-gate     int wfd;
1513*7c478bd9Sstevel@tonic-gate     char *wiobuf;
1514*7c478bd9Sstevel@tonic-gate 
1515*7c478bd9Sstevel@tonic-gate     /* find starting pos in correct buffer in Wiobuf	*/
1516*7c478bd9Sstevel@tonic-gate     wfd = WIOFD(fd);
1517*7c478bd9Sstevel@tonic-gate     wiobuf = &Wiobuf[wfd*WRIOBSZ];
1518*7c478bd9Sstevel@tonic-gate 
1519*7c478bd9Sstevel@tonic-gate     if (Wiop[wfd] > wiobuf) {
1520*7c478bd9Sstevel@tonic-gate 	/* there's something in the buffer */
1521*7c478bd9Sstevel@tonic-gate 	while(write(fd, wiobuf, (Wiop[wfd] - wiobuf)) < 0) {
1522*7c478bd9Sstevel@tonic-gate 	    if(errno == EINTR) {
1523*7c478bd9Sstevel@tonic-gate 		if(Intrupt == YES) {
1524*7c478bd9Sstevel@tonic-gate 		    VERBOSE("\ncu: Output blocked\r\n%s", "");
1525*7c478bd9Sstevel@tonic-gate 		    _quit(IOERR);
1526*7c478bd9Sstevel@tonic-gate 		} else
1527*7c478bd9Sstevel@tonic-gate 		    continue;	/* alarm went off */
1528*7c478bd9Sstevel@tonic-gate 	    } else {
1529*7c478bd9Sstevel@tonic-gate 		Wiop[wfd] = wiobuf;
1530*7c478bd9Sstevel@tonic-gate 		return(NO);			/* bad news */
1531*7c478bd9Sstevel@tonic-gate 	    }
1532*7c478bd9Sstevel@tonic-gate 	}
1533*7c478bd9Sstevel@tonic-gate     }
1534*7c478bd9Sstevel@tonic-gate     Wiop[wfd] = wiobuf;
1535*7c478bd9Sstevel@tonic-gate     return(YES);
1536*7c478bd9Sstevel@tonic-gate }
1537*7c478bd9Sstevel@tonic-gate 
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate static void
1540*7c478bd9Sstevel@tonic-gate _w_str(string)
1541*7c478bd9Sstevel@tonic-gate register char *string;
1542*7c478bd9Sstevel@tonic-gate {
1543*7c478bd9Sstevel@tonic-gate     int len;
1544*7c478bd9Sstevel@tonic-gate 
1545*7c478bd9Sstevel@tonic-gate     len = strlen(string);
1546*7c478bd9Sstevel@tonic-gate     if ( write(Cn, string, (unsigned)len) != len )
1547*7c478bd9Sstevel@tonic-gate 	VERBOSE(gettext(P_LINE_GONE),"");
1548*7c478bd9Sstevel@tonic-gate     return;
1549*7c478bd9Sstevel@tonic-gate }
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1552*7c478bd9Sstevel@tonic-gate static void
1553*7c478bd9Sstevel@tonic-gate _onintrpt(sig)
1554*7c478bd9Sstevel@tonic-gate int sig;
1555*7c478bd9Sstevel@tonic-gate {
1556*7c478bd9Sstevel@tonic-gate     (void)signal(SIGINT, _onintrpt);
1557*7c478bd9Sstevel@tonic-gate     (void)signal(SIGQUIT, _onintrpt);
1558*7c478bd9Sstevel@tonic-gate     Intrupt = YES;
1559*7c478bd9Sstevel@tonic-gate     return;
1560*7c478bd9Sstevel@tonic-gate }
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate static void
1563*7c478bd9Sstevel@tonic-gate _rcvdead(arg)	/* this is executed only in the receive process */
1564*7c478bd9Sstevel@tonic-gate int arg;
1565*7c478bd9Sstevel@tonic-gate {
1566*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call _rcvdead(%d)\r\n", arg);
1567*7c478bd9Sstevel@tonic-gate     (void)kill(getppid(), SIGUSR1);
1568*7c478bd9Sstevel@tonic-gate     exit((arg == SIGHUP)? SIGHUP: arg);
1569*7c478bd9Sstevel@tonic-gate     /*NOTREACHED*/
1570*7c478bd9Sstevel@tonic-gate }
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate static void
1573*7c478bd9Sstevel@tonic-gate _quit(arg)	/* this is executed only in the parent process */
1574*7c478bd9Sstevel@tonic-gate int arg;
1575*7c478bd9Sstevel@tonic-gate {
1576*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call _quit(%d)\r\n", arg);
1577*7c478bd9Sstevel@tonic-gate     (void)kill(Child, SIGKILL);
1578*7c478bd9Sstevel@tonic-gate     _bye(arg);
1579*7c478bd9Sstevel@tonic-gate     /*NOTREACHED*/
1580*7c478bd9Sstevel@tonic-gate }
1581*7c478bd9Sstevel@tonic-gate 
1582*7c478bd9Sstevel@tonic-gate static void
1583*7c478bd9Sstevel@tonic-gate _bye(arg)	/* this is executed only in the parent proccess */
1584*7c478bd9Sstevel@tonic-gate int arg;
1585*7c478bd9Sstevel@tonic-gate {
1586*7c478bd9Sstevel@tonic-gate     int status;
1587*7c478bd9Sstevel@tonic-gate     pid_t obit;
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate     if ( Shell > 0 )
1590*7c478bd9Sstevel@tonic-gate 	while ((obit = wait(&status)) != Shell) {
1591*7c478bd9Sstevel@tonic-gate 	    if (obit == -1 && errno != EINTR)
1592*7c478bd9Sstevel@tonic-gate 		break;
1593*7c478bd9Sstevel@tonic-gate 	    /* _receive (Child) may have ended - check it out */
1594*7c478bd9Sstevel@tonic-gate 	    if (obit == Child)
1595*7c478bd9Sstevel@tonic-gate 		Child = 0;
1596*7c478bd9Sstevel@tonic-gate 	}
1597*7c478bd9Sstevel@tonic-gate 
1598*7c478bd9Sstevel@tonic-gate     /* give user customary message after escape command returns */
1599*7c478bd9Sstevel@tonic-gate     if (arg == SIGUSR1)
1600*7c478bd9Sstevel@tonic-gate 	VERBOSE("\r\nLost Carrier\r\n%s", "");
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call _bye(%d)\r\n", arg);
1603*7c478bd9Sstevel@tonic-gate 
1604*7c478bd9Sstevel@tonic-gate     (void)signal(SIGINT, SIG_IGN);
1605*7c478bd9Sstevel@tonic-gate     (void)signal(SIGQUIT, SIG_IGN);
1606*7c478bd9Sstevel@tonic-gate     /* if _receive() ended already, don't wait for it again */
1607*7c478bd9Sstevel@tonic-gate     if ( Child != 0 )
1608*7c478bd9Sstevel@tonic-gate 	while ((obit = wait(&status)) != Child)
1609*7c478bd9Sstevel@tonic-gate 	    if (obit == -1 && errno != EINTR)
1610*7c478bd9Sstevel@tonic-gate 		break;
1611*7c478bd9Sstevel@tonic-gate     VERBOSE("\r\nDisconnected\007\r\n%s", "");
1612*7c478bd9Sstevel@tonic-gate     cleanup((arg == SIGUSR1)? (status >>= 8): arg);
1613*7c478bd9Sstevel@tonic-gate     /*NOTREACHED*/
1614*7c478bd9Sstevel@tonic-gate }
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate 
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate void
1619*7c478bd9Sstevel@tonic-gate cleanup(code) 	/*this is executed only in the parent process*/
1620*7c478bd9Sstevel@tonic-gate int code;	/*Closes device; removes lock files	  */
1621*7c478bd9Sstevel@tonic-gate {
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate     CDEBUG(4,"call cleanup(%d)\r\n", code);
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate     if (Docmd) {
1626*7c478bd9Sstevel@tonic-gate 	if (Child > 0)
1627*7c478bd9Sstevel@tonic-gate 	    (void)kill(Child, SIGTERM);
1628*7c478bd9Sstevel@tonic-gate     } else
1629*7c478bd9Sstevel@tonic-gate 	(void) setuid(Euid);
1630*7c478bd9Sstevel@tonic-gate     if(Cn > 0) {
1631*7c478bd9Sstevel@tonic-gate 	fchmod(Cn, Dev_mode);
1632*7c478bd9Sstevel@tonic-gate 	fd_rmlock(Cn);
1633*7c478bd9Sstevel@tonic-gate 	(void)close(Cn);
1634*7c478bd9Sstevel@tonic-gate     }
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 
1637*7c478bd9Sstevel@tonic-gate     rmlock((char*) NULL);	/* remove all lock files for this process */
1638*7c478bd9Sstevel@tonic-gate     if (!Docmd)
1639*7c478bd9Sstevel@tonic-gate 	_mode(0);
1640*7c478bd9Sstevel@tonic-gate     exit(code);		/* code=negative for signal causing disconnect*/
1641*7c478bd9Sstevel@tonic-gate }
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 
1645*7c478bd9Sstevel@tonic-gate void
1646*7c478bd9Sstevel@tonic-gate tdmp(arg)
1647*7c478bd9Sstevel@tonic-gate int arg;
1648*7c478bd9Sstevel@tonic-gate {
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate     struct termio xv;
1651*7c478bd9Sstevel@tonic-gate     int i;
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate     VERBOSE("\rdevice status for fd=%d\r\n", arg);
1654*7c478bd9Sstevel@tonic-gate     VERBOSE("F_GETFL=%o,", fcntl(arg, F_GETFL,1));
1655*7c478bd9Sstevel@tonic-gate     if(ioctl(arg, TCGETA, &xv) < 0) {
1656*7c478bd9Sstevel@tonic-gate 	char	buf[100];
1657*7c478bd9Sstevel@tonic-gate 	i = errno;
1658*7c478bd9Sstevel@tonic-gate 	(void)snprintf(buf, sizeof (buf), gettext("\rtdmp for fd=%d"), arg);
1659*7c478bd9Sstevel@tonic-gate 	errno = i;
1660*7c478bd9Sstevel@tonic-gate 	perror(buf);
1661*7c478bd9Sstevel@tonic-gate 	return;
1662*7c478bd9Sstevel@tonic-gate     }
1663*7c478bd9Sstevel@tonic-gate     VERBOSE("iflag=`%o',", xv.c_iflag);
1664*7c478bd9Sstevel@tonic-gate     VERBOSE("oflag=`%o',", xv.c_oflag);
1665*7c478bd9Sstevel@tonic-gate     VERBOSE("cflag=`%o',", xv.c_cflag);
1666*7c478bd9Sstevel@tonic-gate     VERBOSE("lflag=`%o',", xv.c_lflag);
1667*7c478bd9Sstevel@tonic-gate     VERBOSE("line=`%o'\r\n", xv.c_line);
1668*7c478bd9Sstevel@tonic-gate     VERBOSE("cc[0]=`%o',",  xv.c_cc[0]);
1669*7c478bd9Sstevel@tonic-gate     for(i=1; i<8; ++i) {
1670*7c478bd9Sstevel@tonic-gate 	VERBOSE("[%d]=", i);
1671*7c478bd9Sstevel@tonic-gate 	VERBOSE("`%o',",xv.c_cc[i]);
1672*7c478bd9Sstevel@tonic-gate     }
1673*7c478bd9Sstevel@tonic-gate     VERBOSE("\r\n%s", "");
1674*7c478bd9Sstevel@tonic-gate     return;
1675*7c478bd9Sstevel@tonic-gate }
1676*7c478bd9Sstevel@tonic-gate 
1677*7c478bd9Sstevel@tonic-gate 
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate static void
1680*7c478bd9Sstevel@tonic-gate sysname(name)
1681*7c478bd9Sstevel@tonic-gate char * name;
1682*7c478bd9Sstevel@tonic-gate {
1683*7c478bd9Sstevel@tonic-gate 
1684*7c478bd9Sstevel@tonic-gate     register char *s;
1685*7c478bd9Sstevel@tonic-gate 
1686*7c478bd9Sstevel@tonic-gate     if(uname(&utsn) < 0)
1687*7c478bd9Sstevel@tonic-gate 	s = "Local";
1688*7c478bd9Sstevel@tonic-gate     else
1689*7c478bd9Sstevel@tonic-gate 	s = utsn.nodename;
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate     strcpy(name, s);
1692*7c478bd9Sstevel@tonic-gate     return;
1693*7c478bd9Sstevel@tonic-gate }
1694*7c478bd9Sstevel@tonic-gate 
1695*7c478bd9Sstevel@tonic-gate 
1696*7c478bd9Sstevel@tonic-gate static void
1697*7c478bd9Sstevel@tonic-gate blckcnt(count)
1698*7c478bd9Sstevel@tonic-gate long count;
1699*7c478bd9Sstevel@tonic-gate {
1700*7c478bd9Sstevel@tonic-gate     static long lcharcnt = 0;
1701*7c478bd9Sstevel@tonic-gate     register long c1, c2;
1702*7c478bd9Sstevel@tonic-gate     register int i;
1703*7c478bd9Sstevel@tonic-gate     char c;
1704*7c478bd9Sstevel@tonic-gate 
1705*7c478bd9Sstevel@tonic-gate     if(count == (long) (-1)) {	/* initialization call */
1706*7c478bd9Sstevel@tonic-gate 	lcharcnt = 0;
1707*7c478bd9Sstevel@tonic-gate 	return;
1708*7c478bd9Sstevel@tonic-gate     }
1709*7c478bd9Sstevel@tonic-gate     c1 = lcharcnt/BUFSIZ;
1710*7c478bd9Sstevel@tonic-gate     if(count != (long)(-2)) {	/* regular call */
1711*7c478bd9Sstevel@tonic-gate 	c2 = count/BUFSIZ;
1712*7c478bd9Sstevel@tonic-gate 	for(i = c1; i++ < c2;) {
1713*7c478bd9Sstevel@tonic-gate 	    c = '0' + i%10;
1714*7c478bd9Sstevel@tonic-gate 	    write(2, &c, 1);
1715*7c478bd9Sstevel@tonic-gate 	    if(i%NPL == 0)
1716*7c478bd9Sstevel@tonic-gate 		write(2, "\n\r", 2);
1717*7c478bd9Sstevel@tonic-gate 	}
1718*7c478bd9Sstevel@tonic-gate 	lcharcnt = count;
1719*7c478bd9Sstevel@tonic-gate     } else {
1720*7c478bd9Sstevel@tonic-gate 	c2 = (lcharcnt + BUFSIZ -1)/BUFSIZ;
1721*7c478bd9Sstevel@tonic-gate 	if(c1 != c2)
1722*7c478bd9Sstevel@tonic-gate 	    write(2, "+\n\r", 3);
1723*7c478bd9Sstevel@tonic-gate 	else if(c2%NPL != 0)
1724*7c478bd9Sstevel@tonic-gate 	    write(2, "\n\r", 2);
1725*7c478bd9Sstevel@tonic-gate 	lcharcnt = 0;
1726*7c478bd9Sstevel@tonic-gate     }
1727*7c478bd9Sstevel@tonic-gate     return;
1728*7c478bd9Sstevel@tonic-gate }
1729*7c478bd9Sstevel@tonic-gate 
1730*7c478bd9Sstevel@tonic-gate /*VARARGS*/
1731*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1732*7c478bd9Sstevel@tonic-gate void
1733*7c478bd9Sstevel@tonic-gate assert (s1, s2, i1, s3, i2)
1734*7c478bd9Sstevel@tonic-gate char *s1, *s2, *s3;
1735*7c478bd9Sstevel@tonic-gate int i1, i2;
1736*7c478bd9Sstevel@tonic-gate { }		/* for ASSERT in gnamef.c */
1737*7c478bd9Sstevel@tonic-gate 
1738*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1739*7c478bd9Sstevel@tonic-gate void
1740*7c478bd9Sstevel@tonic-gate logent (s1, s2)
1741*7c478bd9Sstevel@tonic-gate char *s1, *s2;
1742*7c478bd9Sstevel@tonic-gate { }		/* so we can load ulockf() */
1743